""" E2E test fixtures for Docker-based Blender testing. Manages Docker container lifecycle for real Blender tests. """ import pytest import docker import shutil import zipfile from pathlib import Path import time @pytest.fixture(scope="module") def docker_client(): """Provide Docker client for container management.""" try: client = docker.from_env() # Verify Docker is running client.ping() return client except docker.errors.DockerException as e: pytest.skip(f"Docker not available: {e}") @pytest.fixture(scope="module") def blender_image(docker_client): """Build Blender Docker image if not exists.""" image_tag = "text-texture-generator-e2e:latest" dockerfile_path = Path(__file__).parent / "docker" try: # Try to get existing image docker_client.images.get(image_tag) print(f"Using existing Docker image: {image_tag}") except docker.errors.ImageNotFound: print(f"Building Docker image: {image_tag}") # Build image docker_client.images.build( path=str(dockerfile_path), tag=image_tag, rm=True ) return image_tag @pytest.fixture(scope="function") def blender_container(docker_client, blender_image, tmp_path): """ Spin up Blender container for test execution. Yields container instance, cleans up after test. """ container = None try: # Start container with addon mounted container = docker_client.containers.run( blender_image, command="/bin/sleep 3600", # Keep alive for test duration detach=True, remove=False, # We'll remove manually after cleanup volumes={ str(tmp_path): {"bind": "/addon-test", "mode": "rw"} } ) # Wait for container to be ready timeout = 10 start = time.time() while time.time() - start < timeout: container.reload() if container.status == "running": break time.sleep(0.5) if container.status != "running": pytest.fail(f"Container failed to start: {container.status}") yield container finally: # Cleanup if container: try: container.stop(timeout=5) container.remove() except Exception as e: print(f"Warning: Container cleanup failed: {e}") @pytest.fixture(scope="function") def addon_package(tmp_path): """ Package the addon as a zip file for installation in Blender. Returns path to the packaged addon zip. """ src_dir = Path(__file__).parent.parent.parent / "src" addon_zip = tmp_path / "text_texture_generator.zip" # Create zip with addon contents with zipfile.ZipFile(addon_zip, 'w', zipfile.ZIP_DEFLATED) as zf: for file_path in src_dir.rglob("*"): if file_path.is_file(): # Add file with relative path from src/ arc_name = f"text_texture_generator/{file_path.relative_to(src_dir)}" zf.write(file_path, arc_name) return addon_zip