From 4383eb009ebd21cf65ea063cc17d90dbbb2806e4 Mon Sep 17 00:00:00 2001 From: msramalho <19508417+msramalho@users.noreply.github.com> Date: Thu, 20 Feb 2025 10:00:39 +0000 Subject: [PATCH] fix to interoperability endpoint --- app/shared/business_logic.py | 9 ++++ app/tests/shared/test_business_logic.py | 50 +++++++++++++++++-- .../web/endpoints/test_interoperability.py | 14 ++++-- app/web/endpoints/interoperability.py | 7 +-- 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/app/shared/business_logic.py b/app/shared/business_logic.py index ffd9cb2..d179fda 100644 --- a/app/shared/business_logic.py +++ b/app/shared/business_logic.py @@ -10,7 +10,16 @@ from app.shared.db import worker_crud def get_store_archive_until(db: Session, group_id: str) -> datetime.datetime: group = worker_crud.get_group(db, group_id) assert group, f"Group {group_id} not found." + assert group.permissions and type(group.permissions) == dict, f"Group {group_id} has no permissions." + max_lifespan = group.permissions.get("max_archive_lifespan_months", -1) if max_lifespan == -1: return None return datetime.datetime.now() + datetime.timedelta(days=30 * max_lifespan) + + +def get_store_archive_until_or_never(db: Session, group_id: str) -> datetime.datetime: + try: + return get_store_archive_until(db, group_id) + except AssertionError as e: + return None diff --git a/app/tests/shared/test_business_logic.py b/app/tests/shared/test_business_logic.py index 80eecb3..225fb11 100644 --- a/app/tests/shared/test_business_logic.py +++ b/app/tests/shared/test_business_logic.py @@ -1,7 +1,8 @@ from datetime import datetime, timedelta from unittest.mock import MagicMock, patch import pytest -from app.shared.business_logic import get_store_archive_until +from app.shared.business_logic import get_store_archive_until, get_store_archive_until_or_never + class Test_get_store_archive_until: GROUP_ID = "test-group" @@ -11,6 +12,12 @@ class Test_get_store_archive_until: get_store_archive_until(db_session, self.GROUP_ID) assert str(exc.value) == f"Group {self.GROUP_ID} not found." + @patch("app.shared.db.worker_crud.get_group", return_value=MagicMock(permissions=None)) + def test_group_no_permissions(self, db_session): + with pytest.raises(AssertionError) as exc: + get_store_archive_until(db_session, self.GROUP_ID) + assert str(exc.value) == f"Group {self.GROUP_ID} has no permissions." + @patch("app.shared.db.worker_crud.get_group") def test_no_max_lifespan(self, mock_get_group, db_session): group = MagicMock() @@ -29,8 +36,45 @@ class Test_get_store_archive_until: result = get_store_archive_until(db_session, self.GROUP_ID) expected = datetime.now() + timedelta(days=180) # 6 months - + assert isinstance(result, datetime) # Allow 1 second difference due to execution time assert abs(result - expected) < timedelta(seconds=1) - mock_get_group.assert_called_once_with(db_session, self.GROUP_ID) \ No newline at end of file + mock_get_group.assert_called_once_with(db_session, self.GROUP_ID) + + +class Test_get_store_archive_until_or_never: + GROUP_ID = "test-group" + + def test_group_not_found(self, db_session): + result = get_store_archive_until_or_never(db_session, self.GROUP_ID) + assert result is None + + @patch("app.shared.db.worker_crud.get_group", return_value=MagicMock(permissions=None)) + def test_group_no_permissions(self, db_session): + result = get_store_archive_until_or_never(db_session, self.GROUP_ID) + assert result is None + + @patch("app.shared.db.worker_crud.get_group") + def test_no_max_lifespan(self, mock_get_group, db_session): + group = MagicMock() + group.permissions = {"max_archive_lifespan_months": -1} + mock_get_group.return_value = group + + result = get_store_archive_until_or_never(db_session, self.GROUP_ID) + assert result is None + mock_get_group.assert_called_once_with(db_session, self.GROUP_ID) + + @patch("app.shared.db.worker_crud.get_group") + def test_with_max_lifespan(self, mock_get_group, db_session): + group = MagicMock() + group.permissions = {"max_archive_lifespan_months": 6} + mock_get_group.return_value = group + + result = get_store_archive_until_or_never(db_session, self.GROUP_ID) + expected = datetime.now() + timedelta(days=180) # 6 months + + assert isinstance(result, datetime) + # Allow 1 second difference due to execution time + assert abs(result - expected) < timedelta(seconds=5) + mock_get_group.assert_called_once_with(db_session, self.GROUP_ID) diff --git a/app/tests/web/endpoints/test_interoperability.py b/app/tests/web/endpoints/test_interoperability.py index 14cd245..31cf8f0 100644 --- a/app/tests/web/endpoints/test_interoperability.py +++ b/app/tests/web/endpoints/test_interoperability.py @@ -47,10 +47,14 @@ def test_submit_manual_archive_invalid_json(client_with_token): assert r.json() == {"detail": "Invalid JSON in result field."} -@patch("app.web.endpoints.interoperability.business_logic") -def test_submit_manual_archive_no_store_until(m_b, client_with_token, db_session): - m_b.get_store_archive_until.side_effect = AssertionError("AssertionError") +@patch("app.web.endpoints.interoperability.business_logic.get_store_archive_until", side_effect=AssertionError("AssertionError")) +def test_submit_manual_archive_no_store_until(m_sau, client_with_token, db_session): aa_metadata = json.dumps({"status": "test: success", "metadata": {"url": "http://example.com"}, "media": [{"filename": "fn1", "urls": ["http://example.s3.com"]}]}) r = client_with_token.post("/interop/submit-archive", json={"result": aa_metadata, "public": True, "author_id": "jerry@gmail.com", "group_id": "spaceship", "tags": ["test"], "url": "http://example.com"}) - assert r.status_code == 422 - assert r.json() == {"detail": "AssertionError"} + assert r.status_code == 201 + assert len(r.json()["id"]) == 36 + res = db_session.query(models.Archive).filter(models.Archive.id == r.json()["id"]).first() + assert res.store_until is None + # testing that store_until = None is not comparable with datetime, and will always return False + res = db_session.query(models.Archive).filter(models.Archive.id == r.json()["id"], models.Archive.store_until < datetime.now()).first() + assert res is None diff --git a/app/web/endpoints/interoperability.py b/app/web/endpoints/interoperability.py index 085bacc..06ea175 100644 --- a/app/web/endpoints/interoperability.py +++ b/app/web/endpoints/interoperability.py @@ -34,11 +34,8 @@ def submit_manual_archive( manual.author_id = manual.author_id or ALLOW_ANY_EMAIL manual.tags.add("manual") - try: - store_until=business_logic.get_store_archive_until(db, manual.group_id) - except AssertionError as e: - log_error(e) - raise HTTPException(status_code=422, detail=str(e)) + store_until = business_logic.get_store_archive_until_or_never(db, manual.group_id) + logger.debug(f"[MANUAL ARCHIVE] {manual.author_id} {manual.url} {store_until}") try: archive = schemas.ArchiveCreate(