class KepcoTests(object): """ Tests for the KEPCO. """ def setUp(self): self._lewis, self._ioc = get_running_lewis_and_ioc("kepco", DEVICE_PREFIX) self.ca = ChannelAccess(default_timeout=30, device_prefix=DEVICE_PREFIX) self._lewis.backdoor_run_function_on_device("reset") self.ca.assert_that_pv_exists("VOLTAGE", timeout=30) reset_calibration_file(self.ca, "default_calib.dat") def _write_voltage(self, expected_voltage): self._lewis.backdoor_set_on_device("voltage", expected_voltage) self._ioc.set_simulated_value("SIM:VOLTAGE", expected_voltage) def _write_current(self, expected_current): self._lewis.backdoor_set_on_device("current", expected_current) self._ioc.set_simulated_value("SIM:CURRENT", expected_current) def _set_IDN(self, expected_idn_no_firmware, expected_firmware): self._lewis.backdoor_set_on_device("idn_no_firmware", expected_idn_no_firmware) self._lewis.backdoor_set_on_device("firmware", expected_firmware) expected_idn = "{}{}".format(expected_idn_no_firmware, str(expected_firmware))[:39] # EPICS limited to 40 chars self._ioc.set_simulated_value("SIM:IDN", expected_idn) self._ioc.set_simulated_value("SIM:FIRMWARE", str(expected_firmware)) # Both firmware and IDN are passive so must be updated self.ca.process_pv("FIRMWARE") self.ca.process_pv("IDN") return expected_idn def _set_output_mode(self, expected_output_mode): self._lewis.backdoor_set_on_device("output_mode", expected_output_mode) self._ioc.set_simulated_value("SIM:OUTPUTMODE", expected_output_mode) def _set_output_status(self, expected_output_status): self._lewis.backdoor_set_on_device("output_status", expected_output_status) def test_GIVEN_voltage_set_WHEN_read_THEN_voltage_is_as_expected(self): expected_voltage = 1.2 self._write_voltage(expected_voltage) self.ca.assert_that_pv_is("VOLTAGE", expected_voltage) def test_GIVEN_current_set_WHEN_read_THEN_current_is_as_expected(self): expected_current = 1.5 self._write_current(expected_current) self.ca.assert_that_pv_is("CURRENT", expected_current) def test_GIVEN_setpoint_voltage_set_WHEN_read_THEN_setpoint_voltage_is_as_expected(self): # Get current Voltage current_voltage = self.ca.get_pv_value("VOLTAGE") # Set new Voltage via SP self.ca.set_pv_value("VOLTAGE:SP", current_voltage + 5) # Check SP RBV matches new current self.ca.assert_that_pv_is("VOLTAGE:SP:RBV", current_voltage + 5) @parameterized.expand(parameterized_list([-5.1, 7.8])) def test_GIVEN_setpoint_current_set_WHEN_read_THEN_setpoint_current_is_as_expected(self, _, expected_current): self.ca.set_pv_value("CURRENT:SP", expected_current) # Check SP RBV matches new current self.ca.assert_that_pv_is("CURRENT:SP:RBV", expected_current) def test_GIVEN_output_mode_set_WHEN_read_THEN_output_mode_is_as_expected(self): expected_output_mode_flag = UnitFlags.CURRENT expected_output_mode_str = OutputMode.CURRENT self._set_output_mode(expected_output_mode_flag) # Check OUTPUT MODE matches new OUTPUT MODE self.ca.assert_that_pv_is("OUTPUTMODE", expected_output_mode_str) def test_GIVEN_output_status_set_WHEN_read_THEN_output_STATUS_is_as_expected(self): expected_output_status_flag = UnitFlags.ON expected_output_status_str = Status.ON self.ca.set_pv_value("OUTPUTSTATUS:SP", expected_output_status_flag) self.ca.assert_that_pv_is("OUTPUTSTATUS:SP:RBV", expected_output_status_str) @parameterized.expand(parameterized_list(IDN_LIST)) def test_GIVEN_idn_set_WHEN_read_THEN_idn_is_as_expected(self, _, idn_no_firmware, firmware): expected_idn = self._set_IDN(idn_no_firmware, firmware) self.ca.process_pv("IDN") self.ca.assert_that_pv_is("IDN", expected_idn) @skip_if_recsim("In rec sim you can not diconnect the device") def test_GIVEN_diconnected_WHEN_read_THEN_alarms_on_readbacks(self): self._lewis.backdoor_set_on_device("connected", False) self.ca.assert_that_pv_alarm_is("OUTPUTMODE", self.ca.Alarms.INVALID) self.ca.assert_that_pv_alarm_is("CURRENT", self.ca.Alarms.INVALID) self.ca.assert_that_pv_alarm_is("VOLTAGE", self.ca.Alarms.INVALID) def _test_ramp_to_target(self, start_current, target_current, ramp_rate, step_number, wait_between_changes): self._write_current(start_current) self.ca.set_pv_value("CURRENT:SP", start_current) self.ca.assert_that_pv_is("CURRENT:SP:RBV", start_current) self.ca.set_pv_value("RAMP:RATE:SP", ramp_rate) self.ca.set_pv_value("RAMP:STEPS:SP", step_number) self.ca.set_pv_value("RAMPON:SP", "ON") self.ca.set_pv_value("CURRENT:SP", target_current, sleep_after_set=0.0) if start_current < target_current: self.ca.assert_that_pv_value_is_increasing("CURRENT:SP:RBV", wait=wait_between_changes) else: self.ca.assert_that_pv_value_is_decreasing("CURRENT:SP:RBV", wait=wait_between_changes) self.ca.assert_that_pv_is("RAMPING", "YES") # Device stops ramping when it gets to target self.ca.assert_that_pv_is("CURRENT:SP:RBV", target_current, timeout=40) self._write_current(target_current) self.ca.assert_that_pv_is("RAMPING", "NO") self.ca.assert_that_pv_value_is_unchanged("CURRENT:SP:RBV", wait=wait_between_changes) self.ca.set_pv_value("RAMPON:SP", "OFF") def test_GIVEN_rampon_WHEN_target_set_THEN_current_ramps_to_target(self): self._test_ramp_to_target(1, 2, 2, 20, 7) def test_GIVEN_rampon_WHEN_target_set_with_different_step_rate_THEN_current_ramps_to_target_more_finely(self): self._test_ramp_to_target(4, 3, 2, 60, 2) @parameterized.expand(parameterized_list(IDN_LIST)) def test_GIVEN_idn_set_AND_firmware_set_THEN_firmware_pv_correct(self, _, idn_no_firmware, firmware): self._set_IDN(idn_no_firmware, firmware) self.ca.process_pv("FIRMWARE") self.ca.assert_that_pv_is("FIRMWARE", firmware) @parameterized.expand(parameterized_list([ ("default_calib.dat", 100, 100), ("field_double_amps.dat", 100, 50), ])) @skip_if_recsim("Calibration lookup does not work in recsim") def test_GIVEN_calibration_WHEN_field_set_THEN_current_as_expected(self, _, calibration_file, field, expected_current): with use_calibration_file(self.ca, calibration_file, "default_calib.dat"): self.ca.set_pv_value("FIELD:SP", field) self.ca.assert_that_pv_is("FIELD:SP:RBV", field) self.ca.assert_that_pv_is("CURRENT:SP", expected_current) self.ca.assert_that_pv_is("CURRENT:SP:RBV", expected_current) @parameterized.expand(parameterized_list([ ("default_calib.dat", 100, 100), ("field_double_amps.dat", 100, 200), ])) @skip_if_recsim("Calibration lookup does not work in recsim") def test_GIVEN_calibration_WHEN_current_set_THEN_field_as_expected(self, _, calibration_file, current, expected_field): with use_calibration_file(self.ca, calibration_file, "default_calib.dat"): self._write_current(current) self.ca.assert_that_pv_is("CURRENT", current) self.ca.assert_that_pv_is("FIELD", expected_field) @skip_if_recsim("Lewis not available in recsim") def test_WHEN_sending_setpoint_THEN_only_one_setpoint_sent(self): self._lewis.backdoor_set_and_assert_set("current_set_count", 0) self.ca.set_pv_value("CURRENT:SP", 100) self._lewis.assert_that_emulator_value_is("current_set_count", 1) # Wait a short time and make sure count is not being incremented again later. time.sleep(5) self._lewis.assert_that_emulator_value_is("current_set_count", 1)
class Knr1050Tests(unittest.TestCase): """ Tests for the Knr1050 IOC. """ def setUp(self): self._lewis, self._ioc = get_running_lewis_and_ioc(device_name, DEVICE_PREFIX) self.ca = ChannelAccess(device_prefix=DEVICE_PREFIX, default_wait_time=0.0) self._lewis.backdoor_run_function_on_device("reset") # Set the device in remote mode ready to receive instructions self.ca.set_pv_value("MODE:SP", "REMOTE") self.ca.set_pv_value("MODE.PROC", 1) # Set the flow and concentrations to a default state that enable pump switch on self.ca.set_pv_value("STOP:SP", 1) self.ca.set_pv_value("STATUS", "OFF") self.ca.set_pv_value("FLOWRATE:SP", 0.01) self.ca.set_pv_value("PRESSURE:MIN:SP", 0) self.ca.set_pv_value("PRESSURE:MAX:SP", 100) self.ca.set_pv_value("COMP:A:SP", 100) self.ca.set_pv_value("COMP:B:SP", 0) self.ca.set_pv_value("COMP:C:SP", 0) self.ca.set_pv_value("COMP:D:SP", 0) self.ca.set_pv_value("STATUS:GET.PROC", 1) self.ca.set_pv_value("DISABLE:CHECK.PROC", 1) def _set_pressure_limit_low(self, limit): self._lewis.backdoor_set_on_device("pressure_limit_low", limit) def _set_pressure_limit_high(self, limit): self._lewis.backdoor_set_on_device("pressure_limit_high", limit) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_start_pump_sent_THEN_pump_starts(self): self.ca.set_pv_value("START:SP", 1) self.ca.assert_that_pv_is("STATUS", "IDLE") @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_timed_pump_sent_THEN_pump_starts(self): self.ca.set_pv_value("TIMED:SP", 1) self.ca.assert_that_pv_is("STATUS", "IDLE") @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_stop_pump_sent_via_ioc_THEN_device_state_off(self): expected_dev_state = "OFF" self.ca.set_pv_value("STOP:SP", 1) self.ca.assert_that_pv_is("STATUS", expected_dev_state) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_pump_is_turned_on_via_ioc_THEN_pump_is_on(self): self.ca.set_pv_value("START:SP", 1) pump_status = self._lewis.backdoor_get_from_device("pump_on") self.assertEqual(pump_status, True) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_concentration_via_ioc_WHEN_ramp_command_sent_via_ioc_THEN_correct_concentration_set(self): expected_concentrations = [0, 50, 35, 15] self.ca.set_pv_value("COMP:A:SP", expected_concentrations[0]) self.ca.set_pv_value("COMP:B:SP", expected_concentrations[1]) self.ca.set_pv_value("COMP:C:SP", expected_concentrations[2]) self.ca.set_pv_value("COMP:D:SP", expected_concentrations[3]) self.ca.set_pv_value("START:SP", 1) sleep(1.0) # allow emulator to process above data concentrations = [self.ca.get_pv_value("COMP:A"), self.ca.get_pv_value("COMP:B"), self.ca.get_pv_value("COMP:C"), self.ca.get_pv_value("COMP:D")] self.assertEqual(expected_concentrations, concentrations) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_stop_pump_sent_THEN_lewis_pump_stops(self): expected_pump_status = False self.ca.set_pv_value("STOP:SP", 1) pump_status = self._lewis.backdoor_get_from_device("pump_on") self.assertEqual(pump_status, expected_pump_status) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_stop2_command_sent_THEN_expected_stop_type(self): self._lewis.backdoor_set_on_device("keep_last_values", False) stopped_status = self._lewis.backdoor_get_from_device("keep_last_values") self.assertEqual(stopped_status, False) self.ca.set_pv_value("_STOP:KLV:SP", 1) stopped_status = self._lewis.backdoor_get_from_device("keep_last_values") self.assertEqual(stopped_status, True) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_an_ioc_WHEN_pump_switched_on_then_back_to_off_THEN_device_state_off(self): expected_dev_state = "OFF" self.ca.set_pv_value("START:SP", 1) self.ca.set_pv_value("STOP:SP", 1) sleep(1.0) # allow emulator to process above data state = self._lewis.backdoor_get_from_device("state") self.assertEqual(expected_dev_state, state) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_low_pressure_limit_via_backdoor_WHEN_get_low_pressure_limits_via_IOC_THEN_get_expected_pressure_limit(self): expected_pressure = 10 self._set_pressure_limit_low(expected_pressure) self.ca.set_pv_value("PRESSURE:LIMITS.PROC", 1) self.ca.assert_that_pv_is("PRESSURE:MIN", expected_pressure) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_high_pressure_limit_via_backdoor_WHEN_get_high_pressure_limits_via_IOC_THEN_get_expected_pressure_limit(self): expected_pressure = 100 self._set_pressure_limit_high(expected_pressure) self.ca.set_pv_value("PRESSURE:LIMITS.PROC", 1) self.ca.assert_that_pv_is("PRESSURE:MAX", expected_pressure) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_low_pressure_limit_via_ioc_WHEN_get_low_pressure_limit_THEN_get_expected_pressure_limit(self): expected_pressure = 10 self.ca.set_pv_value("PRESSURE:MIN:SP", expected_pressure) self.ca.set_pv_value("PRESSURE:LIMITS.PROC", 1) self.ca.assert_that_pv_is("PRESSURE:MIN", expected_pressure) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_high_pressure_limit_via_ioc_WHEN_get_high_pressure_limit_via_backdoor_THEN_get_expected_pressure_limit(self): expected_pressure = 200 self.ca.set_pv_value("PRESSURE:MAX:SP", expected_pressure) self.ca.set_pv_value("PRESSURE:LIMITS.PROC", 1) self.ca.assert_that_pv_is("PRESSURE:MAX", expected_pressure) self.assertEqual(self._lewis.backdoor_get_from_device("pressure_limit_high"), expected_pressure) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_low_pressure_limit_via_ioc_WHEN_get_low_pressure_limit_via_IOC_THEN_get_expected_value(self): expected_pressure = 45 self.ca.set_pv_value("PRESSURE:MIN:SP", expected_pressure) self.ca.set_pv_value("PRESSURE:LIMITS.PROC", 1) self.ca.assert_that_pv_is("PRESSURE:MIN", expected_pressure) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_high_pressure_limit_via_ioc_WHEN_get_high_pressure_limit_via_IOC_THEN_get_expected_value(self): expected_pressure = 500 self.ca.set_pv_value("PRESSURE:MAX:SP", expected_pressure) self.ca.set_pv_value("PRESSURE:LIMITS.PROC", 1) self.ca.assert_that_pv_is("PRESSURE:MAX", expected_pressure) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_flow_limit_min_via_ioc_WHEN_ramp_command_sent_via_IOC_THEN_correct_flow_limit_set(self): expected_flow = 0.01 self.ca.set_pv_value("FLOWRATE:SP", expected_flow) self.ca.set_pv_value("START:SP", 1) self.ca.assert_that_pv_is("FLOWRATE", expected_flow) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_set_flow_limit_min_via_ioc_WHEN_get_flow_via_IOC_THEN_correct_flow_limit(self): expected_flow = 0.01 self.ca.set_pv_value("FLOWRATE:SP", expected_flow) self.assertEqual(self.ca.get_pv_value("FLOWRATE:SP:RBV"), expected_flow) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_ioc_turned_on_WHEN_get_dev_state_via_ioc_THEN_off_state_returned(self): expected_dev_state = 'OFF' state = self.ca.get_pv_value("STATUS") self.assertEqual(expected_dev_state, state) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_ioc_turned_on_WHEN_set_local_mode_via_IOC_THEN_disabled_mode(self): expected_mode = 'Disabled' self.ca.set_pv_value("MODE:SP", "LOCAL") self.ca.assert_that_pv_is("DISABLE", expected_mode) @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_local_mode_WHEN_set_pump_on_via_IOC_THEN_pump_disabled(self): self.ca.set_pv_value("MODE:SP", "LOCAL") self.ca.set_pv_value("START:SP", 1) self.ca.assert_that_pv_is("STATUS", 'OFF') @skip_if_recsim("Recsim simulation not implemented") def test_GIVEN_incorrect_gradients_WHEN_set_pump_on_via_IOC_THEN_pump_disabled(self): self.ca.set_pv_value("COMP:A:SP", 50) # sum of gradients =/= 100% self.ca.set_pv_value("START:SP", 1) self.ca.assert_that_pv_is("STATUS", 'OFF') @skip_if_recsim("Can not test disconnection in rec sim") def test_GIVEN_device_not_connected_WHEN_get_status_THEN_alarm(self): self._lewis.backdoor_set_on_device('connected', False) self.ca.assert_that_pv_alarm_is('PRESSURE:LIMITS', ChannelAccess.Alarms.INVALID) @skip_if_recsim("Can not test disconnection in rec sim") def test_GIVEN_timed_run_started_THEN_remaining_time_decreases(self): self.ca.set_pv_value("TIME:SP", 10) self.ca.set_pv_value("TIMED:SP", 1) self.ca.assert_that_pv_value_is_decreasing("TIME:REMAINING", wait=5) @skip_if_recsim("Can not test disconnection in rec sim") def test_GIVEN_timed_run_started_THEN_pump_stopped_once_finished_run(self): self.ca.set_pv_value("TIME:SP", 10) self.ca.set_pv_value("TIMED:SP", 1) self.ca.assert_that_pv_is("STATUS", 'OFF', timeout=15) @skip_if_recsim("Can not test disconnection in rec sim") def test_GIVEN_long_timed_run_started_THEN_if_remaining_time_checked_then_not_finished(self): self.ca.set_pv_value("TIME:SP", 100) self.ca.set_pv_value("TIMED:SP", 1) self.ca.assert_that_pv_is("TIME:CHECK", 0) @skip_if_recsim("Can not test disconnection in rec sim") def test_GIVEN_set_volume_run_started_THEN_remaining_volume_decreases(self): self.ca.set_pv_value("FLOWRATE:SP", 0.02) self.ca.set_pv_value("VOL:SP", 0.05) self.ca.set_pv_value("TIMED:SP", 1) self.ca.assert_that_pv_is_not("VOL:REMAINING", 0.0, timeout=5) self.ca.assert_that_pv_value_is_decreasing("VOL:REMAINING", wait=5) @skip_if_recsim("Can't use lewis backdoor in RECSIM") def test_GIVEN_input_error_THEN_error_string_captured(self): expected_error = "20,Instrument in standalone mode" self._lewis.backdoor_set_on_device("input_correct", False) self.ca.assert_that_pv_is("ERROR:STR", expected_error, timeout=5)