diff --git a/lambdas/handlers/fhir_document_reference_search_handler.py b/lambdas/handlers/fhir_document_reference_search_handler.py index c29ab7ec0..a6c1093de 100644 --- a/lambdas/handlers/fhir_document_reference_search_handler.py +++ b/lambdas/handlers/fhir_document_reference_search_handler.py @@ -67,15 +67,8 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]: api_request_context=event.get("requestContext", {}), ) - if not document_references: + if document_references["total"] < 1: logger.info(f"No document references found for NHS number: {nhs_number}") - return ApiGatewayResponse( - 404, - LambdaError.DocumentReferenceNotFound.create_error_response().create_error_fhir_response( - LambdaError.DocumentReferenceNotFound.value.get("fhir_coding") - ), - "GET", - ).create_api_gateway_response() return ApiGatewayResponse( 200, json.dumps(document_references), "GET" ).create_api_gateway_response() diff --git a/lambdas/services/document_reference_search_service.py b/lambdas/services/document_reference_search_service.py index 439ad15da..f0c681c11 100644 --- a/lambdas/services/document_reference_search_service.py +++ b/lambdas/services/document_reference_search_service.py @@ -106,15 +106,12 @@ def _search_tables_for_documents( ) document_resources.extend(processed_documents) - if not document_resources: - return None - logger.info(f"Found {len(document_resources)} document references") if return_fhir: return self._create_fhir_bundle(document_resources) - else: - return document_resources + + return document_resources or None def _get_filter_expression( self, filters: dict[str, str] = None, upload_completed=False @@ -175,7 +172,7 @@ def _build_document_model(self, document: DocumentReference) -> dict: "created", "virus_scanner_result", "file_size", - "version" + "version", }, ) return document_formatted diff --git a/lambdas/tests/e2e/api/__snapshots__/test_search_patient_api/test_no_records.json b/lambdas/tests/e2e/api/__snapshots__/test_search_patient_api/test_no_records.json index 925675356..5899ce1df 100644 --- a/lambdas/tests/e2e/api/__snapshots__/test_search_patient_api/test_no_records.json +++ b/lambdas/tests/e2e/api/__snapshots__/test_search_patient_api/test_no_records.json @@ -1,19 +1,6 @@ { - "issue": [ - { - "code": "exception", - "details": { - "coding": [ - { - "code": "RESOURCE_NOT_FOUND", - "display": "Resource not found", - "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-SpineErrorOrWarningCode" - } - ] - }, - "diagnostics": "Document reference not found", - "severity": "error" - } - ], - "resourceType": "OperationOutcome" + "entry": [], + "resourceType": "Bundle", + "total": 0, + "type": "searchset" } diff --git a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py index c65f5f88d..525a1676c 100644 --- a/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py +++ b/lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py @@ -30,6 +30,18 @@ def search_document_reference(nhs_number, client_cert_path=None, client_key_path return session.get(url, headers=headers) +def test_search_nonexistent_document_references_for_patient_details(): + response = search_document_reference("9912003071") + assert response.status_code == 200 + + bundle = response.json() + assert bundle["resourceType"] == "Bundle" + assert bundle["type"] == "searchset" + assert bundle["total"] == 0 + assert "entry" in bundle + assert bundle["entry"] == [] + + def test_search_patient_details(test_data): create_and_store_pdm_record(test_data) @@ -66,7 +78,6 @@ def test_multiple_cancelled_search_patient_details(test_data): @pytest.mark.parametrize( "nhs_number,expected_status,expected_code,expected_diagnostics", [ - ("9912003071", 404, "RESOURCE_NOT_FOUND", "Document reference not found"), ("9999999993", 400, "INVALID_SEARCH_DATA", "Invalid patient number 9999999993"), ("123", 400, "INVALID_SEARCH_DATA", "Invalid patient number 123"), ], diff --git a/lambdas/tests/e2e/api/test_search_patient_api.py b/lambdas/tests/e2e/api/test_search_patient_api.py index b776fe782..ad7c7c79f 100644 --- a/lambdas/tests/e2e/api/test_search_patient_api.py +++ b/lambdas/tests/e2e/api/test_search_patient_api.py @@ -104,7 +104,14 @@ def test_no_records(snapshot_json): response = requests.request("GET", url, headers=headers) bundle = response.json() - assert bundle == snapshot_json + assert bundle == snapshot_json( + exclude=paths( + "entry.0.resource.id", + "entry.0.resource.date", + "entry.0.resource.content.0.attachment.url", + "timestamp", + ) + ) def test_invalid_patient(snapshot_json): diff --git a/lambdas/tests/unit/handlers/test_fhir_document_reference_search_handler.py b/lambdas/tests/unit/handlers/test_fhir_document_reference_search_handler.py index 4d2bd34d8..68140c720 100644 --- a/lambdas/tests/unit/handlers/test_fhir_document_reference_search_handler.py +++ b/lambdas/tests/unit/handlers/test_fhir_document_reference_search_handler.py @@ -13,6 +13,62 @@ from utils.lambda_handler_utils import extract_bearer_token +MOCK_DOCUMENT_REFERENCE_RESULT = { + "entry": [ + { + "resource": { + "author": [ + { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "H81109", + } + } + ], + "content": [ + { + "attachment": { + "contentType": "application/pdf", + "creation": "2023-01-01", + "language": "en-GB", + "title": "1of1_Lloyd_George_Record_[Holly Lorna MAGAN]_[9449305943]_[29-05-2006].pdf", + } + } + ], + "custodian": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "H81109", + } + }, + "docStatus": "final", + "meta": {"versionId": "1"}, + "resourceType": "DocumentReference", + "status": "current", + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9000000009", + } + }, + "type": { + "coding": [ + { + "code": "16521000000101", + "display": "Lloyd George record folder", + "system": "http://snomed.info/sct", + } + ] + }, + } + } + ], + "resourceType": "Bundle", + "total": 1, + "type": "searchset", +} + + @pytest.fixture def valid_nhs_number_event(): return { @@ -130,18 +186,14 @@ def mock_dynamic_config_service(): def test_lambda_handler_returns_200_with_documents( mock_document_reference_search_service, valid_nhs_number_event, context, set_env ): - mock_document_references = [ - {"resourceType": "DocumentReference", "status": "current"}, - {"resourceType": "DocumentReference", "status": "current"}, - ] mock_document_reference_search_service.get_document_references.return_value = ( - mock_document_references + MOCK_DOCUMENT_REFERENCE_RESULT ) response = lambda_handler(valid_nhs_number_event, context) assert response["statusCode"] == 200 - assert json.loads(response["body"]) == mock_document_references + assert json.loads(response["body"]) == MOCK_DOCUMENT_REFERENCE_RESULT mock_document_reference_search_service.get_document_references.assert_called_once_with( nhs_number="9000000009", return_fhir=True, @@ -151,14 +203,20 @@ def test_lambda_handler_returns_200_with_documents( ) -def test_lambda_handler_returns_404_when_no_documents( +def test_lambda_handler_returns_a_200_with_an_empty_bundle_when_no_documents( mock_document_reference_search_service, valid_nhs_number_event, context, set_env ): - mock_document_reference_search_service.get_document_references.return_value = [] + mock_document_reference_search_service.get_document_references.return_value = { + "resourceType": "Bundle", + "type": "searchset", + "timestamp": 1763647621, + "total": 0, + "entry": [], + } response = lambda_handler(valid_nhs_number_event, context) - - assert response["statusCode"] == 404 + body = json.loads(response["body"]) + assert response["statusCode"] == 200 mock_document_reference_search_service.get_document_references.assert_called_once_with( nhs_number="9000000009", return_fhir=True, @@ -166,6 +224,9 @@ def test_lambda_handler_returns_404_when_no_documents( check_upload_completed=False, api_request_context={}, ) + assert body["resourceType"] == "Bundle" + assert body["total"] == 0 + assert body["entry"] == [] def test_lambda_handler_returns_400_for_invalid_nhs_number( @@ -191,17 +252,14 @@ def test_lambda_handler_returns_400_for_missing_nhs_number( def test_lambda_handler_with_additional_filters( mock_document_reference_search_service, valid_event_with_filters, context, set_env ): - mock_document_references = [ - {"resourceType": "DocumentReference", "status": "current"}, - ] mock_document_reference_search_service.get_document_references.return_value = ( - mock_document_references + MOCK_DOCUMENT_REFERENCE_RESULT ) response = lambda_handler(valid_event_with_filters, context) assert response["statusCode"] == 200 - assert json.loads(response["body"]) == mock_document_references + assert json.loads(response["body"]) == MOCK_DOCUMENT_REFERENCE_RESULT # Check that the filters were correctly parsed and passed expected_filters = {"file_type": "736253002", "custodian": "Y12345"} @@ -224,11 +282,8 @@ def test_lambda_handler_with_auth_validation( set_env, ): # Setup mocks - mock_document_references = [ - {"resourceType": "DocumentReference", "status": "current"} - ] mock_document_reference_search_service.get_document_references.return_value = ( - mock_document_references + MOCK_DOCUMENT_REFERENCE_RESULT ) # Mock successful authorisation @@ -244,7 +299,7 @@ def test_lambda_handler_with_auth_validation( response = lambda_handler(valid_event_with_auth, context) assert response["statusCode"] == 200 - assert json.loads(response["body"]) == mock_document_references + assert json.loads(response["body"]) == MOCK_DOCUMENT_REFERENCE_RESULT # Verify authorisation flow mock_dynamic_config_service.set_auth_ssm_prefix.assert_called_once() diff --git a/lambdas/tests/unit/services/test_document_reference_search_service.py b/lambdas/tests/unit/services/test_document_reference_search_service.py index 73a16b6e7..4a63f2cd7 100644 --- a/lambdas/tests/unit/services/test_document_reference_search_service.py +++ b/lambdas/tests/unit/services/test_document_reference_search_service.py @@ -107,15 +107,26 @@ def test_get_document_references_raise_dynamodb_error(mock_document_service): ) -def test_get_document_references_dynamo_return_empty_response(mock_document_service): +def test_get_document_references_dynamo_return_empty_response_with_fhir( + mock_document_service, +): mock_document_service.fetch_documents_from_table_with_nhs_number.return_value = [] - expected_results = None actual = mock_document_service._search_tables_for_documents( "1234567890", ["table1", "table2"], return_fhir=True ) + assert actual["resourceType"] == "Bundle" + assert actual["entry"] == [] + assert actual["total"] == 0 - assert actual == expected_results + +def test_get_document_references_dynamo_return_empty_response(mock_document_service): + mock_document_service.fetch_documents_from_table_with_nhs_number.return_value = [] + + actual = mock_document_service._search_tables_for_documents( + "1234567890", ["table1", "table2"], return_fhir=False + ) + assert actual is None def test_get_document_references_dynamo_return_successful_response_single_table(