diff --git a/.vscode/settings.json b/.vscode/settings.json index 0bc99f9b..0229c98c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -107,4 +107,5 @@ "python.analysis.extraPaths": [ "./gateway-api/stubs" ], + "python-envs.defaultEnvManager": "ms-python.python:pyenv", } diff --git a/README.md b/README.md index 68b562f6..6a783995 100644 --- a/README.md +++ b/README.md @@ -157,11 +157,11 @@ Environment variables control whether stubs are used in place of the real PDS, S | Variable | Description | | --- | --- | | `PDS_URL` | The URL for the PDS FHIR API; set as `stub` to use development stub. | -| `PDS_API_TOKEN`| Leave unset in development environment. | -| `PDS_API_SECRET`| Leave unset in development environment. | -| `PDS_API_KID`| Leave unset in development environment. | +| `PDS_API_TOKEN` | Leave unset in development environment. | +| `PDS_API_SECRET` | Leave unset in development environment. | +| `PDS_API_KID` | Leave unset in development environment. | | `SDS_URL` | The URL for the SDS FHIR API; set as `stub` to use development stub. | -| `SDS_API_TOKEN`| Leave unset in development environment. | +| `SDS_API_TOKEN` | Leave unset in development environment. | | `PROVIDER_URL` | The URL for the GP Provider; set as `stub` to use development stub. | | `CDG_DEBUG` | `true`, return additional debug information when the call to the GP provider returns an error. | diff --git a/bruno/gateway-api/collections/Steel_Thread/environments/localInt.yml b/bruno/gateway-api/collections/Steel_Thread/environments/localInt.yml new file mode 100644 index 00000000..56a8c8e8 --- /dev/null +++ b/bruno/gateway-api/collections/Steel_Thread/environments/localInt.yml @@ -0,0 +1,8 @@ +name: localInt +variables: + - name: base_url + value: http://localhost:5000 + - name: nhs_number + value: "9658218865" + - name: from_ods + value: A20047 diff --git a/gateway-api/src/gateway_api/app.py b/gateway-api/src/gateway_api/app.py index 0ff3f695..53803d40 100644 --- a/gateway-api/src/gateway_api/app.py +++ b/gateway-api/src/gateway_api/app.py @@ -37,6 +37,7 @@ def configure_app(app: Flask) -> None: "FLASK_PORT": get_env_var("FLASK_PORT", int), "PDS_URL": get_env_var("PDS_URL", str), "SDS_URL": get_env_var("SDS_URL", str), + "SDS_API_TOKEN": get_env_var("SDS_API_TOKEN", str), } app.config.update(config) @@ -108,7 +109,9 @@ def get_structured_record() -> Response: try: get_structured_record_request = GetStructuredRecordRequest(request) controller = Controller( - pds_base_url=app.config["PDS_URL"], sds_base_url=app.config["SDS_URL"] + pds_base_url=app.config["PDS_URL"], + sds_base_url=app.config["SDS_URL"], + sds_api_key=app.config["SDS_API_TOKEN"], ) provider_response = controller.run(request=get_structured_record_request) response.add_provider_response(provider_response) diff --git a/gateway-api/src/gateway_api/controller.py b/gateway-api/src/gateway_api/controller.py index 539bea71..27aba9f4 100644 --- a/gateway-api/src/gateway_api/controller.py +++ b/gateway-api/src/gateway_api/controller.py @@ -29,6 +29,7 @@ def __init__( self, pds_base_url: str, sds_base_url: str, + sds_api_key: str, timeout: int = 10, ) -> None: """ @@ -36,6 +37,7 @@ def __init__( """ self.pds_base_url = pds_base_url self.sds_base_url = sds_base_url + self.sds_api_key = sds_api_key self.timeout = timeout self.gp_provider_client = None @@ -194,6 +196,7 @@ def _get_sds_details( # SDS: Get provider details (ASID + endpoint) for provider ODS sds = SdsClient( base_url=self.sds_base_url, + api_key=self.sds_api_key, timeout=self.timeout, ) diff --git a/gateway-api/src/gateway_api/sds/__init__.py b/gateway-api/src/gateway_api/sds/__init__.py index 8f6e5ec0..bfbe89ef 100644 --- a/gateway-api/src/gateway_api/sds/__init__.py +++ b/gateway-api/src/gateway_api/sds/__init__.py @@ -1,7 +1,4 @@ -from gateway_api.sds.client import SdsClient +from gateway_api.sds.client import SdsClient, get from gateway_api.sds.search_results import SdsSearchResults -__all__ = [ - "SdsClient", - "SdsSearchResults", -] +__all__ = ["SdsClient", "SdsSearchResults", "get"] diff --git a/gateway-api/src/gateway_api/sds/client.py b/gateway-api/src/gateway_api/sds/client.py index f195876d..d36242b5 100644 --- a/gateway-api/src/gateway_api/sds/client.py +++ b/gateway-api/src/gateway_api/sds/client.py @@ -16,7 +16,9 @@ from fhir import Resource from fhir.constants import FHIRSystem from fhir.r4 import Bundle, Device, Endpoint -from requests import HTTPError +from requests import HTTPError, Response +from requests import get as external_sds_get +from stubs import SdsFhirApiStub from gateway_api.common.error import SdsRequestFailedError from gateway_api.get_structured_record import ( @@ -25,17 +27,21 @@ ) from gateway_api.sds.search_results import SdsSearchResults -# TODO [GPCAPIM-359]: Once stub servers/containers made for PDS, SDS and provider -# we should remove the SDS_URL environment variable and just -# use the stub client -STUB_SDS = os.environ["SDS_URL"].lower() == "stub" -if not STUB_SDS: - from requests import get -else: - from stubs import SdsFhirApiStub - sds = SdsFhirApiStub() - get = sds.get # type: ignore +def get( + url: str, + headers: dict[str, str], + params: dict[str, str], + timeout: int, +) -> Response: + STUB_SDS = os.environ["SDS_URL"].lower() == "stub" + if not STUB_SDS: + return external_sds_get(url, headers=headers, params=params, timeout=timeout) + else: + return SdsFhirApiStub().get( + url, headers=headers, params=params, timeout=timeout + ) + _logger = logging.getLogger(__name__) @@ -83,12 +89,13 @@ class SdsClient: def __init__( self, base_url: str, + api_key: str, timeout: int = 10, service_interaction_id: str | None = None, ) -> None: self.base_url = base_url.rstrip("/") self.timeout = timeout - self.api_key = self._get_api_key() + self.api_key = api_key if service_interaction_id is not None: self.service_interaction_id = service_interaction_id @@ -169,19 +176,6 @@ def get_org_details( return SdsSearchResults(asid=asid, endpoint=endpoint_url) - @staticmethod - def _get_api_key() -> str: - """ - Retrieve the API key to use for SDS requests. - - This is a placeholder at present because we don't have a real API key. - Ultimately it will probably obtain the key from AWS secrets - """ - - # TODO [GPCAPIM-366]: Obtain key from AWS secrets - # DO NOT PUT A REAL KEY HERE, IT WILL BE VISIBLE ON GITHUB - return "test_api_key_DO_NOT_REPLACE_HERE" - def _query_sds( self, ods_code: str, diff --git a/gateway-api/src/gateway_api/sds/test_client.py b/gateway-api/src/gateway_api/sds/test_client.py index 51358c30..99e3d187 100644 --- a/gateway-api/src/gateway_api/sds/test_client.py +++ b/gateway-api/src/gateway_api/sds/test_client.py @@ -2,6 +2,8 @@ Unit tests for :mod:`gateway_api.sds_search`. """ +from unittest.mock import Mock, patch + import pytest from fhir.constants import FHIRSystem from fhir.r4.resources.bundle import Bundle @@ -9,15 +11,12 @@ from stubs.sds.stub import SdsFhirApiStub from gateway_api.common.error import SdsRequestFailedError -from gateway_api.conftest import FakeResponse +from gateway_api.conftest import FakeResponse, ScopedEnvVars from gateway_api.get_structured_record import ( ACCESS_RECORD_STRUCTURED_INTERACTION_ID, SDS_SANDBOX_INTERACTION_ID, ) -from gateway_api.sds import ( - SdsClient, - SdsSearchResults, -) +from gateway_api.sds import SdsClient, SdsSearchResults, get @pytest.fixture @@ -32,15 +31,14 @@ def stub(monkeypatch: pytest.MonkeyPatch) -> SdsFhirApiStub: return stub -def test_sds_client_get_org_details_success( - stub: SdsFhirApiStub, -) -> None: +def test_sds_client_get_org_details_success(stub: SdsFhirApiStub) -> None: """ Test SdsClient can successfully look up organization details. :param stub: SDS stub fixture. + :param mock_flask: Mock Flask app fixture. """ - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") result = client.get_org_details(ods_code="PROVIDER") @@ -56,9 +54,7 @@ def test_sds_client_get_org_details_success( ) -def test_sds_client_get_org_details_with_endpoint( - stub: SdsFhirApiStub, -) -> None: +def test_sds_client_get_org_details_with_endpoint(stub: SdsFhirApiStub) -> None: """ Test SdsClient retrieves endpoint when available. @@ -111,7 +107,7 @@ def test_sds_client_get_org_details_with_endpoint( }, ) - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") result = client.get_org_details(ods_code="TESTORG") assert result is not None @@ -119,38 +115,33 @@ def test_sds_client_get_org_details_with_endpoint( assert result.endpoint == "https://testorg.example.com/fhir" -def test_sds_client_sends_correct_headers( - stub: SdsFhirApiStub, -) -> None: +def test_sds_client_sends_correct_headers(stub: SdsFhirApiStub) -> None: """ Test that SdsClient sends X-Correlation-Id and apikey headers when provided. :param stub: SDS stub fixture. :param mock_requests_get: Capture fixture for request details. """ - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") correlation_id = "test-correlation-123" client.get_org_details(ods_code="PROVIDER", correlation_id=correlation_id) # Check that the headers were assert stub.get_headers["X-Correlation-Id"] == correlation_id - - # In future when _get_api_key calls AWS secrets, this will break. - # That's a good thing, because we'll want to mock that call. - assert stub.get_headers["apikey"] == "test_api_key_DO_NOT_REPLACE_HERE" + assert stub.get_headers["apikey"] == "example_api_key" -def test_sds_client_timeout_parameter( - stub: SdsFhirApiStub, -) -> None: +def test_sds_client_timeout_parameter(stub: SdsFhirApiStub) -> None: """ Test that SdsClient passes timeout parameter to requests. :param stub: SDS stub fixture. :param mock_requests_get: Capture fixture for request details. """ - client = SdsClient(base_url="https://test.com", timeout=30) + client = SdsClient( + base_url="https://test.com", api_key="example_api_key", timeout=30 + ) client.get_org_details(ods_code="PROVIDER", timeout=60) @@ -158,9 +149,7 @@ def test_sds_client_timeout_parameter( assert stub.get_timeout == 60 -def test_sds_client_custom_service_interaction_id( - stub: SdsFhirApiStub, -) -> None: +def test_sds_client_custom_service_interaction_id(stub: SdsFhirApiStub) -> None: """ Test that SdsClient uses custom interaction ID when provided. @@ -194,6 +183,7 @@ def test_sds_client_custom_service_interaction_id( client = SdsClient( base_url="https://test.com", service_interaction_id=custom_interaction, + api_key="example_api_key", ) result = client.get_org_details(ods_code="CUSTOMINT", get_endpoint=False) @@ -209,16 +199,14 @@ def test_sds_client_custom_service_interaction_id( assert result.asid == "777777777777" -def test_sds_client_builds_correct_device_query_params( - stub: SdsFhirApiStub, -) -> None: +def test_sds_client_builds_correct_device_query_params(stub: SdsFhirApiStub) -> None: """ Test that SdsClient builds Device query parameters correctly. :param stub: SDS stub fixture. :param mock_requests_get: Capture fixture for request details. """ - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") client.get_org_details(ods_code="PROVIDER") @@ -268,7 +256,8 @@ def test_sds_client_uses_sandbox_interaction_id_for_sandbox_url( ) client = SdsClient( - base_url="https://sandbox.api.service.nhs.uk/spine-directory/FHIR/R4" + base_url="https://sandbox.api.service.nhs.uk/spine-directory/FHIR/R4", + api_key="example_api_key", ) result = client.get_org_details(ods_code="SANDBOX_ORG", get_endpoint=False) @@ -313,7 +302,7 @@ def get_without_apikey( monkeypatch.setattr("gateway_api.sds.client.get", get_without_apikey) - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") with pytest.raises(SdsRequestFailedError, match="SDS FHIR API request failed"): client.get_org_details(ods_code="PROVIDER") @@ -353,7 +342,7 @@ def test_sds_client_endpoint_entry_without_address_returns_none( }, ) - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") result = client.get_org_details(ods_code="NOADDR") assert result.asid == "111111111111" @@ -369,7 +358,7 @@ def test_sds_client_empty_device_bundle_returns_none_asid() -> None: :param stub: SDS stub fixture. """ - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") # "UNKNOWN_ORG" has no seeded devices, so the bundle entry list will be empty result = client.get_org_details(ods_code="UNKNOWN_ORG", get_endpoint=False) @@ -398,24 +387,44 @@ def test_sds_client_no_endpoint_bundle_entries_returns_none_endpoint( ) # Deliberately do not seed any endpoint for NOENDPOINT - client = SdsClient(base_url="https://test.com") + client = SdsClient(base_url="https://test.com", api_key="example_api_key") result = client.get_org_details(ods_code="NOENDPOINT") assert result.asid == "222222222222" assert result.endpoint is None -def test_sds_client_respects_url( - mocker: MockerFixture, -) -> None: +def test_sds_client_respects_url(mocker: MockerFixture) -> None: empty_bundle = Bundle.empty("searchset").model_dump() mocked_get = mocker.patch( "gateway_api.sds.client.get", return_value=FakeResponse(status_code=200, headers={}, _json=empty_bundle), ) - client = SdsClient(base_url="https://a.different.url/base") + client = SdsClient( + base_url="https://a.different.url/base", api_key="example_api_key" + ) _ = client.get_org_details(ods_code="A12345", get_endpoint=False) actual_url = mocked_get.call_args.args[0] + actual_headers = mocked_get.call_args.kwargs["headers"] assert actual_url == "https://a.different.url/base/Device" + assert actual_headers["apikey"] == "example_api_key" + + +@patch("gateway_api.sds.client.SdsFhirApiStub") +@patch("gateway_api.sds.client.external_sds_get") +def test_get_with_stub(mock_external_get: Mock, mock_stub: Mock) -> None: + with ScopedEnvVars({"SDS_URL": "stub"}): + get("https://example.com/", headers={}, params={}, timeout=10) + assert mock_stub.return_value.get.called + assert not mock_external_get.called + + +@patch("gateway_api.sds.client.SdsFhirApiStub") +@patch("gateway_api.sds.client.external_sds_get") +def test_get_without_stub(mock_external_get: Mock, mock_stub: Mock) -> None: + with ScopedEnvVars({"SDS_URL": "https://www.example.com/"}): + get("https://example.com/", headers={}, params={}, timeout=10) + assert mock_external_get.called + assert not mock_stub.return_value.get.called diff --git a/gateway-api/src/gateway_api/test_app.py b/gateway-api/src/gateway_api/test_app.py index 140a8905..f25d3eba 100644 --- a/gateway-api/src/gateway_api/test_app.py +++ b/gateway-api/src/gateway_api/test_app.py @@ -3,7 +3,7 @@ import json from collections.abc import Generator from copy import copy -from typing import Any +from typing import Any, cast from unittest.mock import Mock import pytest @@ -11,6 +11,7 @@ from flask.testing import FlaskClient from pytest_mock import MockerFixture +import gateway_api from gateway_api.app import ( app, configure_app, @@ -20,6 +21,10 @@ ) from gateway_api.conftest import ScopedEnvVars +PDS_URL = "http://test-pds-url" +SDS_URL = "http://test-sds-url" +SDS_API_TOKEN = "example-token" # noqa: S105 Not a real token + @pytest.fixture def client() -> Generator[FlaskClient[Flask]]: @@ -27,8 +32,9 @@ def client() -> Generator[FlaskClient[Flask]]: { "FLASK_HOST": "localhost", "FLASK_PORT": "5000", - "PDS_URL": "http://test-pds-url", - "SDS_URL": "http://test-sds-url", + "PDS_URL": PDS_URL, + "SDS_URL": SDS_URL, + "SDS_API_TOKEN": SDS_API_TOKEN, } ): configure_app(app) @@ -58,6 +64,7 @@ def test_configure_app(self) -> None: "FLASK_PORT": "1234", "PDS_URL": "test_pds_url", "SDS_URL": "test_sds_url", + "SDS_API_TOKEN": "test_sds_api_token", } with ScopedEnvVars(config): @@ -68,6 +75,7 @@ def test_configure_app(self) -> None: "FLASK_PORT": 1234, "PDS_URL": "test_pds_url", "SDS_URL": "test_sds_url", + "SDS_API_TOKEN": "test_sds_api_token", } test_app.config.update.assert_called_with(expected) @@ -118,6 +126,18 @@ def test_valid_get_structured_record_request_returns_expected_bundle( actual_bundle = get_structured_record_response.get_json() assert actual_bundle == valid_simple_response_payload + @pytest.mark.usefixtures("mock_controller_constructor") + def test_valid_get_structured_record_request_calls_controller_correctly( + self, + get_structured_record_response: Flask, + ) -> None: + get_structured_record_response.get_json() + cast("Mock", gateway_api.controller.Controller.__init__).assert_called_with( + pds_base_url=PDS_URL, + sds_base_url=SDS_URL, + sds_api_key=SDS_API_TOKEN, + ) + @pytest.mark.usefixtures("mock_positive_return_value_from_controller_run") def test_valid_get_structured_record_request_returns_200( self, @@ -291,6 +311,13 @@ def mock_positive_return_value_from_controller_run( "gateway_api.controller.Controller.run", return_value=positive_response ) + @staticmethod + @pytest.fixture + def mock_controller_constructor( + mocker: MockerFixture, + ) -> None: + mocker.patch("gateway_api.controller.Controller.__init__", return_value=None) + @staticmethod @pytest.fixture def mock_raise_error_from_controller_run( diff --git a/gateway-api/src/gateway_api/test_controller.py b/gateway-api/src/gateway_api/test_controller.py index 0cb660ef..728e07ad 100644 --- a/gateway-api/src/gateway_api/test_controller.py +++ b/gateway-api/src/gateway_api/test_controller.py @@ -1,6 +1,7 @@ """Unit tests for :mod:`gateway_api.controller`.""" from typing import Any +from unittest.mock import Mock import pytest from fhir.r4 import ( @@ -24,6 +25,13 @@ from gateway_api.sds import SdsSearchResults +@pytest.fixture +def mock_flask() -> Mock: + mock_flask = Mock() + mock_flask.config = {"SDS_API_TOKEN": "example"} + return mock_flask + + def _create_patient(nhs_number: str, gp_ods_code: str | None) -> Patient: general_practitioner = None if gp_ods_code is not None: @@ -45,8 +53,13 @@ def _create_patient(nhs_number: str, gp_ods_code: str | None) -> Patient: def create_test_controller( pds_base_url: str = "https://example.test/pds", sds_base_url: str = "https://example.test/sds", + sds_api_key: str = "example_sds_api_key", ) -> Controller: - return Controller(pds_base_url=pds_base_url, sds_base_url=sds_base_url) + return Controller( + pds_base_url=pds_base_url, + sds_base_url=sds_base_url, + sds_api_key=sds_api_key, + ) def test_controller_run_happy_path_returns_200_status_code( @@ -382,61 +395,35 @@ def test_controller_respects_pds_url( assert actual_pds_url == "https://a.different.url/base/Patient/9000000009" -def test_controller_respects_sds_url( +def test_controller_respects_sds_vars( mocker: MockerFixture, ) -> None: """ - Test that the controller uses the SDS URL provided in the constructor. + Test that the controller uses the SDS URL and API token provided in the constructor. """ - device_bundle = { - "resourceType": "Bundle", - "type": "searchset", - "total": 1, - "entry": [ - { - "fullUrl": "https://example.test/sds/Device/1", - "resource": { - "resourceType": "Device", - "identifier": [ - { - "system": "https://fhir.nhs.uk/Id/nhsSpineASID", - "value": "test-asid", - }, - { - "system": "https://fhir.nhs.uk/Id/nhsMhsPartyKey", - "value": "test-party-key", - }, - ], - }, - } - ], - } - endpoint_bundle = { - "resourceType": "Bundle", - "type": "searchset", - "total": 1, - "entry": [ - { - "fullUrl": "https://example.test/sds/Endpoint/1", - "resource": { - "resourceType": "Endpoint", - "address": "https://example.provider.org/endpoint", - }, - } - ], - } - mocked_get_sds = mocker.patch( - "gateway_api.sds.client.get", - side_effect=[ - FakeResponse(status_code=200, headers={}, _json=device_bundle), - FakeResponse(status_code=200, headers={}, _json=endpoint_bundle), - FakeResponse(status_code=200, headers={}, _json=device_bundle), - ], + provider_sds_results = SdsSearchResults( + asid="ProviderASID", endpoint="https://example.provider.org/endpoint" + ) + consumer_sds_results = SdsSearchResults( + asid="ConsumerASID", endpoint="https://example.consumer.org/endpoint" + ) + sds_results = [provider_sds_results, consumer_sds_results] + mocker.patch( + "gateway_api.sds.SdsClient.get_org_details", + side_effect=sds_results, + ) + mocked_sds_client = mocker.patch( + "gateway_api.controller.SdsClient.__init__", return_value=None ) custom_sds_url = "https://a.different.url/base" + custom_sds_api_token = "custom-sds-api-token" # noqa: S105 Not a real token - controller = create_test_controller(sds_base_url=custom_sds_url) + controller = create_test_controller( + sds_base_url=custom_sds_url, sds_api_key=custom_sds_api_token + ) controller._get_sds_details("test-ods-1", "test-ods-2") - actual_sds_url = mocked_get_sds.call_args.args[0] - assert actual_sds_url == "https://a.different.url/base/Device" + actual_sds_url = mocked_sds_client.call_args.kwargs["base_url"] + actual_sds_api_token = mocked_sds_client.call_args.kwargs["api_key"] + assert actual_sds_url == "https://a.different.url/base" + assert actual_sds_api_token == custom_sds_api_token diff --git a/gateway-api/stubs/stubs/data/bundles/bundles.py b/gateway-api/stubs/stubs/data/bundles/bundles.py index d714c29d..62574e31 100644 --- a/gateway-api/stubs/stubs/data/bundles/bundles.py +++ b/gateway-api/stubs/stubs/data/bundles/bundles.py @@ -18,3 +18,4 @@ def _wrap_patient_in_bundle(patient: dict[str, Any]) -> dict[str, Any]: } ALICE_JONES_9999999999 = _wrap_patient_in_bundle(Patients.ALICE_JONES_9999999999) + INT_9658218865 = _wrap_patient_in_bundle(Patients.INT_9658218865) diff --git a/gateway-api/stubs/stubs/data/patients/int_9658218865.json b/gateway-api/stubs/stubs/data/patients/int_9658218865.json new file mode 100644 index 00000000..54800668 --- /dev/null +++ b/gateway-api/stubs/stubs/data/patients/int_9658218865.json @@ -0,0 +1,35 @@ +{ + "resourceType": "Patient", + "id": "9658218865", + "meta": { + "versionId": "1", + "lastUpdated": "2020-01-01T00:00:00Z" + }, + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9658218865" + } + ], + "name": [ + { + "use": "official", + "family": "Samual", + "given": ["Lucien"], + "period": {"start": "1900-01-01", "end": "9999-12-31"} + } + ], + "gender": "male", + "birthDate": "1938-12-11", + "generalPractitioner": [ + { + "id": "1", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "A20047", + "period": {"start": "2020-01-01", "end": "9999-12-31"} + } + } + ] +} diff --git a/gateway-api/stubs/stubs/data/patients/patients.py b/gateway-api/stubs/stubs/data/patients/patients.py index 1b6a5a0d..a16141d1 100644 --- a/gateway-api/stubs/stubs/data/patients/patients.py +++ b/gateway-api/stubs/stubs/data/patients/patients.py @@ -27,3 +27,4 @@ def load_patient(filename: str) -> dict[str, Any]: ) ALICE_JONES_9999999999 = load_patient("alice_jones_9999999999.json") ORANGE_BOX_TRIGGER_9690937278 = load_patient("orange_box_trigger_9690937278.json") + INT_9658218865 = load_patient("int_9658218865.json") diff --git a/gateway-api/stubs/stubs/pds/stub.py b/gateway-api/stubs/stubs/pds/stub.py index 09ab014b..e26b09dd 100644 --- a/gateway-api/stubs/stubs/pds/stub.py +++ b/gateway-api/stubs/stubs/pds/stub.py @@ -53,6 +53,7 @@ def __init__(self, strict_headers: bool = True) -> None: ("9000000012", Patients.INDUCE_PROVIDER_ERROR_9000000012), ("9000000013", Patients.BLANK_ENDPOINT_SDS_RESULT_9000000013), ("9690937278", Patients.ORANGE_BOX_TRIGGER_9690937278), + ("9658218865", Patients.INT_9658218865), ] for nhs_number, patient in test_patients: self.upsert_patient( diff --git a/gateway-api/stubs/stubs/provider/stub.py b/gateway-api/stubs/stubs/provider/stub.py index 78d864e0..d11de632 100644 --- a/gateway-api/stubs/stubs/provider/stub.py +++ b/gateway-api/stubs/stubs/provider/stub.py @@ -279,6 +279,12 @@ def access_record_structured( json_data=Bundles.ALICE_JONES_9999999999, ) + if nhs_number == "9658218865": + return self._create_response( + status_code=200, + json_data=Bundles.INT_9658218865, + ) + return self._create_response( status_code=404, json_data={ diff --git a/scripts/env/app/pds.sh b/scripts/env/app/pds.sh index 8054b96f..f29fd790 100755 --- a/scripts/env/app/pds.sh +++ b/scripts/env/app/pds.sh @@ -9,7 +9,7 @@ get_pds_url() { return 0 ;; int) - echo "https://int.api.service.nhs.uk/personal-demographics/FHIR/R4/" + echo "stub" return 0 ;; *)