class DataModel(object): """ This object describes the status/verdict data model used by TCR reference link: https://wiki.ith.intel.com/display/DRD/Campaign+-+Data+model """ STATUS = AttributeDict({ "COMPLETED": "COMPLETED", "ABORTED": "CANCELLED", "CANCELLED": "CANCELLED", "INIT": "PENDING", "PENDING": "PENDING", "ONGOING": "RUNNING", "RUNNING": "RUNNING", "TIMEOUT": "TIMEOUT" }) VERDICT = AttributeDict({ "BLOCKED": "BLOCKED", "FAIL": "FAILED", "FAILED": "FAILED", "PASSED": "PASSED", "PASS": "******", "VALID": "VALID", "INVALID": "INVALID", "INCONCLUSIVE": "INCONCLUSIVE", "NA": "NA" })
def _load_bench_conf(self): """ Loads The Bench Configuration from its XML representation into a dict """ self._bench_conf = AttributeDict() # New way of defining device parameters == as defined in the device catalog try: self._bench_tree_node = etree.parse(self.bench_conf_filename) except XMLParsingErrors: _error("Corrupted file {0}: {1}".format( self.bench_conf_filename, Utils.get_exception_info()[1])) node = self.bench_device_node if node is not None and len(node) > 0: # To load proper device config, need to get device model name device_conf = self.device_conf if device_conf: self._device_model_name = device_conf.get("DeviceModel") if self._device_model_name in ('', "", None, 'multi'): self._device_model_name = node[0].get("deviceModel") conf = self._parse_bench_node(node[0]) if conf: self._bench_conf.update(conf)
def update_global_config(): """ For now, pupdr_common is based on exec script Update globals with fake exec script in order to make this code retro compliant """ self._globals["EXEC_UC"] = AttributeDict() fake_tc_params = AttributeDict() fake_tc_params._attrs_override = {"TcExpectedResult": ""} fake_tc_params.get_name = lambda: "FLASH_UC" self._globals["EXEC_UC"]._tc_parameters = fake_tc_params
def _parse_bench_node(self, node): """ Parses XML `Phone` node(s) from Bench Catalog file and maps it into a python structure (dict) :return: A dict mapping XML configuration :rtype: AttributeDict :raise AcsConfigException.INVALID_BENCH_CONFIG: If a (or more) deprecated parameter(s) is/are found in a Phone node """ LOGGER_FWK.info( 'Loading optional device model parameters from CLI and/or BenchConfig ' 'for {0} ({1})...'.format(self._device_name, self._device_model_name)) buf_params = AttributeDict() # Storing value to avoid recomputing each call device_model_name = self.device_model_name if device_model_name: buf_params["Name"] = device_model_name if self.device_conf_filename: buf_params["DeviceConfigPath"] = self.device_conf_filename # Get phone properties for attrs in node.xpath(".//Parameter"): name, value, description = attrs.get("name"), attrs.get( "value"), attrs.get("description") if name in self.PROHIBITIVE_KEYS: # Do not allow to override internal keys # as it would lead to nasty & unexpected behavior !! continue # Not supported anymore, raise AcsConfigException.INVALID_BENCH_CONFIG !! if name and value: buf_params[name] = value self._bench_conf_deprecated[name] = (value, description) else: buf_params.update(attrs.attrib) # Report Errors if so if self.bench_contains_errors: LOGGER_FWK.error(self._report_errors()) _error( 'Invalid Bench Parameters format found! {0}'.format(', '.join( self._bench_conf_deprecated.keys())), AcsConfigException.INVALID_BENCH_CONFIG) # Extracting device modules if so buf_params.device_modules = self.extract_device_modules(node) return buf_params
def __init__(self): """ DeviceModuleBase module """ self.__device = None self.__logger = None self.__module_conf_file = None self.__module_config = None self.__global_conf = None self.__module_config = AttributeDict() self.__name = None
def extract_params(s_node): """ Get Section properties :param s_node: The Section node :type s_node: etree.Element :return: A dict of Section's attributes :rtype: AttributeDict """ params = AttributeDict() for attrs in s_node.xpath(".//Parameter"): params.update(attrs.attrib) return params
def __init__(self, config, logger): """ Constructor :type config: dict :param config: Device configuration to use :type logger: logger :param logger: Logger to use """ device_man = DeviceManager.DeviceManager() self._global_config = device_man.get_global_config() self._device_config = config self._uecmd_path = self._device_config.UECmd self._device_model_name = self._device_config.Name self._wait_btwn_cmd = self.get_config("waitBetweenCmd", 5, float) self._min_file_install_timeout = self.get_config("minFileInstallTimeout", 30, int) self._device_name = config.device_name self._acs_agent = None self._userdata_path = None self.uecommands = {} self._device_capabilities = [] self._logger = logger self.__uecmd_instances = {} self.retrieve_tc_debug_log = None self._module_instances = AttributeDict() self._device_properties = DeviceProperties() self._flash_device_properties = FlashDeviceProperties() self._device_capabilities = DCManager.load_device_capabilities(self._device_config.deviceCapabilities, self._logger) campaign_report_tree = self._global_config.campaignConfig["campaignReportTree"] campaign_report_tree.set_hw_variant_name(self.hw_variant_name) campaign_report_tree.create_report_folder()
def test_list_when_uploadCrashToServer_activated(self, mock_run_cmd, mock_download_crastooluploader): """ 'uploadCrashToServer' set to True in device config Check that 'list' return CRASH events """ mock_download_crastooluploader.return_value = "" mock_run_cmd.return_value = Global.SUCCESS, "" device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "uploadCrashToServer": "True", "crashServerSilentMode": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config crash_mod = self.__get_crash_module(device=device) crash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") crash_listed = self.__get_crash_list(crash_mod) self.assertNotEqual(crash_listed, []) self.assertEqual(len(crash_listed), 2) for event in crash_listed: self.assertTrue(event["_id"] in ["10", "11"])
def device_only_params(self): """ Get a map with only parameters, no sections ! :return: A map with only parameters :rtype: AttributeDict() """ if not self._device_only_params: # Store the Current Device's configuration self._device_only_params = AttributeDict() self._load_params_only(self.device_conf, self._device_only_params) # Updating all unchecked extra parameters self._device_only_params.update(self.device_extra_params) if 'description' in self.device_extra_params: del self.device_extra_params['description'] return self._device_only_params
def load(config): """ Load global device conf to the device conf objects :type config: dict :param config: device global conf dictionary """ device_conf = AttributeDict() for key, value in config.items(): device_conf[key] = value return device_conf
def extract_device_modules(cls, node): """ Get DeviceModule Node(s) properties :param node: The root node :type node: etree.Element :return: A dict of DeviceModule's attributes :rtype: AttributeDict """ # Extract device modules module_params = AttributeDict() for device_module in node.xpath(".//DeviceModule/*"): if device_module.tag not in module_params: # init module config as list module_params[device_module.tag] = [] module_config = AttributeDict() module_config.class_name = device_module.get("className") module_config.config = device_module.get("config") # Handle parameter overload module_config.parameter_overloaded = {} for module_param in device_module.xpath("Parameter"): module_config.parameter_overloaded.update(module_param.attrib) # store config of the module module_params[device_module.tag].append(module_config) # Removing the node for post processing device_module.getparent().remove(device_module) return module_params
def test_list_when_retrieveDeviceCrashLog_deactivated(self): """ 'retrieveDeviceCrashLog' set to False in device config Check that 'list' do no """ device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "retrieveDeviceCrashLog": "False", "crashServerSilentMode": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config flash_mod = self.__get_crash_module(device=device) flash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") self.assertEqual(flash_mod.list(), [])
def test_list_when_uploadCrashToServer_deactivated(self, mock_download_crastooluploader): """ 'uploadCrashToServer' set to False in device config Check that 'list' do nothing """ mock_download_crastooluploader.return_value = "" device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "uploadCrashToServer": "False", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002"})) type(device).config = config crash_mod = self.__get_crash_module(device=device) crash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") self.assertEqual(crash_mod.list(), [])
def test_list_when_retrieveDeviceCrashLog_activated(self): """ 'retrieveDeviceCrashLog' set to True in device config Check that 'list' return CRASH events """ device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "retrieveDeviceCrashLog": "True", "crashServerSilentMode": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config # add 3 elements: 2 CRASH only crash1 = dict(_id=10, eventName="CRASH", date="2014-07-09/10:39:44", eventId=10, type="IPANIC", crashdir="/home/acs/my_log") crash2 = dict(_id=50, eventName="CRASH", date="2014-07-09/10:41:37", eventId=50, type="ANR", crashdir="/home/acs/my_log1") crash3 = dict(_id=55, eventName="CRASH_NOT", date="2014-07-09/10:42:57", eventId=55, type="IPANIC", crashdir="/home/acs/my_log2") self.__crash_lib.get_event.return_value = [crash1, crash2, crash3] flash_mod = self.__get_crash_module(device=device) flash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") crash_listed = flash_mod.list() self.assertNotEqual(crash_listed, []) for event in crash_listed: self.assertTrue(event["_id"]in [crash1["_id"], crash2["_id"]]) self.assertFalse(dict(event) == crash3)
def test_disable_clota_when_disableCLOTA_activated(self): """ 'disableCLOTA' set to True in device config Check that 'disable_clota' call will run a cmd on the device """ device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "retrieveDeviceCrashLog": "True", "crashServerSilentMode": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config device.run_cmd.return_value = 0, "cmd ok" flash_mod = self.__get_crash_module(device=device) flash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") flash_mod.disable_clota() self.assertGreaterEqual(device.run_cmd.call_count, 1)
def test_fetch_when_retrieveDeviceCrashLog_activated_and_no_event(self): """ 'retrieveDeviceCrashLog' set to True in device config Check that 'fetch' fetch all event """ device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "retrieveDeviceCrashLog": "True", "crashServerSilentMode": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config flash_mod = self.__get_crash_module(device=device) flash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") self.__crash_lib.get_event.return_value = [] self.assertTrue(flash_mod.fetch()) self.assertGreaterEqual(self.__crash_lib.get_event.call_count, 1)
def test_fetch_event_id_when_uploadCrashToServer_activated(self, mock_run_cmd, mock_download_crastooluploader): """ 'uploadCrashToServer' set to False in device config Check that 'fetch' do nothing """ mock_download_crastooluploader.return_value = "" mock_run_cmd.return_value = Global.SUCCESS, "" device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "True", "retrieveDeviceLogOnCriticalFailure": "False", "uploadCrashToServer": "True", "crashServerSilentMode": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config crash_mod = self.__get_crash_module(device=device) crash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") self.assertTrue(crash_mod.fetch(event_id=10))
def test_disable_clota_when_disableCLOTA_deactivated(self, mock_download_crastooluploader): """ 'disableCLOTA' set to False in device config Check that 'disable_clota' do nothing on the phone """ mock_download_crastooluploader.return_value = "" device = MagicMock() config = PropertyMock(return_value=AttributeDict({"disableCLOTA": "False", "retrieveDeviceLogOnCriticalFailure": "False", "uploadCrashToServer": "True", "crashServer": "crashtool.iind.intel.com", "crashServerPort": "4002" })) type(device).config = config device.run_cmd.return_value = 0, "cmd ok" crash_mod = self.__get_crash_module(device=device) crash_mod.init(device_serial_number="ACSPHONE1234567", cache_folder="") results = crash_mod.disable_clota() self.assertEqual(device.run_cmd.call_count, 0) self.assertEqual(results, False)
def _parse_device_node(self): """ Parses XML Device Catalog file and maps it into a python structure (dict) :return: A dict mapping XML configuration :rtype: AttributeDict """ def extract_params(s_node): """ Get Section properties :param s_node: The Section node :type s_node: etree.Element :return: A dict of Section's attributes :rtype: AttributeDict """ params = AttributeDict() for attrs in s_node.xpath(".//Parameter"): params.update(attrs.attrib) return params buf_params = AttributeDict() # Storing value to avoid recomputing each call device_model_name = self.device_model_name if device_model_name: buf_params["Name"] = device_model_name if self.device_conf_filename: buf_params["DeviceConfigPath"] = self.device_conf_filename node = self.device_root_node buf_params['device_modules'] = self.extract_device_modules(node) for section_node in list(node): buf_params[section_node.tag] = extract_params(section_node) self._device_conf = buf_params
def __init__(self): super(SystemModule, self).__init__() self._system_info = AttributeDict()
class DeviceModuleBase(object): """ Device module interface """ def __init__(self): """ DeviceModuleBase module """ self.__device = None self.__logger = None self.__module_conf_file = None self.__module_config = None self.__global_conf = None self.__module_config = AttributeDict() self.__name = None @property def name(self): return self.__name @name.setter def name(self, new_name): self.__name = new_name @property def configuration_file(self): return self.__module_conf_file @configuration_file.setter def configuration_file(self, new_conf): self.__module_conf_file = new_conf @property def configuration(self): return self.__module_config @property def path(self): return path.dirname(path.abspath(inspect.getfile(self.__class__))) @property def device(self): """ Retrieve the device instance associated to that module """ return self.__device @device.setter def device(self, new_device): """ Set the device instance associated to that module """ self.__device = new_device @property def logger(self): """ Retrieve the logger associated to that module """ return self.__logger @logger.setter def logger(self, new_logger): """ Set the logger associated to that module """ self.__logger = new_logger @property def global_conf(self): return self.__global_conf @global_conf.setter def global_conf(self, conf): self.__global_conf = conf def load_conf(self): """ Load the configuration of the module. Need to be overloaded is you expect to use a specific configuration file. """ if self.configuration_file and path.isfile(self.configuration_file): parser = Parser.get_parser(self.configuration_file) for module_conf in parser.get("/ModuleConfiguration/*"): if self.device.config.get(module_conf.tag): # Parameter is available in the device config # it may be an old override, take it for back compatibility self.__module_config[module_conf.tag] = self.device.config[ module_conf.tag] else: self.__module_config[module_conf.tag] = module_conf.text # If the XML parameter has some attributes - parse them if len(module_conf.attrib) != 0: self.__module_config.update(module_conf.attrib) else: self.logger.error("No module configuration to load!")
def __init__(self): super(CWSModule, self).__init__() self._cws_properties = AttributeDict()
def __init__(self): super(EmModule, self).__init__() self._em_properties = AttributeDict()
def __init__(self, name, device_model_name, global_config, cli_params): """ Constructor :param global_config: The Global configuration :type global_config: AttributeDict or dict """ # ################ Global ################# # Global Configuration instance (grouping all needed parameters) self._global_config = global_config # ################ CmdLine ################# # Command line parameters self._cli_params = cli_params # Unknown Parameter(s) found in the Command line arguments (``-o``) self._cli_unknown_parameters = {} # ################ Device ################# # The current Device's name self._device_name = name # The Device parameters only (no sections) self._device_only_params = {} # The Device extra unchecked parameters reference self._device_extra_params = {} # The Device Model's map with its sections (dict) self._device_conf_sections = None # The Device Model name self._device_model_name = device_model_name # The Device Model final XML node self._device_model_final = None # Device Configuration etree.ElementTree self._device_tree_node = None # Device Configuration root node (etree.Element) self._device_root_node = None # Device Configuration filename (abspath) self._device_conf_filename = None # Device configuration instance (AttributeDict) self._device_conf = None # Device's XML Schema reference self._device_schema = None # ################ Bench ################# # Unknown Parameter(s) found in the BenchConfig file self._bench_unknown_parameters = {} # Global Bench Configuration instance self._bench_conf_global = None # Bench Configuration etree.ElementTree self._bench_tree_node = None # Bench Configuration root node (etree.Element) self._bench_root_node = None # Bench Configuration `Phone` node (etree.Element) # for the given Device Model name self._bench_device_node = None # Bench Configuration filename (abspath) self._bench_conf_filename = None # Bench configuration instance (AttributeDict) self._bench_conf = None # Bench configuration instance (AttributeDict) self._bench_conf_deprecated = AttributeDict()
def __init__(self): super(PnpModule, self).__init__() self._pnp_properties = AttributeDict()
class Device(object): """ A Device Class, representing a D.U.T with its : * Parameters * Overrides mechanisms * Parameters checker """ ROOT_TAG = 'DeviceModel' SCHEMA_LOCATION_KEY = '{http://www.w3.org/2001/XMLSchema-instance}noNamespaceSchemaLocation' DEPRECATED_OVERRIDE_MSG = 'Unsupported format detected in {0}' DEPRECATED_ELEMENT_MSG = '\n\t<Parameter name="{0}" value="{1}" {2} />' RECOMMENDED_ELEMENT_MSG = '\n\t<Parameter {0}="{1}" {2} />' PROHIBITIVE_KEYS = ('Name', 'DeviceConfigPath', 'device_modules', 'parameter_overloaded') @classmethod def dict2xml(cls, xml_map, parent, parameter_tag='Parameter'): """ This class method maps into the given XML root node, all what is contained into inner configuration dict. It produces an XML node which can either pass or not validations :param xml_map: The XML map :type xml_map: dict or AttributeDict :param parent: The root/parent node :type parent: etree.Element :param parameter_tag: The Parameter `tag` name :type parameter_tag: str """ def generic_processing(): """ This method's purpose is to structure inner actions only .. important:: For parameters details see parent definition (:meth:`DeviceConfigLoader.dict2xml`) """ for key, value in xml_map.iteritems(): if isinstance(value, (dict, AttributeDict)): section = etree.Element(_tag=key) parent.append(section) cls.dict2xml(value, section, parameter_tag=parameter_tag) else: parent.append( etree.Element(_tag=parameter_tag, attrib={key: value})) if not isinstance(parent, EtreeElementType): _error('Need A XML node as `parent` attribute ! Got => {0}'.format( type(parent))) # Hack for non-generic Implementation tag. if parent.tag == 'Implementation': parent.append(etree.Element(_tag=parameter_tag, attrib=xml_map)) else: generic_processing() @classmethod def extract_schema(cls, node, schema_folder, file_only=True): """ Class Method which extracts the XML Schema file reference if so. :param node: The XML Node or the XML file to be parsed into a node :type node: etree.Element :param schema_folder: If provided the value is concatenated to the schema basename if available :type schema_folder: str :param file_only: If set to True the schema is not loaded :type file_only: bool :return: Either the schema filename or its corresponding XML instance ( :rtype: str or etree.XMLSchema """ schema_files = [] if isinstance(node, basestring) and path.isfile(node): node = etree.parse(node).getroot() schema_file = node.attrib.get(cls.SCHEMA_LOCATION_KEY) if schema_file and schema_folder and path.isdir(schema_folder): schema_file = PathMgr.absjoin(schema_folder, path.basename(schema_file)) schema_files = os.listdir(schema_folder) try: self_name = node.base except AttributeError: self_name = "Unknown" if not schema_file or not path.isfile(schema_file): _error(("Your Configuration file : {0} does not define an" " 'xsi:noNamespaceSchemaLocation' in root element!" ).format(self_name)) if path.basename(schema_file) not in schema_files: _error( "Your Device Model file : {0} does not define a Valid Schema" " 'xsi:noNamespaceSchemaLocation' in root element!").format( self_name) if file_only: return schema_file try: return etree.XMLSchema(etree.parse(schema_file)) except etree.Error as schema_error: _error(schema_error.message) @classmethod def extract_device_modules(cls, node): """ Get DeviceModule Node(s) properties :param node: The root node :type node: etree.Element :return: A dict of DeviceModule's attributes :rtype: AttributeDict """ # Extract device modules module_params = AttributeDict() for device_module in node.xpath(".//DeviceModule/*"): if device_module.tag not in module_params: # init module config as list module_params[device_module.tag] = [] module_config = AttributeDict() module_config.class_name = device_module.get("className") module_config.config = device_module.get("config") # Handle parameter overload module_config.parameter_overloaded = {} for module_param in device_module.xpath("Parameter"): module_config.parameter_overloaded.update(module_param.attrib) # store config of the module module_params[device_module.tag].append(module_config) # Removing the node for post processing device_module.getparent().remove(device_module) return module_params @property def cli_parameters(self): """ Property/Generator yielding the CLI parameter(s) from list to dict-style For example, -o bootTimeout="300" in CLI produces a list like this : .. code-block:: python [bootTimeout="300"] It becomes : .. code-block:: python {bootTimeout: "300"} """ if isinstance(self._cli_params, list): for device_parameter in self._cli_params: split_device_param = device_parameter.split("=") # Set parameters which are correctly set in ACS command line # as follow : -o bootTimeout="300" or --op=bootTimeout="300" or # --override_device_parameter=bootTimeout="300" if len(split_device_param) == 2: # Store device parameter name and value yield split_device_param @property def device_extra_params(self): """ Property holding All extra parameters found either in Bench Config file or CLI that are not referenced in the corresponding Device Model Schema. Since those parameters cannot be validated, we just update device configuration with it ! :return: The Current Device's configuration :rtype: AttributeDict """ if not self._device_extra_params: self._device_extra_params = {} self._device_extra_params.update(self._bench_unknown_parameters) self._device_extra_params.update(self._cli_unknown_parameters) return self._device_extra_params @property def device_only_params(self): """ Get a map with only parameters, no sections ! :return: A map with only parameters :rtype: AttributeDict() """ if not self._device_only_params: # Store the Current Device's configuration self._device_only_params = AttributeDict() self._load_params_only(self.device_conf, self._device_only_params) # Updating all unchecked extra parameters self._device_only_params.update(self.device_extra_params) if 'description' in self.device_extra_params: del self.device_extra_params['description'] return self._device_only_params @property def device_model_final(self): """ Property computing/holding the final Device Model XML node, rebuild from its mapped AttributeDict :return: The final Device Model XML node :rtype: etree.Element """ if self._device_model_final is None: self._device_model_final = etree.Element(_tag=self.ROOT_TAG) # Hack to match XSD, ACS input is not compliant! xml_map = self.device_conf.copy() dm_key = 'device_modules' if dm_key in xml_map: _override_filter(xml_map, conf_key=dm_key, klass=(list, ), callback=lambda v: v[0] if v else None) xml_map['DeviceModule'] = xml_map[dm_key] for unexpected_key in self.PROHIBITIVE_KEYS: if unexpected_key in xml_map: del xml_map[unexpected_key] self.dict2xml(xml_map, self._device_model_final) return self._device_model_final @property def device_model_name(self): """ Computes the Current Device Model name :return: Current Device Model name :rtype: str """ if not self._device_model_name: if self._device_name == AcsConstants.DEFAULT_DEVICE_NAME: # For PHONE1 we need to retrieve the device model name if self._device_model_name and "multi" not in self._device_model_name: pass elif ((not self._device_model_name or "multi" in self._device_model_name) and self.bench_conf and "Name" in self.bench_conf): # Device model name is not specified or in "multi" mode # Get it from bench config self._device_model_name = self.bench_conf.Name else: _error( "No device model specified/configured. Cannot instantiate the device." ) else: # For any other phone than phone1, the information comes from the bench config. self._device_model_name = self.bench_conf.Name return self._device_model_name @property def device_root_node(self): """ Property holding the Device root's node :return: The device root's node :rtype: etree.Element .. note:: Consider etree.Element as an `etree._Element` instance factory The real Class is **etree._Element** """ if self._device_root_node is None and self._device_tree_node is not None: self._device_root_node = self._device_tree_node.getroot() if self._device_root_node is None: _error("Device catalog is corrupted! Unable to parse {0}".format( self.device_conf_filename)) return self._device_root_node @property def device_schema(self): """ Property holding the Device associated XML Schema instance :return: The device XML Schema instance :rtype: etree.XMLSchema """ return self._device_schema @property def device_conf_filename(self): """ Property holding the Device configuration filename (full path) :return: The Device configuration filename :rtype: str """ if not self._device_conf_filename: device_model, catalog_path = self.device_model_name, Paths.DEVICE_MODELS_CATALOG device_config_filename = "{0}.xml".format(device_model) files = FileUtilities.find_file(catalog_path, device_config_filename) files_count = len(files) error = None if files_count == 0: error = ("Device {0} not found in the catalog {1} !".format( device_model, catalog_path), AcsConfigException.FILE_NOT_FOUND) elif files_count > 1: error = ("Device {0} found multiple times in the catalog {1}. " "{2}".format(device_model, catalog_path, "\n at ".join(files)), AcsConfigException.PROHIBITIVE_BEHAVIOR) else: self._device_conf_filename = files[0] if error: _error(*error) return self._device_conf_filename @property def device_conf(self): """ Property holding the Current Device's configuration :return: The Current Device's configuration :rtype: AttributeDict """ return self._device_conf @property def bench_contains_errors(self): """ Property holding whether or not the Bench Configuration file is properly filled in. :return: Whether or not the Bench Configuration file is properly filled in :rtype: bool """ return len(self._bench_conf_deprecated) > 0 @property def bench_root_node(self): """ Property holding the Bench root's node :return: The Bench root's node :rtype: etree.Element .. note:: Consider etree.Element as an `etree._Element` instance factory The real Class is **etree._Element** """ if self._bench_root_node is None and self._bench_tree_node is not None: self._bench_root_node = self._bench_tree_node.getroot() return self._bench_root_node @property def bench_device_node(self): """ Property holding the Current Device Bench Phone's node :return: The Current Device Bench Phone's node :rtype: etree.Element .. note:: Consider etree.Element as an `etree._Element` instance factory The real Class is **etree._Element** """ if self._bench_tree_node is not None: xpath = "//Phone[@name='{0}']".format(self._device_name) self._bench_device_node = self._bench_tree_node.xpath(xpath) return self._bench_device_node # noinspection PyUnresolvedReferences @property def bench_conf_global(self): """ Property holding the Global Bench Configuration instance .. seealso:: Constructor parameters. :return: The Global Bench configuration instance :rtype: AttributeDict """ if not self._bench_conf_global: self._bench_conf_global = self._global_config.benchConfig return self._bench_conf_global @property def bench_conf_filename(self): """ Property holding the Bench Configuration filename (abspath) :return: The Bench configuration filename :rtype: str """ if not self._bench_conf_filename: self._bench_conf_filename = self.bench_conf_global.file return self._bench_conf_filename @property def bench_conf(self): """ Property holding the Current Device's Bench configuration :return: The Current Device's Bench configuration :rtype: AttributeDict """ return self._bench_conf def __init__(self, name, device_model_name, global_config, cli_params): """ Constructor :param global_config: The Global configuration :type global_config: AttributeDict or dict """ # ################ Global ################# # Global Configuration instance (grouping all needed parameters) self._global_config = global_config # ################ CmdLine ################# # Command line parameters self._cli_params = cli_params # Unknown Parameter(s) found in the Command line arguments (``-o``) self._cli_unknown_parameters = {} # ################ Device ################# # The current Device's name self._device_name = name # The Device parameters only (no sections) self._device_only_params = {} # The Device extra unchecked parameters reference self._device_extra_params = {} # The Device Model's map with its sections (dict) self._device_conf_sections = None # The Device Model name self._device_model_name = device_model_name # The Device Model final XML node self._device_model_final = None # Device Configuration etree.ElementTree self._device_tree_node = None # Device Configuration root node (etree.Element) self._device_root_node = None # Device Configuration filename (abspath) self._device_conf_filename = None # Device configuration instance (AttributeDict) self._device_conf = None # Device's XML Schema reference self._device_schema = None # ################ Bench ################# # Unknown Parameter(s) found in the BenchConfig file self._bench_unknown_parameters = {} # Global Bench Configuration instance self._bench_conf_global = None # Bench Configuration etree.ElementTree self._bench_tree_node = None # Bench Configuration root node (etree.Element) self._bench_root_node = None # Bench Configuration `Phone` node (etree.Element) # for the given Device Model name self._bench_device_node = None # Bench Configuration filename (abspath) self._bench_conf_filename = None # Bench configuration instance (AttributeDict) self._bench_conf = None # Bench configuration instance (AttributeDict) self._bench_conf_deprecated = AttributeDict() def _load_params_only(self, conf, data): """ Loads in memory into `data` parameter only the DUT parameters (without sections) :param conf: The Device Model Configuration :type conf: dict or AttributeDict """ dm_key = 'device_modules' for key, value in conf.iteritems(): is_device_modules = key == dm_key if is_device_modules: _override_filter(conf, conf_key=dm_key, klass=(AttributeDict, dict), callback=lambda v: [v]) if isinstance(value, (dict, AttributeDict)) and not is_device_modules: self._load_params_only(value, data) else: data[key] = value def _load_cli_conf(self): """ Loads Overridden Device Configuration parameters from CLI into a dict Some keys are not allowed in CLI overridden parameters:: 1. "Name" => Used for the whole process, `DeviceModel alias` (**INTERNAL USE ONLY**) 2. "DeviceConfigPath" => The associated Bench configuration file path (**INTERNAL USE ONLY**) 3. "DeviceModel" => There's no point in overriding this property """ _remove_prohibited_keys(self._cli_params, self.PROHIBITIVE_KEYS + ("DeviceModel", )) def _load_device_conf(self): """ Loads The Device Configuration from its XML representation into a dict """ try: self._device_tree_node = etree.parse(self.device_conf_filename) except XMLParsingErrors: _error("Corrupted file {0}: {1}".format( self.device_conf_filename, Utils.get_exception_info()[1])) self._parse_device_node() self._device_schema = self.extract_schema( self.device_root_node, schema_folder=Paths.FWK_DEVICE_MODELS_CATALOG, file_only=False) def _load_bench_conf(self): """ Loads The Bench Configuration from its XML representation into a dict """ self._bench_conf = AttributeDict() # New way of defining device parameters == as defined in the device catalog try: self._bench_tree_node = etree.parse(self.bench_conf_filename) except XMLParsingErrors: _error("Corrupted file {0}: {1}".format( self.bench_conf_filename, Utils.get_exception_info()[1])) node = self.bench_device_node if node is not None and len(node) > 0: # To load proper device config, need to get device model name device_conf = self.device_conf if device_conf: self._device_model_name = device_conf.get("DeviceModel") if self._device_model_name in ('', "", None, 'multi'): self._device_model_name = node[0].get("deviceModel") conf = self._parse_bench_node(node[0]) if conf: self._bench_conf.update(conf) def _parse_device_node(self): """ Parses XML Device Catalog file and maps it into a python structure (dict) :return: A dict mapping XML configuration :rtype: AttributeDict """ def extract_params(s_node): """ Get Section properties :param s_node: The Section node :type s_node: etree.Element :return: A dict of Section's attributes :rtype: AttributeDict """ params = AttributeDict() for attrs in s_node.xpath(".//Parameter"): params.update(attrs.attrib) return params buf_params = AttributeDict() # Storing value to avoid recomputing each call device_model_name = self.device_model_name if device_model_name: buf_params["Name"] = device_model_name if self.device_conf_filename: buf_params["DeviceConfigPath"] = self.device_conf_filename node = self.device_root_node buf_params['device_modules'] = self.extract_device_modules(node) for section_node in list(node): buf_params[section_node.tag] = extract_params(section_node) self._device_conf = buf_params def _parse_bench_node(self, node): """ Parses XML `Phone` node(s) from Bench Catalog file and maps it into a python structure (dict) :return: A dict mapping XML configuration :rtype: AttributeDict :raise AcsConfigException.INVALID_BENCH_CONFIG: If a (or more) deprecated parameter(s) is/are found in a Phone node """ LOGGER_FWK.info( 'Loading optional device model parameters from CLI and/or BenchConfig ' 'for {0} ({1})...'.format(self._device_name, self._device_model_name)) buf_params = AttributeDict() # Storing value to avoid recomputing each call device_model_name = self.device_model_name if device_model_name: buf_params["Name"] = device_model_name if self.device_conf_filename: buf_params["DeviceConfigPath"] = self.device_conf_filename # Get phone properties for attrs in node.xpath(".//Parameter"): name, value, description = attrs.get("name"), attrs.get( "value"), attrs.get("description") if name in self.PROHIBITIVE_KEYS: # Do not allow to override internal keys # as it would lead to nasty & unexpected behavior !! continue # Not supported anymore, raise AcsConfigException.INVALID_BENCH_CONFIG !! if name and value: buf_params[name] = value self._bench_conf_deprecated[name] = (value, description) else: buf_params.update(attrs.attrib) # Report Errors if so if self.bench_contains_errors: LOGGER_FWK.error(self._report_errors()) _error( 'Invalid Bench Parameters format found! {0}'.format(', '.join( self._bench_conf_deprecated.keys())), AcsConfigException.INVALID_BENCH_CONFIG) # Extracting device modules if so buf_params.device_modules = self.extract_device_modules(node) return buf_params def _override_through_sections(self, conf, key_lookup, value_lookup, unknown): """ Implement Section Lookup through a dict. :param conf: The configuration dict :type conf: dict or AttributeDict .. important:: As the method returns nothing (None), you must pass a reference you hold as `conf` parameter. **This reference is modified inside the method only** :param key_lookup: The key to look up :type key_lookup: str :param value_lookup: The value to set :type value_lookup: object :param unknown: A dict designed to store unknown Key(s)/Value(s) :type unknown: dict or AttributeDict """ for existing_key, v in conf.copy().iteritems(): if isinstance(v, dict): self._override_through_sections(v, key_lookup, value_lookup, unknown) continue if existing_key != key_lookup: unknown[key_lookup] = value_lookup else: conf[key_lookup] = value_lookup def _override_parameters_cli(self): """ Override device config with device parameters available in CLI parameters (**-o**) if applicable. """ if self._device_name == AcsConstants.DEFAULT_DEVICE_NAME: for param, value in self.cli_parameters: self._override_through_sections(self.device_conf, param, value, self._cli_unknown_parameters) def _override_parameters_bench(self): """ Override device config with device parameters available in bench config if applicable. """ device_model_name = self.device_model_name device_name = self._device_name if self.bench_conf: do_the_override = False if device_name == AcsConstants.DEFAULT_DEVICE_NAME: if "Name" not in self.bench_conf: # No device specified in the bench config for PHONE1 # Do the override then do_the_override = True elif self.bench_conf.Name == device_model_name: # Same device specified on the command line then in the bench config # Do the override do_the_override = True else: warning_msg = ( "Different device model specified on the command line ({0}) " "then in the bench config ({1}) for {2}! Related parameters specified " "in bench config will be ignored !").format( device_model_name, self.bench_conf.Name, AcsConstants.DEFAULT_DEVICE_NAME) LOGGER_FWK.warning(warning_msg) else: # For other phones (PHONE2, ...) we do the override every time do_the_override = True if do_the_override: for key, value in self.bench_conf.iteritems(): if key == "device_modules": for module, module_conf in value.iteritems(): self.device_conf.device_modules[ module] = module_conf else: self._override_through_sections( self.device_conf, key, value, self._bench_unknown_parameters) def _validate(self): """ Asserts that the given Device Model Configuration match its associated Contract :raise: AcsConfigException """ try: self.device_schema.assertValid(self.device_model_final) except (etree.XMLSchemaParseError, etree.DocumentInvalid) as assert_error: flag = AcsConfigException.XML_PARSING_ERROR if isinstance(assert_error, etree.DocumentInvalid): flag = AcsConfigException.INVALID_PARAMETER _error(assert_error.message, flag) def _report_errors(self): """ Reports all warnings found in BenchConfig, CLI, ... """ report = None if self.bench_contains_errors: report = self.DEPRECATED_OVERRIDE_MSG.format( self.bench_conf_filename) report += '\n\nUnsupported format\n' report += '******************\n' for k, data in self._bench_conf_deprecated.iteritems(): value, description = data report += self.DEPRECATED_ELEMENT_MSG.format( k, value, 'description="{0}"'.format(description) if description else "") report += '\n\nExpected format (to copy in BenchConfig)\n' report += '****************************************\n' for k, data in self._bench_conf_deprecated.iteritems(): value, description = data report += self.RECOMMENDED_ELEMENT_MSG.format( k, _check_and_format_value(value), 'description="{0}"'.format(description) if description else "") report += '\n' return report def load(self): """ Public method which acts as device configuration loader. :rtype: dict :return: A dict containing all device parameters """ self._load_cli_conf() self._load_bench_conf() self._load_device_conf() # Load the device config from the device catalog if not self.device_conf: _error( "ACS single mode : No device config found for device {0} !". format(self._device_model_name), AcsConfigException.INVALID_PARAMETER) # Override Current DUT parameters from Bench ... self._override_parameters_bench() # ... and CLI self._override_parameters_cli() LOGGER_FWK.info('Checking device model integrity...') # Asserts All Device Model is valid (Parameters) self._validate() return self.device_only_params
def __init__(self): super(CameraModule, self).__init__() self._camera_properties = AttributeDict()
def __init__(self): super(NetworkingModule, self).__init__() self._networking_properties = AttributeDict()