Skip to content

Commit

Permalink
prmdr-327 format
Browse files Browse the repository at this point in the history
  • Loading branch information
NogaNHS committed Oct 17, 2023
1 parent 0923b82 commit 74a0449
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 71 deletions.
2 changes: 1 addition & 1 deletion lambdas/enums/pds_ssm_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ class SSMParameter(Enum):
PDS_API_KEY = "/prs/dev/user-input/pds-fhir-private-key"
NHS_OAUTH_ENDPOINT = "/prs/dev/user-input/nhs-oauth-endpoint"
PDS_API_ENDPOINT = "/prs/dev/user-input/pds-fhir-endpoint"
PDS_API_ACCESS_TOKEN = "/prs/dev-ndr/pds-fhir-access-token"
PDS_API_ACCESS_TOKEN = "/prs/dev-ndr/pds-fhir-access-token"
16 changes: 13 additions & 3 deletions lambdas/handlers/search_patient_details_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
from pydantic import ValidationError
from requests import HTTPError
from services.pds_api_service import PdsApiService
from utils.exceptions import (InvalidResourceIdException,
PatientNotFoundException, PdsErrorException)
from utils.exceptions import (
InvalidResourceIdException,
PatientNotFoundException,
PdsErrorException,
)
from utils.lambda_response import ApiGatewayResponse

from services.ssm_service import SSMService
Expand All @@ -15,8 +18,15 @@

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def get_pds_service():
return PdsApiService if not bool(os.getenv("PDS_FHIR_IS_STUBBED")) else MockPdsApiService
return (
PdsApiService
if not bool(os.getenv("PDS_FHIR_IS_STUBBED"))
else MockPdsApiService
)


def lambda_handler(event, context):
logger.info("API Gateway event received - processing starts")
Expand Down
17 changes: 13 additions & 4 deletions lambdas/services/pds_api_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ def get_new_access_token(self):
return token_access_response["access_token"]

def get_parameters_for_new_access_token(self):
parameters = [SSMParameter.NHS_OAUTH_ENDPOINT, SSMParameter.PDS_KID, SSMParameter.NHS_OAUTH_KEY, SSMParameter.PDS_API_KEY]
parameters = [
SSMParameter.NHS_OAUTH_ENDPOINT,
SSMParameter.PDS_KID,
SSMParameter.NHS_OAUTH_KEY,
SSMParameter.PDS_API_KEY,
]
return self.ssm_service.get_ssm_parameters(parameters, with_decryption=True)

def update_access_token_ssm(self, parameter_value: str):
Expand All @@ -112,15 +117,19 @@ def update_access_token_ssm(self, parameter_value: str):
def get_parameters_for_pds_api_request(self):
parameters = [
SSMParameter.PDS_API_ENDPOINT,
SSMParameter.PDS_API_ACCESS_TOKEN,
SSMParameter.PDS_API_ACCESS_TOKEN,
]
ssm_response = self.ssm_service.get_ssm_parameters(
parameters, with_decryption=True
)
return ssm_response[parameters[0]], json.loads(ssm_response[parameters[1]])

def create_jwt_token_for_new_access_token_request(self, access_token_ssm_parameters):
nhs_oauth_endpoint = access_token_ssm_parameters[SSMParameter.NHS_OAUTH_ENDPOINT]
def create_jwt_token_for_new_access_token_request(
self, access_token_ssm_parameters
):
nhs_oauth_endpoint = access_token_ssm_parameters[
SSMParameter.NHS_OAUTH_ENDPOINT
]
kid = access_token_ssm_parameters[SSMParameter.PDS_KID]
nhs_key = access_token_ssm_parameters[SSMParameter.NHS_OAUTH_KEY]
pds_key = access_token_ssm_parameters[SSMParameter.PDS_API_KEY]
Expand Down
22 changes: 16 additions & 6 deletions lambdas/tests/unit/handlers/test_search_patient_details_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from requests.models import Response
from tests.unit.helpers.data.pds.pds_patient_response import PDS_PATIENT


