feat(v4): add docker-compose and production-ready application

This commit is contained in:
2026-07-09 10:15:44 +03:30
parent 2112e00982
commit ece63caa22
13 changed files with 482 additions and 30 deletions

View File

@@ -8,6 +8,9 @@ from django.test import TestCase, override_settings
from PIL import Image
from rest_framework.test import APIClient
from processing.models import ImageState
from processing.storage import load_image_array
def png_upload(color=(32, 64, 128), size=(4, 4), name="sample.png"):
buffer = BytesIO()
@@ -15,6 +18,12 @@ def png_upload(color=(32, 64, 128), size=(4, 4), name="sample.png"):
return SimpleUploadedFile(name, buffer.getvalue(), content_type="image/png")
def grayscale_png_upload(value=96, size=(4, 4), name="gray.png"):
buffer = BytesIO()
Image.new("L", size, value).save(buffer, format="PNG")
return SimpleUploadedFile(name, buffer.getvalue(), content_type="image/png")
class ApiTests(TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
@@ -59,9 +68,13 @@ class ApiTests(TestCase):
self.assertIn("box_filter", operation_ids)
self.assertIn("median_filter", operation_ids)
self.assertIn("noise_filter", operation_ids)
self.assertIn("average_noisy_copies", operation_ids)
self.assertIn("rgb_to_gray", operation_ids)
self.assertEqual(operations["histeq"]["params"], {})
self.assertEqual(operations["noise_filter"]["label"], "Noise Filter")
self.assertEqual(operations["average_noisy_copies"]["label"], "Average N Noisy Copies")
self.assertEqual(operations["average_noisy_copies"]["params"]["N"]["default"], 100)
self.assertFalse(operations["average_noisy_copies"]["repeatable"])
self.assertEqual(operations["box_filter"]["label"], "Average / Box Filter")
self.assertEqual(operations["gaussian_filter"]["label"], "Gaussian Filter")
self.assertFalse(operations["negative"]["repeatable"])
@@ -173,6 +186,45 @@ class ApiTests(TestCase):
self.assertEqual(response.data["operation"], "noise_filter")
self.assertEqual(response.data["params"]["kind"], "salt_pepper")
def test_noise_filter_preserves_uploaded_grayscale_channel_count(self):
upload = self.client.post("/api/images/", {"image": grayscale_png_upload()}, format="multipart")
self.assertEqual(upload.status_code, 201)
self.assertEqual(upload.data["channels"], 1)
self.assertEqual(upload.data["color_mode"], "L")
s0_id = upload.data["states"][0]["state_id"]
response = self.client.post(
f"/api/states/{s0_id}/operations/",
{"operation": "noise_filter", "params": {"kind": "gaussian", "mean": 0, "variance": 0.01}},
format="json",
)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.data["channels"], 1)
self.assertEqual(response.data["color_mode"], "L")
state = ImageState.objects.get(id=response.data["state_id"])
self.assertEqual(load_image_array(state.image).ndim, 2)
def test_average_noisy_copies_creates_single_grayscale_result_state(self):
upload = self.client.post("/api/images/", {"image": grayscale_png_upload(value=96)}, format="multipart")
s0_id = upload.data["states"][0]["state_id"]
response = self.client.post(
f"/api/states/{s0_id}/operations/",
{"operation": "average_noisy_copies", "params": {"N": 10, "kind": "gaussian", "mean": 0, "variance": 0}},
format="json",
)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.data["operation"], "average_noisy_copies")
self.assertEqual(response.data["params"]["N"], 10)
self.assertEqual(response.data["channels"], 1)
self.assertEqual(response.data["color_mode"], "L")
self.assertEqual(ImageState.objects.count(), 2)
state = ImageState.objects.get(id=response.data["state_id"])
result = load_image_array(state.image)
self.assertEqual(result.ndim, 2)
self.assertEqual(int(result[0, 0]), 96)
def test_grayscale_operation_creates_state(self):
upload = self.client.post("/api/images/", {"image": png_upload()}, format="multipart")
s0_id = upload.data["states"][0]["state_id"]
@@ -183,6 +235,17 @@ class ApiTests(TestCase):
)
self.assertEqual(gray.status_code, 201)
self.assertEqual(gray.data["operation"], "rgb_to_gray")
self.assertEqual(gray.data["channels"], 1)
self.assertEqual(gray.data["color_mode"], "L")
noisy = self.client.post(
f"/api/states/{gray.data['state_id']}/operations/",
{"operation": "noise_filter", "params": {"kind": "salt_pepper", "amount": 0.1, "salt_ratio": 0.5}},
format="json",
)
self.assertEqual(noisy.status_code, 201)
self.assertEqual(noisy.data["channels"], 1)
self.assertEqual(noisy.data["color_mode"], "L")
@patch("processing.services.run_batch_job.delay")
def test_batch_returns_job_id(self, delay):