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
Exemple #2
0
def test_returns_datetimes_between_start_and_end_datetime():
    start_datetime = a_datetime(year=2021,
                                month=2,
                                day=1,
                                hour=0,
                                minute=0,
                                second=0)
    end_datetime = a_datetime(year=2021,
                              month=2,
                              day=3,
                              hour=0,
                              minute=0,
                              second=0)

    actual = convert_date_range_to_dates(start_datetime, end_datetime)

    expected = [
        datetime(year=2021,
                 month=2,
                 day=1,
                 hour=0,
                 minute=0,
                 second=0,
                 tzinfo=UTC),
        datetime(year=2021,
                 month=2,
                 day=2,
                 hour=0,
                 minute=0,
                 second=0,
                 tzinfo=UTC),
    ]

    assert actual == expected
def test_produces_sla_of_successful_conversation():
    conversation = build_mock_gp2gp_conversation(
        request_completed_time=a_datetime(year=2020,
                                          month=6,
                                          day=1,
                                          hour=12,
                                          minute=42,
                                          second=0),
        final_acknowledgement_time=a_datetime(year=2020,
                                              month=6,
                                              day=1,
                                              hour=13,
                                              minute=52,
                                              second=0),
    )
    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
Exemple #4
0
def ehr_integration_failed(**kwargs) -> List[Message]:
    """
    This scenario is an example of a GP2GP transfer that failed to integrate.
    """
    ehr_ack_time = kwargs.get("ehr_acknowledge_time", a_datetime())
    req_complete_time = kwargs.get("request_completed_time", a_datetime())
    ehr_ack_error = kwargs.get("error_code", 28)
    conversation_id = a_string()
    ehr_guid = a_string()

    return (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(message_ref=conversation_id).with_core_ehr(
        guid=ehr_guid, time=req_complete_time).with_requester_acknowledgement(
            time=ehr_ack_time, message_ref=ehr_guid,
            error_code=ehr_ack_error).build())
def build_mock_gp2gp_conversation(**kwargs):
    conversation_id = kwargs.get("conversation_id", a_string())
    final_ack_time = kwargs.get("final_acknowledgement_time", a_datetime())
    req_completed_time = kwargs.get("request_completed_time", a_datetime())
    sending_practice_asid = kwargs.get("sending_practice_asid", a_string())
    requesting_practice_asid = kwargs.get("requesting_practice_asid",
                                          a_string())

    conversation = Mock()
    conversation.conversation_id.return_value = conversation_id
    conversation.effective_final_acknowledgement_time.return_value = final_ack_time
    conversation.effective_request_completed_time.return_value = req_completed_time
    conversation.sending_practice_asid.return_value = sending_practice_asid
    conversation.requesting_practice_asid.return_value = requesting_practice_asid

    return conversation
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_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_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
Exemple #9
0
def successful_integration_with_copc_fragments(**kwargs) -> List[Message]:
    """
    A GP2GP transfer where the record was large enough (or had enough attachments)
    to necessitate using COPC messages to transmit the data in multiple chunks.
    In this instance, all transmitted COPC messages have been acknowledged by the requester,
    and the record has been integrated.
    """
    req_complete_time = kwargs.get("request_completed_time", a_datetime())
    ehr_ack_time = kwargs.get("ehr_acknowledge_time",
                              req_complete_time + timedelta(days=1))
    conversation_id = a_string()
    ehr_guid = a_string()
    fragment1_guid = a_string()
    fragment2_guid = a_string()
    fragment3_guid = a_string()

    return (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(message_ref=conversation_id).with_core_ehr(
        guid=ehr_guid, time=req_complete_time).with_copc_fragment_continue(
        ).with_copc_fragment(guid=fragment1_guid).with_copc_fragment(
            guid=fragment2_guid).with_requester_acknowledgement(
                message_ref=fragment1_guid).with_requester_acknowledgement(
                    message_ref=fragment2_guid).with_copc_fragment(
                        guid=fragment3_guid).with_requester_acknowledgement(
                            message_ref=fragment3_guid).
            with_requester_acknowledgement(message_ref=ehr_guid,
                                           time=ehr_ack_time).build())
Exemple #10
0
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,
    )
