diff --git a/layer/nrlf/core/dynamodb/repository.py b/layer/nrlf/core/dynamodb/repository.py index 26a36deef..7c2ef6954 100644 --- a/layer/nrlf/core/dynamodb/repository.py +++ b/layer/nrlf/core/dynamodb/repository.py @@ -344,6 +344,7 @@ def delete_by_id(self, id_: str, can_ignore_delete_fail: bool = False): key = f"D#{id_}" try: self.table.delete_item(Key={"pk": key, "sk": key}) + logger.log(LogReference.REPOSITORY027, id=id_) except Exception as exc: if can_ignore_delete_fail: logger.log( @@ -352,6 +353,13 @@ def delete_by_id(self, id_: str, can_ignore_delete_fail: bool = False): stacklevel=5, error=str(exc), ) + else: + raise OperationOutcomeError( + status_code="500", + severity="error", + code="exception", + details=SpineErrorConcept.from_code("INTERNAL_SERVER_ERROR"), + ) from exc def _query(self, **kwargs) -> Iterator[DocumentPointer]: """ diff --git a/layer/nrlf/core/dynamodb/tests/test_repository.py b/layer/nrlf/core/dynamodb/tests/test_repository.py index 75a8b605d..387df8d0d 100644 --- a/layer/nrlf/core/dynamodb/tests/test_repository.py +++ b/layer/nrlf/core/dynamodb/tests/test_repository.py @@ -1,7 +1,33 @@ +from unittest.mock import patch + import pytest +from moto import mock_aws from nrlf.core.constants import PointerTypes -from nrlf.core.dynamodb.repository import _get_sk_ids_for_type +from nrlf.core.dynamodb.model import DocumentPointer +from nrlf.core.dynamodb.repository import ( + DocumentPointerRepository, + _get_sk_ids_for_type, +) +from nrlf.core.errors import OperationOutcomeError +from nrlf.core.log_references import LogReference +from nrlf.tests.data import load_document_reference +from nrlf.tests.dynamodb import mock_repository + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def make_document_pointer(id: str = "Y05868-99999-99999-999999") -> DocumentPointer: + doc_ref = load_document_reference("Y05868-736253002-Valid") + doc_ref.id = id + return DocumentPointer.from_document_reference(doc_ref) + + +# --------------------------------------------------------------------------- +# _get_sk_ids_for_type +# --------------------------------------------------------------------------- def test_get_sk_ids_for_type_exception_thrown_for_invalid_type(): @@ -30,4 +56,97 @@ def test_get_sk_ids_for_type_exception_thrown_if_new_type_has_no_category(): ) -# TODO: Add unit tests for Repository Class +# --------------------------------------------------------------------------- +# DocumentPointerRepository.supersede +# --------------------------------------------------------------------------- + + +@mock_aws +@mock_repository +def test_supersede_creates_new_and_deletes_old(repository: DocumentPointerRepository): + old_doc = make_document_pointer(id="Y05868-OLD0001") + repository.create(old_doc) + assert repository.get_by_id("Y05868-OLD0001") is not None + + new_doc = make_document_pointer(id="Y05868-NEW0001") + result = repository.supersede(new_doc, ids_to_delete=["Y05868-OLD0001"]) + + assert result.id == "Y05868-NEW0001" + assert repository.get_by_id("Y05868-NEW0001") is not None + assert repository.get_by_id("Y05868-OLD0001") is None + + +@mock_aws +@mock_repository +@patch("nrlf.core.dynamodb.repository.logger") +def test_supersede_with_can_ignore_delete_fail( + mock_logger, + repository: DocumentPointerRepository, +): + new_doc = make_document_pointer(id="Y05868-NEW0003") + + with patch.object( + repository.table, + "delete_item", + side_effect=Exception("simulated delete failure"), + ): + result = repository.supersede( + new_doc, + ids_to_delete=["Y05868-NONEXISTENT"], + can_ignore_delete_fail=True, + ) + + assert result.id == "Y05868-NEW0003" + log_codes = [c.args[0] for c in mock_logger.log.call_args_list] + assert LogReference.REPOSITORY026a in log_codes + + +# --------------------------------------------------------------------------- +# DocumentPointerRepository.delete_by_id +# --------------------------------------------------------------------------- + + +@mock_aws +@mock_repository +def test_delete_by_id_removes_document_pointer(repository: DocumentPointerRepository): + doc = make_document_pointer() + repository.create(doc) + assert repository.get_by_id(doc.id) is not None + + repository.delete_by_id(doc.id) + + assert repository.get_by_id(doc.id) is None + + +@mock_aws +@mock_repository +def test_delete_by_id_raises_error_when_can_ignore_delete_fail_is_false( + repository: DocumentPointerRepository, +): + with patch.object( + repository.table, + "delete_item", + side_effect=Exception("simulated delete failure"), + ): + with pytest.raises(OperationOutcomeError) as exc_info: + repository.delete_by_id("Y05868-NONEXISTENT", can_ignore_delete_fail=False) + + assert exc_info.value.status_code == "500" + + +@mock_aws +@mock_repository +@patch("nrlf.core.dynamodb.repository.logger") +def test_delete_by_id_ignores_error_when_can_ignore_delete_fail_is_true( + mock_logger, + repository: DocumentPointerRepository, +): + with patch.object( + repository.table, + "delete_item", + side_effect=Exception("simulated delete failure"), + ): + repository.delete_by_id("Y05868-NONEXISTENT", can_ignore_delete_fail=True) + + log_codes = [c.args[0] for c in mock_logger.log.call_args_list] + assert LogReference.REPOSITORY026a in log_codes