126 lines
3.7 KiB
Python
126 lines
3.7 KiB
Python
"""
|
|
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, request):
|
|
"""
|
|
Package the addon as a zip file for installation in Blender.
|
|
|
|
Detects version type from test file name and patches VERSION_TYPE accordingly.
|
|
|
|
Returns path to the packaged addon zip.
|
|
"""
|
|
src_dir = Path(__file__).parent.parent.parent / "src"
|
|
|
|
# Determine version type from test module name
|
|
test_file = request.node.fspath.basename
|
|
version_type = "free" if "free_version" in test_file else "full"
|
|
|
|
# Copy src to temp and patch constants.py
|
|
temp_src = tmp_path / "src_temp"
|
|
shutil.copytree(src_dir, temp_src)
|
|
|
|
constants_file = temp_src / "utils" / "constants.py"
|
|
content = constants_file.read_text()
|
|
content = content.replace('VERSION_TYPE = "free"', f'VERSION_TYPE = "{version_type}"')
|
|
constants_file.write_text(content)
|
|
|
|
# Create zip from patched source
|
|
addon_zip = tmp_path / "text_texture_generator.zip"
|
|
with zipfile.ZipFile(addon_zip, 'w', zipfile.ZIP_DEFLATED) as zf:
|
|
for file_path in temp_src.rglob("*"):
|
|
if file_path.is_file():
|
|
arc_name = f"text_texture_generator/{file_path.relative_to(temp_src)}"
|
|
zf.write(file_path, arc_name)
|
|
|
|
return addon_zip
|