def test_forwarder_sends_pv_updates_single_pv_double(docker_compose): """ Test the forwarder pushes new PV value when the value is updated. :param docker_compose: Test fixture :return: None """ data_topic = "TEST_forwarderData_double_pv_update" pvs = [PVDOUBLE] prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, data_topic) prod.add_config(pvs) # Wait for config to be pushed sleep(2) cons = create_consumer() cons.subscribe([data_topic]) # Update value change_pv_value(PVDOUBLE, 5) # Wait for PV to be updated sleep(5) first_msg = poll_for_valid_message(cons) check_expected_values(first_msg, Value.Double, PVDOUBLE, 0.0) second_msg = poll_for_valid_message(cons) check_expected_values(second_msg, Value.Double, PVDOUBLE, 5.0) cons.close()
def test_forwarder_sends_pv_updates_single_pv_string(docker_compose): """ Test the forwarder pushes new PV value when the value is updated. :param docker_compose: Test fixture :return: None """ data_topic = "TEST_forwarderData_string_pv_update" pvs = [PVSTR] prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, data_topic) prod.add_config(pvs) # Wait for config to be pushed sleep(2) cons = create_consumer() # Update value change_pv_value(PVSTR, "stop") # Wait for PV to be updated sleep(5) cons.subscribe([data_topic]) # Poll for empty update - initial value of PVSTR is nothing poll_for_valid_message(cons) # Poll for message which should contain forwarded PV update data_msg = poll_for_valid_message(cons) check_expected_values(data_msg, Value.String, PVSTR, b'stop') cons.close()
def test_forwarder_sends_pv_updates_single_pv_enum(docker_compose): """ Test the forwarder pushes new PV value when the value is updated. NOTE: Enums are converted to Ints in the forwarder. :param docker_compose: Test fixture :return: None """ data_topic = "TEST_forwarderData_enum_pv_update" pvs = [PVENUM] prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, data_topic) prod.add_config(pvs) # Wait for config to be pushed sleep(5) cons = create_consumer() # Update value change_pv_value(PVENUM, "START") # Wait for PV to be updated sleep(5) cons.subscribe([data_topic]) first_msg = poll_for_valid_message(cons) check_expected_values(first_msg, Value.Int, PVENUM, 0) second_msg = poll_for_valid_message(cons) check_expected_values(second_msg, Value.Int, PVENUM, 1) cons.close()
def test_forwarder_sends_pv_updates_single_pv_long(docker_compose): """ Test the forwarder pushes new PV value when the value is updated. NOTE: longs are converted to ints in the forwarder as they will fit in a 32 bit integer :param docker_compose: Test fixture :return: None """ data_topic = "TEST_forwarderData_long_pv_update" pvs = [PVLONG] prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, data_topic) prod.add_config(pvs) # Wait for config to be pushed sleep(2) cons = create_consumer() # Set initial PV value change_pv_value(PVLONG, 0) sleep(2) # Update value change_pv_value(PVLONG, 5) # Wait for PV to be updated sleep(2) cons.subscribe([data_topic]) first_msg = poll_for_valid_message(cons) check_expected_values(first_msg, Value.Int, PVLONG, 0) second_msg = poll_for_valid_message(cons) check_expected_values(second_msg, Value.Int, PVLONG, 5) cons.close()
def test_forwarder_sends_pv_updates_single_pv_enum(docker_compose_no_command, start_ioc): """ GIVEN PV of enum type is configured to be forwarded WHEN PV value is updated THEN Forwarder publishes the update to Kafka NOTE: Enums are converted to Ints in the forwarder. """ data_topic = "TEST_forwarderData_enum_pv_update" pvs = [PVENUM] prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, data_topic) prod.add_config(pvs) # Wait for config to be pushed sleep(5) cons = create_consumer() # Update value change_pv_value(PVENUM, "START") # Wait for PV to be updated cons.subscribe([data_topic]) sleep(5) first_msg, _ = poll_for_valid_message(cons) check_expected_values(first_msg, Value.Int, PVENUM, 0) second_msg, _ = poll_for_valid_message(cons) check_expected_values(second_msg, Value.Int, PVENUM, 1) cons.close()
def test_connection_status_messages(docker_compose_no_command): """ GIVEN PV is configured to be forwarded WHEN Connection status changes THEN Forwarder publishes ep00 message with connection status NOTE: Enums are converted to Ints in the forwarder. """ data_topic = "TEST_forwarderData_connection_status" pvs = [PVENUM] prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, data_topic) prod.add_config(pvs) # Wait for config to be pushed sleep(5) cons = create_consumer() # Update value change_pv_value(PVENUM, "START") # Wait for PV to be updated sleep(5) cons.subscribe([data_topic]) first_msg = poll_for_connection_status_message(cons) check_expected_connection_status_values(first_msg, EventType.CONNECTED) cons.close()
def test_long_run(docker_compose_lr, start_ioc): """ Test that the channel defined in the config file is created. :param docker_compose: Test fixture :return: None """ # Set up consumer now and subscribe from earliest offset on data topic cons = create_consumer("earliest") cons.subscribe(["TEST_forwarderDataLR"]) with open(os.path.join("logs", "forwarder_lr_stats.log"), "w+") as stats_file: with open(os.path.join("logs", "forwarder_lr_missedupdates.log"), "w+") as file: for i in range(5150): # minimum 12 hours with 4 second sleep time # Change pv value now change_pv_value(PVDOUBLE, i) # Wait for the forwarder to push the update sleep(3) try: msg, _ = poll_for_valid_message(cons) except MsgErrorException: sleep(3) msg, _ = poll_for_valid_message(cons) try: check_expected_values(msg, Value.Double, PVDOUBLE, float(i)) except AssertionError: # Message is either incorrect or empty - log expected value to file file.write(str(i) + "\n") container = False # Report stats every 10th iteration if i % 10 == 0: client = docker.from_env() for item in client.containers.list(): if "forwarder" in item.name: container = item break if container: stats_file.write("{}\t{}\n".format( datetime.now(), container.stats( stream=False)["memory_stats"]["usage"], ))
def teardown_function(function): """ Stops forwarder pv listening and resets any values in EPICS """ print("Resetting PVs", flush=True) prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, "") prod.stop_all_pvs() defaults = { PVDOUBLE: 0.0, # We have to use this as the second parameter for caput gets parsed as empty so does not change the value of # the PV PVSTR: '""', PVLONG: 0, PVENUM: "INIT", } for key, value in defaults.items(): change_pv_value(key, value) change_array_pv_value(PVFLOATARRAY, "3 1.1 2.2 3.3") sleep(3)
def test_config_file_channel_created_correctly(docker_compose): """ Test that the channel defined in the config file is created. :param docker_compose: Test fixture :return: None """ cons = create_consumer() cons.subscribe(['TEST_forwarderData_pv_from_config']) sleep(5) # Change the PV value, so something is forwarded change_pv_value(PVDOUBLE, 10) # Wait for PV to be updated sleep(5) # Check the initial value is forwarded first_msg = poll_for_valid_message(cons) check_expected_values(first_msg, Value.Double, PVDOUBLE, 0.0) # Check the new value is forwarded second_msg = poll_for_valid_message(cons) check_expected_values(second_msg, Value.Double, PVDOUBLE, 10.0) cons.close()
def teardown_function(function): """ Stops forwarder pv listening and resets any values in EPICS :param docker_compose: test fixture to apply to :return: """ print("Resetting PVs", flush=True) prod = ProducerWrapper("localhost:9092", CONFIG_TOPIC, "") prod.stop_all_pvs() defaults = { PVDOUBLE: 0.0, # We have to use this as the second parameter for caput gets parsed as empty so does not change the value of # the PV PVSTR: "\"\"", PVLONG: 0, PVENUM: "INIT" } for key, value in defaults.items(): change_pv_value(key, value) sleep(3)