test: make live DNS tests robust instead of gated (closes #93)
All checks were successful
check / check (push) Successful in 1m18s

The resolver's live-DNS tests failed nondeterministically, a different
subset each run. Three structural causes, all test-side:

- Burst fan-out. Every test in the package is parallel and the build
  hosts have many cores, so all ~35 iterative resolutions started at
  the same instant and, because queryServers walks rootServerList() in
  fixed order, hit the same root server within milliseconds. Root
  servers rate-limit that.
- No retry anywhere. One dropped UDP packet in a delegation chain
  failed a test outright.
- Unanimity assertions. TestQueryAllNameservers_AllReturnOK and
  _NXDomainFromAllNS required every one of a domain's nameservers to
  answer, with no tolerance for one being slow.

New internal/resolver/livedns_test.go addresses each: a package-wide
gate bounds how many live resolutions are in flight at once, every
live operation gets three attempts with exponential backoff and its
own deadline, and multi-nameserver assertions now need a strict
majority rather than unanimity. The retry predicate is deliberately
transport-level -- "did a nameserver answer at all" -- never the
assertion under test, so a resolver that answers incorrectly still
fails on the first attempt. A nameserver that stays silent is
tolerated; one that answers wrongly is not.

livedns_harness_test.go tests that machinery directly: quorum
arithmetic, status counting, the gate's concurrency bound, per-attempt
deadlines, and recovery from a transient failure. It touches no DNS.

Nothing is mocked, faked, stubbed, recorded, skipped or build-tagged,
and production resolver behaviour is unchanged.

Test caps move to the new org-wide values ruled at prompts issue 41:
60s hard cap, 20s target, 90s -timeout backstop. REPO_POLICIES.md is
re-vendored byte-identical from sneak/prompts rather than hand-edited,
which also picks up the golangci-lint paragraph this copy had drifted
behind on. TESTING.md's stale 30-second target follows to 60.

#93
This commit is contained in:
2026-08-10 13:09:17 +00:00
parent cc86473410
commit 9cb2c2b7e0
7 changed files with 709 additions and 213 deletions

View File

@@ -32,32 +32,17 @@ func newTestResolver(t *testing.T) *resolver.Resolver {
return resolver.NewFromLogger(log)
}
func testContext(t *testing.T) context.Context {
t.Helper()
ctx, cancel := context.WithTimeout(
context.Background(), 60*time.Second,
)
t.Cleanup(cancel)
return ctx
}
// findOneNSForDomain picks one authoritative nameserver to aim a
// test at. Live-DNS retry, concurrency and quorum handling live in
// livedns_test.go.
func findOneNSForDomain(
t *testing.T,
r *resolver.Resolver,
ctx context.Context, //nolint:revive // test helper
domain string,
) string {
t.Helper()
nameservers, err := r.FindAuthoritativeNameservers(
ctx, domain,
)
require.NoError(t, err)
require.NotEmpty(t, nameservers)
return nameservers[0]
return liveFindAuthoritative(t, r, domain)[0]
}
// ----------------------------------------------------------------
@@ -70,13 +55,7 @@ func TestFindAuthoritativeNameservers_ValidDomain(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
nameservers, err := r.FindAuthoritativeNameservers(
ctx, "google.com",
)
require.NoError(t, err)
require.NotEmpty(t, nameservers)
nameservers := liveFindAuthoritative(t, r, "google.com")
hasGoogleNS := false
@@ -99,13 +78,9 @@ func TestFindAuthoritativeNameservers_Subdomain(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
nameservers := liveFindAuthoritative(t, r, "www.google.com")
nameservers, err := r.FindAuthoritativeNameservers(
ctx, "www.google.com",
)
require.NoError(t, err)
require.NotEmpty(t, nameservers)
assert.NotEmpty(t, nameservers)
}
func TestFindAuthoritativeNameservers_ReturnsSorted(
@@ -114,12 +89,7 @@ func TestFindAuthoritativeNameservers_ReturnsSorted(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
nameservers, err := r.FindAuthoritativeNameservers(
ctx, "google.com",
)
require.NoError(t, err)
nameservers := liveFindAuthoritative(t, r, "google.com")
assert.True(
t,
@@ -134,17 +104,8 @@ func TestFindAuthoritativeNameservers_Deterministic(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
first, err := r.FindAuthoritativeNameservers(
ctx, "google.com",
)
require.NoError(t, err)
second, err := r.FindAuthoritativeNameservers(
ctx, "google.com",
)
require.NoError(t, err)
first := liveFindAuthoritative(t, r, "google.com")
second := liveFindAuthoritative(t, r, "google.com")
assert.Equal(t, first, second)
}
@@ -155,17 +116,8 @@ func TestFindAuthoritativeNameservers_TrailingDot(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns1, err := r.FindAuthoritativeNameservers(
ctx, "google.com",
)
require.NoError(t, err)
ns2, err := r.FindAuthoritativeNameservers(
ctx, "google.com.",
)
require.NoError(t, err)
ns1 := liveFindAuthoritative(t, r, "google.com")
ns2 := liveFindAuthoritative(t, r, "google.com.")
assert.Equal(t, ns1, ns2)
}
@@ -176,13 +128,7 @@ func TestFindAuthoritativeNameservers_CloudflareDomain(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
nameservers, err := r.FindAuthoritativeNameservers(
ctx, "cloudflare.com",
)
require.NoError(t, err)
require.NotEmpty(t, nameservers)
nameservers := liveFindAuthoritative(t, r, "cloudflare.com")
for _, ns := range nameservers {
assert.True(t, strings.HasSuffix(ns, "."),
@@ -199,13 +145,9 @@ func TestQueryNameserver_BasicA(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
ns := findOneNSForDomain(t, r, "google.com")
resp := liveQueryNameserver(t, r, ns, "www.google.com")
resp, err := r.QueryNameserver(
ctx, ns, "www.google.com",
)
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, resolver.StatusOK, resp.Status)
@@ -222,13 +164,8 @@ func TestQueryNameserver_AAAA(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "cloudflare.com")
resp, err := r.QueryNameserver(
ctx, ns, "cloudflare.com",
)
require.NoError(t, err)
ns := findOneNSForDomain(t, r, "cloudflare.com")
resp := liveQueryNameserver(t, r, ns, "cloudflare.com")
aaaaRecords := resp.Records["AAAA"]
require.NotEmpty(t, aaaaRecords,
@@ -247,13 +184,8 @@ func TestQueryNameserver_MX(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
resp, err := r.QueryNameserver(
ctx, ns, "google.com",
)
require.NoError(t, err)
ns := findOneNSForDomain(t, r, "google.com")
resp := liveQueryNameserver(t, r, ns, "google.com")
mxRecords := resp.Records["MX"]
require.NotEmpty(t, mxRecords,
@@ -265,13 +197,8 @@ func TestQueryNameserver_TXT(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
resp, err := r.QueryNameserver(
ctx, ns, "google.com",
)
require.NoError(t, err)
ns := findOneNSForDomain(t, r, "google.com")
resp := liveQueryNameserver(t, r, ns, "google.com")
txtRecords := resp.Records["TXT"]
require.NotEmpty(t, txtRecords,
@@ -297,14 +224,10 @@ func TestQueryNameserver_NXDomain(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
resp, err := r.QueryNameserver(
ctx, ns,
"this-surely-does-not-exist-xyz.google.com",
ns := findOneNSForDomain(t, r, "google.com")
resp := liveQueryNameserver(
t, r, ns, "this-surely-does-not-exist-xyz.google.com",
)
require.NoError(t, err)
assert.Equal(t, resolver.StatusNXDomain, resp.Status)
}
@@ -313,13 +236,8 @@ func TestQueryNameserver_RecordsSorted(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
resp, err := r.QueryNameserver(
ctx, ns, "google.com",
)
require.NoError(t, err)
ns := findOneNSForDomain(t, r, "google.com")
resp := liveQueryNameserver(t, r, ns, "google.com")
for recordType, values := range resp.Records {
assert.True(
@@ -336,13 +254,8 @@ func TestQueryNameserver_ResponseIncludesNameserver(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "cloudflare.com")
resp, err := r.QueryNameserver(
ctx, ns, "cloudflare.com",
)
require.NoError(t, err)
ns := findOneNSForDomain(t, r, "cloudflare.com")
resp := liveQueryNameserver(t, r, ns, "cloudflare.com")
assert.Equal(t, ns, resp.Nameserver)
}
@@ -353,14 +266,10 @@ func TestQueryNameserver_EmptyRecordsOnNXDomain(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
resp, err := r.QueryNameserver(
ctx, ns,
"this-surely-does-not-exist-xyz.google.com",
ns := findOneNSForDomain(t, r, "google.com")
resp := liveQueryNameserver(
t, r, ns, "this-surely-does-not-exist-xyz.google.com",
)
require.NoError(t, err)
totalRecords := 0
for _, values := range resp.Records {
@@ -374,18 +283,9 @@ func TestQueryNameserver_TrailingDotHandling(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ns := findOneNSForDomain(t, r, ctx, "google.com")
resp1, err := r.QueryNameserver(
ctx, ns, "google.com",
)
require.NoError(t, err)
resp2, err := r.QueryNameserver(
ctx, ns, "google.com.",
)
require.NoError(t, err)
ns := findOneNSForDomain(t, r, "google.com")
resp1 := liveQueryNameserver(t, r, ns, "google.com")
resp2 := liveQueryNameserver(t, r, ns, "google.com.")
assert.Equal(t, resp1.Status, resp2.Status)
}
@@ -398,15 +298,9 @@ func TestQueryAllNameservers_ReturnsAllNS(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
results := liveQueryAllNameservers(t, r, "google.com")
results, err := r.QueryAllNameservers(
ctx, "google.com",
)
require.NoError(t, err)
require.NotEmpty(t, results)
assert.GreaterOrEqual(t, len(results), 2)
assert.GreaterOrEqual(t, len(results), minNameservers)
for ns, resp := range results {
assert.Equal(t, ns, resp.Nameserver)
@@ -417,19 +311,27 @@ func TestQueryAllNameservers_AllReturnOK(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
results := liveQueryAllNameservers(t, r, "google.com")
results, err := r.QueryAllNameservers(
ctx, "google.com",
// A quorum, not unanimity: one authoritative server being
// slow or rate-limiting us is a property of the live
// internet, not a resolver defect.
assert.GreaterOrEqual(
t,
countStatus(results, resolver.StatusOK),
liveQuorum(len(results)),
"a quorum of nameservers should answer OK: %s",
describeStatuses(results),
)
require.NoError(t, err)
for ns, resp := range results {
assert.Equal(
t, resolver.StatusOK, resp.Status,
"NS %s should return OK", ns,
)
}
// Any nameserver claiming google.com does not exist is a
// real failure and is never tolerated.
assert.Zero(
t,
countStatus(results, resolver.StatusNXDomain),
"no nameserver should report NXDOMAIN: %s",
describeStatuses(results),
)
}
func TestQueryAllNameservers_NXDomainFromAllNS(
@@ -438,20 +340,26 @@ func TestQueryAllNameservers_NXDomainFromAllNS(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
results, err := r.QueryAllNameservers(
ctx,
"this-surely-does-not-exist-xyz.google.com",
results := liveQueryAllNameservers(
t, r, "this-surely-does-not-exist-xyz.google.com",
)
require.NoError(t, err)
for ns, resp := range results {
assert.Equal(
t, resolver.StatusNXDomain, resp.Status,
"NS %s should return nxdomain", ns,
)
}
assert.GreaterOrEqual(
t,
countStatus(results, resolver.StatusNXDomain),
liveQuorum(len(results)),
"a quorum of nameservers should report NXDOMAIN: %s",
describeStatuses(results),
)
// Silence is tolerated; a positive answer for a name that
// does not exist is not.
assert.Zero(
t,
countStatus(results, resolver.StatusOK),
"no nameserver should answer OK: %s",
describeStatuses(results),
)
}
// ----------------------------------------------------------------
@@ -462,11 +370,7 @@ func TestLookupNS_ValidDomain(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
nameservers, err := r.LookupNS(ctx, "google.com")
require.NoError(t, err)
require.NotEmpty(t, nameservers)
nameservers := liveLookupNS(t, r, "google.com")
for _, ns := range nameservers {
assert.True(t, strings.HasSuffix(ns, "."),
@@ -479,10 +383,7 @@ func TestLookupNS_Sorted(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
nameservers, err := r.LookupNS(ctx, "google.com")
require.NoError(t, err)
nameservers := liveLookupNS(t, r, "google.com")
assert.True(t, sort.StringsAreSorted(nameservers))
}
@@ -491,15 +392,8 @@ func TestLookupNS_MatchesFindAuthoritative(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
fromLookup, err := r.LookupNS(ctx, "google.com")
require.NoError(t, err)
fromFind, err := r.FindAuthoritativeNameservers(
ctx, "google.com",
)
require.NoError(t, err)
fromLookup := liveLookupNS(t, r, "google.com")
fromFind := liveFindAuthoritative(t, r, "google.com")
assert.Equal(t, fromFind, fromLookup)
}
@@ -512,11 +406,7 @@ func TestResolveIPAddresses_ReturnsIPs(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ips, err := r.ResolveIPAddresses(ctx, "google.com")
require.NoError(t, err)
require.NotEmpty(t, ips)
ips := liveResolveIPs(t, r, "google.com")
for _, ip := range ips {
parsed := net.ParseIP(ip)
@@ -530,10 +420,7 @@ func TestResolveIPAddresses_Deduplicated(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ips, err := r.ResolveIPAddresses(ctx, "google.com")
require.NoError(t, err)
ips := liveResolveIPs(t, r, "google.com")
seen := make(map[string]bool)
@@ -547,10 +434,7 @@ func TestResolveIPAddresses_Sorted(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ips, err := r.ResolveIPAddresses(ctx, "google.com")
require.NoError(t, err)
ips := liveResolveIPs(t, r, "google.com")
assert.True(t, sort.StringsAreSorted(ips))
}
@@ -561,13 +445,10 @@ func TestResolveIPAddresses_NXDomainReturnsEmpty(
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ips, err := r.ResolveIPAddresses(
ctx,
"this-surely-does-not-exist-xyz.google.com",
ips := liveResolveIPsAllowingEmpty(
t, r, "this-surely-does-not-exist-xyz.google.com",
)
require.NoError(t, err)
assert.Empty(t, ips)
}
@@ -575,11 +456,9 @@ func TestResolveIPAddresses_CloudflareDomain(t *testing.T) {
t.Parallel()
r := newTestResolver(t)
ctx := testContext(t)
ips := liveResolveIPs(t, r, "cloudflare.com")
ips, err := r.ResolveIPAddresses(ctx, "cloudflare.com")
require.NoError(t, err)
require.NotEmpty(t, ips)
assert.NotEmpty(t, ips)
}
// ----------------------------------------------------------------