From bfc91f32539909448c3c8197dacaa5ffec6c598a Mon Sep 17 00:00:00 2001 From: sneak Date: Fri, 2 Oct 2026 05:22:57 +0000 Subject: [PATCH] resolver tests: retry an answer missing the record type read (closes #218) QueryNameserver sends one query per record type. When only the AAAA or MX query was lost, the answer still had status ok, liveQueryNameserver did not retry it, and the test found no AAAA or MX records. liveQueryNameserver now takes the record types a test reads and, through livednstest, retries an answer that holds records of none of them. The A, AAAA, MX and TXT tests name theirs. A resolver that loses a type for good still fails, after the last attempt instead of the first. Model: opus-5-5 --- TODO.md | 2 ++ internal/resolver/livedns_test.go | 18 ++++++++++++++++++ internal/resolver/resolver_test.go | 8 ++++---- 3 files changed, 24 insertions(+), 4 deletions(-) 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,