fix: mock DNS in resolver tests for hermetic, fast unit tests

- Extract DNSClient interface from resolver to allow dependency injection
- Convert all resolver methods from package-level to receiver methods
  using the injectable DNS client
- Rewrite resolver_test.go with a mock DNS client that simulates the
  full delegation chain (root → TLD → authoritative) in-process
- Move 2 integration tests (real DNS) behind //go:build integration tag
- Add NewFromLoggerWithClient constructor for test injection
- Add LookupAllRecords implementation (was returning ErrNotImplemented)

All unit tests are hermetic (no network) and complete in <1s.
Total make check passes in ~5s.

Closes #12
This commit is contained in:
clawbot
2026-02-20 00:17:23 -08:00
committed by user
parent 1e04a29fbf
commit 0486dcfd07
7 changed files with 741 additions and 446 deletions

View File

@@ -39,7 +39,9 @@ type NameserverResponse struct {
// Resolver performs iterative DNS resolution from root servers.
type Resolver struct {
log *slog.Logger
log *slog.Logger
client DNSClient
tcp DNSClient
}
// New creates a new Resolver instance for use with uber/fx.
@@ -48,14 +50,33 @@ func New(
params Params,
) (*Resolver, error) {
return &Resolver{
log: params.Logger.Get(),
log: params.Logger.Get(),
client: &udpClient{timeout: queryTimeoutDuration},
tcp: &tcpClient{timeout: queryTimeoutDuration},
}, nil
}
// NewFromLogger creates a Resolver directly from an slog.Logger,
// useful for testing without the fx lifecycle.
func NewFromLogger(log *slog.Logger) *Resolver {
return &Resolver{log: log}
return &Resolver{
log: log,
client: &udpClient{timeout: queryTimeoutDuration},
tcp: &tcpClient{timeout: queryTimeoutDuration},
}
}
// NewFromLoggerWithClient creates a Resolver with a custom DNS
// client, useful for testing with mock DNS responses.
func NewFromLoggerWithClient(
log *slog.Logger,
client DNSClient,
) *Resolver {
return &Resolver{
log: log,
client: client,
tcp: client,
}
}
// Method implementations are in iterative.go.