mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	First commit
This commit is contained in:
		
							
								
								
									
										477
									
								
								core/parse/parsing_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										477
									
								
								core/parse/parsing_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user