Exemple #11
0
def ehr_integrated_with_duplicate_having_second_sender_ack_after_integration(
    **kwargs, ) -> List[Message]:
    """
    While normally the "request completed" message (aka "core ehr" message)
    is only transmitted once, sometimes there are duplicate copies sent by
    the sending practice. In this instance, the sender first sent two copies
    and the requester reported via negative ack that the first was a duplicate
    and that the second was integrated. After this the sender sent a third copy,
    which was ignored.
    """
    req_complete_time = kwargs.get("request_completed_time", a_datetime())
    req_complete_time_duplicate = req_complete_time - timedelta(hours=1)
    ehr_ack_time = kwargs.get("ehr_acknowledge_time", req_complete_time)
    sender_ack_time = ehr_ack_time - timedelta(hours=1)
    request_complete_time_after_integration = ehr_ack_time + timedelta(hours=1)
    conversation_id = a_string()
    ehr_guid = a_string()
    duplicate_ehr_guid = a_string()

    return (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(
        message_ref=conversation_id, time=sender_ack_time).with_core_ehr(
            guid=duplicate_ehr_guid,
            time=req_complete_time_duplicate).with_core_ehr(
                guid=ehr_guid,
                time=req_complete_time).with_requester_acknowledgement(
                    message_ref=duplicate_ehr_guid,
                    error_code=DUPLICATE_EHR_ERROR).
            with_requester_acknowledgement(
                time=ehr_ack_time, message_ref=ehr_guid).with_core_ehr(
                    guid=duplicate_ehr_guid,
                    time=request_complete_time_after_integration).build())
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_logs_negative_sla_warning():
    conversation_id = a_string()
    mock_probe = Mock()
    conversation = build_mock_gp2gp_conversation(
        conversation_id=conversation_id,
        final_acknowledgement_time=a_datetime(year=2021, month=12, day=1),
        request_completed_time=a_datetime(year=2021, month=12, day=2),
    )
    mock_lookup = Mock()

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

    transfer_service.derive_transfer(conversation, mock_lookup)

    mock_probe.record_negative_sla.assert_called_once_with(conversation)
def test_exposes_date_delivered():
    date_delivered = a_datetime()
    status_timestamp_header = date_delivered.strftime("%Y%m%d%H%M%S")
    client_message = mock_client_message(mex_headers=build_mex_headers(
        status_timestamp=status_timestamp_header))
    message = MeshMessage(client_message)

    assert message.date_delivered == date_delivered
def test_negative_sla_duration_clamped_to_zero():
    conversation = build_mock_gp2gp_conversation(
        request_completed_time=a_datetime(year=2021, month=1, day=5),
        final_acknowledgement_time=a_datetime(year=2021, month=1, day=4),
    )

    expected_sla_duration = timedelta(0)
    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)

    assert actual.sla_duration == expected_sla_duration
Exemple #16
0
def mock_mesh_message(**kwargs):
    message = MagicMock()
    message.id = kwargs.get("message_id", a_string())
    message.file_name = kwargs.get("file_name", a_string())
    message.sender = kwargs.get("sender", a_string())
    message.recipient = kwargs.get("recipient", a_string())
    message.validate.side_effect = kwargs.get("validation_error", None)
    message.acknowledge.side_effect = kwargs.get("acknowledge_error", None)
    message.date_delivered = kwargs.get("date_delivered", a_datetime())
    return message
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
Exemple #18
0
def request_acknowledged_successfully(**kwargs) -> List[Message]:
    """
    In this example, the sender responded to the initial request
    with a successful ack, but is yet to send the core EHR.
    """
    conversation_id = a_string()
    return (GP2GPTestCase(conversation_id=conversation_id).with_request().
            with_sender_acknowledgement(
                message_ref=conversation_id,
                time=kwargs.get("sender_ack_time", a_datetime()),
            ).build())
Exemple #19
0
def test_convert_to_datetimes_string_returns_datetimes_string_given_datetimes(
):
    some_datetime = a_datetime(year=2021,
                               month=11,
                               day=13,
                               hour=2,
                               minute=0,
                               second=0)
    some_other_datetime = a_datetime(year=2022,
                                     month=10,
                                     day=13,
                                     hour=2,
                                     minute=0,
                                     second=0)

    actual = convert_to_datetimes_string([some_datetime, some_other_datetime])

    expected = ["2021-11-13T02:00:00+00:00", "2022-10-13T02:00:00+00:00"]

    assert actual == expected
Exemple #20
0
def _concluded_with_conflicting_acks(**kwargs) -> List[Message]:
    conversation_id = a_string()
    default_codes_and_times = [(None, a_datetime()),
                               (DUPLICATE_EHR_ERROR, a_datetime())]
    codes_and_times = kwargs.get("codes_and_times", default_codes_and_times)
    req_complete_time = kwargs.get("request_completed_time", a_datetime())
    ehr_guid = a_string()

    test_case = (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(message_ref=conversation_id).with_core_ehr(
        guid=ehr_guid, time=req_complete_time))

    for code, ack_time in codes_and_times:
        test_case = test_case.with_requester_acknowledgement(
            message_ref=ehr_guid,
            error_code=code,
            time=ack_time,
        )

    return test_case.build()
Exemple #21
0
def ehr_integrated_after_duplicate(**kwargs) -> List[Message]:
    """
    While normally the "request completed" message (aka "core ehr" message)
    is only transmitted once, sometimes there are duplicate copies sent by
    the sending practice. In this instance, the requester reported via negative
    ack that the second was a duplicate, then successfully integrated the first copy.
    """
    ehr_ack_time = kwargs.get("ehr_acknowledge_time", a_datetime())
    req_complete_time = kwargs.get("request_completed_time", a_datetime())
    conversation_id = a_string()
    ehr_guid = a_string()
    duplicate_ehr_guid = a_string()

    return (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(message_ref=conversation_id).with_core_ehr(
        guid=ehr_guid, time=req_complete_time).with_core_ehr(
            guid=duplicate_ehr_guid).with_requester_acknowledgement(
                message_ref=duplicate_ehr_guid,
                error_code=DUPLICATE_EHR_ERROR).with_requester_acknowledgement(
                    time=ehr_ack_time, message_ref=ehr_guid).build())
