Skip to content

Commit 2ff24a7

Browse files
committed
Fix root issue and add python unit tests
1 parent f5f902e commit 2ff24a7

6 files changed

Lines changed: 94 additions & 14 deletions

File tree

.github/workflows/run-e2e-automation-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ jobs:
197197
echo "::add-mask::$CODE"
198198
199199
echo "Requesting access token from Apigee..."
200-
response=$(curl -s -X POST "https://login.apigee.com/oauth/token" \
200+
response=$(curl -s --retry 3 -X POST "https://login.apigee.com/oauth/token" \
201201
-H "Content-Type: application/x-www-form-urlencoded" \
202202
-H "Accept: application/json;charset=utf-8" \
203203
-H "Authorization: Basic $APIGEE_BASIC_AUTH_TOKEN" \

lambdas/backend/src/filter.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Functions for filtering a FHIR Immunization Resource"""
22

3-
from common.models.constants import Urls
3+
from common.models.constants import Constants, Urls
44
from common.models.utils.generic_utils import (
55
get_contained_patient,
66
get_contained_practitioner,
@@ -28,23 +28,34 @@ def create_reference_to_patient_resource(patient_full_url: str, patient: dict) -
2828
"""
2929
Returns a reference to the given patient which includes the patient nhs number identifier (system and value fields
3030
only) and a reference to patient full url. "Type" field is set to "Patient".
31+
32+
Due to validation business rules, it is possible (VED-1073) for a patient to be created without a value for NHS
33+
Number or indeed an entry for their identifier.
3134
"""
32-
patient_nhs_number_identifier = [x for x in patient["identifier"] if x.get("system") == Urls.NHS_NUMBER][0]
35+
patient_nhs_number_identifier: dict | None = None
36+
37+
for identifier in patient.get("identifier", []):
38+
if identifier.get("system", "") == Urls.NHS_NUMBER:
39+
patient_nhs_number_identifier = identifier
40+
break
41+
42+
if patient_nhs_number_identifier is None:
43+
return {
44+
"reference": patient_full_url,
45+
"type": Constants.PATIENT_RESOURCE_TYPE,
46+
}
3347

3448
return {
3549
"reference": patient_full_url,
36-
"type": "Patient",
37-
"identifier": {
38-
"system": patient_nhs_number_identifier["system"],
39-
"value": patient_nhs_number_identifier["value"],
40-
},
50+
"type": Constants.PATIENT_RESOURCE_TYPE,
51+
"identifier": patient_nhs_number_identifier,
4152
}
4253

4354

4455
def replace_address_postal_codes(imms: dict) -> dict:
4556
"""Replace any postal codes found in contained patient address with 'ZZ99 3CZ'"""
4657
for resource in imms.get("contained", [{}]):
47-
if resource.get("resourceType") == "Patient":
58+
if resource.get("resourceType") == Constants.PATIENT_RESOURCE_TYPE:
4859
for address in resource.get("address", [{}]):
4960
if address.get("postalCode") is not None:
5061
address["postalCode"] = "ZZ99 3CZ"

lambdas/backend/tests/service/test_fhir_service.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,38 @@ def test_get_immunization_by_identifier_when_elements_parameter_provided(self):
288288
Immunization.construct(**{"resourceType": "Immunization", "id": "1234-some-id", "meta": {"versionId": 1}}),
289289
)
290290

291+
def test_get_immunization_by_identifier_returns_patient_created_without_nhs_number(self):
292+
"""VED-1073 - the contained patient within an Immunization resource MAY be created without an NHS Number as per
293+
the business rules. The identifier retrieval should still succeed when this is the case."""
294+
mock_resource_no_nhs_number = create_covid_immunization_dict("1234-some-id", omit_nhs_number=True)
295+
296+
self.mock_redis.hget.return_value = "COVID"
297+
self.mock_redis_getter.return_value = self.mock_redis
298+
self.authoriser.authorise.return_value = True
299+
self.imms_repo.get_immunization_by_identifier.return_value = mock_resource_no_nhs_number, self.mock_resource_meta
300+
301+
# When
302+
result = self.fhir_service.get_immunization_by_identifier(self.test_identifier, self.MOCK_SUPPLIER_NAME, None)
303+
304+
# Then
305+
self.imms_repo.get_immunization_by_identifier.assert_called_once_with(self.test_identifier)
306+
self.authoriser.authorise.assert_called_once_with(self.MOCK_SUPPLIER_NAME, ApiOperationCode.SEARCH, {"COVID"})
307+
308+
self.assertEqual(result.type, "searchset")
309+
self.assertEqual(result.total, 1)
310+
self.assertEqual(
311+
result.link[0],
312+
BundleLink.construct(
313+
relation="self",
314+
url="https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4/Immunization?identifier=some-"
315+
"system|some-value",
316+
),
317+
)
318+
319+
# Search function adds meta to the resource
320+
mock_resource_no_nhs_number["meta"] = {"versionId": "1"}
321+
self.assertEqual(result.entry[0].resource, Immunization.parse_obj(mock_resource_no_nhs_number))
322+
291323

292324
class TestCreateImmunization(TestFhirServiceBase):
293325
"""Tests for FhirService.create_immunization"""

lambdas/backend/tests/test_filter.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,38 @@ def test_create_reference_to_patient_resource(self):
8686
expected_output,
8787
)
8888

89+
def test_create_reference_to_patient_resource_when_identifier_missing(self):
90+
"""Test that create_reference_to_patient_resource creates an appropriate reference without identifier info
91+
where the saved patient record does not contain this information"""
92+
test_data = deepcopy(self.bundle_patient_resource)
93+
del test_data["identifier"]
94+
95+
patient_uuid = str(uuid4())
96+
expected_output = {"reference": patient_uuid, "type": "Patient"}
97+
98+
self.assertEqual(
99+
create_reference_to_patient_resource(patient_uuid, test_data),
100+
expected_output,
101+
)
102+
103+
def test_create_reference_to_patient_resource_when_nhs_number_missing(self):
104+
"""Test that create_reference_to_patient_resource creates an appropriate reference with empty identifier info
105+
where the saved patient record does not contain this information"""
106+
test_data = deepcopy(self.bundle_patient_resource)
107+
del test_data["identifier"][0]["value"]
108+
109+
patient_uuid = str(uuid4())
110+
expected_output = {
111+
"reference": patient_uuid,
112+
"type": "Patient",
113+
"identifier": {"system": "https://fhir.nhs.uk/Id/nhs-number"},
114+
}
115+
116+
self.assertEqual(
117+
create_reference_to_patient_resource(patient_uuid, test_data),
118+
expected_output,
119+
)
120+
89121
def test_add_use_to_identifier(self):
90122
"""Test that a use of "offical" is added to identifier[0] is no use already given"""
91123
input_data = deepcopy(self.covid_immunization_event)

lambdas/shared/src/common/models/constants.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class Constants:
4545
"address",
4646
},
4747
}
48-
49-
ALLOWED_CONTAINED_RESOURCES = {"Practitioner", "Patient"}
48+
PATIENT_RESOURCE_TYPE = "Patient"
49+
PRACTITIONER_RESOURCE_TYPE = "Practitioner"
50+
ALLOWED_CONTAINED_RESOURCES = {PRACTITIONER_RESOURCE_TYPE, PATIENT_RESOURCE_TYPE}
5051

5152
# As per Personal Demographics Service (PDS) FHIR API, the maximum length of a family name is 35 characters:
5253
# https://digital.nhs.uk/developer/api-catalogue/personal-demographics-service-fhir#post-/Patient

lambdas/shared/tests/test_common/testing_utils/immunization_utils.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ def create_covid_immunization_dict(
1818
nhs_number: str = VALID_NHS_NUMBER,
1919
occurrence_date_time: str = "2021-02-07T13:28:17+00:00",
2020
status: str = "completed",
21+
omit_nhs_number: bool = False,
2122
):
2223
immunization_json = load_json_data("completed_covid_immunization_event.json")
2324
immunization_json["id"] = imms_id
2425

25-
[x for x in immunization_json["contained"] if x.get("resourceType") == "Patient"][0]["identifier"][0]["value"] = (
26-
nhs_number
27-
)
26+
for contained_resource in immunization_json.get("contained", []):
27+
if contained_resource.get("resourceType") == "Patient":
28+
if omit_nhs_number:
29+
del contained_resource["identifier"][0]["value"]
30+
else:
31+
contained_resource["identifier"][0]["value"] = nhs_number
2832

2933
immunization_json["occurrenceDateTime"] = occurrence_date_time
3034
immunization_json["status"] = status

0 commit comments

Comments
 (0)