|
@@ -0,0 +1,85 @@
|
|
|
|
|
+"""Archiving a pending upload into a project checks the project first.
|
|
|
|
|
+
|
|
|
|
|
+The project id from the request was stored on the archive and the pending
|
|
|
|
|
+upload unchecked, after the file had already been archived: an unknown project
|
|
|
|
|
+failed with a server error on PostgreSQL (foreign key) with the archive files
|
|
|
|
|
+already written, and was stored as a broken link on SQLite. 0 skipped the
|
|
|
|
|
+archive but was stored on the pending upload.
|
|
|
|
|
+"""
|
|
|
|
|
+
|
|
|
|
|
+from __future__ import annotations
|
|
|
|
|
+
|
|
|
|
|
+from unittest.mock import AsyncMock, patch
|
|
|
|
|
+
|
|
|
|
|
+import pytest
|
|
|
|
|
+from httpx import AsyncClient
|
|
|
|
|
+from sqlalchemy import select
|
|
|
|
|
+
|
|
|
|
|
+from backend.app.models.archive import PrintArchive
|
|
|
|
|
+from backend.app.models.pending_upload import PendingUpload
|
|
|
|
|
+
|
|
|
|
|
+pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+async def _pending(db_session, tmp_path) -> PendingUpload:
|
|
|
|
|
+ file = tmp_path / "part.3mf"
|
|
|
|
|
+ file.write_bytes(b"3mf")
|
|
|
|
|
+ upload = PendingUpload(
|
|
|
|
|
+ filename="part.3mf", file_path=str(file), file_size=3, source_ip="192.168.1.100", status="pending"
|
|
|
|
|
+ )
|
|
|
|
|
+ db_session.add(upload)
|
|
|
|
|
+ await db_session.commit()
|
|
|
|
|
+ await db_session.refresh(upload)
|
|
|
|
|
+ return upload
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+async def test_an_unknown_project_is_refused_before_anything_is_archived(
|
|
|
|
|
+ async_client: AsyncClient, db_session, tmp_path
|
|
|
|
|
+):
|
|
|
|
|
+ upload_id = (await _pending(db_session, tmp_path)).id
|
|
|
|
|
+
|
|
|
|
|
+ with patch("backend.app.api.routes.pending_uploads.ArchiveService.archive_print", new=AsyncMock()) as archive:
|
|
|
|
|
+ response = await async_client.post(f"/api/v1/pending-uploads/{upload_id}/archive", json={"project_id": 9999})
|
|
|
|
|
+
|
|
|
|
|
+ assert response.status_code == 400, response.text
|
|
|
|
|
+ assert response.json()["detail"] == "Project not found"
|
|
|
|
|
+ archive.assert_not_awaited()
|
|
|
|
|
+ db_session.expire_all()
|
|
|
|
|
+ row = (
|
|
|
|
|
+ await db_session.execute(
|
|
|
|
|
+ select(PendingUpload.status, PendingUpload.project_id).where(PendingUpload.id == upload_id)
|
|
|
|
|
+ )
|
|
|
|
|
+ ).one()
|
|
|
|
|
+ assert tuple(row) == ("pending", None)
|
|
|
|
|
+ assert (tmp_path / "part.3mf").exists()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+async def _fake_archive_print(self, **_kwargs) -> PrintArchive:
|
|
|
|
|
+ """Stands in for archiving a real 3MF: one archive row in the route's session."""
|
|
|
|
|
+ archive = PrintArchive(filename="part.3mf", file_path="archive/part.3mf", file_size=3, status="archived")
|
|
|
|
|
+ self.db.add(archive)
|
|
|
|
|
+ await self.db.flush()
|
|
|
|
|
+ return archive
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@pytest.mark.parametrize("given", ["known", 0, None])
|
|
|
|
|
+async def test_a_known_project_or_none_is_stored(async_client: AsyncClient, db_session, tmp_path, given):
|
|
|
|
|
+ upload_id = (await _pending(db_session, tmp_path)).id
|
|
|
|
|
+ project_id = None
|
|
|
|
|
+ if given == "known":
|
|
|
|
|
+ project_id = (await async_client.post("/api/v1/projects/", json={"name": "P"})).json()["id"]
|
|
|
|
|
+
|
|
|
|
|
+ with patch("backend.app.api.routes.pending_uploads.ArchiveService.archive_print", new=_fake_archive_print):
|
|
|
|
|
+ response = await async_client.post(
|
|
|
|
|
+ f"/api/v1/pending-uploads/{upload_id}/archive",
|
|
|
|
|
+ json={"project_id": project_id if given == "known" else given},
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ assert response.status_code == 200, response.text
|
|
|
|
|
+ db_session.expire_all()
|
|
|
|
|
+ stored = (
|
|
|
|
|
+ await db_session.execute(select(PrintArchive.project_id).where(PrintArchive.id == response.json()["id"]))
|
|
|
|
|
+ ).scalar()
|
|
|
|
|
+ pending = (await db_session.execute(select(PendingUpload.project_id).where(PendingUpload.id == upload_id))).scalar()
|
|
|
|
|
+ assert stored == project_id
|
|
|
|
|
+ assert pending == project_id
|