def test_update_handler_throws_if_schema_not_recognised():
    producer = FakeProducer()
    context = FakeContext()
    non_existing_schema = "DOESNTEXIST"
    with pytest.raises(ValueError):
        CAUpdateHandler(producer, context, "source_name", "output_topic",
                        non_existing_schema)  # type: ignore
def test_update_handler_publishes_enum_update():
    producer = FakeProducer()
    context = FakeContext()

    pv_caproto_type = ChannelType.TIME_ENUM
    pv_source_name = "source_name"
    update_handler = CAUpdateHandler(producer, context, pv_source_name,
                                     "output_topic", "f142")  # type: ignore

    # Nothing gets published when ENUM type update is received, the handler will resubscribe using STRING
    # type as the string is more useful to forwarder to the filewriter than the enum int
    metadata = (0, 0, TimeStamp(4, 0))
    context.call_monitor_callback_with_fake_pv_update(
        ReadNotifyResponse(
            np.array([0]),
            pv_caproto_type,
            1,
            1,
            1,
            metadata=metadata,
        ))
    # Second update, with STRING type
    enum_string_value = "ENUM_STRING"
    context.call_monitor_callback_with_fake_pv_update(
        ReadNotifyResponse(
            [enum_string_value.encode("utf8")],
            ChannelType.TIME_STRING,
            1,
            1,
            1,
            metadata=metadata,
        ))

    assert (
        producer.messages_published == 1
    ), "Only expected a single message with string payload, not the original enum update"
    assert producer.published_payload is not None
    pv_update_output = deserialise_f142(producer.published_payload)
    assert pv_update_output.value == enum_string_value
    assert pv_update_output.source_name == pv_source_name

    update_handler.stop()
def test_update_handler_does_not_include_alarm_details_if_unchanged_in_subsequent_updates(
):
    producer = FakeProducer()
    context = FakeContext()

    pv_value = 42
    pv_caproto_type = ChannelType.TIME_INT
    pv_numpy_type = np.int32
    pv_source_name = "source_name"
    alarm_status = 6  # AlarmStatus.LOW
    alarm_severity = 1  # AlarmSeverity.MINOR

    update_handler = CAUpdateHandler(producer, context, pv_source_name,
                                     "output_topic", "f142")  # type: ignore
    metadata = (alarm_status, alarm_severity, TimeStamp(4, 0))
    context.call_monitor_callback_with_fake_pv_update(
        ReadNotifyResponse(
            np.array([pv_value]).astype(pv_numpy_type),
            pv_caproto_type,
            1,
            1,
            1,
            metadata=metadata,
        ))
    # Second update, with unchanged alarm
    context.call_monitor_callback_with_fake_pv_update(
        ReadNotifyResponse(
            np.array([pv_value]).astype(pv_numpy_type),
            pv_caproto_type,
            1,
            1,
            1,
            metadata=metadata,
        ))

    assert producer.messages_published == 2
    pv_update_output = deserialise_f142(producer.published_payload)
    assert pv_update_output.alarm_status == AlarmStatus.NO_CHANGE
    assert pv_update_output.alarm_severity == AlarmSeverity.NO_CHANGE

    update_handler.stop()
Esempio n. 4
0
def create_update_handler(
    producer: KafkaProducer,
    ca_context: CAContext,
    pva_context: PVAContext,
    channel: ConfigChannel,
    fake_pv_period_ms: int,
    periodic_update_ms: Optional[int] = None,
) -> UpdateHandler:
    if not channel.name:
        raise RuntimeError(
            "PV name not specified when adding handler for channel")
    if not channel.output_topic:
        raise RuntimeError(
            f"Output topic not specified when adding handler for channel {channel.name}"
        )
    if not channel.schema:
        raise RuntimeError(
            f"Schema not specified when adding handler for channel {channel.name}"
        )
    if channel.protocol == EpicsProtocol.PVA:
        return PVAUpdateHandler(
            producer,
            pva_context,
            channel.name,
            channel.output_topic,
            channel.schema,
            periodic_update_ms,
        )
    elif channel.protocol == EpicsProtocol.CA:
        return CAUpdateHandler(
            producer,
            ca_context,
            channel.name,
            channel.output_topic,
            channel.schema,
            periodic_update_ms,
        )
    elif channel.protocol == EpicsProtocol.FAKE:
        return FakeUpdateHandler(
            producer,
            channel.name,
            channel.output_topic,
            channel.schema,
            fake_pv_period_ms,
        )
    raise RuntimeError("Unexpected EpicsProtocol in create_update_handler")