infrasynth-backend-kit/tests/test_files/test_processing.py
2026-08-28 14:38:47 -05:00

129 lines
4.9 KiB
Python

import io
import pytest
from django.core.files.uploadedfile import SimpleUploadedFile
from infrasynth.files.models import PipelineExecution, ProcessingPipeline
from infrasynth.files.processing import PipelineExecutor, run_pipeline_execution
from infrasynth.files.services import FileService
pytestmark = pytest.mark.django_db
def _make_image_png(width=200, height=100):
from PIL import Image
buffer = io.BytesIO()
Image.new("RGB", (width, height), color="red").save(buffer, format="PNG")
return buffer.getvalue()
@pytest.fixture
def image_file():
return SimpleUploadedFile("image.png", _make_image_png(), content_type="image/png")
@pytest.fixture
def stored_image(user, media_root, image_file):
return FileService().upload(image_file, filename="image.png", user=user)
@pytest.fixture
def sync_processing(settings):
settings.INFRASYNTH_FILES = {
**settings.INFRASYNTH_FILES,
"PROCESSING_BACKEND": "sync",
}
class TestPipelineExecutor:
def test_resize_step(self, stored_image, sync_processing):
pipeline = ProcessingPipeline.objects.create(
name="Resize",
slug="resize",
steps=[{"type": "resize", "params": {"width": 50}}],
)
execution = PipelineExecution.objects.create(file=stored_image, pipeline=pipeline)
PipelineExecutor().execute(execution)
execution.refresh_from_db()
assert execution.status == PipelineExecution.Status.COMPLETED
assert execution.output_file_id is not None
from PIL import Image
out = execution.output_file
backend = FileService()._resolve_file(out.id)
from infrasynth.files.storage import get_storage_backend
fh = get_storage_backend("local").open(backend.storage_key, "rb")
img = Image.open(fh)
assert img.width <= 50
assert img.height <= 50
def test_optimize_and_scan_steps(self, stored_image, sync_processing):
pipeline = ProcessingPipeline.objects.create(
name="Optimize",
slug="optimize",
steps=[{"type": "optimize", "params": {}}, {"type": "scan"}],
)
execution = PipelineExecution.objects.create(file=stored_image, pipeline=pipeline)
PipelineExecutor().execute(execution)
execution.refresh_from_db()
assert execution.status == PipelineExecution.Status.COMPLETED
assert execution.output_file_id is not None
def test_watermark_step(self, stored_image, sync_processing):
pipeline = ProcessingPipeline.objects.create(
name="Watermark",
slug="watermark",
steps=[{"type": "watermark", "params": {"text": "CONF"}}],
)
execution = PipelineExecution.objects.create(file=stored_image, pipeline=pipeline)
PipelineExecutor().execute(execution)
execution.refresh_from_db()
assert execution.status == PipelineExecution.Status.COMPLETED
assert execution.output_file.mime_type == "image/png"
def test_unknown_step_marks_failed(self, stored_image, sync_processing):
pipeline = ProcessingPipeline.objects.create(
name="Bad",
slug="bad",
steps=[{"type": "explode"}],
)
execution = PipelineExecution.objects.create(file=stored_image, pipeline=pipeline)
PipelineExecutor().execute(execution)
execution.refresh_from_db()
assert execution.status == PipelineExecution.Status.FAILED
assert "Unknown pipeline step" in execution.error
def test_emits_file_processed_signal(self, stored_image, sync_processing):
from infrasynth.files.signals import file_processed
sent = []
receiver = lambda **kw: sent.append(kw) # noqa: E731
file_processed.connect(receiver, weak=False)
pipeline = ProcessingPipeline.objects.create(
name="Resize", slug="resize2", steps=[{"type": "resize", "params": {}}]
)
execution = PipelineExecution.objects.create(file=stored_image, pipeline=pipeline)
PipelineExecutor().execute(execution)
assert sent
assert sent[0]["file_id"] == stored_image.id
assert sent[0]["pipeline_name"] == "resize2"
assert sent[0]["status"] == "completed"
file_processed.disconnect(receiver)
class TestRunPipelineExecutionTask:
def test_task_completes_execution(self, stored_image):
pipeline = ProcessingPipeline.objects.create(
name="Resize", slug="resize_task", steps=[{"type": "resize", "params": {}}]
)
execution = PipelineExecution.objects.create(file=stored_image, pipeline=pipeline)
result = run_pipeline_execution.delay(execution.id)
execution.refresh_from_db()
assert execution.status == PipelineExecution.Status.COMPLETED
assert result.id
def test_task_missing_execution_returns_none(self):
assert run_pipeline_execution.run(999999) is None