mirror of
https://github.com/foxcpp/maddy.git
synced 2025-04-05 05:57:39 +03:00
205 lines
4.3 KiB
Go
205 lines
4.3 KiB
Go
package maps
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/foxcpp/maddy/internal/config"
|
|
"github.com/foxcpp/maddy/internal/testutils"
|
|
)
|
|
|
|
func TestReadFile(t *testing.T) {
|
|
test := func(file string, expected map[string]string) {
|
|
t.Helper()
|
|
|
|
f, err := ioutil.TempFile("", "maddy-tests-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(f.Name())
|
|
defer f.Close()
|
|
if _, err := f.WriteString(file); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
actual := map[string]string{}
|
|
err = readFile(f.Name(), actual)
|
|
if expected == nil {
|
|
if err == nil {
|
|
t.Errorf("expected failure, got %+v", actual)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Errorf("unexpected failure: %v", err)
|
|
return
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Errorf("wrong results\n want %+v\n got %+v", expected, actual)
|
|
}
|
|
}
|
|
|
|
test("a: b", map[string]string{"a": "b"})
|
|
test("a@example.org: b@example.com", map[string]string{"a@example.org": "b@example.com"})
|
|
test(`"a @ a"@example.org: b@example.com`, map[string]string{`"a @ a"@example.org`: "b@example.com"})
|
|
test(`a@example.org: "b @ b"@example.com`, map[string]string{`a@example.org`: `"b @ b"@example.com`})
|
|
test(`"a @ a": "b @ b"`, map[string]string{`"a @ a"`: `"b @ b"`})
|
|
test("a: b, c", map[string]string{"a": "b, c"})
|
|
test(": b", nil)
|
|
test(":", nil)
|
|
test("aaa", map[string]string{"aaa": ""})
|
|
test(": b", nil)
|
|
test(" testing@example.com : arbitrary-whitespace@example.org ",
|
|
map[string]string{"testing@example.com": "arbitrary-whitespace@example.org"})
|
|
test(`# skip comments
|
|
a: b`, map[string]string{"a": "b"})
|
|
test(`# and empty lines
|
|
|
|
a: b`, map[string]string{"a": "b"})
|
|
test("# with whitespace too\n \na: b", map[string]string{"a": "b"})
|
|
}
|
|
|
|
func TestFileReload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const file = `cat: dog`
|
|
|
|
f, err := ioutil.TempFile("", "maddy-tests-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(f.Name())
|
|
if _, err := f.WriteString(file); err != nil {
|
|
f.Close()
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
mod, err := NewFile("", "", nil, []string{f.Name()})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := mod.(*File)
|
|
m.log = testutils.Logger(t, "file_map")
|
|
defer m.Close()
|
|
|
|
if err := mod.Init(&config.Map{Block: &config.Node{}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// This delay is somehow important. Not sure why.
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
if err := ioutil.WriteFile(f.Name(), []byte("dog: cat"), os.ModePerm); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
time.Sleep(reloadInterval + 50*time.Millisecond)
|
|
m.mLck.RLock()
|
|
if m.m["dog"] != "" {
|
|
m.mLck.RUnlock()
|
|
break
|
|
}
|
|
m.mLck.RUnlock()
|
|
}
|
|
|
|
m.mLck.RLock()
|
|
defer m.mLck.RUnlock()
|
|
if m.m["dog"] == "" {
|
|
t.Fatal("New m were not loaded")
|
|
}
|
|
}
|
|
|
|
func TestFileReload_Broken(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const file = `cat: dog`
|
|
|
|
f, err := ioutil.TempFile("", "maddy-tests-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(f.Name())
|
|
if _, err := f.WriteString(file); err != nil {
|
|
f.Close()
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
mod, err := NewFile("", "", nil, []string{f.Name()})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := mod.(*File)
|
|
m.log = testutils.Logger(t, FileModName)
|
|
defer m.Close()
|
|
|
|
if err := mod.Init(&config.Map{Block: &config.Node{}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// This delay is somehow important. Not sure why.
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
if err := ioutil.WriteFile(f.Name(), []byte(":"), os.ModePerm); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
time.Sleep(3 * reloadInterval)
|
|
|
|
m.mLck.RLock()
|
|
defer m.mLck.RUnlock()
|
|
if m.m["cat"] == "" {
|
|
t.Fatal("New m were loaded or map changed", m.m)
|
|
}
|
|
}
|
|
|
|
func TestFileReload_Removed(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const file = `cat: dog`
|
|
|
|
f, err := ioutil.TempFile("", "maddy-tests-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := f.WriteString(file); err != nil {
|
|
f.Close()
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
mod, err := NewFile("", "", nil, []string{f.Name()})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := mod.(*File)
|
|
m.log = testutils.Logger(t, FileModName)
|
|
defer m.Close()
|
|
|
|
if err := mod.Init(&config.Map{Block: &config.Node{}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// This delay is somehow important. Not sure why.
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
os.Remove(f.Name())
|
|
|
|
time.Sleep(3 * reloadInterval)
|
|
|
|
m.mLck.RLock()
|
|
defer m.mLck.RUnlock()
|
|
if m.m["cat"] != "" {
|
|
t.Fatal("Old m are still loaded")
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
reloadInterval = 250 * time.Millisecond
|
|
}
|