@pytest.fixture
def patch_env_vars():
env_vars = {
Expand All @@ -14,13 +15,17 @@ def patch_env_vars():
with patch.dict(os.environ, env_vars):
yield env_vars

def test_lambda_handler_valid_id_returns_200(valid_id_event, context, mocker, patch_env_vars):

def test_lambda_handler_valid_id_returns_200(
valid_id_event, context, mocker, patch_env_vars
):
response = Response()
response.status_code = 200
response._content = PDS_PATIENT

mocker.patch(
"services.mock_pds_service.MockPdsApiService.fake_pds_request", return_value=response
"services.mock_pds_service.MockPdsApiService.fake_pds_request",
return_value=response,
)

actual = lambda_handler(valid_id_event, context)
Expand All @@ -41,12 +46,15 @@ def test_lambda_handler_valid_id_returns_200(valid_id_event, context, mocker, pa
assert expected == actual


def test_lambda_handler_invalid_id_returns_400(invalid_id_event, context, mocker, patch_env_vars):
def test_lambda_handler_invalid_id_returns_400(
invalid_id_event, context, mocker, patch_env_vars
):
response = Response()
response.status_code = 400

mocker.patch(
"services.mock_pds_service.MockPdsApiService.fake_pds_request", return_value=response
"services.mock_pds_service.MockPdsApiService.fake_pds_request",
return_value=response,
)

actual = lambda_handler(invalid_id_event, context)
Expand All @@ -72,7 +80,8 @@ def test_lambda_handler_valid_id_not_in_pds_returns_404(
response.status_code = 404

mocker.patch(
"services.mock_pds_service.MockPdsApiService.fake_pds_request", return_value=response
"services.mock_pds_service.MockPdsApiService.fake_pds_request",
return_value=response,
)

actual = lambda_handler(valid_id_event, context)
Expand All @@ -98,7 +107,8 @@ def test_lambda_handler_missing_id_in_query_params_returns_400(
response.status_code = 400

mocker.patch(
"services.mock_pds_service.MockPdsApiService.fake_pds_request", return_value=response
"services.mock_pds_service.MockPdsApiService.fake_pds_request",
return_value=response,
)

actual = lambda_handler(missing_id_event, context)
Expand Down
6 changes: 4 additions & 2 deletions lambdas/tests/unit/models/test_pds_models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import pytest
from models.pds_models import PatientDetails
from tests.unit.helpers.data.pds.utils import (create_restricted_patient,
create_unrestricted_patient)
from tests.unit.helpers.data.pds.utils import (
create_restricted_patient,
create_unrestricted_patient,
)
from utils.exceptions import InvalidResourceIdException
from utils.utilities import validate_id

Expand Down
12 changes: 8 additions & 4 deletions lambdas/tests/unit/services/test_mock_pds_api_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
from models.pds_models import PatientDetails
from requests.models import Response
from tests.unit.helpers.data.pds.pds_patient_response import PDS_PATIENT
from utils.exceptions import (InvalidResourceIdException,
PatientNotFoundException, PdsErrorException)
from utils.exceptions import (
InvalidResourceIdException,
PatientNotFoundException,
PdsErrorException,
)

from services.mock_pds_service import MockPdsApiService

pds_service = MockPdsApiService()


def test_fetch_patient_details_valid_returns_PatientDetails(mocker):
nhs_number = "9000000025"

Expand All @@ -17,7 +21,8 @@ def test_fetch_patient_details_valid_returns_PatientDetails(mocker):
response._content = PDS_PATIENT

mocker.patch(
"services.mock_pds_service.MockPdsApiService.fake_pds_request", return_value=response
"services.mock_pds_service.MockPdsApiService.fake_pds_request",
return_value=response,
)

actual = pds_service.fetch_patient_details(nhs_number)
Expand All @@ -40,4 +45,3 @@ def test_fetch_patient_details_invalid_nhs_number_raises_InvalidResourceIdExcept

with pytest.raises(InvalidResourceIdException):
pds_service.fetch_patient_details(nhs_number)

39 changes: 26 additions & 13 deletions lambdas/tests/unit/services/test_pds_api_service.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import pytest
from models.pds_models import PatientDetails
from tests.unit.helpers.data.pds.pds_patient_response import PDS_PATIENT
from utils.exceptions import (InvalidResourceIdException,
PatientNotFoundException, PdsErrorException)
from utils.exceptions import (
InvalidResourceIdException,
PatientNotFoundException,
PdsErrorException,
)

from services.pds_api_service import PdsApiService

Expand All @@ -19,6 +22,7 @@ def get_ssm_parameters(self, *arg, **kwargs):

pds_service = PdsApiService(FakeSSMService)


def test_handle_response_200_returns_PatientDetails(mocker):
nhs_number = "9000000025"

Expand Down Expand Up @@ -70,24 +74,29 @@ def test_handle_response_catch_all_raises_PdsErrorException(mocker):
with pytest.raises(PdsErrorException):
pds_service.handle_response(response, nhs_number)


def test_request_new_token_is_call_with_correct_data(mocker):
mock_jwt_token = "testtest"
mock_endpoint = "api.endpoint/mock"
access_token_headers = {"content-type": "application/x-www-form-urlencoded"}
access_token_data = {
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": mock_jwt_token,
}
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": mock_jwt_token,
}
mock_post = mocker.patch("requests.post")
pds_service.request_new_access_token(mock_jwt_token, mock_endpoint)
mock_post.assert_called_with(url=mock_endpoint, headers=access_token_headers, data=access_token_data)
mock_post.assert_called_with(
url=mock_endpoint, headers=access_token_headers, data=access_token_data
)


def test_create_jwt_for_new_access_token(mocker):
access_token_parameters = {SSMParameter.NHS_OAUTH_ENDPOINT : "api.endpoint/mock",
SSMParameter.PDS_KID: "test_string_pds_kid",
SSMParameter.NHS_OAUTH_KEY: "test_string_key_oauth",
SSMParameter.PDS_API_KEY: "test_string_key_pds"
access_token_parameters = {
SSMParameter.NHS_OAUTH_ENDPOINT: "api.endpoint/mock",
SSMParameter.PDS_KID: "test_string_pds_kid",
SSMParameter.NHS_OAUTH_KEY: "test_string_key_oauth",
SSMParameter.PDS_API_KEY: "test_string_key_pds",
}
expected_payload = {
"iss": "test_string_key_oauth",
Expand All @@ -101,5 +110,9 @@ def test_create_jwt_for_new_access_token(mocker):

mock_jwt_encode = mocker.patch("jwt.encode")
pds_service.create_jwt_token_for_new_access_token_request(access_token_parameters)
mock_jwt_encode.assert_called_with(expected_payload, "test_string_key_pds", algorithm="RS512", headers={"kid": "test_string_pds_kid"})

mock_jwt_encode.assert_called_with(
expected_payload,
"test_string_key_pds",
algorithm="RS512",
headers={"kid": "test_string_pds_kid"},
)
86 changes: 48 additions & 38 deletions lambdas/tests/unit/services/test_ssm_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,43 @@
from services.ssm_service import SSMService

MOCK_SSM_PARAMETERS_RESPONSE = {
'Parameters': [
"Parameters": [
{
'Name': 'ssm_parameter_key',
'Type': 'SecureString',
'Value': 'string',
'Version': 123,
'Selector': 'string',
'SourceResult': 'string',
'LastModifiedDate': datetime(2015, 1, 1),
'ARN': 'string',
'DataType': 'string'
"Name": "ssm_parameter_key",
"Type": "SecureString",
"Value": "string",
"Version": 123,
"Selector": "string",
"SourceResult": "string",
"LastModifiedDate": datetime(2015, 1, 1),
"ARN": "string",
"DataType": "string",
},
{
'Name': 'another_key',
'Type': 'SecureString',
'Value': 'string',
'Version': 123,
'Selector': 'string',
'SourceResult': 'string',
'LastModifiedDate': datetime(2015, 1, 1),
'ARN': 'string',
'DataType': 'string'
"Name": "another_key",
"Type": "SecureString",
"Value": "string",
"Version": 123,
"Selector": "string",
"SourceResult": "string",
"LastModifiedDate": datetime(2015, 1, 1),
"ARN": "string",
"DataType": "string",
},
],
}

MOCK_SSM_PARAMETER_RESPONSE = {
'Parameter': {
'Name': 'ssm_parameter_key',
'Type': 'String',
'Value': 'string',
'Version': 123,
'Selector': 'string',
'SourceResult': 'string',
'LastModifiedDate': datetime(2015, 1, 1),
'ARN': 'string',
'DataType': 'string'
"Parameter": {
"Name": "ssm_parameter_key",
"Type": "String",
"Value": "string",
"Version": 123,
"Selector": "string",
"SourceResult": "string",
"LastModifiedDate": datetime(2015, 1, 1),
"ARN": "string",
"DataType": "string",
}
}

Expand All @@ -49,23 +49,26 @@ def test_get_ssm_parameter(mocker):
service = SSMService()
mock_get_parameter = mocker.patch.object(service.client, "get_parameter")
mock_get_parameter.return_value = MOCK_SSM_PARAMETER_RESPONSE
actual = service.get_ssm_parameter(parameter_key='ssm_parameter_key')
actual = service.get_ssm_parameter(parameter_key="ssm_parameter_key")

mock_get_parameter.assert_called_once_with(
Name='ssm_parameter_key', WithDecryption=False
Name="ssm_parameter_key", WithDecryption=False
)
assert actual == 'string'
assert actual == "string"


def test_get_ssm_parameters(mocker):
mocker.patch("boto3.client")
service = SSMService()
mock_get_parameters = mocker.patch.object(service.client, "get_parameters")
mock_get_parameters.return_value = MOCK_SSM_PARAMETERS_RESPONSE
actual = service.get_ssm_parameters(parameters_keys=['ssm_parameter_key', 'another_key'])
expected = {'ssm_parameter_key': 'string', 'another_key': 'string'}
actual = service.get_ssm_parameters(
parameters_keys=["ssm_parameter_key", "another_key"]
)
expected = {"ssm_parameter_key": "string", "another_key": "string"}

mock_get_parameters.assert_called_once_with(
Names=['ssm_parameter_key', 'another_key'], WithDecryption=False
Names=["ssm_parameter_key", "another_key"], WithDecryption=False
)
assert actual == expected

Expand All @@ -74,8 +77,15 @@ def test_update_ssm_parameter(mocker):
mocker.patch("boto3.client")
service = SSMService()
mock_put_parameter = mocker.patch.object(service.client, "put_parameter")
service.update_ssm_parameter(parameter_key='ssm_parameter_key', parameter_value='parameter_value', parameter_type='SecureString')
service.update_ssm_parameter(
parameter_key="ssm_parameter_key",
parameter_value="parameter_value",
parameter_type="SecureString",
)

mock_put_parameter.assert_called_once_with(
Name='ssm_parameter_key', Value='parameter_value', Type='SecureString', Overwrite=True
)
Name="ssm_parameter_key",
Value="parameter_value",
Type="SecureString",
Overwrite=True,
)

0 comments on commit 74a0449

Please sign in to comment.