def build_message(**kwargs):
    return Message(
        time=kwargs.get("time", a_datetime()),
        conversation_id=kwargs.get("conversation_id", a_string(36)),
        guid=kwargs.get("guid", a_string(36)),
        interaction_id=kwargs.get("interaction_id", a_string(17)),
        from_party_ods=kwargs.get("from_party_ods", a_string(6)),
        to_party_ods=kwargs.get("to_party_ods", a_string(6)),
        message_ref=kwargs.get("message_ref", None),
        error_code=kwargs.get("error_code", None),
    )
Exemple #23
0
def core_ehr_sent(**kwargs) -> List[Message]:
    """
    In this example, the sender has returned an EHR, but the requester is yet to acknowledge.
    """
    conversation_id = a_string()
    req_complete_time = kwargs.get("request_completed_time", a_datetime())

    return (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(
        message_ref=conversation_id,
        time=req_complete_time -
        timedelta(hours=1)).with_core_ehr(time=req_complete_time).build())
Exemple #24
0
def ehr_suppressed_with_conflicting_duplicate_and_conflicting_error_ack(
        **kwargs) -> List[Message]:
    """
    Usually a requesting system acknowledges the GP2GP request completed message
    (aka core EHR) once. However, in this case there are three conflicting acknowledgements
    to the Core EHR message, with the requester reporting an error code, a duplicate,
    and a suppressed record.
    """
    request_completed_time = kwargs.setdefault("request_completed_time",
                                               a_datetime())
    ehr_ack_time = kwargs.get("ehr_acknowledge_time",
                              request_completed_time + timedelta(hours=4))

    return _concluded_with_conflicting_acks(
        **kwargs,
        codes_and_times=[
            (11, a_datetime()),
            (DUPLICATE_EHR_ERROR, a_datetime()),
            (SUPPRESSED_EHR_ERROR, ehr_ack_time),
        ],
    )
Exemple #25
0
def first_ehr_integrated_after_second_ehr_failed(**kwargs) -> List[Message]:
    """
    While normally the "request completed" message (aka "core ehr" message)
    is only transmitted once, sometimes there are duplicate copies sent by
    the sending practice. In this instance, the requester sent a negative
    acknowledgment in response to the second copy, then integrated the first.
    """
    ehr_ack_time = kwargs.get("ehr_acknowledge_time", a_datetime())
    req_complete_time = kwargs.get("request_completed_time", a_datetime())
    ehr_ack_error = kwargs.get("error_code", 11)
    conversation_id = a_string()
    first_ehr_guid = a_string()
    second_ehr_guid = a_string()

    return (GP2GPTestCase(conversation_id=conversation_id).with_request(
    ).with_sender_acknowledgement(message_ref=conversation_id).with_core_ehr(
        guid=first_ehr_guid, time=req_complete_time).with_core_ehr(
            guid=second_ehr_guid).with_requester_acknowledgement(
                message_ref=second_ehr_guid,
                error_code=ehr_ack_error).with_requester_acknowledgement(
                    message_ref=first_ehr_guid, time=ehr_ack_time).build())
Exemple #26
0
def test_returns_correct_time_when_conversation_has_concluded(test_case):
    acknowledgement_time = a_datetime()
    gp2gp_messages: List[Message] = test_case(
        ehr_acknowledge_time=acknowledgement_time, )
    conversation = Gp2gpConversation(
        gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    expected = acknowledgement_time

    actual = conversation.effective_final_acknowledgement_time()

    assert actual == expected
Exemple #27
0
def test_returns_correct_time_when_conversation_has_concluded(test_case):
    request_completed_time = a_datetime()
    gp2gp_messages: List[Message] = test_case(
        request_completed_time=request_completed_time)
    conversation = Gp2gpConversation(
        gp2gp_messages, mock_gp2gp_conversation_observability_probe)

    expected = request_completed_time

    actual = conversation.effective_request_completed_time()

    assert actual == expected
Exemple #28
0
def test_convert_to_datetime_string_returns_datetime_string_given_a_datetime():
    some_datetime = a_datetime(year=2021,
                               month=11,
                               day=13,
                               hour=2,
                               minute=0,
                               second=0)

    actual = convert_to_datetime_string(some_datetime)

    expected = "2021-11-13T02:00:00+00:00"

    assert actual == expected
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_resolver_returns_correct_asid_lookup_uri_given_date_anchor():
    asid_lookup_bucket = a_string()
    date_anchor = a_datetime()
    year = date_anchor.year
    month = date_anchor.month

    uri_resolver = OdsDownloaderS3UriResolver(
        asid_lookup_bucket=asid_lookup_bucket, ods_metadata_bucket=a_string())

    actual = uri_resolver.asid_lookup(date_anchor)

    expected = f"s3://{asid_lookup_bucket}/{year}/{month}/asidLookup.csv.gz"

    assert actual == expected