aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGravatar Chris O'Haver <cohaver@infoblox.com> 2022-09-08 14:56:27 -0400
committerGravatar GitHub <noreply@github.com> 2022-09-08 14:56:27 -0400
commitb56b080a7c1125cd97c0a2edd7ae21bc1bdcd2a5 (patch)
tree1494a9542db6d6f69db39113734c8518a6701daf /test
parent1f0a41a66597cb8ab4aace8ea5b5bad880bcd23b (diff)
downloadcoredns-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.go163
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)
+ }
+ })
+}