Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
9 changes: 3 additions & 6 deletions lambdas/services/document_reference_search_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -175,7 +172,7 @@ def _build_document_model(self, document: DocumentReference) -> dict:
"created",
"virus_scanner_result",
"file_size",
"version"
"version",
},
)
return document_formatted
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
13 changes: 12 additions & 1 deletion lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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"),
],
Expand Down
9 changes: 8 additions & 1 deletion lambdas/tests/e2e/api/test_search_patient_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -151,21 +203,30 @@ 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,
additional_filters={},
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(
Expand All @@ -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"}
Expand All @@ -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
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading