Docker Testing Utilities
Relevant source files
The following files were used as context for generating this wiki page:
- src/flext_tests/_docker_parts/docker_part_01.py
- src/flext_tests/_docker_parts/docker_part_02.py
- src/flext_tests/_docker_parts/docker_part_03.py
- src/flext_tests/_docker_parts/docker_part_04.py
- src/flext_tests/_docker_parts/docker_part_05.py
- src/flext_tests/_docker_parts/docker_part_06.py
- src/flext_tests/_models/docker.py
The Docker Testing Utilities within flext-tests provide a robust infrastructure for managing Docker-based test environments. This system simplifies the lifecycle of containers, stacks, and shared services used during testing, offering a fluent DSL for orchestration, readiness validation, and state persistence.
The core of the system is the FlextTestsDocker class, which integrates with both the standard Docker SDK and python-on-whales to handle complex docker-compose operations. It ensures that test dependencies are consistently started, monitored for readiness, and cleaned up to prevent cross-test contamination.
Sources: src/flext_tests/_docker_parts/docker_part_01.py:1-20, README.md:1-10
Core Architecture and State Management
The architecture is built on a multi-part class hierarchy that separates concerns into model definition, client management, compose operations, and fluent API implementation.
State Persistence and Worker Isolation
The system tracks "dirty" containers—those that have been modified or require recreation—using a persistent JSON state file. This file is isolated by worker_id, allowing parallel test execution without state collisions between different test runners.
The state file is stored in ~/.flext/docker_state_{worker_id}.json.
Sources: src/flext_tests/_docker_parts/docker_part_02.py:17-30, src/flext_tests/_docker_parts/docker_part_02.py:73-100
Client Initialization
The system maintains two types of clients:
- WhalesDockerClient: A class-level static client used for high-level
docker-composeoperations. - DockerSDKClient: A lazily initialized instance-level client used for low-level container inspection and status checks.
Sources: src/flext_tests/_docker_parts/docker_part_01.py:22-25, src/flext_tests/_docker_parts/docker_part_02.py:38-51
Fluent DSL and Target Configuration
The utilities provide a Fluent DSL for defining test targets, allowing developers to quickly spin up shared infrastructure or specific compose stacks.
Target Resolution Flow
When a target is defined (via shared, compose, or stack), the system resolves the configuration into a ContainerConfig model.
Key Data Models
| Model | Field | Description |
|---|---|---|
ContainerConfig | container_name | Name of the container for inspection. |
compose_file | Resolved path to the docker-compose.yml. | |
service | Specific service name to start within the stack. | |
port | Host port used for readiness checks. | |
ContainerInfo | status | Current lifecycle status (running, exited, etc.). |
ports | Mapping of internal container ports to host ports. | |
image | Source image tag. |
Sources: src/flext_tests/_models/docker.py:19-75
Execution and Readiness Logic
The execute() method represents the primary entry point for ensuring a container is ready for testing. It orchestrates the entire lifecycle: checking status, starting if stopped, recreating if dirty, and polling for readiness.
Execution Workflow
Readiness Probes
Readiness is determined by attempting to establish a TCP connection to the resolved host port. The system automatically maps container ports to host ports by inspecting the Docker bindings.
def wait_for_port_ready(
self,
host: str,
port: int,
max_wait: int = 30,
) -> p.Result[bool]:
"""Wait until a TCP port is accepting connections."""
waited = 0.0
while waited < max_wait:
try:
with socket.create_connection((host, port), timeout=1):
return r[bool].ok(value=True)
except (ConnectionRefusedError, TimeoutError, OSError):
time.sleep(0.5)
waited += 0.5
return r[bool].ok(value=False)
Sources: src/flext_tests/_docker_parts/docker_part_04.py:57-73, src/flext_tests/_docker_parts/docker_part_01.py:80-94
Compose Operations
Low-level operations are handled via python-on-whales. The system dynamically manages the compose_files configuration in the client to target specific files during up and down operations.
- Up: Executes
docker compose up --detach --remove-orphans. Supportsforce_recreatewhich triggers adownfirst. - Down: Executes
docker compose down --volumes --remove-orphans. - Cleanup: Iterates through
dirty_container_namesand recreates them using their original shared configuration.
Sources: src/flext_tests/_docker_parts/docker_part_03.py:28-100, src/flext_tests/_docker_parts/docker_part_05.py:108-132
Summary
The Docker Testing Utilities provide a highly structured way to manage external dependencies. By combining persistent state tracking with a fluent DSL, the system ensures that Docker environments are isolated, predictable, and resilient across complex test suites. Developers can interact with these utilities through the tk (test kit) facade, which abstracts the underlying complexity of container synchronization and readiness validation.