Skip to content

Commit 1eb4bb4

Browse files
steph-torres-nhsNogaNHSrobg-test
authored
[PRMP-1596] Documents incorrectly sent to review queue when PDS response body fails to parse (#1176)
Co-authored-by: NogaNHS <127490765+NogaNHS@users.noreply.github.com> Co-authored-by: Robert Gaskin <106234256+robg-test@users.noreply.github.com>
1 parent 53534b6 commit 1eb4bb4

10 files changed

+149
-17
lines changed

lambdas/services/bulk_upload_service.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
PatientNotFoundException,
3333
PatientRecordAlreadyExistException,
3434
PdsErrorException,
35+
PdsHttpErrorException,
36+
PdsPatientValidationException,
3537
PdsTooManyRequestsException,
3638
S3FileNotFoundException,
3739
VirusScanFailedException,
@@ -203,6 +205,21 @@ def handle_sqs_message(self, message: dict):
203205
"PDS record is restricted",
204206
)
205207

208+
except (PdsPatientValidationException, PdsHttpErrorException) as error:
209+
logger.info(
210+
f"Detected issue related to patient number: {staging_metadata.nhs_number}",
211+
)
212+
logger.error(error)
213+
logger.info("Will stop processing Lloyd George record for this patient.")
214+
logger.info("A PDS error occurred, not sending message to review queue.")
215+
self.dynamo_repository.write_report_upload_to_dynamo(
216+
staging_metadata,
217+
UploadStatus.FAILED,
218+
str(error),
219+
patient_ods_code,
220+
sent_to_review=False,
221+
)
222+
return
206223
except (
207224
InvalidNhsNumberException,
208225
LGInvalidFilesException,
@@ -214,13 +231,10 @@ def handle_sqs_message(self, message: dict):
214231
)
215232
logger.error(error)
216233
logger.info("Will stop processing Lloyd George record for this patient.")
217-
218-
reason = str(error)
219-
220234
self.dynamo_repository.write_report_upload_to_dynamo(
221235
staging_metadata,
222236
UploadStatus.FAILED,
223-
reason,
237+
str(error),
224238
patient_ods_code,
225239
sent_to_review=self.send_to_review_enabled,
226240
)

