Run tests inside Docker container. Uses path-based unique naming for containers and volumes to support multiple project folders and enable efficient caching. Args: args: Test arguments Returns: Exit code (0 for success, non-zero for failure)
(args: TestArgs)
| 337 | |
| 338 | |
| 339 | def run_docker_tests(args: TestArgs) -> int: |
| 340 | """Run tests inside Docker container. |
| 341 | |
| 342 | Uses path-based unique naming for containers and volumes to support |
| 343 | multiple project folders and enable efficient caching. |
| 344 | |
| 345 | Args: |
| 346 | args: Test arguments |
| 347 | |
| 348 | Returns: |
| 349 | Exit code (0 for success, non-zero for failure) |
| 350 | """ |
| 351 | project_root = Path.cwd() |
| 352 | |
| 353 | # Check Docker availability |
| 354 | if not _check_docker_available(): |
| 355 | ts_print("Error: Docker is not available or not running") |
| 356 | ts_print("") |
| 357 | ts_print("Please install Docker Desktop and ensure it's running:") |
| 358 | ts_print(" https://www.docker.com/products/docker-desktop") |
| 359 | return 1 |
| 360 | |
| 361 | # Build the Docker image |
| 362 | if not _build_docker_image(project_root, rebuild=args.clean): |
| 363 | return 1 |
| 364 | |
| 365 | # Get unique container and volume names based on project path |
| 366 | container_name = _get_container_name(project_root) |
| 367 | volumes = _get_volume_names(project_root) |
| 368 | path_hash = _get_path_hash(project_root) |
| 369 | |
| 370 | ts_print(f"Project path hash: {path_hash}") |
| 371 | ts_print(f"Container: {container_name}") |
| 372 | ts_print( |
| 373 | f"Volumes: {volumes.venv_volume}, {volumes.build_volume}, {volumes.cache_volume}" |
| 374 | ) |
| 375 | |
| 376 | # Run garbage collection (non-blocking, best-effort) |
| 377 | _run_garbage_collection() |
| 378 | |
| 379 | # Build the test command |
| 380 | test_cmd = _build_test_command(args) |
| 381 | test_cmd_str = " ".join(test_cmd) |
| 382 | |
| 383 | ts_print("=== Running Tests in Docker ===") |
| 384 | ts_print(f"Command: {test_cmd_str}") |
| 385 | ts_print("") |
| 386 | |
| 387 | # Remove any existing container with same name (in case of previous crash) |
| 388 | existing_container_id = docker_container_exists(container_name) |
| 389 | if existing_container_id: |
| 390 | ts_print(f"Removing existing container: {container_name}") |
| 391 | success, error_msg = docker_force_remove_container(existing_container_id) |
| 392 | if not success: |
| 393 | ts_print(f"Warning: Failed to remove existing container: {error_msg}") |
| 394 | |
| 395 | # Build rsync script for syncing host files to container |
| 396 | sync_script = _build_sync_script() |