package dsl_test import ( "errors" "fmt" "github.com/BytemarkHosting/go-pdns/pipe/backend" . "github.com/BytemarkHosting/go-pdns/pipe/dsl" h "github.com/BytemarkHosting/go-pdns/pipe/test_helpers" "strings" "testing" ) func ReplyHandler(x string) func(c *Context) { return func(c *Context) { c.Reply(x) } } func NullHandler(c *Context) {} var ErrorReplyError = errors.New("Foo") func ErrorReplyHandler(c *Context) { c.Error = ErrorReplyError } func SOAQuery() *backend.Query { q := h.FakeQuery(3) q.QName = "example.com" q.QType = "SOA" return q } func AssertTableEntry(t *testing.T, d *DSL, qtype, matcher, msg string) { table := qtype + "\t:\t" + matcher + "\n" h.AssertEqualString(t, table, d.String(), msg) } func AssertLookup(t *testing.T, d *DSL, q *backend.Query, n int, err error) []*backend.Response { rsp, rspErr := d.Lookup(q) if err == nil { h.RefuteError(t, err, "Lookup shouldn't return error") } else if rspErr == nil { t.Logf("Expected error %s but no error was returned", err) t.FailNow() } else { h.AssertEqualString(t, err.Error(), rspErr.Error(), "Expected error not returned") } rspStrs := []string{} for _, r := range rsp { r.ProtocolVersion = 1 str, err := r.String() h.RefuteError(t, err, "sanity") rspStrs = append(rspStrs, str) } h.AssertEqualInt(t, n, len(rsp), fmt.Sprintf("One response expected, got:\n%s", strings.Join(rspStrs, ""))) return rsp } // Don't test all the autogenerated helpers explicitly, just a common one. func TestAutogeneratedExampleRegistersCorrectCallbackWhenRun(t *testing.T) { d := New() d.SOA(`example\.com`, NullHandler) AssertTableEntry(t, d, "SOA", `^(?i)example\.com$`, "SOA callback not registered") } func TestDefaultTTLFromNewIsOneHour(t *testing.T) { d := New() d.SOA(`*`, ReplyHandler("Foo")) rsp := AssertLookup(t, d, SOAQuery(), 1, nil) h.AssertEqualString(t, "3600", rsp[0].TTL, "Default TTL not honoured") } func TestAlternativeTTLCanBeSpecifiedUsingNewWithTTL(t *testing.T) { d := NewWithTTL(86400) d.SOA(`*`, ReplyHandler("Foo")) rsp := AssertLookup(t, d, SOAQuery(), 1, nil) h.AssertEqualString(t, "86400", rsp[0].TTL, "Custom TTL not honoured") } func TestBeforeCallbackIsCalledIfSpecified(t *testing.T) { d := New() d.Before(ReplyHandler("Before")) d.SOA(`*`, ReplyHandler("SOA 1")) d.SOA(`*`, ReplyHandler("SOA 2")) rsp := AssertLookup(t, d, SOAQuery(), 4, nil) h.AssertEqualString(t, "Before", rsp[0].Content, "First Before not called") h.AssertEqualString(t, "SOA 1", rsp[1].Content, "First SOA not called") h.AssertEqualString(t, "Before", rsp[2].Content, "Second Before not called") h.AssertEqualString(t, "SOA 2", rsp[3].Content, "Second SOA not called") } func TestLookupCallbackOrderIsDefined(t *testing.T) { d := New() d.SOA(`*`, ReplyHandler("SOA 1")) d.MX(`*`, ReplyHandler("MX 1")) d.SOA(`*`, ReplyHandler("SOA 2")) d.SOA(`*`, ReplyHandler("SOA 3")) d.AAAA(`*`, ReplyHandler("AAAA 1")) d.A(`*`, ReplyHandler("AAAA 2")) rsp := AssertLookup(t, d, h.FakeQuery(1), 6, nil) msg := "Order is wrong" h.AssertEqualString(t, "SOA 1", rsp[0].Content, msg) h.AssertEqualString(t, "SOA 2", rsp[1].Content, msg) h.AssertEqualString(t, "SOA 3", rsp[2].Content, msg) h.AssertEqualString(t, "MX 1", rsp[3].Content, msg) h.AssertEqualString(t, "AAAA 1", rsp[4].Content, msg) h.AssertEqualString(t, "AAAA 2", rsp[5].Content, msg) } func TestOnlyMatchingCallbacksAreRun(t *testing.T) { d := New() d.SOA(`example\.com`, ReplyHandler("Good")) d.SOA(`example\.org`, ReplyHandler("Bad")) rsp := AssertLookup(t, d, SOAQuery(), 1, nil) h.AssertEqualString(t, "Good", rsp[0].Content, "Wrong callback run") } func TestOnlyCallbacksOfTheRightQTypeAreRun(t *testing.T) { d := New() d.SOA(`example\.com`, ReplyHandler("Good")) d.NS(`example\.com`, ReplyHandler("Bad")) rsp := AssertLookup(t, d, SOAQuery(), 1, nil) h.AssertEqualString(t, "Good", rsp[0].Content, "Wrong callback run") } func TestCaptureGroupsArePutIntoContextMatches(t *testing.T) { d := New() var captures []string d.SOA(`([a-z]{3})\.([a-z]{3})\.([a-z]{3})\.example\.com`, func(c *Context) { captures = c.Matches c.Reply("OK") }) q := SOAQuery() q.QName = "BAZ.bar.foo.example.com" rsp := AssertLookup(t, d, q, 1, nil) h.AssertEqualInt(t, 3, len(captures), "Wrong number of match groups returned") h.AssertEqualString(t, "OK", rsp[0].Content, "Wrong callback run?") // case-insensitive, so we don't mangle these h.AssertEqualString(t, "BAZ", captures[0], "Part 1 not captured") h.AssertEqualString(t, "bar", captures[1], "Part 2 not captured") h.AssertEqualString(t, "foo", captures[2], "Part 3 not captured") } func TestBeforeCanModifyCaptureGroups(t *testing.T) { d := New() d.Before(func(c *Context) { c.Matches = append(c.Matches, "modify-cg") }) d.SOA(`*`, func(c *Context) { c.Reply(c.Matches[0]) }) rsp := AssertLookup(t, d, SOAQuery(), 1, nil) h.AssertEqualString(t, "modify-cg", rsp[0].Content, "Capture modification lost") } func TestChangesToMatchesInOrdinaryCallbacksDoNotPersist(t *testing.T) { d := New() var ok bool d.SOA(`*`, func(c *Context) { c.Matches = append(c.Matches, "Bad") }) d.SOA(`*`, func(c *Context) { ok = (len(c.Matches) == 0) }) AssertLookup(t, d, SOAQuery(), 0, nil) h.Assert(t, ok, "Change was persisted") } func TestCallbackReturningErrorIsReported(t *testing.T) { d := New() d.SOA(`*`, ErrorReplyHandler) AssertLookup(t, d, SOAQuery(), 0, ErrorReplyError) } func TestCallbackReturningErrorBlanksAnswers(t *testing.T) { d := New() d.SOA(`*`, ReplyHandler("Foo")) d.SOA(`*`, ErrorReplyHandler) AssertLookup(t, d, SOAQuery(), 0, ErrorReplyError) } func TestCallbackReturningErrorStopsLaterCallbacksFromRunning(t *testing.T) { d := New() ok := true d.SOA(`*`, ErrorReplyHandler) d.SOA(`*`, func(c *Context) { ok = false }) AssertLookup(t, d, SOAQuery(), 0, ErrorReplyError) h.Assert(t, ok, "Later callback was run") }