"""A reprint of a single-plate archive does not leave the old video behind. A video attached by hand, or before the plate column existed, has no plate on record. On a reprint it was always kept, because on a Send All archive it can be another plate's only copy; on an archive with one plate there is no other plate, so it was just an orphan file per reprint. It is now deleted there, and still kept when the archive's 3MF has several plates or cannot be read. """ import zipfile from contextlib import ExitStack from unittest.mock import AsyncMock, MagicMock, patch import pytest from backend.app.core.config import settings as app_settings from backend.app.main import register_expected_print from backend.tests.unit.test_reprint_clears_stale_timelapse import ( # noqa: F401 _build_mocks, _clear_dicts, _patches, ) pytestmark = pytest.mark.asyncio def _three_mf(path, plates: int | None): path.parent.mkdir(parents=True, exist_ok=True) if plates is None: path.write_bytes(b"not a zip") return body = "".join(f'' for n in range(1, plates + 1)) with zipfile.ZipFile(path, "w") as zf: zf.writestr("Metadata/slice_info.config", f"{body}") async def _reprint(tmp_path, plates): relpath = "archives/42/timelapse/by-hand.mp4" video = tmp_path / relpath video.parent.mkdir(parents=True, exist_ok=True) video.write_bytes(b"old video") _three_mf(tmp_path / "archives/42/MyModel.3mf", plates) printer = MagicMock(id=1, auto_archive=True, external_camera_enabled=False, external_camera_url=None) archive = MagicMock( id=42, filename="MyModel.3mf", subtask_id=None, print_time_seconds=None, created_by_id=None, printer_id=1, print_name="MyModel", status="archived", file_path="archives/42/MyModel.3mf", energy_start_kwh=None, timelapse_path=relpath, timelapse_plate_id=None, # not on record ) register_expected_print(1, "MyModel.3mf", archive_id=42, ams_mapping=None, plate_id=1) session = _build_mocks(printer, archive) patches = _patches() with ExitStack() as stack: maker, notif, plug, ws, pm, relay = (stack.enter_context(p) for p in patches[:6]) for extra in patches[6:]: stack.enter_context(extra) stack.enter_context(patch.object(app_settings, "base_dir", tmp_path)) # The mock printer has no camera to reach. stack.enter_context( patch("backend.app.services.camera.capture_camera_frame_bytes", AsyncMock(return_value=None)) ) maker.return_value = session notif.on_print_start = AsyncMock() plug.on_print_start = AsyncMock() ws.send_print_start = AsyncMock() ws.send_archive_updated = AsyncMock() relay.on_print_start = AsyncMock() pm.get_printer = MagicMock(return_value=MagicMock(name="Test", serial_number="TEST123")) from backend.app.main import on_print_start await on_print_start(1, {"filename": "MyModel.3mf", "subtask_name": "MyModel"}) return video, archive async def test_on_a_single_plate_archive_it_is_deleted(tmp_path): video, archive = await _reprint(tmp_path, plates=1) assert archive.timelapse_path is None assert not video.exists() @pytest.mark.parametrize("plates", [2, None], ids=["several-plates", "unreadable-3mf"]) async def test_where_it_could_be_another_plates_it_is_kept(tmp_path, plates): video, archive = await _reprint(tmp_path, plates=plates) assert archive.timelapse_path is None assert video.exists()