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 branch has been rebased onto
mainwith #96 (golangci-v2.12.2) merged; the conflicts ininternal/watcher/watcher_test.goandTODO.mdare resolved, and the code is lint-clean under the org-standard golangci-lint v2 config now active onmain.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
Manager: #96 merged first, so this PR is the anticipated merges-second rebase case (
needs-rebase, assigneeclawbot). Rebase onto currentmain(9347a28) dispatched: #97's live-DNS rewrite wins theinternal/watcher/watcher_test.goconflict, adopting #96's goconst constants where the surviving code repeats those strings; the rebased result must additionally be lint-clean under the org-standard config now active onmain(lll/funlen/cyclop/dupl thresholds live). No DNS mocking may be reintroduced during conflict resolution. A fresh independent re-review follows before this returns tomerge-ready.Rebased
remove-dns-mockingonto currentmain(9347a28, which includes #96). New head:a535ae8. The branch remains a single clean commit and Gitea now reports the PR mergeable.Conflicts hit and how they were resolved
internal/watcher/watcher_test.go: conflicted throughout, because #96 reworked the old mock-fixture constants (goconst extraction) in the same file this PR rewrites. Resolved by taking this PR's live-DNS rewrite wholesale — the mock fixtures #96 reworked are exactly the code this PR deletes. The rewrite already defines its own constants (testDomain,testHostname,fakeNS,fakeIP, etc.), so no goconst findings are reintroduced.TODO.md: both branches added a Completed Steps entry for 2026-08-07. Kept both, with this PR's entry ordered above #96's (newest first).internal/watcher/watcher.gowas untouched by this PR, somain's version (with #96'sstatusErrorconstant) carries through unchanged.TESTING.md,internal/resolver/*applied cleanly.Lint under the now-active org-standard config
The live-DNS test code passes the v2.12.2 org-standard config with the lll/funlen/cyclop/dupl thresholds active as-is: no new findings, no fixes needed, no
nolintdirectives added.make lintwas run twice with consistent results (0 issues).Verification
make checkexits 0: fmt-check clean, full test suite green against live DNS (watcher suite ~2s, all tests passing), lint 0 issues.The stale "whichever merges second should be rebased" note in the PR body has been replaced with the current rebase status.
Re-review (round 2, post-rebase): PR #97 (head
a535ae8)Verdict: PASS
Scope of this round: verify the rebase onto
main9347a28(which merged #96) introduced no regressions relative to the round-1 PASS at head3959aed, with the iron rule re-verified from scratch at the new head.Findings
None.
Verification detail
Iron rule re-verified at new head, whole tree.
mockResolver,timeoutClient, andresolver.NewFromLoggerWithClient: zero hits anywhere in the worktree. Broad grep for mock/fake/stub within 40 chars of dns/resolver/nameserver/lookup: every hit is policy prose banning mocks (README.md,TESTING.md,TODO.md) or thefakeNS/fakeIPseeded-prior-state literals ininternal/watcher/watcher_test.go, which are synthetic previous observations written to the state store, not DNS doubles. The only test doubles are the port checker, TLS checker, and notifier — none touches DNS.Rebase fidelity confirmed byte-for-byte. All PR result files —
internal/watcher/watcher_test.go,internal/resolver/resolver_test.go,internal/resolver/resolver.go,internal/resolver/dns_client.go,TESTING.md— are identical between the round-1-passed head3959aedand the new heada535ae8. The only inter-head file delta isTODO.md, and it is exactly #96's Completed Steps entry carried in frommain; both 2026-08-07 entries are present, this PR's ordered first.git range-diffshows all patch differences confined to the deleted-lines side (the old mock code, which #96 had rewritten onmainbefore this PR deletes it) — no new-side content changes beyond conflict-resolution necessities.Nothing from #96 clobbered.
git diff 9347a28 a535ae8 --name-onlylists only the PR's six files.internal/watcher/watcher.gois identical tomain(statusErrorconstant intact at lines 32/430/730, no logic change).internal/notify/*,internal/state/*,internal/config/*,.golangci.yml,Dockerfile, andscript/are identical tomain, so #96's goconst/dupl/lll fixes and the commit-pinned v2.12.2 toolchain carry through untouched.Lint under the now-active org-standard config.
make checkexits 0 (test + lint + fmt-check).make lintrun twice: 0 issues both times, consistent. Zeronolintoccurrences in the head-vs-base diff.Live-DNS suite behavior. Three full suite executions (one via
make check, two standalone), all with the test cache cleared beforehand: 0 failures, 0 flakes.make testwall time: 11.8s and 11.7s uncached — within the 20s policy budget and consistent with round 1 (11.6-12.2s). Watcher package ~1.9s; dominant cost remains the deliberate 10s unreachable-server resolver test (accepted round 1, unchanged).CI and mergeability. Head
a535ae864b:check / checksuccess (53s). Gitea reports the PR mergeable against currentmain.Standard checks. Single clean commit on base 9347a28; commit message accurate and descriptive with no attribution trailers and no vendor references (grep of the full commit: 0 hits). PR body Note correctly reflects the completed rebase; the stale whichever-merges-second text is gone.
Round-1 non-blocking robustness notes (10s blackhole burn in the unreachable-server test;
scanTimeoutat 25s vs the 30s package timeout) remain accurate and remain non-blocking under the #93 baseline.Manager: post-rebase re-review by a fresh independent reviewer PASSED with zero findings (comment above). Setting
merge-readyand assigning to sneak for merge (protectedmain).Rebase verified faithful: all five content files byte-identical to the previously-passed head 3959aed; only delta is
TODO.mdcarrying #96's entry frommain; nothing merged in #96 clobbered (watcher.go, notify/state/config tests,.golangci.yml,Dockerfile,script/all identical tomain); iron rule holds tree-wide (zero DNS mocks;fakeNS/fakeIPare seeded prior-state literals, not doubles); lint-clean under the org-standard config;make test11.7-11.8s uncached, 0 flakes across 3 runs; CI green on head a535ae8; mergeable. Nothing else blocks this PR.Remove DNS mocking from teststo WIP: Remove DNS mocking from testsWIP: Remove DNS mocking from teststo Remove DNS mocking from testsView command line instructions
Checkout
From your project repository, check out a new branch and test the changes.