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()
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")