Skip to content

Commit 2cc7d71

Browse files
authored
[NDR-286] Set search to return an empty bundle with no results (#897)
1 parent 729bb8d commit 2cc7d71

File tree

7 files changed

+117
-56
lines changed

7 files changed

+117
-56
lines changed

lambdas/handlers/fhir_document_reference_search_handler.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,8 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
6767
api_request_context=event.get("requestContext", {}),
6868
)
6969

70-
if not document_references:
70+
if document_references["total"] < 1:
7171
logger.info(f"No document references found for NHS number: {nhs_number}")
72-
return ApiGatewayResponse(
73-
404,
74-
LambdaError.DocumentReferenceNotFound.create_error_response().create_error_fhir_response(
75-
LambdaError.DocumentReferenceNotFound.value.get("fhir_coding")
76-
),
77-
"GET",
78-
).create_api_gateway_response()
7972
return ApiGatewayResponse(
8073
200, json.dumps(document_references), "GET"
8174
).create_api_gateway_response()

lambdas/services/document_reference_search_service.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,12 @@ def _search_tables_for_documents(
106106
)
107107
document_resources.extend(processed_documents)
108108

109-
if not document_resources:
110-
return None
111-
112109
logger.info(f"Found {len(document_resources)} document references")
113110

114111
if return_fhir:
115112
return self._create_fhir_bundle(document_resources)
116-
else:
117-
return document_resources
113+
114+
return document_resources or None
118115

119116
def _get_filter_expression(
120117
self, filters: dict[str, str] = None, upload_completed=False
@@ -175,7 +172,7 @@ def _build_document_model(self, document: DocumentReference) -> dict:
175172
"created",
176173
"virus_scanner_result",
177174
"file_size",
178-
"version"
175+
"version",
179176
},
180177
)
181178
return document_formatted
Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
11
{
2-
"issue": [
3-
{
4-
"code": "exception",
5-
"details": {
6-
"coding": [
7-
{
8-
"code": "RESOURCE_NOT_FOUND",
9-
"display": "Resource not found",
10-
"system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-SpineErrorOrWarningCode"
11-
}
12-
]
13-
},
14-
"diagnostics": "Document reference not found",
15-
"severity": "error"
16-
}
17-
],
18-
"resourceType": "OperationOutcome"
2+
"entry": [],
3+
"resourceType": "Bundle",
4+
"total": 0,
5+
"type": "searchset"
196
}

