Remove DNS mocking from tests #97
Reference in New Issue
Block a user
Delete Branch "remove-dns-mocking"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
DNS is never mocked in this repository: tests exercise live DNS, and robustness comes from handling real-world DNS behavior with tolerant assertions and sensible timeouts, not from mocks.
What was removed
mockResolverininternal/watcher/watcher_test.go: the watcher tests are now wired to the real iterative resolver and query stable public names (example.com,www.example.com).timeoutClient(a fakeDNSClient) ininternal/resolver/resolver_test.go.resolver.NewFromLoggerWithClient, the constructor whose only purpose was injecting mock DNS clients.TESTING.mdcarve-out that permitted DNS mocks in packages consuming the resolver; the live-DNS policy now applies to every package.How the rewritten tests exercise live DNS
Every watcher test resolves live DNS on every run. Change detection is driven by seeding the state store with a synthetic previous observation that live DNS cannot match (reserved
.invalidnameserver names, RFC 5737 documentation addresses) and then re-running against live DNS:ns-baseline.invalid.; the next live run detects the difference.203.0.113.1; the next live run observes the real records and notifies.The port checker, TLS checker, and notifier remain test doubles — they are not DNS — and were generalized ("all ports open/closed", "one cert for any address") so assertions hold for whatever addresses live DNS returns, including multi-IP and AAAA answers.
The resolver timeout test now queries
192.0.2.1(RFC 5737, no nameserver can exist there) through the real UDP client and asserts a classified non-OK response with no records.Coverage intentionally dropped
StatusTimeoutclassification: the fake client guaranteed a timeout error; a real unreachable address may instead fail fast (ICMP unreachable) depending on the network path, so the live test tolerantly accepts any failure classification rather than assertingtimeoutspecifically.Everything else the mocked tests covered is covered live.
make checkandscript/cibuild(Docker, pinned toolchain) are green.Note: this will conflict slightly with #96 (
golangci-v2.12.2) ininternal/watcher/watcher_test.go(goconst fixture constants); whichever merges second should be rebased — this branch intentionally stays onmain's current linter config.Review: PR #97 (head
3959aed)Verdict: PASS
Mandate verification
No DNS mocking remains anywhere in the tree at this head. Full-tree grep for mock/fake/stub near DNS/resolver/nameserver terms: zero hits.
timeoutClient,timeoutError, andmockResolverare gone; themiekg/dnsimport is gone frominternal/resolver/resolver_test.go; nonet.DefaultResolveroverrides, dial hooks, or hosts-file tricks anywhere. The only remaining test doubles aremockPortChecker,mockTLSChecker, andmockNotifierininternal/watcher/watcher_test.go— none touches DNS. Their generalization does not hollow out the assertions:TestPortStateChangestill flips open-to-closed and requires aPort Change:notification;TestTLSExpiryWarningDeduprequires at least one warning and then a stable count;TestDomainPortAndTLSChecksstill asserts nonzero call counts and populated state.resolver.NewFromLoggerWithClientremoval is clean. Zero remaining references in the tree; internal package, nothing external can depend on it; everything compiles and passes.Dropped coverage is exactly as documented, plus one trivial sibling. Old vs new test enumeration:
internal/watcher/watcher_test.gohas 13 test functions before and after — every old scenario (baseline, NS change, record change, port change, TLS expiry + dedup, graceful shutdown, DNS-before-port/TLS ordering, startup notification x3, NS failure/recovery) survives; the NS failure/recovery test now covers both directions in one cycle. In the resolver test,TestQueryNameserverIP_TimeoutbecameTestQueryNameserverIP_UnreachableServer; the exactStatusTimeoutassertion is dropped as documented, and with it the (undocumented but subsumed)assert.NotEmpty(resp.Error)— minor, acceptable: on a live 192.0.2.1 path the failure mode genuinely varies, and the new test still requires a classified non-OK status with zero records and no error/hang. The oldmockResolvererror-injection fields (lookupNSErretc.) were never exercised by any removed test, so nothing else was lost.Seeded-state design is sound.
fakeNSuses the RFC 2606.invalidTLD, which can never appear in live NS answers;fakeIP(203.0.113.1) and 192.0.2.1 are RFC 5737 documentation addresses that IANA-operatedexample.com/www.example.comcan never legitimately resolve to. No hard assertions on example.com record contents, no specific IP-count or ordering assumptions (liveIPsdeduplicates and sorts), and no IPv6-connectivity assumption (AAAA answers are recorded from DNS; connections go only through the mocked port/TLS checkers, which accept any address). Startup-notification tests poll with a deadline instead of sleeping a fixed scan duration. Residual brittleness, noted as within the accepted live-DNS baseline (#93), not blockers: (a)TestQueryNameserverIP_UnreachableServerburns its full 10s context when packets to 192.0.2.1 drop silently (observed 10.01s locally), one third of the resolver package's 30s budget; (b)scanTimeoutof 25s in the watcher tests sits close to the 30sgo testtimeout, so a badly degraded network would surface as a package timeout panic rather than a clean single-test failure. Observed watcher package time is ~2-3s, so headroom is real today.make testtiming: within policy. Two fully uncached runs (test cache cleared between): 12.2s and 11.6s wall, against the 20s policy budget and 30s Makefile timeout. Dominant cost is the deliberate 10s unreachable-server test running parallel inside the resolver package (11.0s package time); watcher package 2.0-2.8s.make check: exit 0 (test + lint + fmt-check), lint reports 0 issues, fmt-check clean. Zero test failures and zero flakes across 3 total live-DNS suite executions (2 uncached). CI on head3959aed:check / checksuccess (50s).#96 interplay claim confirmed.
origin/golangci-v2.12.2rewrites the mocked fixture literals ininternal/watcher/watcher_test.gointo constants (108+/97-) — the very code this PR deletes. The hunks overlap; whichever merges second needs a rebase (and if this merges first, most of #96's watcher_test.go delta becomes moot since this PR already introducestestDomain/testHostnameconstants). This branch staying on main's current lint config is coherent: local lint passes 0 issues against the current.golangci.yml.Standard checks. No new
nolint(all 15 in-tree hits pre-date this PR). No attribution trailers or vendor references anywhere.TESTING.mdchanges correctly extend the live-DNS rule to every package and remove the mock carve-out, consistent with the iron rule and with the #93 discussion (which this PR neither closes nor pre-empts — the default-suite gating decision there remains open and untouched).TODO.mdupdates are in scope (stale mock references). Commit message is accurate and descriptive; no(closes #N)because no issue defines this work — the only related open issue (#93) is intentionally not closed by it. Mergeable against currentmain(f79cd98): confirmed; main's one commit past the branch point touches onlyREADME.md, which this PR does not modify.Verification detail
3959aedb6a.make test(uncached run 1): 12.2s, all packages ok. (uncached run 2 aftergo clean -testcache): 11.6s, all packages ok. Coverage: watcher 83.7%, resolver 77.4%.make check: exit 0, lint 0 issues.NewFromLoggerWithClient0 hits; DNS-adjacent mock/fake/stub 0 hits;timeoutClient/timeoutError0 hits.Manager: independent adversarial review PASSED (comment above). Setting
merge-readyand assigning to sneak for merge (protectedmain).Review highlights: no DNS mock/fake/stub remains anywhere in the tree (iron rule fully implemented);
NewFromLoggerWithClientremoval is clean with zero remaining references; 13 watcher test functions before and after (nothing silently dropped); the one documented coverage drop (exactStatusTimeoutclassification) plus its minor sibling (assert.NotEmpty(resp.Error)) judged acceptable — the live test still requires a classified non-OK response with zero records;make testmeasured at 11.6-12.2s uncached (inside the 20s policy budget), 0 flakes across 3 suite executions; CI green on head3959aed.Non-blocking robustness notes for the record (within the accepted #93 baseline, candidates for future hardening, not this PR):
TestQueryNameserverIP_UnreachableServerburns its full 10s context when 192.0.2.1 blackholes;scanTimeout = 25sininternal/watcher/watcher_test.gosits close to the 30sgo testtimeout, so a badly degraded network would present as a package-timeout panic rather than a clean single-test failure.Merge-order note: #96 (also
merge-ready) rewrites the sameinternal/watcher/watcher_test.goregion this PR deletes — whichever merges second needs a small rebase; ping this repo's manager (or leave a comment) and the rebase will be run through the loop.@clawbot merged the other one first, fix pls
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.