def test_StaticPositioner(self): n_images = 10 positioner = StaticPositioner(n_images) positioner_generator = positioner.get_generator() image_index = [] for _ in range(n_images): image_index.append(next(positioner_generator)) self.assertEqual(len(image_index), n_images, "Number of images does not match.") self.assertEqual(image_index, list(range(n_images)), "Received array not expected.")
def test_bs_read_default_values(self): # DO NOT INCLUDE IN README - default. config.bs_connection_mode = "pull" config.bs_default_missing_property_value = Exception n_images = 10 # Get 10 images. positioner = StaticPositioner(n_images) # Get CAMERA1 X, Y property, and 2 invalid properites with default values. default_invalid2_value = -999 readables = [ "bs://CAMERA1:X", "bs://CAMERA1:Y", bs_property("invalid", None), bs_property("invalid2", default_invalid2_value) ] result = scan(positioner, readables) self.assertEqual(len(result), n_images) self.assertTrue(all(x[2] is None for x in result), "Default property value not as expected.") self.assertTrue(all(x[3] == default_invalid2_value for x in result), "Default property value not as expected.") # A missing bs_property without default value should rise an exception. readables = [ "bs://CAMERA1:X", "bs://CAMERA1:Y", bs_property("invalid") ] with self.assertRaisesRegex( Exception, "Property 'invalid' missing in bs stream."): scan(positioner, readables)
def test_bs_read_filter(self): config.bs_connection_mode = "pull" n_images = 10 positioner = StaticPositioner(n_images) readables = ["bs://CAMERA1:X"] # Count how many messages passed. def mock_filter(message): if message: nonlocal filter_pass filter_pass += 1 return True filter_pass = 0 settings = scan_settings(bs_read_filter=mock_filter) # settings = scan_settings(bs_read_filter=mock_filter) result = scan(positioner=positioner, readables=readables, settings=settings) # The length should still be the same - the filter just throws away messages we do not want. self.assertEqual(len(result), n_images) self.assertTrue(filter_pass >= n_images, "The filter passed less then the received messages.")
def test_DictionaryDataProcessor(self): n_images = 10 positioner = StaticPositioner(n_images) readables = [ epics_pv("PYSCAN:TEST:OBS1"), epics_pv("PYSCAN:TEST:OBS2"), epics_pv("PYSCAN:TEST:OBS3") ] # Shift each OBS by 1, so we can resolve them when comparing results. fixed_values["PYSCAN:TEST:OBS1"] = iter(range(0, n_images)) fixed_values["PYSCAN:TEST:OBS2"] = iter(range(1, n_images + 1)) fixed_values["PYSCAN:TEST:OBS3"] = iter(range(2, n_images + 2)) data_processor = DictionaryDataProcessor(readables) result = scan(positioner=positioner, readables=readables, data_processor=data_processor) for index in range(n_images): self.assertEqual(result[index]["PYSCAN:TEST:OBS1"], index, "Unexpected result for OBS1.") self.assertEqual(result[index]["PYSCAN:TEST:OBS2"], index + 1, "Unexpected result for OBS2.") self.assertEqual(result[index]["PYSCAN:TEST:OBS3"], index + 2, "Unexpected result for OBS3.")
def test_data_and_position_references(self): n_images = 10 positioner = StaticPositioner(n_images) readables = [ epics_pv("PYSCAN:TEST:OBS1"), epics_pv("PYSCAN:TEST:OBS2"), epics_pv("PYSCAN:TEST:OBS3") ] # Shift each OBS by 1, so we can resolve them when comparing results. fixed_values["PYSCAN:TEST:OBS1"] = iter(range(0, n_images)) fixed_values["PYSCAN:TEST:OBS2"] = iter(range(1, n_images + 1)) fixed_values["PYSCAN:TEST:OBS3"] = iter(range(2, n_images + 2)) positions = [] data = [] data_processor = SimpleDataProcessor(positions, data) def after_read(): nonlocal current_number_of_items self.assertEqual( len(positions), len(data), "The number of positions and data is out of sync.") self.assertEqual(len(data), current_number_of_items + 1, "More than 1 data point was taken.") current_number_of_items += 1 current_number_of_items = 0 scan(positioner=positioner, readables=readables, data_processor=data_processor, after_read=after_read)
def test_mulitple_messages_on_same_position(self): # DO NOT INCLUDE IN README - default. config.bs_connection_mode = "pull" config.bs_default_host = "localhost" config.bs_default_port = 9999 config.bs_default_missing_property_value = Exception # Lets acquire 10 messages from the stream. n_images = 5 n_measurements = 3 positioner = StaticPositioner(n_images) settings = scan_settings(n_measurements=n_measurements) # Read camera X and Y value. readables = [bs_property("CAMERA1:X"), bs_property("CAMERA1:Y")] # The result will have 10 consecutive, valid, messages from the stream. result = scan(positioner=positioner, readables=readables, settings=settings) self.assertEqual(n_images, len(result)) for position_index in range(n_images): first = result[position_index][0] for measurement_index in range(1, n_measurements): self.assertNotEqual(first, result[position_index][measurement_index])
def test_bsread_timestamp_read(self): config.bs_connection_mode = "pull" config.bs_default_host = "localhost" config.bs_default_port = 9999 settling_time = 0.2 messages_expected_factor = settling_time / MOCK_SENDER_INTERVAL n_images = 10 positioner = StaticPositioner(n_images) readables = ["bs://CAMERA1:X"] settings = scan_settings(settling_time=settling_time) # settings = scan_settings(bs_read_filter=mock_filter) result = scan(positioner=positioner, readables=readables, settings=settings) # For messages_expected_factor=4; [[4], [8], [12], ...] expected_results = [[x] for x in [(index + 1) * messages_expected_factor for index in range(n_images)]] self.assertListEqual(result, expected_results)
def test_same_condition_multiple_times(self): config.bs_connection_mode = "pull" config.bs_default_host = "localhost" config.bs_default_port = 9999 positioner = StaticPositioner(5) readables = [bs_property("CAMERA1:X")] conditions = [ bs_condition("CAMERA1:VALID", 10, operation=ConditionComparison.EQUAL), bs_condition("CAMERA1:VALID", 10, operation=ConditionComparison.EQUAL) ] result = scan(positioner=positioner, readables=readables, conditions=conditions, settings=scan_settings(measurement_interval=0.25, n_measurements=1)) self.assertTrue(all(x[0] == i + 1 for i, x in enumerate(result)), "The result is wrong.")
def test_multiple_conditions(self): config.bs_connection_mode = "pull" config.bs_default_host = "localhost" config.bs_default_port = 9999 positioner = StaticPositioner(5) initialization = [action_set_epics_pv("PYSCAN:TEST:VALID1", 778)] readables = [bs_property("CAMERA1:X")] conditions = [ bs_condition("CAMERA1:VALID", 10, operation=ConditionComparison.EQUAL), bs_condition("CAMERA1:VALID", 11, operation=ConditionComparison.LOWER), epics_condition("PYSCAN:TEST:VALID1", 778, operation=ConditionComparison.LOWER_OR_EQUAL), epics_condition("PYSCAN:TEST:VALID1", 779, operation=ConditionComparison.LOWER) ] result = scan(positioner=positioner, readables=readables, conditions=conditions, initialization=initialization, settings=scan_settings(measurement_interval=0.25, n_measurements=1)) self.assertTrue(all(x[0] == i + 1 for i, x in enumerate(result)), "The result is wrong.")
def test_readables_function_value(self): # Initialize the function counter to prevent test interferences. function_value.function_count = 0 def simple_counter(): nonlocal counter counter += 1 return counter counter = 0 n_images = 2 readables = [simple_counter, simple_counter] positioner = StaticPositioner(n_images) result = scan(positioner, readables) self.assertEqual(result, [[1, 2], [3, 4]], "Result not as expected") def double_counter(): nonlocal counter counter += 1 return [counter, counter] counter = 0 readables = [ function_value(double_counter, "double_trouble"), simple_counter, simple_counter ] data_processor = DictionaryDataProcessor(readables) result = scan(positioner, readables, data_processor=data_processor) expected_result = [ OrderedDict([('double_trouble', [1, 1]), ('function_2', 2), ('function_3', 3)]), OrderedDict([('double_trouble', [4, 4]), ('function_2', 5), ('function_3', 6)]) ] self.assertEqual(result, expected_result, "Result not as expected.") readables = [ simple_counter, "ca://PYSCAN:TEST:OBS1", double_counter, "ca://PYSCAN:TEST:OBS2" ] data_processor = DictionaryDataProcessor(readables) result = scan(positioner, readables, data_processor=data_processor) expected_result = [ OrderedDict([('function_6', 7), ('PYSCAN:TEST:OBS1', 1), ('function_7', [8, 8]), ('PYSCAN:TEST:OBS2', 'PYSCAN:TEST:OBS2')]), OrderedDict([('function_6', 9), ('PYSCAN:TEST:OBS1', 1), ('function_7', [10, 10]), ('PYSCAN:TEST:OBS2', 'PYSCAN:TEST:OBS2')]) ] self.assertEqual(result, expected_result, "Result not as expected.")
def test_condition_function_value(self): def pass_condition(): return True n_images = 2 readables = ["something1"] positioner = StaticPositioner(n_images) conditions = pass_condition scan(positioner, readables, conditions=conditions) def fail_condition(): return False conditions = fail_condition with self.assertRaisesRegex(ValueError, "Function condition function_condition_"): scan(positioner, readables, conditions=conditions)
def test_pshell_function_in_scan(self): n_steps = 3 pshell_test = MockPShellFunction(script_name="", parameters={}) n_positions = 5 positioner = StaticPositioner(n_positions) readables = function_value(pshell_test.read) result = scan(positioner=positioner, readables=readables) self.assertEqual(n_positions, len(result)) for position_index in range(n_positions): for step_index in range(n_steps): result[position_index][0][step_index][0] == float(10)
def test_bs_read_config_default_value(self): # DO NOT INCLUDE IN README - default. config.bs_connection_mode = "pull" # Get 10 images. n_images = 3 positioner = StaticPositioner(n_images) readables = ["bs://CAMERA1:INVALID"] with self.assertRaisesRegex( Exception, "Property 'CAMERA1:INVALID' missing in bs stream."): scan(positioner, readables) default_value = 42 config.bs_default_missing_property_value = default_value result = scan(positioner, readables) self.assertEqual(len(result), n_images) self.assertTrue(all(x[0] == default_value for x in result), "Default value from properties not working.")