def test_GIVEN_multiple_channels_WHEN_parse_THEN_have_mulitple_blocks_containing_all_info( self): expected_names = ["BLOCK1", "block_2", "block3"] expected_expected_connectivities = [True, True, False] given_values = ["0.001", "hello", "null"] given_units = ["mA", "", ""] expected_values = ["0.001 mA", "hello", "null"] expected_alarm = ["", "MINOR/LOW", ""] channels = [] for name, connectivity, value, units, alarm in zip( expected_names, expected_expected_connectivities, given_values, given_units, expected_alarm): channels.append( ArchiveMother.create_channel(name=name, is_connected=connectivity, units=units, alarm=alarm, value=value)) json = ArchiveMother.create_info_page(channels) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result, has_length(len(expected_names))) for name, connectivity, expected_value, alarm in zip( expected_names, expected_expected_connectivities, expected_values, expected_alarm): assert_that(result[name].get_name(), is_(name)) assert_that(result[name].get_alarm(), is_(alarm)) assert_that(result[name].is_connected(), is_(connectivity)) assert_that(result[name].get_description()["value"], is_(expected_value)) assert_that(result[name].get_visibility(), is_(True))
def test_GIVEN_no_channels_WHEN_parse_THEN_channels_are_blank(self): json = ArchiveMother.create_info_page([]) parser = WebPageParser() result = parser.extract_blocks(json) self.assertEqual(len(result), 0, "Length of result")
def test_GIVEN_one_invalid_channels_WHEN_parse_THEN_no_blocks_returned( self): expected_name = "BLOCK" json = ArchiveMother.create_info_page([None]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result, has_length(0))
def test_GIVEN_one_channels_WHEN_parse_THEN_block_is_visible(self): expected_name = "BLOCK" json = ArchiveMother.create_info_page( [ArchiveMother.create_channel(expected_name)]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_visibility(), is_(True))
def test_GIVEN_no_object_WHEN_parse_THEN_exception(self): json = {} parser = WebPageParser() try: parser.extract_blocks(json) self.fail("Should have thrown exception") except BlocksParseError: pass
def test_GIVEN_one_channels_WHEN_parse_THEN_blocks_contain_channel(self): expected_name = "BLOCK" json = ArchiveMother.create_info_page( [ArchiveMother.create_channel(expected_name)]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result, has_length(1)) assert_that(result[expected_name].name, is_(expected_name))
def test_GIVEN_one_channels_in_alarm_WHEN_parse_THEN_block_has_alarm(self): expected_name = "BLOCK" expected_alarm = u"INVALID/UDF_ALARM" json = ArchiveMother.create_info_page([ ArchiveMother.create_channel(name=expected_name, alarm=expected_alarm) ]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_alarm(), is_(expected_alarm))
def test_GIVEN_one_channels_has_value_WHEN_parse_THEN_block_has_value( self): expected_name = "BLOCK" expected_value = u"5.4" json = ArchiveMother.create_info_page([ ArchiveMother.create_channel(name=expected_name, value=expected_value) ]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_value(), is_(expected_value))
def __init__(self, host="localhost", reader=None): """ Initialize. Args: host: The host of the instrument from which to read the information. reader: A reader object to get external information. """ if reader is None: self.reader = DataSourceReader(host) else: self.reader = reader self.web_page_parser = WebPageParser()
def test_GIVEN_one_channels_with_value_with_incorrect_utf8_in_WHEN_parse_THEN_block_has_correct_utf8_in( self): expected_name = "BLOCK" value = u'mu \\u-062\\u-075' expected_value = u'mu \u00B5' # decimal 181 channel = ArchiveMother.create_channel(name=expected_name, value=value) del channel['Current Value']["Units"] json = ArchiveMother.create_info_page([channel]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_description()["value"], is_(expected_value))
def test_GIVEN_one_channels_is_disconnected_WHEN_parse_THEN_block_has_value_null( self): expected_name = "BLOCK" expected_connectivity = False expected_value = u"null" json = ArchiveMother.create_info_page([ ArchiveMother.create_channel(name=expected_name, value=expected_value, is_connected=expected_connectivity) ]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_value(), is_(expected_value))
def test_GIVEN_one_channels_is_connected_WHEN_parse_THEN_block_is_connected_and_status_reflects_this( self): expected_name = "BLOCK" expected_connectivity = True expected_status = "Connected" json = ArchiveMother.create_info_page([ ArchiveMother.create_channel(name=expected_name, is_connected=expected_connectivity) ]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].is_connected(), is_(expected_connectivity)) assert_that(result[expected_name].status, is_(expected_status))
def test_GIVEN_one_channels_is_disconnected_WHEN_parse_THEN_block_is_disconnected_and_status_reflects_this( self): expected_name = "BLOCK" expected_connectivity = False expected_status = "Disconnected" # Don't use constant this is the word expected in the js file. json = ArchiveMother.create_info_page([ ArchiveMother.create_channel(name=expected_name, is_connected=expected_connectivity) ]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].is_connected(), is_(expected_connectivity)) assert_that(result[expected_name].status, is_(expected_status))
def test_GIVEN_one_channels_with_no_units_but_connected_WHEN_parse_THEN_block_has_units( self): """ e.g. CS:PS: PVs """ expected_name = "BLOCK" value = u'0.000' expected_value = "{}".format(value) channel = ArchiveMother.create_channel(name=expected_name, value=value) del channel['Current Value']["Units"] json = ArchiveMother.create_info_page([channel]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_description()["value"], is_(expected_value))
def test_GIVEN_one_channels_with_units_WHEN_parse_THEN_block_has_units( self): expected_name = "BLOCK" units = u'uA hour' value = u'0.000' expected_value = "{} {}".format(value, units) json = ArchiveMother.create_info_page([ ArchiveMother.create_channel(name=expected_name, units=units, value=value) ]) parser = WebPageParser() result = parser.extract_blocks(json) assert_that(result[expected_name].get_description()["value"], is_(expected_value))
class InstrumentInformationCollator: """ Collect instrument information and summarise as a dictionary. """ # String to use for title and username if they are private PRIVATE_VALUE = "Unavailable" # Name of the username channel USERNAME_CHANNEL_NAME = "_USERNAME" # name of the title channel TITLE_CHANNEL_NAME = "TITLE" # name of the channel which determins of the username and title should be displayed DISPLAY_TITLE_CHANNEL_NAME = "DISPLAY" # name of the channel of the current run duration RUN_DURATION_CHANNEL_NAME = "RUNDURATION" # name of the channel fo the run duration for the current period RUN_DURATION_PD_CHANNEL_NAME = "RUNDURATION_PD" def __init__(self, host="localhost", reader=None): """ Initialize. Args: host: The host of the instrument from which to read the information. reader: A reader object to get external information. """ if reader is None: self.reader = DataSourceReader(host) else: self.reader = reader self.web_page_parser = WebPageParser() def _get_inst_pvs(self, ans, blocks_all): """ Extracts and formats a list of relevant instrument PVs from all instrument PVs. Args: ans: List of blocks from the instrument archive. blocks_all: List of blocks from the block and dataweb archives. Returns: A trimmed list of instrument PVs. """ wanted = {} title_channel_name = InstrumentInformationCollator.TITLE_CHANNEL_NAME username_channel_name = InstrumentInformationCollator.USERNAME_CHANNEL_NAME run_duration_channel_name = InstrumentInformationCollator.RUN_DURATION_CHANNEL_NAME run_duration_pd_channel_name = InstrumentInformationCollator.RUN_DURATION_PD_CHANNEL_NAME required_pvs = [ "RUNSTATE", "RUNNUMBER", "_RBNUMBER", title_channel_name, username_channel_name, "STARTTIME", run_duration_channel_name, run_duration_pd_channel_name, "GOODFRAMES", "GOODFRAMES_PD", "RAWFRAMES", "RAWFRAMES_PD", "PERIOD", "NUMPERIODS", "PERIODSEQ", "BEAMCURRENT", "TOTALUAMPS", "COUNTRATE", "DAEMEMORYUSED", "TOTALCOUNTS", "DAETIMINGSOURCE", "MONITORCOUNTS", "MONITORSPECTRUM", "MONITORFROM", "MONITORTO", "NUMTIMECHANNELS", "NUMSPECTRA", "SHUTTER", "SIM_MODE" ] try: set_rc_values_for_blocks(blocks_all.values(), ans) except Exception as e: logging.error("Error in setting rc values for blocks: " + str(e)) for pv in required_pvs: if pv + ".VAL" in ans: wanted[pv] = ans[pv + ".VAL"] try: self._convert_seconds(wanted[run_duration_channel_name]) except KeyError: pass try: self._convert_seconds(wanted[run_duration_pd_channel_name]) except KeyError: pass display_title_channel_name = InstrumentInformationCollator.DISPLAY_TITLE_CHANNEL_NAME + ".VAL" if display_title_channel_name not in ans or ans[ display_title_channel_name].get_value().lower() != "yes": if title_channel_name in wanted: wanted[title_channel_name].set_value( InstrumentInformationCollator.PRIVATE_VALUE) if username_channel_name in wanted: wanted[username_channel_name].set_value( InstrumentInformationCollator.PRIVATE_VALUE) return wanted def _convert_seconds(self, block): """ Receives the value from the block and converts to hours, minutes and seconds. Args: block: the block to convert """ if not block.is_connected(): return old_value = block.get_value() minutes, seconds = divmod(int(old_value), 60) hours, minutes = divmod(minutes, 60) if hours == 0 and minutes == 0: block.set_value("{} s".format(old_value)) elif hours == 0: block.set_value("{} min {} s".format(str(minutes), str(seconds))) else: block.set_value("{} hr {} min {} s".format(str(hours), str(minutes), str(seconds))) block.set_units("") def collate(self): """ Returns the collated information on instrument configuration, blocks and run status PVs as JSON. Returns: JSON of the instrument's configuration and status. """ instrument_config = InstrumentConfig(self.reader.read_config()) try: # read blocks json_from_blocks_archive = self.reader.get_json_from_blocks_archive( ) blocks_log = self.web_page_parser.extract_blocks( json_from_blocks_archive) json_from_dataweb_archive = self.reader.get_json_from_dataweb_archive( ) blocks_nolog = self.web_page_parser.extract_blocks( json_from_dataweb_archive) blocks_all = dict(blocks_log.items() + blocks_nolog.items()) # get block visibility from config for block_name, block in blocks_all.items(): block.set_visibility( instrument_config.block_is_visible(block_name)) json_from_instrument_archive = self.reader.get_json_from_instrument_archive( ) instrument_blocks = self.web_page_parser.extract_blocks( json_from_instrument_archive) inst_pvs = format_blocks( self._get_inst_pvs(instrument_blocks, blocks_all)) except Exception as e: logger.error("Failed to read blocks: " + str(e)) raise e blocks_all_formatted = format_blocks(blocks_all) groups = {} for group in instrument_config.groups: blocks = {} for block in group["blocks"]: if block in blocks_all_formatted.keys(): blocks[block] = blocks_all_formatted[block] groups[group["name"]] = blocks return { "config_name": instrument_config.name, "groups": groups, "inst_pvs": inst_pvs }