diff --git a/bruno/APIM/Get_Auth_Token.bru b/bruno/APIM/Get_Auth_Token.bru index b3dfc8c..ef77e8e 100644 --- a/bruno/APIM/Get_Auth_Token.bru +++ b/bruno/APIM/Get_Auth_Token.bru @@ -20,15 +20,10 @@ script:pre-request { const jwt = require("jsonwebtoken"); const fs = require("node:fs"); const crypto = require("node:crypto"); -<<<<<<< Updated upstream - const secret = bru.getEnvVar("JWT_SECRET"); - const privateKeyPath = bru.getEnvVar("PRIVATE_KEY_PATH"); -======= const secret = bru.getEnvVar("JWT_SECRET"); const privateKeyPath = bru.getEnvVar("PRIVATE_KEY_PATH"); ->>>>>>> Stashed changes if (!secret) { throw new Error("JWT_SECRET environment variable is missing."); } @@ -38,10 +33,6 @@ script:pre-request { } const privateKey = fs.readFileSync(privateKeyPath); -<<<<<<< Updated upstream -======= - ->>>>>>> Stashed changes const payload = { sub: secret, iss: secret, diff --git a/bruno/APIM/Test_CDAPI-150_Organization_Identifier_With_Empty_String.bru b/bruno/APIM/Test_CDAPI-150_Organization_Identifier_With_Empty_String.bru new file mode 100644 index 0000000..ee78c53 --- /dev/null +++ b/bruno/APIM/Test_CDAPI-150_Organization_Identifier_With_Empty_String.bru @@ -0,0 +1,72 @@ +meta { + name: Test_CDAPI-150_Organization_Identifier_With_Empty_String + type: http + seq: 38 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "nhs-test-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "" + } + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include an Organization resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_CDAPI-150_Organization_Identifier_With_Empty_String_IntEnvi.bru b/bruno/APIM/Test_CDAPI-150_Organization_Identifier_With_Empty_String_IntEnvi.bru new file mode 100644 index 0000000..2f3782e --- /dev/null +++ b/bruno/APIM/Test_CDAPI-150_Organization_Identifier_With_Empty_String_IntEnvi.bru @@ -0,0 +1,72 @@ +meta { + name: Test_CDAPI-150_Organization_Identifier_With_Empty_String_IntEnvi + type: http + seq: 48 +} + +post { + url: https://int.api.service.nhs.uk/pathology-laboratory-reporting/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "nhs-test-number" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "" + } + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include an Organization resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_CDAPI-150_Subject_Identifier_With_Empty_String.bru b/bruno/APIM/Test_CDAPI-150_Subject_Identifier_With_Empty_String.bru new file mode 100644 index 0000000..9642995 --- /dev/null +++ b/bruno/APIM/Test_CDAPI-150_Subject_Identifier_With_Empty_String.bru @@ -0,0 +1,72 @@ +meta { + name: Test_CDAPI-150_Subject_Identifier_With_Empty_String + type: http + seq: 37 +} + +post { + url: https://{{APIM_ENV}}.api.service.nhs.uk/pathology-laboratory-reporting-pr-{{PR_NUMBER}}/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include an Organization resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/bruno/APIM/Test_CDAPI-150_Subject_Identifier_With_Empty_String_IntEnvi.bru b/bruno/APIM/Test_CDAPI-150_Subject_Identifier_With_Empty_String_IntEnvi.bru new file mode 100644 index 0000000..b38df01 --- /dev/null +++ b/bruno/APIM/Test_CDAPI-150_Subject_Identifier_With_Empty_String_IntEnvi.bru @@ -0,0 +1,72 @@ +meta { + name: Test_CDAPI-150_Subject_Identifier_With_Empty_String_IntEnvi + type: http + seq: 47 +} + +post { + url: https://int.api.service.nhs.uk/pathology-laboratory-reporting/FHIR/R4/Bundle + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Bundle", + "type": "document", + "entry": [ + { + "fullUrl": "composition", + "resource": { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": "servicerequest" + } + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "" + } + } + } + }, + { + "fullUrl": "servicerequest", + "resource": { + "resourceType": "ServiceRequest", + "requester": { + "reference": "practitionerrole" + } + } + }, + { + "fullUrl": "practitionerrole", + "resource": { + "resourceType": "PractitionerRole", + "organization": { + "reference": "organization" + } + } + } + ] + } +} + +assert { + res.status: eq 400 + res.body.issue[0].diagnostics: eq Document must include an Organization resource +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/pathology-api/src/pathology_api/handler.py b/pathology-api/src/pathology_api/handler.py index 1ed5062..83a9bac 100644 --- a/pathology-api/src/pathology_api/handler.py +++ b/pathology-api/src/pathology_api/handler.py @@ -103,7 +103,7 @@ def _fetch_requesting_organisation( organisation_identifiers = [ identifier for identifier in requesting_organisation.identifier - if isinstance(identifier, OrganizationIdentifier) + if isinstance(identifier, OrganizationIdentifier) and identifier.value ] if not organisation_identifiers: @@ -141,7 +141,7 @@ def handle_request(bundle: Bundle) -> PdmResponse: _logger.debug("Requesting organization: %s", requesting_organisation) subject = composition.subject - if subject is None: + if subject is None or not subject.identifier.value: raise ValidationError("Composition does not define a valid subject identifier") pdm_response = post_document(bundle) diff --git a/pathology-api/src/pathology_api/test_handler.py b/pathology-api/src/pathology_api/test_handler.py index 71233cf..d43ae86 100644 --- a/pathology-api/src/pathology_api/test_handler.py +++ b/pathology-api/src/pathology_api/test_handler.py @@ -263,10 +263,49 @@ def test_handle_request( bundle_id=result_bundle.id, ) + def test_handle_request_with_empty_subject( + self, build_valid_test_result: Callable[[str, str], Bundle] + ) -> None: + bundle = build_valid_test_result("", "ods_code") + + with pytest.raises( + ValidationError, + match="Composition does not define a valid subject identifier", + ): + handle_request(bundle) + + def test_handle_request_with_empty_ods_code( + self, build_valid_test_result: Callable[[str, str], Bundle] + ) -> None: + bundle = build_valid_test_result("nhs_number_1", "") + + if ( + created_practitioner_role := bundle.get_resource( + url="practitioner_role", t=PractitionerRole + ) + ) is None: + raise ValueError( + "Test setup error: PractitionerRole resource not found in bundle" + ) + + if ( + expected_organisation_reference := created_practitioner_role.organization + ) is None: + raise ValueError( + "Test setup error: PractitionerRole resource does not define an " + "organization reference" + ) + + with pytest.raises( + ValidationError, + match=rf"Organization \({expected_organisation_reference.reference}\) does " + "not define a supported identifier. Supported system 'https://fhir.nhs.uk/Id/ods-organization-code'", + ): + handle_request(bundle) + def test_handle_request_raises_error_when_create_event_fails( self, build_valid_test_result: Callable[[str, str], Bundle] ) -> None: - # Arrange bundle = build_valid_test_result("nhs_number_1", "ods_code") expected_error_message = "Failed to create bundle" diff --git a/pathology-api/tests/integration/test_endpoints.py b/pathology-api/tests/integration/test_endpoints.py index 6614179..bf51e95 100644 --- a/pathology-api/tests/integration/test_endpoints.py +++ b/pathology-api/tests/integration/test_endpoints.py @@ -380,6 +380,27 @@ def test_invalid_payload_returns_error( "Composition does not define a valid subject identifier", id="composition with no subject", ), + pytest.param( + lambda service_request_reference: { + "resourceType": "Composition", + "extension": [ + { + "url": "http://hl7.eu/fhir/StructureDefinition/composition-basedOn-order-or-requisition", + "valueReference": { + "reference": service_request_reference, + }, + } + ], + "subject": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "", + } + }, + }, + "Composition does not define a valid subject identifier", + id="composition with subject with empty identifier value", + ), pytest.param( lambda _: { "resourceType": "Composition", @@ -819,6 +840,21 @@ def test_invalid_practitioner_role_resource( "Supported system 'https://fhir.nhs.uk/Id/ods-organization-code'", id="organization with unknown identifier system", ), + pytest.param( + { + "resourceType": "Organization", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "", + } + ], + }, + "Organization (organization) does not define a " + "supported identifier. " + r"Supported system 'https://fhir.nhs.uk/Id/ods-organization-code'", + id="organization with identifier with empty value", + ), ], ) def test_invalid_organization_resource(