lambdas/tests/e2e/api/fhir/test_search_patient_fhir_api.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ def search_document_reference(nhs_number, client_cert_path=None, client_key_path
3030
return session.get(url, headers=headers)
3131

3232

33+
def test_search_nonexistent_document_references_for_patient_details():
34+
response = search_document_reference("9912003071")
35+
assert response.status_code == 200
36+
37+
bundle = response.json()
38+
assert bundle["resourceType"] == "Bundle"
39+
assert bundle["type"] == "searchset"
40+
assert bundle["total"] == 0
41+
assert "entry" in bundle
42+
assert bundle["entry"] == []
43+
44+
3345
def test_search_patient_details(test_data):
3446
create_and_store_pdm_record(test_data)
3547

@@ -66,7 +78,6 @@ def test_multiple_cancelled_search_patient_details(test_data):
6678
@pytest.mark.parametrize(
6779
"nhs_number,expected_status,expected_code,expected_diagnostics",
6880
[
69-
("9912003071", 404, "RESOURCE_NOT_FOUND", "Document reference not found"),
7081
("9999999993", 400, "INVALID_SEARCH_DATA", "Invalid patient number 9999999993"),
7182
("123", 400, "INVALID_SEARCH_DATA", "Invalid patient number 123"),
7283
],

lambdas/tests/e2e/api/test_search_patient_api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ def test_no_records(snapshot_json):
104104
response = requests.request("GET", url, headers=headers)
105105
bundle = response.json()
106106

107-
assert bundle == snapshot_json
107+
assert bundle == snapshot_json(
108+
exclude=paths(
109+
"entry.0.resource.id",
110+
"entry.0.resource.date",
111+
"entry.0.resource.content.0.attachment.url",
112+
"timestamp",
113+
)
114+
)
108115

109116

110117
def test_invalid_patient(snapshot_json):

lambdas/tests/unit/handlers/test_fhir_document_reference_search_handler.py

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,62 @@
1313
from utils.lambda_handler_utils import extract_bearer_token
1414

1515

16+
MOCK_DOCUMENT_REFERENCE_RESULT = {
17+
"entry": [
18+
{
19+
"resource": {
20+
"author": [
21+
{
22+
"identifier": {
23+
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
24+
"value": "H81109",
25+
}
26+
}
27+
],
28+
"content": [
29+
{
30+
"attachment": {
31+
"contentType": "application/pdf",
32+
"creation": "2023-01-01",
33+
"language": "en-GB",
34+
"title": "1of1_Lloyd_George_Record_[Holly Lorna MAGAN]_[9449305943]_[29-05-2006].pdf",
35+
}
36+
}
37+
],
38+
"custodian": {
39+
"identifier": {
40+
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
41+
"value": "H81109",
42+
}
43+
},
44+
"docStatus": "final",
45+
"meta": {"versionId": "1"},
46+
"resourceType": "DocumentReference",
47+
"status": "current",
48+
"subject": {
49+
"identifier": {
50+
"system": "https://fhir.nhs.uk/Id/nhs-number",
51+
"value": "9000000009",
52+
}
53+
},
54+
"type": {
55+
"coding": [
56+
{
57+
"code": "16521000000101",
58+
"display": "Lloyd George record folder",
59+
"system": "http://snomed.info/sct",
60+
}
61+
]
62+
},
63+
}
64+
}
65+
],
66+
"resourceType": "Bundle",
67+
"total": 1,
68+
"type": "searchset",
69+
}
70+
71+
1672
@pytest.fixture
1773
def valid_nhs_number_event():
1874
return {
@@ -130,18 +186,14 @@ def mock_dynamic_config_service():
130186
def test_lambda_handler_returns_200_with_documents(
131187
mock_document_reference_search_service, valid_nhs_number_event, context, set_env
132188
):
133-
mock_document_references = [
134-
{"resourceType": "DocumentReference", "status": "current"},
135-
{"resourceType": "DocumentReference", "status": "current"},
136-
]
137189
mock_document_reference_search_service.get_document_references.return_value = (
138-
mock_document_references
190+
MOCK_DOCUMENT_REFERENCE_RESULT
139191
)
140192

141193
response = lambda_handler(valid_nhs_number_event, context)
142194

143195
assert response["statusCode"] == 200
144-
assert json.loads(response["body"]) == mock_document_references
196+
assert json.loads(response["body"]) == MOCK_DOCUMENT_REFERENCE_RESULT
145197
mock_document_reference_search_service.get_document_references.assert_called_once_with(
146198
nhs_number="9000000009",
147199
return_fhir=True,
@@ -151,21 +203,30 @@ def test_lambda_handler_returns_200_with_documents(
151203
)
152204

153205

154-
def test_lambda_handler_returns_404_when_no_documents(
206+
def test_lambda_handler_returns_a_200_with_an_empty_bundle_when_no_documents(
155207
mock_document_reference_search_service, valid_nhs_number_event, context, set_env
156208
):
157-
mock_document_reference_search_service.get_document_references.return_value = []
209+
mock_document_reference_search_service.get_document_references.return_value = {
210+
"resourceType": "Bundle",
211+
"type": "searchset",
212+
"timestamp": 1763647621,
213+
"total": 0,
214+
"entry": [],
215+
}
158216

159217
response = lambda_handler(valid_nhs_number_event, context)
160-
161-
assert response["statusCode"] == 404
218+
body = json.loads(response["body"])
219+
assert response["statusCode"] == 200
162220
mock_document_reference_search_service.get_document_references.assert_called_once_with(
163221
nhs_number="9000000009",
164222
return_fhir=True,
165223
additional_filters={},
166224
check_upload_completed=False,
167225
api_request_context={},
168226
)
227+
assert body["resourceType"] == "Bundle"
228+
assert body["total"] == 0
229+
assert body["entry"] == []
169230

170231

171232
def test_lambda_handler_returns_400_for_invalid_nhs_number(
@@ -191,17 +252,14 @@ def test_lambda_handler_returns_400_for_missing_nhs_number(
191252
def test_lambda_handler_with_additional_filters(
192253
mock_document_reference_search_service, valid_event_with_filters, context, set_env
193254
):
194-
mock_document_references = [
195-
{"resourceType": "DocumentReference", "status": "current"},
196-
]
197255
mock_document_reference_search_service.get_document_references.return_value = (
198-
mock_document_references
256+
MOCK_DOCUMENT_REFERENCE_RESULT
199257
)
200258

201259
response = lambda_handler(valid_event_with_filters, context)
202260

203261
assert response["statusCode"] == 200
204-
assert json.loads(response["body"]) == mock_document_references
262+
assert json.loads(response["body"]) == MOCK_DOCUMENT_REFERENCE_RESULT
205263

206264
# Check that the filters were correctly parsed and passed
207265
expected_filters = {"file_type": "736253002", "custodian": "Y12345"}
@@ -224,11 +282,8 @@ def test_lambda_handler_with_auth_validation(
224282
set_env,
225283
):
226284
# Setup mocks
227-
mock_document_references = [
228-
{"resourceType": "DocumentReference", "status": "current"}
229-
]
230285
mock_document_reference_search_service.get_document_references.return_value = (
231-
mock_document_references
286+
MOCK_DOCUMENT_REFERENCE_RESULT
232287
)
233288

234289
# Mock successful authorisation
@@ -244,7 +299,7 @@ def test_lambda_handler_with_auth_validation(
244299
response = lambda_handler(valid_event_with_auth, context)
245300

246301
assert response["statusCode"] == 200
247-
assert json.loads(response["body"]) == mock_document_references
302+
assert json.loads(response["body"]) == MOCK_DOCUMENT_REFERENCE_RESULT
248303

249304
# Verify authorisation flow
250305
mock_dynamic_config_service.set_auth_ssm_prefix.assert_called_once()

lambdas/tests/unit/services/test_document_reference_search_service.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,26 @@ def test_get_document_references_raise_dynamodb_error(mock_document_service):
107107
)
108108

109109

110-
def test_get_document_references_dynamo_return_empty_response(mock_document_service):
110+
def test_get_document_references_dynamo_return_empty_response_with_fhir(
111+
mock_document_service,
112+
):
111113
mock_document_service.fetch_documents_from_table_with_nhs_number.return_value = []
112-
expected_results = None
113114

114115
actual = mock_document_service._search_tables_for_documents(
115116
"1234567890", ["table1", "table2"], return_fhir=True
116117
)
118+
assert actual["resourceType"] == "Bundle"
119+
assert actual["entry"] == []
120+
assert actual["total"] == 0
117121

118-
assert actual == expected_results
122+
123+
def test_get_document_references_dynamo_return_empty_response(mock_document_service):
124+
mock_document_service.fetch_documents_from_table_with_nhs_number.return_value = []
125+
126+
actual = mock_document_service._search_tables_for_documents(
127+
"1234567890", ["table1", "table2"], return_fhir=False
128+
)
129+
assert actual is None
119130

120131

121132
def test_get_document_references_dynamo_return_successful_response_single_table(

0 commit comments

Comments
 (0)