Testing Strategy (TDD)
Relevant source files
The following files were used as context for generating this wiki page:
Kamal employs a multi-layered testing strategy centered around Ruby's Minitest framework and Mocha for mocking. The project enforces a strict requirement that all code must pass the test suite before being merged, emphasizing the addition of new tests for any changes or bug fixes. The strategy spans from isolated unit tests of configuration and command logic to full-scale integration tests that simulate real-world deployments using Docker-in-Docker environments.
Sources: CONTRIBUTING.md:25-33, CLAUDE.md:14, CLAUDE.md:79-83
Test Hierarchy and Architecture
The testing architecture is divided into distinct layers that mirror the application's structure. This allows for fast feedback loops during development while ensuring end-to-end reliability through complex integration scenarios.
Testing Layers
| Layer | Scope | Key Components |
|---|---|---|
| Unit Tests | Logic isolation | Configuration validation, command construction, utility functions. |
| CLI Tests | Command invocation | Thor command flow, mocking SSHKit and Kamal::Cli calls. |
| Integration Tests | Real-world simulation | Docker-in-Docker VMs, registry interactions, full kamal deploy cycles. |
Sources: CLAUDE.md:79-83, test/cli/main_test.rb:1-10, test/configuration_test.rb:1-20
Test Execution Flow
The following diagram illustrates how tests are organized and executed within the project environment.
The testing flow separates logic validation from environment-heavy integration tests to optimize developer time.
Sources: CLAUDE.md:43-48, test/integration/integration_test.rb:14-38
Unit Testing Strategy
Unit tests focus on individual components in isolation, primarily under test/ (excluding the integration folder). These tests do not require Docker and are used to verify the internal logic of the system.
Configuration and Validation
Extensive testing is performed on Kamal::Configuration to ensure that deploy.yml files are parsed correctly, secrets are validated before deployment, and required keys are present.
- Secret Validation: Tests ensure that
validate_secrets!fails fast if referenced secrets are missing, preventing partial or failed deployments. - Role/Host Logic: Tests verify that roles and hosts are correctly mapped, especially when using complex filtering or primary host overrides.
Sources: test/configuration_test.rb:30-60, test/configuration_test.rb:397-440
CLI Command Flow
CLI tests utilize CliTestCase to mock the underlying SSHKit backend. This allows developers to verify that the Kamal::Cli::Main commands (like setup, deploy, rollback) invoke the correct subcommands and scripts with the expected options without actually connecting to remote servers.
Sources: test/cli/main_test.rb:7-40, test/cli/cli_test_case.rb:1-30
Integration Testing Strategy
Integration tests, located in test/integration/, perform real deployments against a Docker-in-Docker (DinD) environment. This is the most comprehensive part of the suite, verifying that the CLI, proxy, and application interact correctly.
Environment Lifecycle
Integration tests manage their own lifecycle using Docker Compose, creating a temporary network of "Virtual Machines" (VMs), a private registry, and a deployer container.
Integration tests simulate the full deployment lifecycle from environment preparation to service validation.
Sources: test/integration/integration_test.rb:14-43, test/integration/main_test.rb:5-30
Key Integration Features
- Project Isolation: Every test run uses a unique
COMPOSE_PROJECT_NAMEbased on a SHA of the worktree path, allowing concurrent test runs across different worktrees. - Health Check Verification: The suite waits for containers to become "healthy" before proceeding, ensuring the proxy and app are fully operational.
- Hook Verification: Integration tests verify that lifecycle hooks (e.g.,
pre-deploy,post-deploy) are executed by checking for the presence of temporary files created by the hooks.
Sources: test/integration/integration_test.rb:10-12, test/integration/integration_test.rb:133-157, test/integration/main_test.rb:9-15
TDD Implementation Rules
The project follows strict Red-Green-Refactor principles, particularly for the dash fork.
- Mandatory Tests: Every new feature or fix must include corresponding tests.
- Fast-Fail Circuit Breaker: Integration tests include a
build_circuitthat trips if the initial Docker build fails, preventing the suite from wasting time on repeated failures for a broken environment. - Mocking and Stubbing:
Mochais used extensively in unit and CLI tests to stubSSHKitcalls, shell executions, and time-based operations likesleep.
Sources: CONTRIBUTING.md:25-33, CLAUDE.md:79-83, test/integration/integration_test.rb:16-19, test/cli/main_test.rb:230-245
Conclusion
Kamal's testing strategy ensures high confidence in deployment operations by balancing fast, isolated unit tests for configuration logic with heavy-duty integration tests for runtime behavior. By leveraging Docker-in-Docker, the project can verify complex networking, proxy, and container orchestration logic in a reproducible environment, adhering to strict TDD practices throughout development.