diff options
author | 2022-09-08 14:56:27 -0400 | |
---|---|---|
committer | 2022-09-08 14:56:27 -0400 | |
commit | b56b080a7c1125cd97c0a2edd7ae21bc1bdcd2a5 (patch) | |
tree | 1494a9542db6d6f69db39113734c8518a6701daf /test | |
parent | 1f0a41a66597cb8ab4aace8ea5b5bad880bcd23b (diff) | |
download | coredns-b56b080a7c1125cd97c0a2edd7ae21bc1bdcd2a5.tar.gz coredns-b56b080a7c1125cd97c0a2edd7ae21bc1bdcd2a5.tar.zst coredns-b56b080a7c1125cd97c0a2edd7ae21bc1bdcd2a5.zip |
plugin/view: Advanced routing interface and new 'view' plugin (#5538)
* introduce new interface "dnsserver.Viewer", that allows a plugin implementing it to decide if a query should be routed into its server block.
* add new plugin "view", that uses the new interface to enable a user to define expression based conditions that must be met for a query to be routed to its server block.
Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/view_test.go | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/test/view_test.go b/test/view_test.go new file mode 100644 index 000000000..f68595380 --- /dev/null +++ b/test/view_test.go @@ -0,0 +1,163 @@ +package test + +import ( + "strings" + "testing" + + "github.com/coredns/coredns/plugin/test" + + "github.com/miekg/dns" +) + +func TestView(t *testing.T) { + // Hack to get an available port - We spin up a temporary dummy coredns on :0 to get the port number, then we re-use + // that one port consistently across all server blocks. + corefile := `example.org:0 { + erratic + }` + tmp, addr, _, err := CoreDNSServerAndPorts(corefile) + if err != nil { + t.Fatalf("Could not get CoreDNS serving instance: %s", err) + } + + port := addr[strings.LastIndex(addr, ":")+1:] + + // Corefile with test views + corefile = ` + # split-type config: splits quries for A/AAAA into separate views + split-type:` + port + ` { + view test-view-a { + expr type() == 'A' + } + hosts { + 1.2.3.4 test.split-type + } + } + split-type:` + port + ` { + view test-view-aaaa { + expr type() == 'AAAA' + } + hosts { + 1:2:3::4 test.split-type + } + } + + # split-name config: splits queries into separate views based on first label in query name ("one", "two") + split-name:` + port + ` { + view test-view-1 { + expr name() matches '^one\\..*\\.split-name\\.$' + } + hosts { + 1.1.1.1 one.test.split-name one.test.test.test.split-name + } + } + split-name:` + port + ` { + view test-view-2 { + expr name() matches '^two\\..*\\.split-name\\.$' + } + hosts { + 2.2.2.2 two.test.split-name two.test.test.test.split-name + } + } + split-name:` + port + ` { + hosts { + 3.3.3.3 default.test.split-name + } + } + + # metadata config: verifies that metadata is properly collected by the server, + # and that metadata function correctly looks up the value of the metadata. + metadata:` + port + ` { + metadata + view test-view-meta1 { + # This is never true + expr metadata('view/name') == 'not-the-view-name' + } + hosts { + 1.1.1.1 test.metadata + } + } + metadata:` + port + ` { + view test-view-meta2 { + # This is never true. The metadata plugin is not enabled in this server block so the metadata function returns + # an empty string + expr metadata('view/name') == 'test-view-meta2' + } + hosts { + 2.2.2.2 test.metadata + } + } + metadata:` + port + ` { + metadata + view test-view-meta3 { + # This is always true. Queries in the zone 'metadata.' should always be served using this view. + expr metadata('view/name') == 'test-view-meta3' + } + hosts { + 2.2.2.2 test.metadata + } + } + metadata:` + port + ` { + # This block should never be reached since the prior view in the same zone is always true + hosts { + 3.3.3.3 test.metadata + } + } + ` + + i, addr, _, err := CoreDNSServerAndPorts(corefile) + if err != nil { + t.Fatalf("Could not get CoreDNS serving instance: %s", err) + } + // there are multiple sever blocks, but they are all on the same port, so it's a single server instance to stop + defer i.Stop() + // stop the temporary instance before starting tests. + tmp.Stop() + + viewTest(t, "split-type A", addr, "test.split-type.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("test.split-type. 303 IN A 1.2.3.4")}) + + viewTest(t, "split-type AAAA", addr, "test.split-type.", dns.TypeAAAA, dns.RcodeSuccess, + []dns.RR{test.AAAA("test.split-type. 303 IN AAAA 1:2:3::4")}) + + viewTest(t, "split-name one.test.test.test.split-name", addr, "one.test.test.test.split-name.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("one.test.test.test.split-name. 303 IN A 1.1.1.1")}) + + viewTest(t, "split-name one.test.split-name", addr, "one.test.split-name.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("one.test.split-name. 303 IN A 1.1.1.1")}) + + viewTest(t, "split-name two.test.test.test.split-name", addr, "two.test.test.test.split-name.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("two.test.test.test.split-name. 303 IN A 2.2.2.2")}) + + viewTest(t, "split-name two.test.split-name", addr, "two.test.split-name.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("two.test.split-name. 303 IN A 2.2.2.2")}) + + viewTest(t, "split-name default.test.split-name", addr, "default.test.split-name.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("default.test.split-name. 303 IN A 3.3.3.3")}) + + viewTest(t, "metadata test.metadata", addr, "test.metadata.", dns.TypeA, dns.RcodeSuccess, + []dns.RR{test.A("test.metadata. 303 IN A 2.2.2.2")}) +} + +func viewTest(t *testing.T, testName, addr, qname string, qtype uint16, expectRcode int, expectAnswers []dns.RR) { + t.Run(testName, func(t *testing.T) { + m := new(dns.Msg) + + m.SetQuestion(qname, qtype) + resp, err := dns.Exchange(m, addr) + if err != nil { + t.Fatalf("Expected to receive reply, but didn't: %s", err) + } + + tc := test.Case{ + Qname: qname, Qtype: qtype, + Rcode: expectRcode, + Answer: expectAnswers, + } + + err = test.SortAndCheck(resp, tc) + if err != nil { + t.Error(err) + } + }) +} |