def build_transfer(**kwargs) -> Transfer: return Transfer( conversation_id=kwargs.get("conversation_id", a_string(36)), sla_duration=kwargs.get("sla_duration", a_duration()), requesting_practice=kwargs.get( "requesting_practice", Practice(asid=a_string(12), supplier=a_string(12), ods_code=a_string(4)), ), sending_practice=kwargs.get( "sending_practice", Practice(asid=a_string(12), supplier=a_string(12), ods_code=a_string(4)), ), sender_error_codes=kwargs.get("sender_error_codes", []), final_error_codes=kwargs.get("final_error_codes", []), intermediate_error_codes=kwargs.get("intermediate_error_codes", []), outcome=kwargs.get( "outcome", TransferOutcome(status=TransferStatus.INTEGRATED_ON_TIME, failure_reason=None), ), date_requested=kwargs.get("date_requested", a_datetime()), date_completed=kwargs.get("date_completed", None), last_sender_message_timestamp=None, )
def derive_transfer( self, conversation: Gp2gpConversation, organisation_lookup: OrganisationLookup ) -> Transfer: sla_duration = _calculate_sla(conversation, self._probe) requesting_practice_asid = conversation.requesting_practice_asid() sending_practice_asid = conversation.sending_practice_asid() return Transfer( conversation_id=conversation.conversation_id(), sla_duration=sla_duration, requesting_practice=Practice( asid=requesting_practice_asid, supplier=conversation.requesting_supplier(), ods_code=organisation_lookup.practice_ods_code_from_asid(requesting_practice_asid), ), sending_practice=Practice( asid=sending_practice_asid, supplier=conversation.sending_supplier(), ods_code=organisation_lookup.practice_ods_code_from_asid(sending_practice_asid), ), sender_error_codes=conversation.sender_error_codes(), final_error_codes=conversation.final_error_codes(), intermediate_error_codes=conversation.intermediate_error_codes(), outcome=TransferOutcome.from_gp2gp_conversation(conversation, sla_duration), date_requested=conversation.date_requested(), date_completed=conversation.effective_final_acknowledgement_time(), last_sender_message_timestamp=conversation.last_sender_message_timestamp(), )
def a_transfer_integrated_beyond_8_days(): return build_transfer( outcome=TransferOutcome( status=TransferStatus.PROCESS_FAILURE, failure_reason=TransferFailureReason.INTEGRATED_LATE, ), sla_duration=timedelta(seconds=EIGHT_DAYS_IN_SECONDS + 1), )
def a_supressed_transfer(**kwargs): return build_transfer( outcome=TransferOutcome( status=TransferStatus.INTEGRATED_ON_TIME, failure_reason=None, ), final_error_codes=[15], sla_duration=kwargs.get("sla_duration", a_duration(max_length=604800)), )
def test_returns_transfer_status_process_failure_with_reason( test_case, expected_reason): gp2gp_messages: List[Message] = test_case() conversation = Gp2gpConversation( gp2gp_messages, probe=mock_gp2gp_conversation_observability_probe) actual = TransferOutcome.from_gp2gp_conversation(conversation, None) assert actual.status == TransferStatus.PROCESS_FAILURE assert actual.failure_reason == expected_reason
def test_returns_transfer_status_integrated_on_time(test_case): gp2gp_messages: List[Message] = test_case() conversation = Gp2gpConversation( gp2gp_messages, mock_gp2gp_conversation_observability_probe) actual = TransferOutcome.from_gp2gp_conversation(conversation, timedelta(days=1)) assert actual.status == TransferStatus.INTEGRATED_ON_TIME assert actual.failure_reason is None
def test_returns_transfer_status_technical_failure_with_reason( test_case, expected_reason): gp2gp_messages: List[Message] = test_case() conversation = Gp2gpConversation( gp2gp_messages, mock_gp2gp_conversation_observability_probe) actual = TransferOutcome.from_gp2gp_conversation(conversation, a_duration()) assert actual.status == TransferStatus.TECHNICAL_FAILURE assert actual.failure_reason == expected_reason
def test_status_is_converted_to_column(): integrated_transfer_outcome = TransferOutcome( status=TransferStatus.INTEGRATED_ON_TIME, failure_reason=None) transfer = build_transfer(transfer_outcome=integrated_transfer_outcome) expected_status_column = {"status": ["Integrated on time"]} table = convert_transfers_to_table([transfer]) actual_status_column = table.select(["status"]).to_pydict() assert actual_status_column == expected_status_column
def test_returns_correct_transfer_outcome_if_fatal_sender_error_code_present( fatal_sender_error_code, ): gp2gp_messages: List[Message] = test_cases.request_acknowledged_with_error( error_code=fatal_sender_error_code) conversation = Gp2gpConversation( gp2gp_messages, mock_gp2gp_conversation_observability_probe) actual = TransferOutcome.from_gp2gp_conversation(conversation, a_duration()) assert actual.status == TransferStatus.TECHNICAL_FAILURE assert actual.failure_reason == TransferFailureReason.FATAL_SENDER_ERROR
def test_return_process_failure_given_an_unacknowledged_ehr_with_duplicate_and_no_copc_fragments( ): gp2gp_messages: List[ Message] = test_cases.acknowledged_duplicate_and_waiting_for_integration( ) conversation = Gp2gpConversation( gp2gp_messages, mock_gp2gp_conversation_observability_probe) actual = TransferOutcome.from_gp2gp_conversation(conversation, None) assert actual.status == TransferStatus.PROCESS_FAILURE assert actual.failure_reason == TransferFailureReason.TRANSFERRED_NOT_INTEGRATED
def test_returns_unclassified_given_unacknowledged_ehr_with_duplicate_and_copc_fragments( ): conversation = build_mock_gp2gp_conversation() conversation.is_integrated.return_value = False conversation.has_concluded_with_failure.return_value = False conversation.contains_unacknowledged_duplicate_ehr_and_copc_fragments.return_value = True actual = TransferOutcome.from_gp2gp_conversation(conversation, None) assert actual.status == TransferStatus.UNCLASSIFIED_FAILURE assert actual.failure_reason == TransferFailureReason.AMBIGUOUS_COPCS
def test_write_transfers_correctly_writes_all_fields(): mock_s3 = MockS3() s3_data_manager = S3DataManager(mock_s3) io = TransferClassifierIO(s3_data_manager) transfer = Transfer( conversation_id="1234", sla_duration=timedelta(days=1), requesting_practice=Practice(asid="123", supplier="Supplier A", ods_code="A12"), sending_practice=Practice(asid="456", supplier="Supplier B", ods_code="B12"), sender_error_codes=[1, None], final_error_codes=[None, 32], intermediate_error_codes=[], outcome=TransferOutcome( status=TransferStatus.PROCESS_FAILURE, failure_reason=TransferFailureReason.FINAL_ERROR), date_requested=datetime(year=2021, month=3, day=5), date_completed=None, last_sender_message_timestamp=None, ) io.write_transfers(transfers=[transfer], s3_uri="s3://a_bucket/some_data.parquet", metadata=_SOME_METADATA) expected_table = { "conversation_id": ["1234"], "sla_duration": [86400], "requesting_practice_asid": ["123"], "requesting_practice_ods_code": ["A12"], "sending_practice_asid": ["456"], "sending_practice_ods_code": ["B12"], "requesting_supplier": ["Supplier A"], "sending_supplier": ["Supplier B"], "sender_error_codes": [[1, None]], "final_error_codes": [[None, 32]], "intermediate_error_codes": [[]], "status": ["Process failure"], "failure_reason": ["Final error"], "date_requested": [datetime(year=2021, month=3, day=5)], "date_completed": [None], "last_sender_message_timestamp": [None], } actual_table = mock_s3.object( "a_bucket", "some_data.parquet").read_parquet().to_pydict() assert actual_table == expected_table
def test_returns_correct_transfer_outcome_given_multiple_conflicting_sender_acks( ): a_fatal_sender_error = choice(FATAL_SENDER_ERROR_CODES) gp2gp_messages: List[ Message] = test_cases.multiple_sender_acknowledgements( error_codes=[None, a_fatal_sender_error]) conversation = Gp2gpConversation( gp2gp_messages, mock_gp2gp_conversation_observability_probe) actual = TransferOutcome.from_gp2gp_conversation(conversation, a_duration()) assert actual.status == TransferStatus.TECHNICAL_FAILURE assert actual.failure_reason == TransferFailureReason.FATAL_SENDER_ERROR
def test_returns_transferred_not_integrated_with_error_given_stalled_with_copc_error( ): conversation = build_mock_gp2gp_conversation() conversation.is_integrated.return_value = False conversation.has_concluded_with_failure.return_value = False conversation.contains_copc_fragments.return_value = True conversation.contains_unacknowledged_duplicate_ehr_and_copc_fragments.return_value = False conversation.contains_copc_error.return_value = True conversation.is_missing_copc_ack.return_value = False actual = TransferOutcome.from_gp2gp_conversation(conversation, None) assert actual.status == TransferStatus.UNCLASSIFIED_FAILURE assert actual.failure_reason == TransferFailureReason.TRANSFERRED_NOT_INTEGRATED_WITH_ERROR
def an_integrated_transfer(**kwargs): return build_transfer( outcome=TransferOutcome(status=TransferStatus.INTEGRATED_ON_TIME, failure_reason=None), sla_duration=kwargs.get("sla_duration", a_duration(max_length=604800)), )
def a_transfer_with_a_final_error(): return build_transfer(outcome=TransferOutcome( status=TransferStatus.TECHNICAL_FAILURE, failure_reason=TransferFailureReason.FINAL_ERROR, ))
def a_transfer_where_no_core_ehr_was_sent(): return build_transfer(outcome=TransferOutcome( status=TransferStatus.TECHNICAL_FAILURE, failure_reason=TransferFailureReason.CORE_EHR_NOT_SENT, ))