129 lines
4.9 KiB
Python
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
|