resolver: the refused-query test asks several operators, one query each (closes #251)
check / check (push) Canceled after 0s

The test asked one operator's recursive resolver for eight record types
at each of its two addresses, and passed only when all eight were
refused within one attempt; when that operator stopped answering, next
went red. It is now TestQueryServers_RecursiveResolverRefused: through
the existing QueryServers test export it sends one A query to public
resolvers of four operators in turn, inside livednstest.Retry, moving
on when one gives no reply. Each refuses a query not asking for
recursion and answers one that does, so putting the resend asking for
recursion back still fails the test at once.

Model: opus-5-5
This commit was merged in pull request #252.
This commit is contained in:
2026-10-02 12:00:48 +02:00
parent 6332b48379
commit 9bd1a71d8f
2 changed files with 37 additions and 38 deletions
+2
View File
@@ -19,6 +19,8 @@ trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149
# Completed Steps
- 2026-10-02: the refused-query test sends one query to four operators' public
resolvers in turn until one replies, not eight to one operator (closes #251).
- 2026-10-02: a name removed from `DNSWATCHER_TARGETS` leaves the state, and so
the dashboard and API, at startup, before the first check (closes #223).
- 2026-10-02: a record type whose query to a nameserver fails keeps its previous
+25 -28
View File
@@ -442,48 +442,45 @@ func TestQueryNameserver_Refused(t *testing.T) {
assert.Equal(t, "server returned REFUSED", resp.Error)
}
// TestQueryNameserverIP_RecursiveResolverRefused asks Quad9, a public
// recursive resolver, about google.com at both of its addresses. Quad9
// refuses a query that does not ask for recursion and answers one that
// does. The resolver never asks for recursion, so it must be reported
// as refusing, never as answering.
func TestQueryNameserverIP_RecursiveResolverRefused(t *testing.T) {
// TestQueryServers_RecursiveResolverRefused passes a public recursive
// resolver to QueryServers as the server of google.com. These resolvers
// refuse a query that does not ask for recursion and answer one that
// does. The resolver never asks for recursion, so the query must be
// reported as refused, never answered. Each resolver is run by a
// different operator, and they are asked in turn until one replies, so
// one operator not answering does not fail the test.
func TestQueryServers_RecursiveResolverRefused(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
resolvers := []string{
"64.6.64.6", "185.222.222.222", "4.2.2.1", "9.9.9.9",
}
for _, ip := range []string{"9.9.9.9", "149.112.112.112"} {
var resp *resolver.NameserverResponse
var err error
livednstest.Retry(
t,
"QueryNameserverIP("+ip+", google.com)",
"QueryServers(public recursive resolvers, google.com)",
func(ctx context.Context) error {
var err error
resp, err = r.QueryNameserverIP(
ctx, ip, ip, "google.com",
for _, ip := range resolvers {
_, err = r.QueryServers(
ctx, []string{ip}, "google.com.", "google.com.",
dns.TypeA,
)
if err != nil {
return err
}
// A timeout or a network error is no reply at all.
if resp.Status == resolver.StatusTimeout ||
strings.HasPrefix(resp.Error, "network error") {
return fmt.Errorf(
"%w: %s: %s",
livednstest.ErrNoAnswer, ip, resp.Error,
)
}
// A refusal or an answer is a reply; anything else may
// be no reply at all, so the next resolver is asked.
if err == nil || errors.Is(err, resolver.ErrRefused) {
return nil
}
}
return fmt.Errorf("%w: %w", livednstest.ErrNoAnswer, err)
},
)
assert.Equal(t, resolver.StatusError, resp.Status, ip)
assert.Equal(t, "server returned REFUSED", resp.Error, ip)
}
require.ErrorIs(t, err, resolver.ErrRefused)
}
// googleNameserverIPv4s returns the IPv4 addresses of google.com's