Beispiel #1
0
def test_returns_one_conversation_given_conversations_over_span_of_days():
    daily_start_datetime = datetime(year=2020, month=1, day=1, tzinfo=UTC)

    conversation_within_day = Gp2gpConversation(
        messages=test_cases.request_made(
            request_sent_date=datetime(year=2020, month=1, day=1, tzinfo=UTC)
        ),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    conversation_before_day = Gp2gpConversation(
        messages=test_cases.request_made(
            request_sent_date=datetime(year=2019, month=12, day=31, tzinfo=UTC)
        ),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    conversation_after_day = Gp2gpConversation(
        messages=test_cases.request_made(
            request_sent_date=datetime(year=2020, month=1, day=2, tzinfo=UTC)
        ),
        probe=mock_gp2gp_conversation_observability_probe,
    )

    gp2gp_conversations = [
        conversation_before_day,
        conversation_within_day,
        conversation_after_day,
    ]

    expected = [conversation_within_day]

    actual = filter_conversations_by_day(gp2gp_conversations, daily_start_datetime)

    assert list(actual) == expected
Beispiel #2
0
 def record_negative_sla(self, conversation: Gp2gpConversation):
     self._logger.warning(
         f":Negative SLA duration for conversation: {conversation.conversation_id()}",
         extra={
             "event": "NEGATIVE_SLA_DETECTED",
             "conversation_id": conversation.conversation_id(),
             "final_acknowledgement_time": conversation.effective_final_acknowledgement_time(),
             "request_completed_time": conversation.effective_request_completed_time(),
         },
     )
Beispiel #3
0
def _calculate_sla(
    conversation: Gp2gpConversation, probe: TransferObservabilityProbe
) -> Optional[timedelta]:
    final_acknowledgement_time = conversation.effective_final_acknowledgement_time()
    request_completed_time = conversation.effective_request_completed_time()

    if final_acknowledgement_time is None:
        return None

    sla_duration = final_acknowledgement_time - request_completed_time

    if sla_duration.total_seconds() < 0:
        probe.record_negative_sla(conversation)

    return max(timedelta(0), sla_duration)
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 _copc_transfer_outcome(
    conversation: Gp2gpConversation,
) -> Tuple[TransferStatus, Optional[TransferFailureReason]]:
    if conversation.contains_unacknowledged_duplicate_ehr_and_copc_fragments():
        return _unclassified_failure(TransferFailureReason.AMBIGUOUS_COPCS)
    elif conversation.contains_copc_error(
    ) and not conversation.is_missing_copc_ack():
        return _unclassified_failure(
            TransferFailureReason.TRANSFERRED_NOT_INTEGRATED_WITH_ERROR)
    elif conversation.is_missing_copc():
        return _technical_failure(TransferFailureReason.COPC_NOT_SENT)
    elif conversation.is_missing_copc_ack():
        return _technical_failure(TransferFailureReason.COPC_NOT_ACKNOWLEDGED)
    else:
        return _process_failure(
            TransferFailureReason.TRANSFERRED_NOT_INTEGRATED)
Beispiel #6
0
def test_returns_true_given_only_duplicate_ehrs_present():
    gp2gp_messages: List[Message] = test_cases.only_acknowledged_duplicates()
    conversation = Gp2gpConversation(gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    actual = conversation.contains_only_duplicate_ehr()

    assert actual
Beispiel #7
0
def test_returns_false_given_an_unacknowledged_ehr_present():
    gp2gp_messages: List[Message] = test_cases.acknowledged_duplicate_and_waiting_for_integration()
    conversation = Gp2gpConversation(gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    actual = conversation.contains_only_duplicate_ehr()

    assert actual is False
def test_produces_last_sender_message_timestamp_from_request_completed_before_integration_only(
):
    request_completed_date = a_datetime(year=2020,
                                        month=6,
                                        day=1,
                                        hour=12,
                                        minute=42,
                                        second=0)

    messages = test_cases.ehr_integrated_with_duplicate_having_second_sender_ack_after_integration(
        request_completed_time=request_completed_date)

    conversation = Gp2gpConversation(
        messages=messages,
        probe=mock_gp2gp_conversation_observability_probe,
    )
    mock_lookup = Mock()

    transfer_service = TransferService(
        message_stream=[],
        cutoff=timedelta(days=14),
        observability_probe=mock_transfer_observability_probe,
    )

    actual = transfer_service.derive_transfer(conversation, mock_lookup)

    expected_last_sender_message_timestamp = request_completed_date

    assert actual.last_sender_message_timestamp == expected_last_sender_message_timestamp
def test_produces_sla_given_failure_with_conflicting_acks_and_duplicate_ehrs():
    failed_acknowledgement_datetime = a_datetime(year=2020,
                                                 month=6,
                                                 day=1,
                                                 hour=13,
                                                 minute=52,
                                                 second=0)
    conversation = Gp2gpConversation(
        messages=test_cases.
        integration_failed_with_conflicting_acks_and_duplicate_ehrs(
            request_completed_time=a_datetime(year=2020,
                                              month=6,
                                              day=1,
                                              hour=12,
                                              minute=42,
                                              second=0),
            ehr_acknowledge_time=failed_acknowledgement_datetime,
        ),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    mock_lookup = Mock()

    transfer_service = TransferService(
        message_stream=[],
        cutoff=timedelta(days=14),
        observability_probe=mock_transfer_observability_probe,
    )

    actual = transfer_service.derive_transfer(conversation, mock_lookup)

    expected_sla_duration = timedelta(hours=1, minutes=10)

    assert actual.sla_duration == expected_sla_duration
    assert actual.date_completed == failed_acknowledgement_datetime
def test_produces_last_sender_message_timestamp_given_request_acked_successfully(
):
    request_acknowledged_date = a_datetime(year=2020,
                                           month=6,
                                           day=1,
                                           hour=12,
                                           minute=42,
                                           second=0)

    conversation = Gp2gpConversation(
        messages=test_cases.request_acknowledged_successfully(
            sender_ack_time=request_acknowledged_date),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    mock_lookup = Mock()

    transfer_service = TransferService(
        message_stream=[],
        cutoff=timedelta(days=14),
        observability_probe=mock_transfer_observability_probe,
    )

    actual = transfer_service.derive_transfer(conversation, mock_lookup)
    expected = request_acknowledged_date
    assert actual.last_sender_message_timestamp == expected
def test_produces_last_sender_message_timestamp_given_copc_fragment_failure():
    copc_fragment_time = a_datetime(year=2020,
                                    month=6,
                                    day=1,
                                    hour=12,
                                    minute=42,
                                    second=0)

    conversation = Gp2gpConversation(
        messages=test_cases.copc_fragment_failure(
            copc_fragment_time=copc_fragment_time),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    mock_lookup = Mock()

    transfer_service = TransferService(
        message_stream=[],
        cutoff=timedelta(days=14),
        observability_probe=mock_transfer_observability_probe,
    )

    actual = transfer_service.derive_transfer(conversation, mock_lookup)

    expected_last_sender_message_timestamp = copc_fragment_time

    assert actual.last_sender_message_timestamp == expected_last_sender_message_timestamp
def test_produces_last_sender_message_timestamp_given_an_integrated_ontime_transfer_with_copcs(
):
    request_completed_date = a_datetime(year=2020,
                                        month=6,
                                        day=1,
                                        hour=12,
                                        minute=42,
                                        second=0)

    conversation = Gp2gpConversation(
        messages=test_cases.successful_integration_with_copc_fragments(
            request_completed_time=request_completed_date),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    mock_lookup = Mock()

    transfer_service = TransferService(
        message_stream=[],
        cutoff=timedelta(days=14),
        observability_probe=mock_transfer_observability_probe,
    )

    actual = transfer_service.derive_transfer(conversation, mock_lookup)

    expected_last_sender_message_timestamp = request_completed_date

    assert actual.last_sender_message_timestamp == expected_last_sender_message_timestamp
Beispiel #13
0
def test_returns_true_given_unacknowledged_duplicate_ehr_and_copcs():
    gp2gp_messages: List[
        Message
    ] = test_cases.unacknowledged_duplicate_with_copcs_and_waiting_for_integration()
    conversation = Gp2gpConversation(gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    actual = conversation.contains_unacknowledged_duplicate_ehr_and_copc_fragments()

    assert actual
def test_extracts_correct_codes_given_successful_transfer(
        test_case, expected_codes):
    gp2gp_messages: List[Message] = test_case()
    conversation = Gp2gpConversation(
        gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    actual = conversation.final_error_codes()

    assert actual == expected_codes
Beispiel #15
0
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_extracts_sender_error_codes_when_sender_error(test_case):
    conversation = Gp2gpConversation(
        messages=test_case(error_code=10),
        probe=mock_gp2gp_conversation_observability_probe)

    actual = conversation.sender_error_codes()

    expected = [10]

    assert actual == expected
Beispiel #17
0
def test_returns_none_when_transfer_in_progress(test_case):
    gp2gp_messages: List[Message] = test_case()
    conversation = Gp2gpConversation(
        gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    expected = None

    actual = conversation.effective_final_acknowledgement_time()

    assert actual == expected
Beispiel #18
0
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
Beispiel #19
0
def test_extracts_error_codes_when_some_messages_unacknowledged():
    conversation = Gp2gpConversation(
        messages=test_cases.copc_fragment_failure_and_missing_copc_fragment_ack(error_code=10),
        probe=mock_gp2gp_conversation_observability_probe,
    )
    actual = conversation.intermediate_error_codes()

    expected_intermediate_error_codes = [10]

    assert actual == expected_intermediate_error_codes
def test_extracts_date_requested_from_request_started_message():
    date_requested = a_datetime()

    gp2gp_messages: List[Message] = test_cases.request_made(request_sent_date=date_requested)

    conversation = Gp2gpConversation(gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    actual = conversation.date_requested()

    assert actual == date_requested
def test_returns_false_when_transfer_concluded_with_failure(test_case):
    conversation = Gp2gpConversation(
        messages=test_case(), probe=mock_gp2gp_conversation_observability_probe
    )

    expected = False

    actual = conversation.is_integrated()

    assert actual == expected
def test_returns_true_when_transfer_was_integrated(test_case):
    conversation = Gp2gpConversation(
        messages=test_case(), probe=mock_gp2gp_conversation_observability_probe
    )

    expected = True

    actual = conversation.is_integrated()

    assert actual == expected
def test_returns_true_given_failed_transfer(test_case):
    conversation = Gp2gpConversation(
        messages=test_case(),
        probe=mock_gp2gp_conversation_observability_probe)

    expected = True

    actual = conversation.has_concluded_with_failure()

    assert actual == expected
def test_returns_false_given_intermediate_error(test_case):
    conversation = Gp2gpConversation(
        messages=test_case(),
        probe=mock_gp2gp_conversation_observability_probe)

    expected = False

    actual = conversation.has_concluded_with_failure()

    assert actual == expected
def test_doesnt_extract_sender_error_codes(test_case):
    gp2gp_messages: List[Message] = test_case()
    conversation = Gp2gpConversation(
        gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    expected: List[int] = []

    actual = conversation.final_error_codes()

    assert actual == expected
def test_observability_probe_called_when_missing_message_for_an_acknowledgement(
):
    mock_probe = Mock()

    messages = ehr_missing_message_for_an_acknowledgement()
    acknowledgement_for_missing_message = messages[1]

    Gp2gpConversation(messages=messages, probe=mock_probe)

    mock_probe.record_ehr_missing_message_for_an_acknowledgement.assert_called_once_with(
        acknowledgement_for_missing_message)
Beispiel #27
0
def test_returns_nothing_when_transfer_in_progress_and_no_errors(test_case):
    conversation = Gp2gpConversation(
        messages=test_cases.ehr_integration_failed(),
        probe=mock_gp2gp_conversation_observability_probe,
    )

    actual = conversation.intermediate_error_codes()

    expected_intermediate_error_codes: List[int] = []

    assert actual == expected_intermediate_error_codes
Beispiel #28
0
def test_ignores_ehr_acknowledgement_error_codes():
    conversation = Gp2gpConversation(
        messages=test_cases.ehr_integration_failed(),
        probe=mock_gp2gp_conversation_observability_probe,
    )

    actual = conversation.intermediate_error_codes()

    expected_intermediate_error_codes: List[int] = []

    assert actual == expected_intermediate_error_codes
Beispiel #29
0
def test_ignores_sender_error_codes():
    conversation = Gp2gpConversation(
        messages=test_cases.request_acknowledged_with_error(),
        probe=mock_gp2gp_conversation_observability_probe,
    )

    actual = conversation.intermediate_error_codes()

    expected_intermediate_error_codes: List[int] = []

    assert actual == expected_intermediate_error_codes
Beispiel #30
0
def test_extracts_multiple_intermediate_message_error_codes():
    conversation = Gp2gpConversation(
        messages=test_cases.copc_fragment_failures(error_codes=[11, None, 10]),
        probe=mock_gp2gp_conversation_observability_probe,
    )

    actual = conversation.intermediate_error_codes()

    expected_intermediate_error_codes = [11, 10]

    assert actual == expected_intermediate_error_codes