diff options
author | 2016-03-18 20:57:35 +0000 | |
---|---|---|
committer | 2016-03-18 20:57:35 +0000 | |
commit | 3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d (patch) | |
tree | fae74c33cfed05de603785294593275f1901c861 /core/parse/parsing_test.go | |
download | coredns-3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d.tar.gz coredns-3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d.tar.zst coredns-3ec0d9fe6b133a64712ae69fd712c14ad1a71f4d.zip |
First commit
Diffstat (limited to 'core/parse/parsing_test.go')
-rw-r--r-- | core/parse/parsing_test.go | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/core/parse/parsing_test.go b/core/parse/parsing_test.go new file mode 100644 index 000000000..493c0fff9 --- /dev/null +++ b/core/parse/parsing_test.go @@ -0,0 +1,477 @@ +package parse + +import ( + "os" + "strings" + "testing" +) + +func TestStandardAddress(t *testing.T) { + for i, test := range []struct { + input string + scheme, host, port string + shouldErr bool + }{ + {`localhost`, "", "localhost", "", false}, + {`localhost:1234`, "", "localhost", "1234", false}, + {`localhost:`, "", "localhost", "", false}, + {`0.0.0.0`, "", "0.0.0.0", "", false}, + {`127.0.0.1:1234`, "", "127.0.0.1", "1234", false}, + {`:1234`, "", "", "1234", false}, + {`[::1]`, "", "::1", "", false}, + {`[::1]:1234`, "", "::1", "1234", false}, + {`:`, "", "", "", false}, + {`localhost:http`, "http", "localhost", "80", false}, + {`localhost:https`, "https", "localhost", "443", false}, + {`:http`, "http", "", "80", false}, + {`:https`, "https", "", "443", false}, + {`http://localhost:https`, "", "", "", true}, // conflict + {`http://localhost:http`, "", "", "", true}, // repeated scheme + {`http://localhost:443`, "", "", "", true}, // not conventional + {`https://localhost:80`, "", "", "", true}, // not conventional + {`http://localhost`, "http", "localhost", "80", false}, + {`https://localhost`, "https", "localhost", "443", false}, + {`http://127.0.0.1`, "http", "127.0.0.1", "80", false}, + {`https://127.0.0.1`, "https", "127.0.0.1", "443", false}, + {`http://[::1]`, "http", "::1", "80", false}, + {`http://localhost:1234`, "http", "localhost", "1234", false}, + {`https://127.0.0.1:1234`, "https", "127.0.0.1", "1234", false}, + {`http://[::1]:1234`, "http", "::1", "1234", false}, + {``, "", "", "", false}, + {`::1`, "", "::1", "", true}, + {`localhost::`, "", "localhost::", "", true}, + {`#$%@`, "", "#$%@", "", true}, + } { + actual, err := standardAddress(test.input) + + if err != nil && !test.shouldErr { + t.Errorf("Test %d (%s): Expected no error, but had error: %v", i, test.input, err) + } + if err == nil && test.shouldErr { + t.Errorf("Test %d (%s): Expected error, but had none", i, test.input) + } + + if actual.Scheme != test.scheme { + t.Errorf("Test %d (%s): Expected scheme '%s', got '%s'", i, test.input, test.scheme, actual.Scheme) + } + if actual.Host != test.host { + t.Errorf("Test %d (%s): Expected host '%s', got '%s'", i, test.input, test.host, actual.Host) + } + if actual.Port != test.port { + t.Errorf("Test %d (%s): Expected port '%s', got '%s'", i, test.input, test.port, actual.Port) + } + } +} + +func TestParseOneAndImport(t *testing.T) { + setupParseTests() + + testParseOne := func(input string) (ServerBlock, error) { + p := testParser(input) + p.Next() // parseOne doesn't call Next() to start, so we must + err := p.parseOne() + return p.block, err + } + + for i, test := range []struct { + input string + shouldErr bool + addresses []address + tokens map[string]int // map of directive name to number of tokens expected + }{ + {`localhost`, false, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{}}, + + {`localhost + dir1`, false, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 1, + }}, + + {`localhost:1234 + dir1 foo bar`, false, []address{ + {"localhost:1234", "", "localhost", "1234"}, + }, map[string]int{ + "dir1": 3, + }}, + + {`localhost { + dir1 + }`, false, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 1, + }}, + + {`localhost:1234 { + dir1 foo bar + dir2 + }`, false, []address{ + {"localhost:1234", "", "localhost", "1234"}, + }, map[string]int{ + "dir1": 3, + "dir2": 1, + }}, + + {`http://localhost https://localhost + dir1 foo bar`, false, []address{ + {"http://localhost", "http", "localhost", "80"}, + {"https://localhost", "https", "localhost", "443"}, + }, map[string]int{ + "dir1": 3, + }}, + + {`http://localhost https://localhost { + dir1 foo bar + }`, false, []address{ + {"http://localhost", "http", "localhost", "80"}, + {"https://localhost", "https", "localhost", "443"}, + }, map[string]int{ + "dir1": 3, + }}, + + {`http://localhost, https://localhost { + dir1 foo bar + }`, false, []address{ + {"http://localhost", "http", "localhost", "80"}, + {"https://localhost", "https", "localhost", "443"}, + }, map[string]int{ + "dir1": 3, + }}, + + {`http://localhost, { + }`, true, []address{ + {"http://localhost", "http", "localhost", "80"}, + }, map[string]int{}}, + + {`host1:80, http://host2.com + dir1 foo bar + dir2 baz`, false, []address{ + {"host1:80", "", "host1", "80"}, + {"http://host2.com", "http", "host2.com", "80"}, + }, map[string]int{ + "dir1": 3, + "dir2": 2, + }}, + + {`http://host1.com, + http://host2.com, + https://host3.com`, false, []address{ + {"http://host1.com", "http", "host1.com", "80"}, + {"http://host2.com", "http", "host2.com", "80"}, + {"https://host3.com", "https", "host3.com", "443"}, + }, map[string]int{}}, + + {`http://host1.com:1234, https://host2.com + dir1 foo { + bar baz + } + dir2`, false, []address{ + {"http://host1.com:1234", "http", "host1.com", "1234"}, + {"https://host2.com", "https", "host2.com", "443"}, + }, map[string]int{ + "dir1": 6, + "dir2": 1, + }}, + + {`127.0.0.1 + dir1 { + bar baz + } + dir2 { + foo bar + }`, false, []address{ + {"127.0.0.1", "", "127.0.0.1", ""}, + }, map[string]int{ + "dir1": 5, + "dir2": 5, + }}, + + {`127.0.0.1 + unknown_directive`, true, []address{ + {"127.0.0.1", "", "127.0.0.1", ""}, + }, map[string]int{}}, + + {`localhost + dir1 { + foo`, true, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 3, + }}, + + {`localhost + dir1 { + }`, false, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 3, + }}, + + {`localhost + dir1 { + } }`, true, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 3, + }}, + + {`localhost + dir1 { + nested { + foo + } + } + dir2 foo bar`, false, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 7, + "dir2": 3, + }}, + + {``, false, []address{}, map[string]int{}}, + + {`localhost + dir1 arg1 + import import_test1.txt`, false, []address{ + {"localhost", "", "localhost", ""}, + }, map[string]int{ + "dir1": 2, + "dir2": 3, + "dir3": 1, + }}, + + {`import import_test2.txt`, false, []address{ + {"host1", "", "host1", ""}, + }, map[string]int{ + "dir1": 1, + "dir2": 2, + }}, + + {`import import_test1.txt import_test2.txt`, true, []address{}, map[string]int{}}, + + {`import not_found.txt`, true, []address{}, map[string]int{}}, + + {`""`, false, []address{}, map[string]int{}}, + + {``, false, []address{}, map[string]int{}}, + } { + result, err := testParseOne(test.input) + + if test.shouldErr && err == nil { + t.Errorf("Test %d: Expected an error, but didn't get one", i) + } + if !test.shouldErr && err != nil { + t.Errorf("Test %d: Expected no error, but got: %v", i, err) + } + + if len(result.Addresses) != len(test.addresses) { + t.Errorf("Test %d: Expected %d addresses, got %d", + i, len(test.addresses), len(result.Addresses)) + continue + } + for j, addr := range result.Addresses { + if addr.Host != test.addresses[j].Host { + t.Errorf("Test %d, address %d: Expected host to be '%s', but was '%s'", + i, j, test.addresses[j].Host, addr.Host) + } + if addr.Port != test.addresses[j].Port { + t.Errorf("Test %d, address %d: Expected port to be '%s', but was '%s'", + i, j, test.addresses[j].Port, addr.Port) + } + } + + if len(result.Tokens) != len(test.tokens) { + t.Errorf("Test %d: Expected %d directives, had %d", + i, len(test.tokens), len(result.Tokens)) + continue + } + for directive, tokens := range result.Tokens { + if len(tokens) != test.tokens[directive] { + t.Errorf("Test %d, directive '%s': Expected %d tokens, counted %d", + i, directive, test.tokens[directive], len(tokens)) + continue + } + } + } +} + +func TestParseAll(t *testing.T) { + setupParseTests() + + for i, test := range []struct { + input string + shouldErr bool + addresses [][]address // addresses per server block, in order + }{ + {`localhost`, false, [][]address{ + {{"localhost", "", "localhost", ""}}, + }}, + + {`localhost:1234`, false, [][]address{ + {{"localhost:1234", "", "localhost", "1234"}}, + }}, + + {`localhost:1234 { + } + localhost:2015 { + }`, false, [][]address{ + {{"localhost:1234", "", "localhost", "1234"}}, + {{"localhost:2015", "", "localhost", "2015"}}, + }}, + + {`localhost:1234, http://host2`, false, [][]address{ + {{"localhost:1234", "", "localhost", "1234"}, {"http://host2", "http", "host2", "80"}}, + }}, + + {`localhost:1234, http://host2,`, true, [][]address{}}, + + {`http://host1.com, http://host2.com { + } + https://host3.com, https://host4.com { + }`, false, [][]address{ + {{"http://host1.com", "http", "host1.com", "80"}, {"http://host2.com", "http", "host2.com", "80"}}, + {{"https://host3.com", "https", "host3.com", "443"}, {"https://host4.com", "https", "host4.com", "443"}}, + }}, + + {`import import_glob*.txt`, false, [][]address{ + {{"glob0.host0", "", "glob0.host0", ""}}, + {{"glob0.host1", "", "glob0.host1", ""}}, + {{"glob1.host0", "", "glob1.host0", ""}}, + {{"glob2.host0", "", "glob2.host0", ""}}, + }}, + } { + p := testParser(test.input) + blocks, err := p.parseAll() + + if test.shouldErr && err == nil { + t.Errorf("Test %d: Expected an error, but didn't get one", i) + } + if !test.shouldErr && err != nil { + t.Errorf("Test %d: Expected no error, but got: %v", i, err) + } + + if len(blocks) != len(test.addresses) { + t.Errorf("Test %d: Expected %d server blocks, got %d", + i, len(test.addresses), len(blocks)) + continue + } + for j, block := range blocks { + if len(block.Addresses) != len(test.addresses[j]) { + t.Errorf("Test %d: Expected %d addresses in block %d, got %d", + i, len(test.addresses[j]), j, len(block.Addresses)) + continue + } + for k, addr := range block.Addresses { + if addr.Host != test.addresses[j][k].Host { + t.Errorf("Test %d, block %d, address %d: Expected host to be '%s', but was '%s'", + i, j, k, test.addresses[j][k].Host, addr.Host) + } + if addr.Port != test.addresses[j][k].Port { + t.Errorf("Test %d, block %d, address %d: Expected port to be '%s', but was '%s'", + i, j, k, test.addresses[j][k].Port, addr.Port) + } + } + } + } +} + +func TestEnvironmentReplacement(t *testing.T) { + setupParseTests() + + os.Setenv("PORT", "8080") + os.Setenv("ADDRESS", "servername.com") + os.Setenv("FOOBAR", "foobar") + + // basic test; unix-style env vars + p := testParser(`{$ADDRESS}`) + blocks, _ := p.parseAll() + if actual, expected := blocks[0].Addresses[0].Host, "servername.com"; expected != actual { + t.Errorf("Expected host to be '%s' but was '%s'", expected, actual) + } + + // multiple vars per token + p = testParser(`{$ADDRESS}:{$PORT}`) + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Addresses[0].Host, "servername.com"; expected != actual { + t.Errorf("Expected host to be '%s' but was '%s'", expected, actual) + } + if actual, expected := blocks[0].Addresses[0].Port, "8080"; expected != actual { + t.Errorf("Expected port to be '%s' but was '%s'", expected, actual) + } + + // windows-style var and unix style in same token + p = testParser(`{%ADDRESS%}:{$PORT}`) + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Addresses[0].Host, "servername.com"; expected != actual { + t.Errorf("Expected host to be '%s' but was '%s'", expected, actual) + } + if actual, expected := blocks[0].Addresses[0].Port, "8080"; expected != actual { + t.Errorf("Expected port to be '%s' but was '%s'", expected, actual) + } + + // reverse order + p = testParser(`{$ADDRESS}:{%PORT%}`) + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Addresses[0].Host, "servername.com"; expected != actual { + t.Errorf("Expected host to be '%s' but was '%s'", expected, actual) + } + if actual, expected := blocks[0].Addresses[0].Port, "8080"; expected != actual { + t.Errorf("Expected port to be '%s' but was '%s'", expected, actual) + } + + // env var in server block body as argument + p = testParser(":{%PORT%}\ndir1 {$FOOBAR}") + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Addresses[0].Port, "8080"; expected != actual { + t.Errorf("Expected port to be '%s' but was '%s'", expected, actual) + } + if actual, expected := blocks[0].Tokens["dir1"][1].text, "foobar"; expected != actual { + t.Errorf("Expected argument to be '%s' but was '%s'", expected, actual) + } + + // combined windows env vars in argument + p = testParser(":{%PORT%}\ndir1 {%ADDRESS%}/{%FOOBAR%}") + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Tokens["dir1"][1].text, "servername.com/foobar"; expected != actual { + t.Errorf("Expected argument to be '%s' but was '%s'", expected, actual) + } + + // malformed env var (windows) + p = testParser(":1234\ndir1 {%ADDRESS}") + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Tokens["dir1"][1].text, "{%ADDRESS}"; expected != actual { + t.Errorf("Expected host to be '%s' but was '%s'", expected, actual) + } + + // malformed (non-existent) env var (unix) + p = testParser(`:{$PORT$}`) + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Addresses[0].Port, ""; expected != actual { + t.Errorf("Expected port to be '%s' but was '%s'", expected, actual) + } + + // in quoted field + p = testParser(":1234\ndir1 \"Test {$FOOBAR} test\"") + blocks, _ = p.parseAll() + if actual, expected := blocks[0].Tokens["dir1"][1].text, "Test foobar test"; expected != actual { + t.Errorf("Expected argument to be '%s' but was '%s'", expected, actual) + } +} + +func setupParseTests() { + // Set up some bogus directives for testing + ValidDirectives = map[string]struct{}{ + "dir1": {}, + "dir2": {}, + "dir3": {}, + } +} + +func testParser(input string) parser { + buf := strings.NewReader(input) + p := parser{Dispenser: NewDispenser("Test", buf), checkDirectives: true} + return p +} |