Testing Guide
Overview
Clawker uses a multi-tier testing strategy with no build tags — test categories are separated by directory.Running Tests
Additional Makefile Targets
The Makefile prefers
gotestsum (if installed) for human-friendly output with icons and colors, falling back to go test.
Running Specific Tests
Golden File Testing
Standard Golden Files
Some tests compare output against golden files or recorded data. To update after intentional changes:Firewall Corefile Golden
The firewall package has a golden file test for CoreDNS config generation (controlplane/firewall/coredns_config_test.go). The golden file at controlplane/firewall/testdata/corefile_basic.golden must be hand-edited to update.
Storage Oracle + Golden Strategy
Theinternal/storage package uses a defense-in-depth approach with two independent guards for merge correctness:
Golden values are code (struct literals), not files — they must be hand-edited to change.
make storage-golden prints new values with interactive confirmation. The STORAGE_GOLDEN_BLESS env var is specific to this one test (no global sweep risk).
Local Development Environment
Themake localenv target creates an isolated XDG directory tree for manual UAT without polluting your real config:
.config/, .local/share/, .local/state/, .cache/). The CLI creates its own clawker/ subdirectories on first use (e.g., clawker project init). The exported env vars point to the app-level paths so the storage resolver picks them up.
Writing Tests
Isolated Test Environments (internal/testenv)
The testenv package provides unified, progressively-configured test environments for any test that needs XDG directory isolation. It eliminates duplicated directory setup across test helpers.
Writing Config Files in Tests
UseWriteYAML to place config files at canonical locations:
ConfigFile constants: ProjectConfig, ProjectConfigLocal, Settings, EgressRules, ProjectRegistry.
Delegation
Higher-level helpers delegate to testenv:configmocks.NewIsolatedTestConfig(t)→testenv.New(t, testenv.WithConfig())projectmocks.NewTestProjectManager(t, gf)→testenv.New(t, testenv.WithProjectManager(gf))test/e2e/harness.NewIsolatedFS()→testenv.New(h.T)+ project dir + chdir
Test Infrastructure
Each package in the dependency DAG provides test utilities so dependents can mock the entire chain:
Rule: If a dependency node lacks test infrastructure, add it before writing tests that depend on it.
Command Test Pattern
Commands are tested using the Cobra+Factory pattern withmocks.FakeClient. Each command’s test file typically defines a testFactory helper that wires the minimum closures needed (Config, Logger, Client, etc.). The pattern looks like:
Three Test Tiers for Commands
E2E Test Harness (test/e2e/harness/)
For E2E tests exercising the full stack with real Docker:
configmocks.NewBlankConfig, mocks.FakeClient, hostproxytest.MockManager, adminv1mocks.AdminServiceClientMock), while Logger always creates a real, settings-driven file logger via logcfg.New (mirroring production), and ProjectManager, GitManager, and SocketBridge default to nil.
Harness Types
Harness Functions
Cleanup
NewIsolatedFS registers a single cleanup chain:
- Stop daemons (firewall down, host-proxy stop)
- Remove shared firewall infrastructure containers (by
purpose=firewalllabel) - Remove control plane container (by
purpose=controlplanelabel) - Remove test-labeled containers, volumes, networks (by
dev.clawker.test.namelabel) - Remove test-labeled images (by
dev.clawker.test.namelabel)
clawker.log, hostproxy.log, and clawker-controlplane.log from the test’s state dir.
Project Test Double Scenarios
Useinternal/project/mocks/stubs.go to pick the lightest project dependency double:
Example:
Key Conventions
- All tests must pass before any change is complete —
make testat minimum - No build tags — test categories separated by directory
- Always use
t.Cleanup()for resource cleanup - Use
context.Background()in cleanup functions — parent context may be cancelled - Unique agent names — include timestamp + random suffix for parallel safety
- Never import
test/e2e/harnessin co-located unit tests — too heavy (pulls Docker SDK) - Never call
factory.New()in tests — construct&cmdutil.Factory{}struct literals directly - Docker resource labeling — all test resources carry
dev.clawker.test=true+dev.clawker.test.name=TestName; whail tests usecom.whail.test.managed=true - Use
make test-cleanto remove leaked Docker resources from failed test runs