diff --git a/TODO.md b/TODO.md index 596ca42..927a598 100644 --- a/TODO.md +++ b/TODO.md @@ -19,6 +19,8 @@ trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149 # Completed Steps +- 2026-10-02: a resolver test that reads one record type from a nameserver's + answer asks again when that type is missing from it (closes #218). - 2026-10-02: a plain `docker build .` of a clone stamps its tag or short commit, not `dev`: the build context now carries `.git` (closes #210). - 2026-10-02: a query a server refuses is not resent asking for recursion, and diff --git a/internal/resolver/livedns_test.go b/internal/resolver/livedns_test.go index 0bbccb4..59f95ca 100644 --- a/internal/resolver/livedns_test.go +++ b/internal/resolver/livedns_test.go @@ -226,11 +226,17 @@ func liveLookupNS( // liveQueryNameserver queries one nameserver, retrying while that // nameserver fails to answer. NXDOMAIN and NODATA are answers and // are returned to the caller to assert on. +// +// QueryNameserver sends one query per record type, so one lost query +// leaves its type out of an answer that is otherwise fine. A test names +// in types the record types it reads; an answer holding records of none +// of them is retried too. func liveQueryNameserver( t *testing.T, r *resolver.Resolver, nameserver string, hostname string, + types ...string, ) *resolver.NameserverResponse { t.Helper() @@ -260,6 +266,18 @@ func liveQueryNameserver( ) } + hasRecords := func(recordType string) bool { + return len(resp.Records[recordType]) > 0 + } + + if len(types) > 0 && !slices.ContainsFunc(types, hasRecords) { + return fmt.Errorf( + "%w: %s returned no %s records", + livednstest.ErrNoAnswer, nameserver, + strings.Join(types, " or "), + ) + } + out = resp return nil diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index e928a35..a07c718 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -171,7 +171,7 @@ func TestQueryNameserver_BasicA(t *testing.T) { r := newTestResolver(t) ns := findOneNSForDomain(t, r, "google.com") - resp := liveQueryNameserver(t, r, ns, "www.google.com") + resp := liveQueryNameserver(t, r, ns, "www.google.com", "A", "CNAME") require.NotNil(t, resp) @@ -190,7 +190,7 @@ func TestQueryNameserver_AAAA(t *testing.T) { r := newTestResolver(t) ns := findOneNSForDomain(t, r, "cloudflare.com") - resp := liveQueryNameserver(t, r, ns, "cloudflare.com") + resp := liveQueryNameserver(t, r, ns, "cloudflare.com", "AAAA") aaaaRecords := resp.Records["AAAA"] require.NotEmpty(t, aaaaRecords, @@ -210,7 +210,7 @@ func TestQueryNameserver_MX(t *testing.T) { r := newTestResolver(t) ns := findOneNSForDomain(t, r, "google.com") - resp := liveQueryNameserver(t, r, ns, "google.com") + resp := liveQueryNameserver(t, r, ns, "google.com", "MX") mxRecords := resp.Records["MX"] require.NotEmpty(t, mxRecords, @@ -223,7 +223,7 @@ func TestQueryNameserver_TXT(t *testing.T) { r := newTestResolver(t) ns := findOneNSForDomain(t, r, "google.com") - resp := liveQueryNameserver(t, r, ns, "google.com") + resp := liveQueryNameserver(t, r, ns, "google.com", "TXT") txtRecords := resp.Records["TXT"] require.NotEmpty(t, txtRecords,