Testing & TDD Guidelines
Relevant source files
The following files were used as context for generating this wiki page:
Testing in the kamal-proxy project is a critical requirement for maintaining the stability of its proxying, certificate management, and security features. The project follows a strict Test-Driven Development (TDD) approach, emphasizing Go table-driven tests to ensure comprehensive coverage across various configurations and edge cases.
The testing architecture is designed to validate the system at multiple levels, from individual logic units (like compression negotiation) to full server-to-backend request cycles using httptest. All contributions must pass make test and maintain gofmt cleanliness before being merged into the dash branch.
Sources: CLAUDE.md:89-91, CLAUDE.md:120-123
Test-Driven Development (TDD) Workflow
The project utilizes specific automation commands to enforce a Red-Green-Refactor cycle. This ensures that features are defined by their tests before implementation and that regressions are caught early.
TDD Cycle Execution
The TDD process follows a structured sequence to ensure technical accuracy and coverage:
- Red (Fail): Define requirements via table-driven tests that fail initially.
- Green (Pass): Implement the minimum logic required to satisfy the test cases.
- Refactor: Clean up the implementation while ensuring the tests continue to pass.
The TDD workflow ensures that every feature is grounded in verifiable test cases before implementation.
Sources: CLAUDE.md:120-123
Testing Patterns & Tools
The repository standardizes on Go's testing package along with the testify library for assertions and requirements.
Table-Driven Tests
The project extensively uses table-driven tests to validate complex logic with multiple inputs, such as header negotiation, path rule parsing, and credential matching.
| Component | Test File | Focus Areas |
|---|---|---|
| Compression | compression_test.go | Q-value negotiation, content-type filtering, option validation |
| Basic Auth | basic_auth_test.go | Credential hashing, challenge logic, security exemptions |
| Path Rules | redirect_rules_test.go | RE2 pattern matching, capture groups, query preservation |
| Service Logic | service_test.go | HTTPS redirects, health check status during pause, request deadlines |
Sources: internal/server/compression_test.go:12-42, internal/server/basic_auth_test.go:70-90, internal/server/redirect_rules_test.go:12-65
Integration Testing with httptest
For features involving the HTTP stack, the project uses httptest.NewServer and httptest.NewRecorder to simulate real backends and capture proxy responses. This is evident in the testing of basic authentication challenges and redirect logic.
Sequence of a typical integration test using Go's httptest package.
Sources: internal/server/service_test.go:487-512, internal/server/basic_auth_test.go:28-40
Specific System Testing
Security & Authentication
Authentication tests verify that sensitive data, such as plaintext passwords, never cross the RPC socket or reach state files. Tests ensure that the proxy strips Authorization headers before forwarding requests to backends.
- Credential Matching: Validates SHA-256 salted hashes.
- Plaintext Leakage: Ensures
WWW-Authenticateis never sent over unencrypted HTTP. - Internal Exemptions: Confirms internal requests (like ACME probes) bypass auth.
Sources: internal/server/basic_auth_test.go:106-116, internal/server/basic_auth_test.go:250-264, internal/server/basic_auth_test.go:445-455
Path-Based Routing & Rewriting
Tests for path rules ensure that URL transformations occur correctly and safely.
- RE2 Integrity: Validates that malformed regular expressions are rejected during the deployment phase.
- Host Escaping: A critical security test ensures that captured paths cannot be used to craft scheme-relative URLs (e.g.,
//evil.com) to escape the configured host. - Rule Ordering: Confirms that the first matching rule in the configuration wins.
Sources: internal/cmd/deploy_path_rules_test.go:61-75, internal/server/redirect_rules_test.go:237-251, internal/server/redirect_rules_test.go:145-148
Resilience & Timeouts
The testing suite includes checks for request deadlines and target health.
- Request Deadlines: Tests verify that
RequestTimeoutcorrectly bounds slow response bodies and triggers a504 Gateway Timeout. - Event Stream Exceptions: Confirms that SSE (
text/event-stream) is exempt from request deadlines to allow long-lived connections.
Sources: internal/server/service_test.go:417-440, internal/server/service_test.go:465-485
Validation Commands
Standardized commands are used to maintain code quality across the repository.
| Command | Purpose |
|---|---|
make test | Runs the full Go test suite without requiring Docker. |
make docker | Performs a local image build as a smoke test. |
gofmt -l | Checks for code formatting compliance (enforced by CI). |
script/release-dash | Validates tag grammar and runs tests before pushing releases. |
Sources: CLAUDE.md:73-82, CLAUDE.md:94-97
Adherence to these testing and TDD guidelines ensures that kamal-proxy remains a reliable infrastructure component, particularly regarding its core responsibilities of traffic routing and security enforcement. Every new feature must be accompanied by relevant table-driven tests in the internal/server or internal/cmd packages.