def test_eq(self): # Copy tree2 = copy.deepcopy(self.tree) self.assertEqual(self.tree, tree2) # Additional node child = mux.MuxTreeNode("20", {'name': 'Heisenbug'}) tree2.children[1].children[1].add_child(child) self.assertNotEqual(self.tree, tree2) # Should match again child.detach() self.assertEqual(self.tree, tree2) # Missing node tree2.children[1].children[1].detach() self.assertNotEqual(self.tree, tree2) self.assertEqual(self.tree.children[0], tree2.children[0]) # Different value tree2.children[0].children[0].children[0].value = {'something': 'else'} self.assertNotEqual(self.tree.children[0], tree2.children[0]) tree3 = mux.MuxTreeNode() self.assertNotEqual(tree3, tree2) # Merge tree3.merge(tree2) self.assertEqual(tree3, tree2) # Add_child existing tree3.add_child(tree2.children[0]) self.assertEqual(tree3, tree2)
def test_tree_mux_node(self): """ Check the extension of fingerprint in MuxTreeNode """ node1 = tree.TreeNode("node1", {"foo": "bar"}) node1m = mux.MuxTreeNode("node1", {"foo": "bar"}) node1m_fingerprint = node1m.fingerprint() self.assertNotEqual(node1.fingerprint(), node1m_fingerprint) node1mduplicate = mux.MuxTreeNode("node1", {"foo": "bar"}) self.assertEqual(node1m_fingerprint, node1mduplicate.fingerprint()) node1mb_ctrl = mux.MuxTreeNode("node1", {"foo": "bar"}) node1mb_ctrl.ctrl = [mux.Control(0, 0)] self.assertNotEqual(node1m_fingerprint, node1mb_ctrl.fingerprint())
def _mapping_to_tree_loader(loader, node, looks_like_node=False): """Maps yaml mapping tag to TreeNode structure""" _value = [] for key_node, value_node in node.value: # Allow only strings as dict keys if key_node.tag.startswith('!'): # reflect tags everywhere key = loader.construct_object(key_node) else: key = loader.construct_scalar(key_node) # If we are to keep them, use following, but we lose the control # for both, nodes and dicts # key = loader.construct_object(key_node) if isinstance(key, mux.Control): looks_like_node = True value = loader.construct_object(value_node) if isinstance(value, ListOfNodeObjects): looks_like_node = True _value.append((key, value)) if not looks_like_node: return collections.OrderedDict(_value) objects = ListOfNodeObjects() for name, values in _value: if isinstance(values, ListOfNodeObjects): # New node from list objects.append(_tree_node_from_values(loader.path, name, values, loader.using)) elif values is None: # Empty node objects.append(mux.MuxTreeNode(astring.to_text(name))) elif values == 'null': objects.append((name, None)) else: # Values objects.append((name, values)) return objects
def create_from_yaml(paths): """Create tree structure from yaml-like file. :param paths: File object to be processed :raise SyntaxError: When yaml-file is corrupted :return: Root of the created tree structure """ def _merge(data, path): """Normal run""" tmp = _create_from_yaml(path) if tmp: data.merge(tmp) data = mux.MuxTreeNode() path = None try: for path in paths: _merge(data, path) # Yaml can raise IndexError on some files except (yaml.YAMLError, IndexError) as details: if ('mapping values are not allowed in this context' in astring.to_text(details)): details = ("%s\nMake sure !tags and colons are separated by a " "space (eg. !include :)" % details) msg = "Invalid multiplex file '%s': %s" % (path, details) raise IOError(2, msg, path) return data
def test_handle_control_path_include_file_does_not_exist(self): with self.assertRaises(ValueError): # pylint: disable=W0212 yaml_to_mux._handle_control_tag( 'original_fake_file.yaml', mux.MuxTreeNode, mux.MuxTreeNode(), (mux.Control( yaml_to_mux.YAML_INCLUDE), 'unexisting_include.yaml'))
def test_handle_control_path_remove(self): node = mux.MuxTreeNode() control = mux.Control(yaml_to_mux.YAML_REMOVE_NODE) to_be_removed = 'node_to_be_removed' # pylint: disable=W0212 yaml_to_mux._handle_control_tag('fake_path', node, (control, to_be_removed)) self.assertEqual(control.value, to_be_removed) self.assertIn(control, node.ctrl)
def initialize(self, config): subcommand = config.get('subcommand') data = None # Merge the multiplex multiplex_files = config.get("yaml_to_mux.files") if multiplex_files: data = mux.MuxTreeNode() try: data.merge(create_from_yaml(multiplex_files)) except IOError as details: error_msg = "%s : %s" % (details.strerror, details.filename) LOG_UI.error(error_msg) if subcommand == 'run': sys.exit(exit_codes.AVOCADO_JOB_FAIL) else: sys.exit(exit_codes.AVOCADO_FAIL) # Extend default multiplex tree of --mux-inject values for inject in config.get("yaml_to_mux.inject"): entry = inject.split(':', 2) if len(entry) < 2: raise ValueError("key:entry pairs required, found only %s" % (entry)) elif len(entry) == 2: # key, entry entry.insert(0, '') # add path='' (root) # We try to maintain the data type of the provided value try: entry[2] = ast.literal_eval(entry[2]) except (ValueError, SyntaxError, NameError, RecursionError): pass if data is None: data = mux.MuxTreeNode() data.get_node(entry[0], True).value[entry[1]] = entry[2] if data is not None: mux_filter_only = config.get('yaml_to_mux.filter_only') mux_filter_out = config.get('yaml_to_mux.filter_out') data = mux.apply_filters(data, mux_filter_only, mux_filter_out) paths = config.get("yaml_to_mux.parameter_paths") self.initialize_mux(data, paths)
def test_merge_trees(self): tree2 = copy.deepcopy(self.tree) tree3 = mux.MuxTreeNode() tree3.add_child(mux.MuxTreeNode('hw', {'another_value': 'bbb'})) tree3.children[0].add_child(mux.MuxTreeNode('nic')) tree3.children[0].children[0].add_child(mux.MuxTreeNode('default')) tree3.children[0].children[0].add_child( mux.MuxTreeNode('virtio', {'nic': 'virtio'})) tree3.children[0].add_child( mux.MuxTreeNode('cpu', {'test_value': ['z']})) tree2.merge(tree3) exp = [ 'intel', 'amd', 'arm', 'scsi', 'virtio', 'default', 'virtio', 'fedora', u'\u0161mint', 'prod' ] self.assertEqual(exp, tree2.get_leaves()) self.assertEqual( { 'corruptlist': ['upper_node_list'], 'another_value': 'bbb' }, tree2.children[0].value) self.assertEqual({ 'joinlist': ['first_item'], 'test_value': ['z'] }, tree2.children[0].children[0].value) self.assertFalse(tree2.children[0].children[2].children[0].value) self.assertEqual({'nic': 'virtio'}, tree2.children[0].children[2].children[1].value)
def _create_from_yaml(path): """Create tree structure from yaml stream""" # Parse file name ([$using:]$path) path = __RE_FILE_SPLIT.split(path, 1) if len(path) == 1: path = __RE_FILE_SUBS.sub(':', path[0]) using = ["run"] else: nodes = __RE_FILE_SUBS.sub(':', path[0]).strip('/').split('/') using = [node for node in nodes if node] if not path[0].startswith('/'): # relative path, put into /run using.insert(0, 'run') path = __RE_FILE_SUBS.sub(':', path[1]) # For loader instance needs different "path" and "using" values class Loader(_BaseLoader): _BaseLoader.path = path _BaseLoader.using = using # Load the tree with open(path, encoding='utf-8') as stream: loaded_tree = yaml.load(stream, Loader) # nosec if loaded_tree is None: return loaded_tree = _tree_node_from_values(path, '', loaded_tree, using) # Add prefix if using: loaded_tree.name = using.pop() while True: if not using: break loaded_tree = mux.MuxTreeNode(using.pop(), children=[loaded_tree]) loaded_tree = mux.MuxTreeNode('', children=[loaded_tree]) return loaded_tree
def _apply_using(name, using, node): """ Create the structure defined by "!using" and return the new root :param name: the tag name to have the "!using" applied to :type name: str :param using: the new location to put the tag into :type using: bool :param node: the node in which to handle control tags :type node: instance of :class:`avocado.core.tree.TreeNode` or similar """ if name != '': for name in using.split('/')[::-1]: node = mux.MuxTreeNode(name, children=[node]) else: using = using.split('/')[::-1] node.name = using.pop() while True: if not using: break name = using.pop() # 'using' is list pylint: disable=E1101 node = mux.MuxTreeNode(name, children=[node]) node = mux.MuxTreeNode('', children=[node]) return node
def _tree_node_from_values(path, name, values, using): """Create `name` node and add values""" # Initialize the node node = mux.MuxTreeNode(astring.to_text(name)) if not values: return node using = '' # Fill the node content from parsed values if isinstance(values, dict): using = _node_content_from_dict(path, node, values, using) else: using = _node_content_from_node(path, node, values, using) # Prefix nodes if tag "!using" was used if using: node = _apply_using(name, using, node) return node
def test_apply_using(self): # pylint: disable=W0212 node = yaml_to_mux._apply_using('bar', 'foo', mux.MuxTreeNode()) self.assertEqual(node.path, '/foo')
def test_empty(self): act = tuple(mux.MuxTree(mux.MuxTreeNode())) self.assertEqual(act, ([ '', ], ))
def test_apply_using(self): node = yaml_to_mux._apply_using('bar', mux.MuxTreeNode, 'foo', mux.MuxTreeNode()) self.assertEqual(node.path, '/foo')