This document outlines the testing strategy for Ansible playbooks in the Torrust Tracker Deployer project. Based on comprehensive research and the implementation of E2E Test Split Architecture, we have established a phase-specific testing approach that uses both LXD containers and Docker containers optimally for different deployment phases.
After extensive research, testing, and architecture evolution, we have adopted a phase-specific testing strategy that prioritizes:
- Phase Separation: Different deployment phases tested with optimal technologies
- Completeness: Full coverage from infrastructure provisioning to application deployment
- Efficiency: Fast feedback loops where possible, comprehensive testing where necessary
- Production Parity: Test environments that accurately reflect production behavior
┌─────────────────────────────────────────────────────────────────┐
│ Ansible Testing Strategy │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────────────────┐ │
│ │ Provision Phase │ │ Configuration Phase │ │
│ │ │ │ │ │
│ │ 🖥️ LXD VMs │ │ 🐳 Docker Containers │ │
│ │ 🏗️ OpenTofu │ │ 📋 Ansible Playbooks │ │
│ │ ☁️ Cloud-init │ │ 🔧 provisioned-instance │ │
│ │ │ │ │ │
│ │ Tests: │ │ Tests: │ │
│ │ • VM creation │ │ • install-docker.yml │ │
│ │ • SSH access │ │ • install-docker-compose │ │
│ │ • User setup │ │ • update-apt-cache.yml │ │
│ │ • Cloud-init ✓ │ │ • Service configuration │ │
│ └─────────────────┘ └─────────────────────────────┘ │
│ ~20-30s ~3-5s per playbook │
└─────────────────────────────────────────────────────────────────┘
- ✅ Test VM provisioning and infrastructure creation
- ✅ Validate cloud-init execution and completion
- ✅ Verify SSH access and user setup
- ✅ Confirm network connectivity and basic system state
- ✅ Test OpenTofu infrastructure management
- ✅ Test Ansible playbooks like
install-docker.yml,install-docker-compose.yml - ✅ Validate software installation and system configuration
- ✅ Support Docker-in-Docker scenarios for application deployment
- ✅ Test service management and configuration
- ✅ Verify package downloads and dependency installation
Use optimal technology per deployment phase based on research findings and E2E test split architecture:
-
Provision Phase: LXD VMs for complete infrastructure testing
- ✅ Full VM provisioning and cloud-init testing
- ✅ Real networking and system-level capabilities
- ✅ Production-equivalent environment behavior
- ⏱️ ~20-30s setup time (acceptable for comprehensive testing)
-
Configuration Phase: Docker Containers for fast Ansible testing
- ✅ Fast feedback loops (~3-5s setup time)
- ✅ Docker-in-Docker support for application deployment
- ✅ Sufficient system capabilities for software installation
- ✅ Reliable GitHub Actions compatibility
# Test infrastructure provisioning and destruction lifecycle with LXD VMs
cargo run --bin e2e-provision-and-destroy-tests
# What this tests:
# - VM creation via OpenTofu + LXD
# - Cloud-init completion and user setup
# - SSH access and connectivity
# - Basic system state validation
# - Infrastructure destruction via DestroyCommand
# - Fallback to manual cleanup on destroy failures
# Time: ~20-30 seconds# Test software installation with Docker containers
cargo run --bin e2e-config-tests
# What this tests:
# - Container creation (provisioned-instance state)
# - Ansible playbook execution:
# - install-docker.yml
# - install-docker-compose.yml
# - update-apt-cache.yml
# - Service configuration and validation
# Time: ~10-15 seconds totalBoth test suites can run independently and in parallel:
# Run both test phases simultaneously
cargo run --bin e2e-provision-and-destroy-tests &
cargo run --bin e2e-config-tests &
wait- Optimal Performance: Fast feedback for configuration changes (~3-5s), comprehensive testing for infrastructure (~20-30s)
- Better Isolation: Infrastructure issues don't block configuration testing and vice versa
- Parallel Execution: Both phases can run simultaneously, reducing total test time
- Technology Fit: Each phase uses the most appropriate technology for its requirements
- Easier Debugging: Clear separation makes it easier to identify whether issues are infrastructure or configuration related
- CI/CD Optimized: Docker containers avoid GitHub Actions networking issues while LXD provides complete VM testing
Note: The following alternatives were extensively researched and informed our final phase-specific approach. See decision records:
- Docker Testing Evolution - Complete evolution from rejection to acceptance
- Docker Testing Revision - Updated decision for configuration phase
Description: Official Ansible testing framework using Docker containers as test instances.
Pros:
- Fast execution (containers vs VMs)
- Built specifically for Ansible testing
- Supports multiple scenarios and test phases
- Good integration with pytest for advanced testing
- Can test idempotency automatically
Cons:
- Limited systemd support in containers (affects service-related playbooks)
- Cannot test kernel modules or low-level system features
- Docker-specific networking might not reflect real VM behavior
Description: Use Vagrant to provision VMs for testing playbooks in isolated environments.
Pros:
- Full VM isolation between tests
- Complete OS environment (systemd, kernel modules, etc.)
- Can test cloud-init integration accurately
- Supports multiple OS distributions
Cons:
- Slower than containers (VM startup overhead)
- Higher resource consumption
- More complex setup and maintenance
Description: Use LXD containers which provide VM-like features with container speed.
Pros:
- Faster than VMs, slower than Docker but more complete
- Better systemd support than Docker
- Can run cloud-init properly
- Good isolation between tests
Cons:
- Requires LXD setup and configuration
- Less portable than Docker solutions
- Still some limitations compared to full VMs
Description: Run tests in CI using different OS versions in GitHub Actions runners.
Pros:
- Real Ubuntu/Debian environments
- Parallel execution across OS versions
- No local resource consumption
- Easy integration with existing CI
Cons:
- Slower feedback loop
- Limited to GitHub-supported OS versions
- Cannot test certain networking scenarios
- Shared runner limitations
Description: Use Docker Compose to orchestrate test environments and Testinfra to verify playbook results.
Pros:
- Fast container-based testing
- Can test multi-host scenarios easily
- Python-based assertions (familiar for many)
- Good for testing final states rather than Ansible execution
Cons:
- Tests the result, not the Ansible execution itself
- Requires maintaining both playbooks and test code
- Limited system-level testing capabilities
Description: Use Test Kitchen (from Chef ecosystem) with Ansible provisioner and multiple drivers.
Pros:
- Supports multiple virtualization backends
- Good lifecycle management (create, converge, verify, destroy)
- Can switch drivers based on test requirements
Cons:
- Less Ansible-native than Molecule
- Additional learning curve
- Primarily designed for Chef, adapted for Ansible
Based on comprehensive research, performance testing, and E2E test split implementation, we have adopted a phase-specific testing strategy that provides:
-
Provision Phase (LXD VMs):
- Complete infrastructure provisioning testing
- Cloud-init and VM lifecycle validation
- OpenTofu infrastructure management testing
- Production-equivalent environment behavior
-
Configuration Phase (Docker Containers):
- Fast Ansible playbook testing
- Software installation and configuration validation
- Docker-in-Docker capability for application deployment
- Efficient CI/CD pipeline integration
-
Container Architecture:
docker/provisioned-instance/- Ubuntu 24.04 LTS base (matches production VMs)
- SSH server via supervisor (not systemd)
- Password + SSH key authentication support
- Ready state for configuration phase testing
Provision Phase Testing:
- Ubuntu 24.04 LXD containers with cloud-init support
- OpenTofu infrastructure management
- SSH access using fixtures/testing_rsa keys
- VM creation and basic system validation
Configuration Phase Testing:
docker/provisioned-instance/container simulation- Ansible connectivity via SSH (password + key auth)
- Docker container lifecycle management
- Software installation and service configuration
Test Execution Patterns:
# Provision and destroy phase (runs independently)
cargo run --bin e2e-provision-and-destroy-tests
# - VM creation ~20-30s
# - Cloud-init validation
# - SSH connectivity verification
# - Infrastructure destruction via DestroyCommand
# - Cleanup and resource management
# Configuration phase (runs independently)
cargo run --bin e2e-config-tests
# - Container creation ~2-3s
# - SSH key setup via password auth
# - Ansible playbook execution
# - Software installation validation
# - Container cleanupPerformance Metrics:
- Provision phase: ~20-30 seconds (comprehensive infrastructure testing)
- Configuration phase: ~10-15 seconds (fast configuration validation)
- Total parallel execution: ~20-30 seconds (both phases simultaneously)
- Significant improvement: 50-60% faster than sequential LXD-only approach
Each playbook must include:
- Pre-condition checks: Verify environment requirements before execution
- Post-condition validation: Confirm expected state after execution
- Idempotency testing: Ensure safe re-execution
- Error handling: Graceful failure with clear messaging
This strategy addresses our specific needs by leveraging the best aspects of both technologies while avoiding their limitations:
- Complete VM Testing: Full cloud-init, networking, and system-level capability testing
- Production Equivalence: LXD containers behave identically to cloud VMs
- Infrastructure Focus: Tests actual VM provisioning and infrastructure management
- OpenTofu Integration: Natural fit for infrastructure-as-code testing
- Fast Feedback: ~3-5s setup enables rapid configuration development cycles
- Docker-in-Docker: Proven capability for application deployment testing (research validated)
- CI/CD Optimized: Avoids GitHub Actions networking issues encountered with LXD
- Sufficient Capabilities: Meets all requirements for software installation and configuration testing
- Optimal Performance: Fast where possible, comprehensive where necessary
- Better Test Isolation: Infrastructure and configuration issues don't interfere with each other
- Parallel Execution: Significant time savings through concurrent test execution
- Technology Appropriateness: Each phase uses the most suitable technology
- Easier Maintenance: Clear separation of concerns reduces complexity
- ✅ Provision and Destroy Phase Testing:
e2e-provision-and-destroy-testsbinary with LXD VM testing - ✅ Docker Container Infrastructure:
docker/provisioned-instance/configuration - ✅ SSH Authentication: Password + SSH key support for container connectivity
- ✅ Supervisor Integration: Container-friendly process management
- ✅ Performance Benchmarking: Validated phase-specific approach benefits
- ✅ Decision Documentation: Comprehensive decision records and architecture docs
- 🔄 Configuration Phase Testing:
e2e-config-testsbinary implementation (Phase B.3) - 🔄 Container Lifecycle Management: Integration with test binary
- 🔄 Ansible Playbook Integration: Testing install-docker.yml, install-docker-compose.yml
- 🔄 GitHub Actions Workflow: CI/CD pipeline for configuration testing
- Complete Phase B.3: Implement
e2e-config-testsbinary with Docker container integration - Playbook Validation: Add comprehensive pre/post-condition checking to all playbooks
- CI/CD Integration: Implement parallel test execution in GitHub Actions
- Future Container Phases: Design
configured-instance,released-instancecontainers - Monitoring and Metrics: Track test performance and reliability over time