lambdas/services/create_document_reference_service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
LGInvalidFilesException,
2626
OdsErrorException,
2727
PatientNotFoundException,
28+
PdsErrorException,
29+
PdsHttpErrorException,
30+
PdsPatientValidationException,
2831
PdsTooManyRequestsException,
2932
)
3033
from utils.lambda_exceptions import DocumentRefException
@@ -123,6 +126,9 @@ def create_document_reference_request(
123126
LGInvalidFilesException,
124127
PdsTooManyRequestsException,
125128
ConfigNotFoundException,
129+
PdsErrorException,
130+
PdsPatientValidationException,
131+
PdsHttpErrorException,
126132
) as e:
127133
logger.error(
128134
f"{LambdaError.DocRefInvalidFiles.to_str()} :{str(e)}",

lambdas/services/document_review_processor_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from datetime import datetime, timezone
44

55
from botocore.exceptions import ClientError
6+
67
from enums.document_review_status import DocumentReviewStatus
78
from models.document_review import (
89
DocumentReviewFileDetails,
@@ -35,9 +36,8 @@ def __init__(self):
3536
self.review_bucket_name = os.environ["PENDING_REVIEW_BUCKET_NAME"]
3637

3738
def process_review_message(self, review_message: ReviewMessageBody) -> None:
38-
logger.info("Processing review queue message")
39-
4039
request_context.patient_nhs_no = review_message.nhs_number
40+
logger.info("Processing review queue message")
4141

4242
review_id = review_message.upload_id
4343
review_files = self._move_files_to_review_bucket(review_message, review_id)

lambdas/services/update_document_reference_service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
LGInvalidFilesException,
2020
OdsErrorException,
2121
PatientNotFoundException,
22+
PdsErrorException,
23+
PdsHttpErrorException,
24+
PdsPatientValidationException,
2225
PdsTooManyRequestsException,
2326
)
2427
from utils.lambda_exceptions import DocumentRefException
@@ -98,6 +101,9 @@ def update_document_reference_request(
98101
InvalidNhsNumberException,
99102
LGInvalidFilesException,
100103
PdsTooManyRequestsException,
104+
PdsPatientValidationException,
105+
PdsErrorException,
106+
PdsHttpErrorException,
101107
) as e:
102108
logger.error(
103109
f"{LambdaError.DocRefInvalidFiles.to_str()} :{str(e)}",

lambdas/tests/unit/services/test_bulk_upload_service.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
InvalidMessageException,
5353
PatientNotFoundException,
5454
PatientRecordAlreadyExistException,
55+
PdsHttpErrorException,
56+
PdsPatientValidationException,
5557
PdsTooManyRequestsException,
5658
S3FileNotFoundException,
5759
TagNotFoundException,
@@ -1397,7 +1399,6 @@ def test_sends_to_review_queue_when_invalid_files(
13971399
repo_with_review_enabled,
13981400
mock_validate_files,
13991401
mock_pds_service,
1400-
mocker,
14011402
):
14021403
mocked_error = LGInvalidFilesException(
14031404
"One or more of the files do not match naming convention",
@@ -1413,6 +1414,41 @@ def test_sends_to_review_queue_when_invalid_files(
14131414
)
14141415

14151416

1417+
def test_does_not_send_to_review_queue_pds_validation_error(
1418+
repo_with_review_enabled,
1419+
mocker,
1420+
):
1421+
mocked_error = PdsPatientValidationException(
1422+
"Fail to parse the patient detail response from PDS API.",
1423+
)
1424+
1425+
mock_pds_service = mocker.patch(
1426+
"services.bulk_upload_service.getting_patient_info_from_pds",
1427+
)
1428+
1429+
mock_pds_service.side_effect = mocked_error
1430+
1431+
repo_with_review_enabled.handle_sqs_message(message=TEST_SQS_MESSAGE)
1432+
1433+
repo_with_review_enabled.sqs_repository.send_message_to_review_queue.assert_not_called()
1434+
1435+
1436+
def test_does_not_send_to_review_queue_pds_http_error(mocker, repo_with_review_enabled):
1437+
mocked_error = PdsHttpErrorException(
1438+
"Failed to retrieve patient date from PDS",
1439+
)
1440+
1441+
mock_pds_service = mocker.patch(
1442+
"services.bulk_upload_service.getting_patient_info_from_pds",
1443+
)
1444+
1445+
mock_pds_service.side_effect = mocked_error
1446+
1447+
repo_with_review_enabled.handle_sqs_message(message=TEST_SQS_MESSAGE)
1448+
1449+
repo_with_review_enabled.sqs_repository.send_message_to_review_queue.assert_not_called()
1450+
1451+
14161452
def test_does_not_send_to_review_queue_when_virus_scan_fails(
14171453
repo_with_review_enabled,
14181454
mock_validate_files,

lambdas/tests/unit/services/test_create_document_reference_service.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@
3333
from utils.common_query_filters import NotDeleted
3434
from utils.constants.ssm import UPLOAD_PILOT_ODS_ALLOWED_LIST
3535
from utils.dynamo_query_filter_builder import DynamoQueryFilterBuilder
36-
from utils.exceptions import PatientNotFoundException
36+
from utils.exceptions import (
37+
PatientNotFoundException,
38+
PdsHttpErrorException,
39+
PdsPatientValidationException,
40+
)
3741
from utils.lambda_exceptions import DocumentRefException
3842
from utils.lloyd_george_validator import LGInvalidFilesException
3943
from utils.request_context import request_context
@@ -305,7 +309,7 @@ def test_create_document_reference_failed_to_parse_pds_response(
305309
mock_getting_patient_info_from_pds,
306310
mock_fetch_available_document_references_by_type,
307311
):
308-
mock_getting_patient_info_from_pds.side_effect = LGInvalidFilesException
312+
mock_getting_patient_info_from_pds.side_effect = PdsPatientValidationException
309313

310314
with pytest.raises(Exception) as exc_info:
311315
mock_create_doc_ref_service.create_document_reference_request(
@@ -344,6 +348,29 @@ def test_cdr_nhs_number_not_found_raises_search_patient_exception(
344348
mock_create_document_reference.assert_not_called()
345349

346350

351+
def test_create_document_reference_pds_general_error_throws_exception(
352+
mock_fhir_doc_ref_base_service,
353+
mock_create_doc_ref_service,
354+
mock_create_document_reference,
355+
mock_getting_patient_info_from_pds,
356+
mock_fetch_available_document_references_by_type,
357+
):
358+
mock_getting_patient_info_from_pds.side_effect = PdsHttpErrorException
359+
360+
with pytest.raises(Exception) as exc_info:
361+
mock_create_doc_ref_service.create_document_reference_request(
362+
TEST_NHS_NUMBER,
363+
LG_FILE_LIST,
364+
)
365+
366+
exception = exc_info.value
367+
assert isinstance(exception, DocumentRefException)
368+
assert exception.status_code == 400
369+
assert exception.message == "Invalid files or id"
370+
371+
mock_create_document_reference.assert_not_called()
372+
373+
347374
def test_cdr_non_pdf_file_raises_exception(
348375
mock_fhir_doc_ref_base_service,
349376
mock_create_doc_ref_service,

lambdas/tests/unit/services/test_update_document_reference_service.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
create_test_doc_store_refs,
1515
create_test_lloyd_george_doc_store_refs,
1616
)
17-
from utils.exceptions import LGInvalidFilesException, PatientNotFoundException
17+
from utils.exceptions import (
18+
LGInvalidFilesException,
19+
PatientNotFoundException,
20+
PdsHttpErrorException,
21+
)
1822
from utils.lambda_exceptions import DocumentRefException
1923
from utils.request_context import request_context
2024

@@ -238,6 +242,32 @@ def test_nhs_number_not_found_raises_exception(
238242
mock_process_fhir_document_reference.assert_not_called()
239243

240244

245+
def test_general_pds_error_raises_exception(
246+
mock_fhir_doc_ref_base_service,
247+
mock_getting_patient_info_from_pds,
248+
mock_update_doc_ref_service,
249+
mock_check_if_ods_code_is_in_pilot,
250+
mock_process_fhir_document_reference,
251+
mock_fetch_documents_from_table,
252+
):
253+
mock_getting_patient_info_from_pds.side_effect = PdsHttpErrorException
254+
mock_fetch_documents_from_table.return_value = create_test_doc_store_refs()
255+
256+
with pytest.raises(DocumentRefException) as exc_info:
257+
mock_update_doc_ref_service.update_document_reference_request(
258+
TEST_NHS_NUMBER,
259+
LG_FILE,
260+
TEST_UUID,
261+
)
262+
263+
exception = exc_info.value
264+
assert isinstance(exception, DocumentRefException)
265+
assert exception.status_code == 400
266+
267+
mock_check_if_ods_code_is_in_pilot.assert_not_called()
268+
mock_process_fhir_document_reference.assert_not_called()
269+
270+
241271
# covers for number of files expected, non-pdf files, incorrect file name format, duplicate files
242272
def test_invalid_files_raises_exception(
243273
mock_fhir_doc_ref_base_service,

lambdas/tests/unit/utils/test_lloyd_george_validator.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
from utils.exceptions import (
3636
PatientNotFoundException,
3737
PatientRecordAlreadyExistException,
38+
PdsErrorException,
39+
PdsHttpErrorException,
40+
PdsPatientValidationException,
3841
PdsTooManyRequestsException,
3942
)
4043
from utils.lloyd_george_validator import (
@@ -881,7 +884,7 @@ def test_bad_request_with_pds_service(mock_pds_call):
881884

882885
mock_pds_call.return_value = response
883886

884-
with pytest.raises(LGInvalidFilesException) as e:
887+
with pytest.raises(PdsHttpErrorException) as e:
885888
getting_patient_info_from_pds("9000000009")
886889
assert str(e.value) == "Failed to retrieve patient data from PDS"
887890

@@ -916,19 +919,19 @@ def test_check_pds_response_404_status_raises_patient_not_found_exception():
916919
check_pds_response_status(response)
917920

918921

919-
def test_check_pds_response_4xx_or_5xx_status_raise_lg_invalid_files_exception():
922+
def test_check_pds_response_4xx_or_5xx_status_raise_pds_error_exception():
920923
response = Response()
921924
response.status_code = 500
922925

923-
with pytest.raises(LGInvalidFilesException):
926+
with pytest.raises(PdsHttpErrorException):
924927
check_pds_response_status(response)
925928

926929

927930
def test_check_pds_response_200_status_not_raise_exception():
928931
response = Response()
929932
response.status_code = 200
930933

931-
with expect_not_to_raise(LGInvalidFilesException):
934+
with expect_not_to_raise(PdsErrorException):
932935
check_pds_response_status(response)
933936

934937

@@ -949,7 +952,7 @@ def test_parse_pds_response_raise_error_when_model_validation_failed():
949952
b"""{"body": "some data that pydantic cannot parse"}"""
950953
)
951954

952-
with pytest.raises(LGInvalidFilesException) as error:
955+
with pytest.raises(PdsPatientValidationException) as error:
953956
parse_pds_response(mock_invalid_pds_response)
954957

955958
assert str(error.value) == "Fail to parse the patient detail response from PDS API."

lambdas/utils/exceptions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,18 @@ class PdsErrorException(Exception):
2222
pass
2323

2424

25+
class PdsPatientValidationException(Exception):
26+
pass
27+
28+
2529
class PdsTooManyRequestsException(Exception):
2630
pass
2731

2832

33+
class PdsHttpErrorException(Exception):
34+
pass
35+
36+
2937
class AuthorisationException(Exception):
3038
pass
3139

lambdas/utils/lloyd_george_validator.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
LGInvalidFilesException,
2020
PatientNotFoundException,
2121
PatientRecordAlreadyExistException,
22+
PdsHttpErrorException,
23+
PdsPatientValidationException,
2224
PdsTooManyRequestsException,
2325
)
2426
from utils.unicode_utils import (
@@ -383,7 +385,7 @@ def check_pds_response_status(pds_response: requests.Response):
383385
pds_response.raise_for_status()
384386
except HTTPError as e:
385387
logger.error(e)
386-
raise LGInvalidFilesException("Failed to retrieve patient data from PDS")
388+
raise PdsHttpErrorException("Failed to retrieve patient data from PDS")
387389

388390

389391
def parse_pds_response(pds_response: requests.Response) -> Patient:
@@ -393,7 +395,7 @@ def parse_pds_response(pds_response: requests.Response) -> Patient:
393395
except pydantic.ValidationError:
394396
error_msg = "Fail to parse the patient detail response from PDS API."
395397
logger.error(error_msg)
396-
raise LGInvalidFilesException(error_msg)
398+
raise PdsPatientValidationException(error_msg)
397399

398400

399401
def get_allowed_ods_codes() -> list[str]:

0 commit comments

Comments
 (0)