def test_GIVEN_axis_param_with_NO_characteristic_value_WHEN_create_beamline_THEN_param_info_contains_empty_value(self):
        param = AxisParameter("MYVALUE", self.comp, ChangeAxis.POSITION)
        pvmanager = self.create_beamline(param)

        pv_definition = pvmanager.PVDB[PARAM_INFO_LOOKUP[BeamlineParameterGroup.COLLIMATION_PLANE]]
        pv_value = convert_from_json(dehex_and_decompress(pv_definition["value"]))

        assert_that(pv_value[0], has_entry("characteristic_value", ""))
    def test_GIVEN_axis_param_with_description_WHEN_create_beamline_THEN_param_info_contains_description(self):
        expected_description = "MOT:MTR0101.RBV"
        param = AxisParameter("MYVALUE", self.comp, ChangeAxis.POSITION,
                              description=expected_description)
        pvmanager = self.create_beamline(param)

        pv_definition = pvmanager.PVDB[PARAM_INFO_LOOKUP[BeamlineParameterGroup.COLLIMATION_PLANE]]
        pv_value = convert_from_json(dehex_and_decompress(pv_definition["value"]))

        assert_that(pv_value[0], has_entry("description", expected_description))
 def handle_pv_write(self, pv, data):
     try:
         if pv == SYNOPTIC_PRE + SYNOPTIC_DELETE:
             self.delete(convert_from_json(data))
             self.update_monitors()
         elif pv == SYNOPTIC_PRE + SYNOPTIC_SET_DETAILS:
             self.save_synoptic_xml(data)
             self.update_monitors()
     except VersionControlException as err:
         print_and_log(str(err),"MINOR")
     except Exception as err:
         print_and_log("Error writing to PV %s: %s" % (pv,str(err)),"MAJOR")
    def save_inactive_config(self, json_data, as_comp=False):
        """Save an inactive configuration.

        Args:
            json_data (string): The JSON data containing the configuration/component
            as_comp (bool): Whether it is a component or not
        """
        new_details = convert_from_json(json_data)
        inactive = InactiveConfigHolder(MACROS, self._vc, ConfigurationFileManager())

        history = self._get_inactive_history(new_details["name"], as_comp)

        inactive.set_config_details(new_details)

        # Set updated history
        history.append(self._get_timestamp())
        inactive.set_history(history)

        config_name = inactive.get_config_name()
        self._check_config_inactive(config_name, as_comp)
        try:
            if not as_comp:
                print_and_log("Saving configuration: %s" % config_name)
                inactive.save_inactive()
                self._config_list.update_a_config_in_list(inactive)
            else:
                print_and_log("Saving component: %s" % config_name)
                inactive.save_inactive(as_comp=True)
                self._config_list.update_a_config_in_list(inactive, True)
            print_and_log("Saved")
        except Exception as err:
            print_and_log("Problem occurred saving configuration: %s" % err)

        # Reload configuration if a component has changed
        if as_comp and new_details["name"] in self._active_configserver.get_component_names():
            self.load_last_config()
    def write(self, reason, value):
        """A method called by SimpleServer when a PV is written to the BlockServer over Channel Access. The write
            commands are queued as Channel Access is single-threaded.

            Note that the filewatcher is disabled as part of the write queue so any operations that intend to modify
            files should use the write queue.

        Args:
            reason (string): The PV that is being requested (without the PV prefix)
            value (string): The data being written to the 'reason' PV

        Returns:
            string : "OK" in compressed and hexed JSON if function succeeds. Otherwise returns the Exception in
            compressed and hexed JSON.
        """
        status = True
        try:
            data = dehex_and_decompress(value).strip('"')
            if reason == BlockserverPVNames.LOAD_CONFIG:
                with self.write_lock:
                    self.write_queue.append((self.load_config, (data,), "LOADING_CONFIG"))
            elif reason == BlockserverPVNames.SAVE_CONFIG:
                with self.write_lock:
                    self.write_queue.append((self.save_active_config, (data,), "SAVING_CONFIG"))
            elif reason == BlockserverPVNames.RELOAD_CURRENT_CONFIG:
                with self.write_lock:
                    self.write_queue.append((self.reload_current_config, (), "RELOAD_CURRENT_CONFIG"))
            elif reason == BlockserverPVNames.START_IOCS:
                with self.write_lock:
                    self.write_queue.append((self.start_iocs, (convert_from_json(data),), "START_IOCS"))
            elif reason == BlockserverPVNames.STOP_IOCS:
                with self.write_lock:
                    self.write_queue.append((self._ioc_control.stop_iocs, (convert_from_json(data),), "STOP_IOCS"))
            elif reason == BlockserverPVNames.RESTART_IOCS:
                with self.write_lock:
                    self.write_queue.append((self._ioc_control.restart_iocs, (convert_from_json(data), True),
                                             "RESTART_IOCS"))
            elif reason == BlockserverPVNames.SET_CURR_CONFIG_DETAILS:
                with self.write_lock:
                    self.write_queue.append((self._set_curr_config, (convert_from_json(data),), "SETTING_CONFIG"))
            elif reason == BlockserverPVNames.SAVE_NEW_CONFIG:
                with self.write_lock:
                    self.write_queue.append((self.save_inactive_config, (data,), "SAVING_NEW_CONFIG"))
            elif reason == BlockserverPVNames.SAVE_NEW_COMPONENT:
                with self.write_lock:
                    self.write_queue.append((self.save_inactive_config, (data, True), "SAVING_NEW_COMP"))
            elif reason == BlockserverPVNames.DELETE_CONFIGS:
                with self.write_lock:
                    self.write_queue.append((self._config_list.delete, (convert_from_json(data),),
                                             "DELETE_CONFIGS"))
            elif reason == BlockserverPVNames.DELETE_COMPONENTS:
                with self.write_lock:
                    self.write_queue.append((self._config_list.delete, (convert_from_json(data), True),
                                             "DELETE_COMPONENTS"))
            elif reason == BlockserverPVNames.BUMPSTRIP_AVAILABLE_SP:
                self.bumpstrip = data
                with self.write_lock:
                    self.write_queue.append((self.update_bumpstrip_availability, None, "UPDATE_BUMPSTRIP"))
            else:
                status = False
                # Check to see if it is a on-the-fly PV
                for h in self.on_the_fly_handlers:
                    if h.write_pv_exists(reason):
                        with self.write_lock:
                            self.write_queue.append((h.handle_pv_write, (reason, data), "SETTING_CONFIG"))
                        status = True
                        break

        except Exception as err:
            value = compress_and_hex(convert_to_json("Error: " + str(err)))
            print_and_log(str(err), "MAJOR")
        else:
            if status:
                value = compress_and_hex(convert_to_json("OK"))

        # store the values
        if status:
            self.setParam(reason, value)
        return status