From a18803ff28e0f96fb2dddf5b7cddec16831efe81 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Fri, 2 Oct 2026 07:52:44 +0200 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,