resolver: the refused-query test asks several operators, one query each (closes #251) #252

Merged
clawbot merged 1 commits from issue-251-quad9-test-robust into next 2026-10-02 12:00:49 +02:00
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 # 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 - 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). 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 - 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) assert.Equal(t, "server returned REFUSED", resp.Error)
} }
// TestQueryNameserverIP_RecursiveResolverRefused asks Quad9, a public // TestQueryServers_RecursiveResolverRefused passes a public recursive
// recursive resolver, about google.com at both of its addresses. Quad9 // resolver to QueryServers as the server of google.com. These resolvers
// refuses a query that does not ask for recursion and answers one that // refuse a query that does not ask for recursion and answer one that
// does. The resolver never asks for recursion, so it must be reported // does. The resolver never asks for recursion, so the query must be
// as refusing, never as answering. // reported as refused, never answered. Each resolver is run by a
func TestQueryNameserverIP_RecursiveResolverRefused(t *testing.T) { // 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() t.Parallel()
r := newTestResolver(t) 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 err error
var resp *resolver.NameserverResponse
livednstest.Retry( livednstest.Retry(
t, t,
"QueryNameserverIP("+ip+", google.com)", "QueryServers(public recursive resolvers, google.com)",
func(ctx context.Context) error { func(ctx context.Context) error {
var err error for _, ip := range resolvers {
_, err = r.QueryServers(
resp, err = r.QueryNameserverIP( ctx, []string{ip}, "google.com.", "google.com.",
ctx, ip, ip, "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 nil
}
}
return fmt.Errorf("%w: %w", livednstest.ErrNoAnswer, err)
}, },
) )
assert.Equal(t, resolver.StatusError, resp.Status, ip) require.ErrorIs(t, err, resolver.ErrRefused)
assert.Equal(t, "server returned REFUSED", resp.Error, ip)
}
} }
// googleNameserverIPv4s returns the IPv4 addresses of google.com's // googleNameserverIPv4s returns the IPv4 addresses of google.com's