Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-03-04 16:41:54 -05:00
parent 8ee8e5e956
commit e8f8574053
34 changed files with 7164 additions and 49 deletions
@@ -0,0 +1,185 @@
# Quickstart: Smart DNS Server Resolution Modes
**Feature Branch**: `002-server-resolution-modes`
**Date**: 2026-03-04
---
## Prerequisites
- Go 1.20 toolchain installed and on `PATH`
- Repository cloned and on branch `002-server-resolution-modes`
- `go mod tidy` run successfully
## Build
```powershell
# From repository root
go build -o dns-helper.exe .
```
Cross-compile (existing build.ps1 pattern):
```powershell
.\build.ps1
```
## Run Tests
```powershell
go test ./... -v
```
## TDD Workflow
This feature follows the Red-Green-Refactor cycle mandated by Constitution Principle VI.
### Order of Implementation
The recommended implementation order (each step follows TDD):
1. **`resolver/parse.go`** — `ParseServerFlag()` and `ExtractLabelLevels()` (pure functions, no I/O)
2. **`platform/network.go`** — `NetworkInfo` type, `NetworkDiscoverer` interface, `FakeNetworkDiscoverer`
3. **`platform/network_windows.go`** — Windows `Discover()` implementation
4. **`platform/network_linux.go`** — Linux `Discover()` implementation
5. **`platform/network_darwin.go`** — macOS `Discover()` implementation
6. **`resolver/pool.go`** — `BuildResolverPool()` and `BootstrapResolvers`
7. **`resolver/transport.go`** — Generalized `udpQuery()` shared transport (extract from existing `resolver.go`)
8. **`resolver/authority.go`** — `ParallelNSFanOut()`, `SelectAuthoritativeNS()`, `QueryAuthoritative()`
9. **`resolver/splithorizon.go`** — `CheckSplitHorizon()` (Stage 2.5 cross-check)
10. **`resolver/fallback.go`** — `ParallelAFallback()`
11. **`resolver/modes.go`** — `Resolve()` mode dispatcher integrating all components
12. **`main.go`** — Update CLI flag parsing, wire new resolver pipeline
### Per-Step TDD Cycle
For each item above:
1. **Red**: Write the test in `*_test.go` — it should fail (function doesn't exist yet).
2. **Green**: Implement the minimum code to make the test pass.
3. **Refactor**: Clean up while keeping tests green.
Example for `ParseServerFlag`:
```go
// resolver/parse_test.go
func TestParseServerFlag_Default(t *testing.T) {
mode, err := resolver.ParseServerFlag("")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mode.Mode != "default" {
t.Errorf("expected mode 'default', got %q", mode.Mode)
}
}
func TestParseServerFlag_Local(t *testing.T) {
mode, err := resolver.ParseServerFlag("local")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mode.Mode != "local" {
t.Errorf("expected mode 'local', got %q", mode.Mode)
}
}
func TestParseServerFlag_InvalidPort(t *testing.T) {
_, err := resolver.ParseServerFlag("10.0.0.53:0")
if err == nil {
t.Fatal("expected error for port 0")
}
}
```
### Testing Parallel Fan-out
Use the existing fake DNS server helpers from `resolver/resolver_test.go`:
```go
// Start multiple fake DNS servers, each responding to NS queries differently.
// Pass their addresses as the resolver pool to ParallelNSFanOut.
ns1 := startFakeDNS(t, handleNSQuery("example.com", []string{"ns1.example.com."}))
ns2 := startFakeDNS(t, handleNSQueryNXDOMAIN)
results := resolver.ParallelNSFanOut(ctx, []string{ns1, ns2}, []string{"example.com"}, 3*time.Second)
// Assert: 2 results, one with NS records, one with nil
```
### Testing Platform Discovery
Use `FakeNetworkDiscoverer` for unit tests — never call real OS commands in unit tests:
```go
fake := &platform.FakeNetworkDiscoverer{
Info: platform.NetworkInfo{
DNSServers: []string{"10.0.0.1", "10.0.0.2"},
Gateway: "10.0.0.1",
Interface: "eth0",
},
}
pool := resolver.BuildResolverPool(resolver.ServerMode{Mode: "default"}, fake.Info)
// Assert: pool contains local resolvers + bootstrap set
```
Platform-specific integration tests (build-tagged) can test real `os/exec` parsing:
```go
//go:build windows
func TestWindowsDiscover(t *testing.T) {
d := &platform.WindowsNetworkDiscoverer{}
info, err := d.Discover()
// Assert: no error, DNSServers non-empty on a typical system
}
```
## Manual Verification
### Smart Default Resolution (no -server)
```powershell
# Should discover authoritative NS for example.com and query it directly
.\dns-helper.exe add -host www.example.com -verbose
```
### Local Resolver Mode
```powershell
.\dns-helper.exe add -host internal.corp.local -server local -verbose
```
### Gateway Mode
```powershell
.\dns-helper.exe add -host www.example.com -server gateway -verbose
```
### Explicit IP (existing, unchanged)
```powershell
.\dns-helper.exe add -host www.example.com -server 8.8.8.8
```
### Timeout Override
```powershell
.\dns-helper.exe add -host www.example.com -timeout 1 -verbose
```
## Key Files Changed (Summary)
| File | Change |
|------|--------|
| `main.go` | Updated `runAdd()`: `-server` optional, new `-timeout`/`-verbose` flags, mode dispatch |
| `resolver/resolver.go` | Existing code unchanged; generalized UDP transport extracted |
| `resolver/parse.go` | **New**: `ParseServerFlag()`, `ExtractLabelLevels()` |
| `resolver/pool.go` | **New**: `BuildResolverPool()`, `BootstrapResolvers` |
| `resolver/transport.go` | **New**: shared `udpQuery()` transport layer |
| `resolver/authority.go` | **New**: `ParallelNSFanOut()`, `SelectAuthoritativeNS()`, `QueryAuthoritative()` |
| `resolver/splithorizon.go` | **New**: `CheckSplitHorizon()` — Stage 2.5 cross-check |
| `resolver/fallback.go` | **New**: `ParallelAFallback()` |
| `resolver/modes.go` | **New**: `Resolve()` mode dispatcher |
| `platform/platform.go` | Extended with `NetworkInfo`, `NetworkDiscoverer` interface |
| `platform/platform_windows.go` | **Extended**: `Discover()` via `netsh` |
| `platform/platform_linux.go` | **Extended**: `Discover()` via `ip route` + `/etc/resolv.conf` |
| `platform/platform_darwin.go` | **Extended**: `Discover()` via `route` + `scutil` |