def test_warning_when_unable_to_determine_purpose_of_message(): mock_logger = Mock() mock_probe = Gp2gpConversationObservabilityProbe(mock_logger) unknown_message_purpose_message = build_message( conversation_id="ASD", guid="abc", interaction_id="urn:nhs:names:services:gp2gp/RCMR_IN010000UK08", ) messages = [ build_message( conversation_id="ASD", interaction_id=EHR_REQUEST_STARTED, ), unknown_message_purpose_message, ] Gp2gpConversation(messages=messages, probe=mock_probe) mock_logger.warning.assert_called_once_with( f":Couldn't determine purpose of message with guid: {unknown_message_purpose_message.guid}", extra={ "event": "UNKNOWN_MESSAGE_PURPOSE", "conversation_id": unknown_message_purpose_message.conversation_id, "interaction_id": unknown_message_purpose_message.interaction_id, }, )
def test_parse_conversation_parses_a_complete_conversation(): request_started_message = build_message( interaction_id=EHR_REQUEST_STARTED, ) request_completed_message = build_message( guid="54F949C0-DC7F-4EBC-8AE2-72BF2D0AF4EE", interaction_id=EHR_REQUEST_COMPLETED, ) request_started_ack_message = build_message( interaction_id=APPLICATION_ACK, ) request_completed_ack_message = build_message( interaction_id=APPLICATION_ACK, message_ref="54F949C0-DC7F-4EBC-8AE2-72BF2D0AF4EE", ) messages = [ request_started_message, request_completed_message, request_started_ack_message, request_completed_ack_message, ] conversation = Conversation("F8DAFCAA-5012-427B-BDB4-354256A4874B", messages) expected = ParsedConversation( id="F8DAFCAA-5012-427B-BDB4-354256A4874B", request_started=request_started_message, request_completed=request_completed_message, request_completed_ack=request_completed_ack_message, ) actual = parse_conversation(conversation) assert actual == expected
def test_parse_conversation_parses_incomplete_conversation(): request_started_message = build_message( interaction_id="urn:nhs:names:services:gp2gp/RCMR_IN010000UK05", ) request_completed_message = build_message( interaction_id="urn:nhs:names:services:gp2gp/RCMR_IN030000UK06", ) request_started_ack_message = build_message( interaction_id="urn:nhs:names:services:gp2gp/MCCI_IN010000UK13", ) messages = [ request_started_message, request_completed_message, request_started_ack_message, ] conversation = Conversation("F8DAFCAA-5012-427B-BDB4-354256A4874B", messages) expected = ParsedConversation( id="F8DAFCAA-5012-427B-BDB4-354256A4874B", request_started=request_started_message, request_completed=request_completed_message, request_completed_ack=None, ) actual = parse_conversation(conversation) assert actual == expected
def test_filter_conversations_by_request_started_time_rejects_conversations_outside_of_range( ): date_range = DateTimeRange(start=datetime(year=2020, month=6, day=1), end=datetime(year=2020, month=7, day=1)) conversation_within_range = build_parsed_conversation( request_started=build_message( time=datetime(year=2020, month=6, day=15))) conversation_before_range = build_parsed_conversation( request_started=build_message( time=datetime(year=2020, month=5, day=28))) conversation_after_range = build_parsed_conversation( request_started=build_message( time=datetime(year=2020, month=7, day=28))) parsed_conversations = [ conversation_before_range, conversation_within_range, conversation_after_range, ] expected = [conversation_within_range] actual = filter_conversations_by_request_started_time( parsed_conversations, date_range) assert list(actual) == expected
def test_parses_a_complete_conversation(): request_started_message = build_message(guid="abc", interaction_id=EHR_REQUEST_STARTED) request_completed_message = build_message(guid="abc-1", interaction_id=EHR_REQUEST_COMPLETED) request_started_ack_message = build_message(interaction_id=APPLICATION_ACK, message_ref="abc") request_completed_ack_message = build_message( interaction_id=APPLICATION_ACK, message_ref="abc-1", ) messages = [ request_started_message, request_completed_message, request_started_ack_message, request_completed_ack_message, ] conversation = Conversation("abc-0", messages) expected = ParsedConversation( id="abc-0", request_started=request_started_message, request_started_ack=request_started_ack_message, request_completed=request_completed_message, intermediate_messages=[], request_completed_ack=request_completed_ack_message, ) actual = parse_conversation(conversation) assert actual == expected
def test_intermediate_error_code_is_empty_list_if_no_errors(): intermediate_messages = [build_message(), build_message(), build_message()] conversations = [build_parsed_conversation(intermediate_messages=intermediate_messages)] actual = derive_transfers(conversations) expected_intermediate_error_codes = [[]] _assert_attributes("intermediate_error_codes", actual, expected_intermediate_error_codes)
def test_is_acknowledgement_of_returns_false_when_message_ref_is_wrong(): message = build_message(interaction_id=APPLICATION_ACK, message_ref="123") other_message = build_message(guid="456") expected = False actual = message.is_acknowledgement_of(other_message) assert actual == expected
def test_is_acknowledgement_of_returns_false_when_message_is_not_an_ack(): message = build_message(interaction_id=COMMON_POINT_TO_POINT, message_ref="123") other_message = build_message(guid="123") expected = False actual = message.is_acknowledgement_of(other_message) assert actual == expected
def test_group_into_conversations_produces_correct_conversations(): message_one = build_message(conversation_id="abc") message_two = build_message(conversation_id="xyz") messages = [message_one, message_two] expected = [Conversation("abc", [message_one]), Conversation("xyz", [message_two])] actual = group_into_conversations(messages) assert list(actual) == expected
def test_is_acknowledgement_of_returns_true_when_given_message_with_matching_ref( ): message = build_message(interaction_id=APPLICATION_ACK, message_ref="123") other_message = build_message(guid="123") expected = True actual = message.is_acknowledgement_of(other_message) assert actual == expected
def test_group_into_conversations_sorts_messages_within_conversations(): message_one = build_message(conversation_id="abc", time=datetime(year=2020, month=6, day=6)) message_two = build_message(conversation_id="abc", time=datetime(year=2020, month=6, day=5)) messages = [message_one, message_two] expected = [Conversation("abc", [message_two, message_one])] actual = group_into_conversations(messages) assert list(actual) == expected
def test_warns_about_conversation_with_negative_sla(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(time=datetime(year=2021, month=1, day=5)), request_completed_ack=build_message(time=datetime(year=2021, month=1, day=4)), ) ] with pytest.warns(RuntimeWarning): list(derive_transfers(conversations))
def test_derive_transfer_produces_no_sla_given_pending_request_completed_ack(): conversation = build_parsed_conversation( request_started=build_message(), request_completed=build_message(), request_completed_ack=None, ) actual = derive_transfer(conversation) expected_sla_duration = None assert actual.sla_duration == expected_sla_duration
def test_derive_transfer_flags_completed_conversation_as_not_pending(): conversation = build_parsed_conversation( request_started=build_message(), request_completed=build_message(), request_completed_ack=build_message(), ) actual = derive_transfer(conversation) expected_pending = False assert actual.pending == expected_pending
def test_date_completed_is_none_when_request_completed_ack_not_present(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(), request_completed_ack=None, ) ] actual = derive_transfers(conversations) _assert_attributes("date_completed", actual, [None])
def test_extracts_multiple_intermediate_message_error_codes(): intermediate_messages = [ build_message(error_code=11), build_message(), build_message(error_code=10), ] conversations = [build_parsed_conversation(intermediate_messages=intermediate_messages)] actual = derive_transfers(conversations) expected_intermediate_error_codes = [[11, 10]] _assert_attributes("intermediate_error_codes", actual, expected_intermediate_error_codes)
def test_has_pending_status_if_no_final_ack_and_no_intermediate_error(): conversations = [ build_parsed_conversation( request_started=build_message(), intermediate_messages=[build_message(error_code=None)], request_completed_ack=None, ) ] actual = derive_transfers(conversations) expected_statuses = [TransferStatus.PENDING] _assert_attributes("status", actual, expected_statuses)
def test_produces_no_sla_given_pending_request_completed_ack(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(), request_completed_ack=None, ) ] actual = derive_transfers(conversations) expected_sla_durations = [None] _assert_attributes("sla_duration", actual, expected_sla_durations)
def test_negative_sla_duration_clamped_to_zero(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(time=datetime(year=2021, month=1, day=5)), request_completed_ack=build_message(time=datetime(year=2021, month=1, day=4)), ) ] expected_sla = timedelta(0) actual = derive_transfers(conversations) _assert_attributes("sla_duration", actual, [expected_sla])
def test_has_integrated_status_if_error_is_supressed(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(), request_completed_ack=build_message(error_code=ERROR_SUPPRESSED), ) ] actual = derive_transfers(conversations) expected_statuses = [TransferStatus.INTEGRATED] _assert_attributes("status", actual, expected_statuses)
def test_has_failed_status_if_error_in_final_ack(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(), request_completed_ack=build_message(error_code=30), ) ] actual = derive_transfers(conversations) expected_statuses = [TransferStatus.FAILED] _assert_attributes("status", actual, expected_statuses)
def test_extracts_date_requested_from_request_started_message(): date_requested = a_datetime() conversations = [ build_parsed_conversation( request_started=build_message(time=date_requested), request_completed=build_message(), request_completed_ack=build_message(), ) ] actual = derive_transfers(conversations) _assert_attributes("date_requested", actual, [date_requested])
def test_produces_correct_conversations(): message_one = build_message(conversation_id="abc") message_two = build_message(conversation_id="xyz") messages = [message_one, message_two] expected = [Conversation("abc", [message_one]), Conversation("xyz", [message_two])] transfer_service = TransferService( message_stream=messages, cutoff=timedelta(days=14), observability_probe=mock_transfer_observability_probe, ) actual = transfer_service.group_into_conversations() assert list(actual) == expected
def test_has_pending_with_error_status_if_error_in_intermediate_message(): conversations = [ build_parsed_conversation( request_started=build_message(), request_completed=build_message(), intermediate_messages=[build_message(error_code=30)], request_completed_ack=None, ) ] actual = derive_transfers(conversations) expected_statuses = [TransferStatus.PENDING_WITH_ERROR] _assert_attributes("status", actual, expected_statuses)
def test_derive_transfer_produces_sla_of_successful_conversation(): conversation = build_parsed_conversation( request_completed=build_message( time=datetime(year=2020, month=6, day=1, hour=12, minute=42, second=0), ), request_completed_ack=build_message( time=datetime(year=2020, month=6, day=1, hour=13, minute=52, second=0), error_code=None ), ) actual = derive_transfer(conversation) expected_sla_duration = timedelta(hours=1, minutes=10) assert actual.sla_duration == expected_sla_duration
def test_sorts_messages_within_conversations(): message_one = build_message(conversation_id="abc", time=datetime(year=2020, month=6, day=6)) message_two = build_message(conversation_id="abc", time=datetime(year=2020, month=6, day=5)) messages = [message_one, message_two] expected = [Conversation("abc", [message_two, message_one])] transfer_service = TransferService( message_stream=messages, cutoff=timedelta(days=14), observability_probe=mock_transfer_observability_probe, ) actual = transfer_service.group_into_conversations() assert list(actual) == expected
def test_derive_transfer_extracts_requesting_practice_ods(): conversation = build_parsed_conversation(request_started=build_message(from_party_ods="A12345")) actual = derive_transfer(conversation) expected_ods = "A12345" assert actual.requesting_practice_ods == expected_ods
def test_is_copc_returns_false_when_interaction_is__not_copc(): message = build_message(interaction_id=APPLICATION_ACK) expected = False actual = message.is_copc() assert actual == expected
def test_is_copc_returns_true_when_interaction_is_copc(): message = build_message(interaction_id=COMMON_POINT_TO_POINT) expected = True actual = message.is_copc() assert actual == expected
def test_is_request_started_returns_true_when_interaction_is_ehr_req_started(): message = build_message(interaction_id=EHR_REQUEST_STARTED) expected = True actual = message.is_ehr_request_started() assert actual == expected