Example #1
0
    def test_tree_concurrent_timeout(self, monkeypatch):
        # Much shorter timeout
        monkeypatch.setattr('fmf.utils.NODE_LOCK_TIMEOUT', 2)

        def long_fetch(*args, **kwargs):
            # Longer than timeout
            time.sleep(7)
            return EXAMPLES

        # Patch fetch to sleep and later return tmpdir path
        monkeypatch.setattr('fmf.utils.fetch_repo', long_fetch)

        # Background thread to get node() acquiring lock
        def target():
            Tree.node({
                'url': 'localhost',
                'name': '/',
            })

        thread = threading.Thread(target=target)
        thread.start()

        # Small sleep to mitigate race
        time.sleep(2)

        # "Real" fetch shouldn't get the lock
        with pytest.raises(utils.GeneralError):
            Tree.node({
                'url': 'localhost',
                'name': '/',
            })

        # Wait on parallel thread to finish
        thread.join()
Example #2
0
 def test_scatter(self):
     """ Scattered files """
     scatter = Tree(EXAMPLES + "scatter").find("/object")
     assert (len(list(scatter.climb())) == 1)
     assert (scatter.data['one'] == 1)
     assert (scatter.data['two'] == 2)
     assert (scatter.data['three'] == 3)
Example #3
0
 def test_deep_dictionary(self):
     """ Get value from a deep dictionary """
     deep = Tree(EXAMPLES + "deep")
     assert deep.data['hardware']['memory']['size'] == 8
     assert deep.get(['hardware', 'memory', 'size']) == 8
     assert deep.get(['hardware', 'bad', 'size'], 12) == 12
     assert deep.get('nonexistent', default=3) == 3
Example #4
0
    def test_tree_node_remote(self):
        reference = {
            'url': FMF_REPO,
            'ref': '0.10',
            'path': 'examples/deep',
            'name': '/one/two/three',
        }

        # Values of test in 0.10 tag
        expected_data = {
            'hardware': {
                'memory': {
                    'size': 8
                },
                'network': {
                    'model': 'e1000'
                }
            },
            'key': 'value'
        }

        # Full identifier
        node = Tree.node(reference)
        assert (node.get() == expected_data)

        # Default ref
        reference.pop('ref')
        node = Tree.node(reference)
        assert (node.get() == expected_data)

        # Raise exception for invalid tree nodes
        with pytest.raises(utils.ReferenceError):
            reference['name'] = 'not_existing_name_'
            node = Tree.node(reference)
Example #5
0
 def test_deep_modify(self):
     """ Deep structures """
     requirements = self.wget.find('/requirements')
     protocols = self.wget.find('/requirements/protocols')
     ftp = self.wget.find('/requirements/protocols/ftp')
     # Modify data and store to disk
     with requirements as data:
         data['new'] = 'some'
     with protocols as data:
         data.update(dict(coverage="changed", new_attr="val"))
     with ftp as data:
         data['server'] = 'vsftpd'
     # Reload the data and verify
     self.wget = Tree(self.tempdir)
     requirements = self.wget.find('/requirements')
     protocols = self.wget.find('/requirements/protocols')
     ftp = self.wget.find('/requirements/protocols/ftp')
     self.assertEqual(requirements.data["new"], "some")
     self.assertEqual(protocols.data["new"], "some")
     self.assertEqual(ftp.data["new"], "some")
     self.assertNotIn("server", protocols.data)
     self.assertIn("server", ftp.data)
     self.assertNotIn("new_attr", requirements.data)
     self.assertIn("new_attr", protocols.data)
     self.assertIn("new_attr", ftp.data)
     self.assertEqual(protocols.data["coverage"], "changed")
     self.assertIn('adjust', ftp.data)
     self.assertEqual(ftp.data['adjust'][0]['enabled'], False)
     self.assertEqual(ftp.data['adjust'][0]['when'], "arch != x86_64")
Example #6
0
 def test_modify_empty(self):
     """ Nodes with no content should be handled as an empty dict """
     with self.wget.find('/download/requirements/spider') as data:
         data['x'] = 1
     self.wget = Tree(self.tempdir)
     node = self.wget.find('/download/requirements/spider')
     self.assertEqual(node.data['x'], 1)
Example #7
0
 def test_basic(self):
     """ No directory path given """
     with pytest.raises(utils.GeneralError):
         Tree("")
     with pytest.raises(utils.GeneralError):
         Tree(None)
     with pytest.raises(utils.RootError):
         Tree("/")
Example #8
0
 def test_modify_unicode(self):
     """ Ensure that unicode characters are properly handled """
     path = os.path.join(self.tempdir, 'unicode.fmf')
     with io.open(path, 'w', encoding='utf-8') as file:
         file.write('jméno: Leoš')
     with Tree(self.tempdir).find('/unicode') as data:
         data['příjmení'] = 'Janáček'
     reloaded = Tree(self.tempdir).find('/unicode')
     assert reloaded.get('jméno') == 'Leoš'
     assert reloaded.get('příjmení') == 'Janáček'
Example #9
0
 def test_modify_clear(self):
     """ Clear node data """
     item = '/requirements/protocols/ftp'
     with self.wget.find(item) as data:
         data.clear()
     self.wget = Tree(self.tempdir)
     node = self.wget.find(item)
     self.assertNotIn('coverage', node.data)
     self.assertIn('tester', node.data)
     self.assertNotIn('requirement', node.data)
Example #10
0
 def test_deep_hierarchy(self):
     """ Multiple virtual hierarchy levels shortcut """
     with open(os.path.join(self.tempdir, 'deep.fmf'), 'w') as file:
         file.write('/one/two/three:\n x: 1\n')
     deep = Tree(self.tempdir).find('/deep/one/two/three')
     with deep as data:
         data['y'] = 2
     deep = Tree(self.tempdir).find('/deep/one/two/three')
     self.assertEqual(deep.get('x'), 1)
     self.assertEqual(deep.get('y'), 2)
Example #11
0
 def test_modify_pop(self):
     """ Pop elements from node data """
     item = '/requirements/protocols/ftp'
     with self.wget.find(item) as data:
         data.pop('coverage')
         data.pop('tester+')
     self.wget = Tree(self.tempdir)
     node = self.wget.find(item)
     self.assertNotIn('coverage', node.data)
     self.assertIn('tester', node.data)
     self.assertIn('requirement', node.data)
Example #12
0
 def test_context_manager(self):
     """ Use context manager to save node data """
     item = '/requirements/protocols/ftp'
     with self.wget.find(item) as data:
         data.pop("coverage")
         data.pop("tester+")
         data.update(dict(server="vsftpd"))
     self.wget = Tree(self.tempdir)
     node = self.wget.find(item)
     self.assertNotIn('coverage', node.data)
     self.assertIn('tester', node.data)
     self.assertIn('requirement', node.data)
     self.assertIn("server", node.data)
Example #13
0
 def test_tree_commit(self, tmpdir):
     # Tag
     node = Tree.node(dict(url=FMF_REPO, ref='0.12'))
     assert node.commit == '6570aa5f10729991625d74036473a71f384d745b'
     # Hash
     node = Tree.node(dict(url=FMF_REPO, ref='fa05dd9'))
     assert 'fa05dd9' in node.commit
     assert 'fa05dd9' in node.commit  # return already detected value
     # Data
     node = Tree(dict(x=1))
     assert node.commit is False
     # No git repository
     tree = Tree(Tree.init(str(tmpdir)))
     assert tree.commit is False
Example #14
0
 def test_tree_node_local(self):
     reference = {
         'path': EXAMPLES + 'wget',
         'name': '/protocols/https',
     }
     node = Tree.node(reference)
     assert node.get('time') == '1 min'
Example #15
0
 def test_scattered_inheritance(self):
     """ Inheritance of scattered files """
     grandson = Tree(EXAMPLES + "child").find("/son/grandson")
     assert (grandson.data['name'] == 'Hugo')
     assert (grandson.data['eyes'] == 'blue')
     assert (grandson.data['nose'] == 'long')
     assert (grandson.data['hair'] == 'fair')
Example #16
0
 def test_inheritance(self):
     """ Inheritance and data types """
     item = self.wget.find('/recursion/deep')
     item_parent = self.wget.find('/recursion')
     # Modify data and store to disk
     with item as data:
         data.update(dict(depth=2000, new="two\nlines"))
     with item.parent as data:
         data.update(dict(parent_attr="value"))
     # Reload the data and verify
     self.wget = Tree(self.tempdir)
     item = self.wget.find('/recursion/deep')
     self.assertEqual(item.data['tags'], ['Tier2'])
     self.assertEqual(item.parent.data['tags'], ['Tier2'])
     self.assertEqual(item.data['depth'], 2000)
     self.assertIn('depth', item.data)
     self.assertNotIn('depth', item.parent.data)
     self.assertEqual(item.data['new'], "two\nlines")
     self.assertEqual(item.data['parent_attr'], "value")
     with open(os.path.join(self.tempdir, 'recursion/deep.fmf')) as file:
         self.assertTrue(re.search('two\n +lines', file.read()))
Example #17
0
 def test_modify_after_adjust(self):
     """ Preserve original data even when adjust is used """
     item = '/requirements/protocols/ftp'
     wget = Tree(self.tempdir)
     # Expects new attribute + original data
     expected = {'new_attr': "new_value"}
     expected.update(wget.find(item).copy().get())
     wget.adjust(Context(arch='ppc64le'))
     with wget.find(item) as data:
         data['new_attr'] = "new_value"
     assert expected == Tree(self.tempdir).find(item).get()
Example #18
0
 def test_inaccessible_directories(self):
     """ Inaccessible directories should be silently ignored """
     directory = tempfile.mkdtemp()
     accessible = os.path.join(directory, 'accessible')
     inaccessible = os.path.join(directory, 'inaccessible')
     os.mkdir(accessible, 511)
     os.mkdir(inaccessible, 000)
     with open(os.path.join(accessible, 'main.fmf'), 'w') as main:
         main.write('key: value\n')
     Tree.init(directory)
     tree = Tree(directory)
     assert tree.find('/accessible').get('key') == 'value'
     assert tree.find('/inaccessible') is None
     os.chmod(inaccessible, 511)
     rmtree(directory)
Example #19
0
 def setUp(self):
     self.wget_path = EXAMPLES + "wget"
     self.tempdir = tempfile.mktemp()
     copytree(self.wget_path, self.tempdir)
     self.wget = Tree(self.tempdir)
Example #20
0
class TestModify(unittest.TestCase):
    """ Verify storing modifed data to disk """
    def setUp(self):
        self.wget_path = EXAMPLES + "wget"
        self.tempdir = tempfile.mktemp()
        copytree(self.wget_path, self.tempdir)
        self.wget = Tree(self.tempdir)

    def tearDown(self):
        rmtree(self.tempdir)

    def test_inheritance(self):
        """ Inheritance and data types """
        item = self.wget.find('/recursion/deep')
        item_parent = self.wget.find('/recursion')
        # Modify data and store to disk
        with item as data:
            data.update(dict(depth=2000, new="two\nlines"))
        with item.parent as data:
            data.update(dict(parent_attr="value"))
        # Reload the data and verify
        self.wget = Tree(self.tempdir)
        item = self.wget.find('/recursion/deep')
        self.assertEqual(item.data['tags'], ['Tier2'])
        self.assertEqual(item.parent.data['tags'], ['Tier2'])
        self.assertEqual(item.data['depth'], 2000)
        self.assertIn('depth', item.data)
        self.assertNotIn('depth', item.parent.data)
        self.assertEqual(item.data['new'], "two\nlines")
        self.assertEqual(item.data['parent_attr'], "value")
        with open(os.path.join(self.tempdir, 'recursion/deep.fmf')) as file:
            self.assertTrue(re.search('two\n +lines', file.read()))

    def test_deep_modify(self):
        """ Deep structures """
        requirements = self.wget.find('/requirements')
        protocols = self.wget.find('/requirements/protocols')
        ftp = self.wget.find('/requirements/protocols/ftp')
        # Modify data and store to disk
        with requirements as data:
            data['new'] = 'some'
        with protocols as data:
            data.update(dict(coverage="changed", new_attr="val"))
        with ftp as data:
            data['server'] = 'vsftpd'
        # Reload the data and verify
        self.wget = Tree(self.tempdir)
        requirements = self.wget.find('/requirements')
        protocols = self.wget.find('/requirements/protocols')
        ftp = self.wget.find('/requirements/protocols/ftp')
        self.assertEqual(requirements.data["new"], "some")
        self.assertEqual(protocols.data["new"], "some")
        self.assertEqual(ftp.data["new"], "some")
        self.assertNotIn("server", protocols.data)
        self.assertIn("server", ftp.data)
        self.assertNotIn("new_attr", requirements.data)
        self.assertIn("new_attr", protocols.data)
        self.assertIn("new_attr", ftp.data)
        self.assertEqual(protocols.data["coverage"], "changed")
        self.assertIn('adjust', ftp.data)
        self.assertEqual(ftp.data['adjust'][0]['enabled'], False)
        self.assertEqual(ftp.data['adjust'][0]['when'], "arch != x86_64")

    def test_deep_hierarchy(self):
        """ Multiple virtual hierarchy levels shortcut """
        with open(os.path.join(self.tempdir, 'deep.fmf'), 'w') as file:
            file.write('/one/two/three:\n x: 1\n')
        deep = Tree(self.tempdir).find('/deep/one/two/three')
        with deep as data:
            data['y'] = 2
        deep = Tree(self.tempdir).find('/deep/one/two/three')
        self.assertEqual(deep.get('x'), 1)
        self.assertEqual(deep.get('y'), 2)

    def test_modify_empty(self):
        """ Nodes with no content should be handled as an empty dict """
        with self.wget.find('/download/requirements/spider') as data:
            data['x'] = 1
        self.wget = Tree(self.tempdir)
        node = self.wget.find('/download/requirements/spider')
        self.assertEqual(node.data['x'], 1)

    def test_modify_pop(self):
        """ Pop elements from node data """
        item = '/requirements/protocols/ftp'
        with self.wget.find(item) as data:
            data.pop('coverage')
            data.pop('tester+')
        self.wget = Tree(self.tempdir)
        node = self.wget.find(item)
        self.assertNotIn('coverage', node.data)
        self.assertIn('tester', node.data)
        self.assertIn('requirement', node.data)

    def test_modify_clear(self):
        """ Clear node data """
        item = '/requirements/protocols/ftp'
        with self.wget.find(item) as data:
            data.clear()
        self.wget = Tree(self.tempdir)
        node = self.wget.find(item)
        self.assertNotIn('coverage', node.data)
        self.assertIn('tester', node.data)
        self.assertNotIn('requirement', node.data)

    def test_modify_unsupported_method(self):
        """ Raise error for trees initialized from a dict """
        with pytest.raises(GeneralError, match='No raw data'):
            with Tree(dict(x=1)) as data:
                data['y'] = 2

    def test_context_manager(self):
        """
        try to use context manager for save node data
        """
        item = '/requirements/protocols/ftp'
        with self.wget.find(item) as data:
            data.pop("coverage")
            data.pop("tester+")
            data.update(dict(server="vsftpd"))
        self.wget = Tree(self.tempdir)
        node = self.wget.find(item)
        self.assertNotIn('coverage', node.data)
        self.assertIn('tester', node.data)
        self.assertIn('requirement', node.data)
        self.assertIn("server", node.data)
Example #21
0
 def test_modify_unsupported_method(self):
     """ Raise error for trees initialized from a dict """
     with pytest.raises(GeneralError, match='No raw data'):
         with Tree(dict(x=1)) as data:
             data['y'] = 2
Example #22
0
class TestTree(object):
    """ Tree class """
    def setup_method(self, method):
        """ Load examples """
        self.wget = Tree(EXAMPLES + "wget")
        self.merge = Tree(EXAMPLES + "merge")

    def test_basic(self):
        """ No directory path given """
        with pytest.raises(utils.GeneralError):
            Tree("")
        with pytest.raises(utils.GeneralError):
            Tree(None)
        with pytest.raises(utils.RootError):
            Tree("/")

    def test_hidden(self):
        """ Hidden files and directories """
        assert (".hidden" not in self.wget.children)

    def test_inheritance(self):
        """ Inheritance and data types """
        deep = self.wget.find('/recursion/deep')
        assert (deep.data['depth'] == 1000)
        assert (deep.data['description'] == 'Check recursive download options')
        assert (deep.data['tags'] == ['Tier2'])

    def test_scatter(self):
        """ Scattered files """
        scatter = Tree(EXAMPLES + "scatter").find("/object")
        assert (len(list(scatter.climb())) == 1)
        assert (scatter.data['one'] == 1)
        assert (scatter.data['two'] == 2)
        assert (scatter.data['three'] == 3)

    def test_scattered_inheritance(self):
        """ Inheritance of scattered files """
        grandson = Tree(EXAMPLES + "child").find("/son/grandson")
        assert (grandson.data['name'] == 'Hugo')
        assert (grandson.data['eyes'] == 'blue')
        assert (grandson.data['nose'] == 'long')
        assert (grandson.data['hair'] == 'fair')

    def test_subtrees(self):
        """ Subtrees should be ignored """
        child = Tree(EXAMPLES + "child")
        assert child.find("/nobody") is None

    def test_empty(self):
        """ Empty structures should be ignored """
        child = Tree(EXAMPLES + "empty")
        assert child.find("/nothing") is None
        assert child.find("/zero") is None

    def test_none_key(self):
        """ Handle None keys """
        with pytest.raises(utils.FormatError):
            tree = Tree({None: "weird key"})

    def test_deep_hierarchy(self):
        """ Deep hierarchy on one line """
        deep = Tree(EXAMPLES + "deep")
        assert len(deep.children) == 1

    def test_deep_dictionary(self):
        """ Get value from a deep dictionary """
        deep = Tree(EXAMPLES + "deep")
        assert deep.data['hardware']['memory']['size'] == 8
        assert deep.get(['hardware', 'memory', 'size']) == 8
        assert deep.get(['hardware', 'bad', 'size'], 12) == 12
        assert deep.get('nonexistent', default=3) == 3

    def test_merge_plus(self):
        """ Extending attributes using the '+' suffix """
        child = self.merge.find('/parent/extended')
        assert ('General' in child.data['description'])
        assert ('Specific' in child.data['description'])
        assert (child.data['tags'] == ['Tier1', 'Tier2', 'Tier3'])
        assert (child.data['time'] == 15)
        assert (child.data['vars'] == dict(x=1, y=2, z=3))
        assert (child.data['disabled'] == True)
        assert ('time+' not in child.data)
        with pytest.raises(utils.MergeError):
            child.data["time+"] = "string"
            child.inherit()

    def test_merge_minus(self):
        """ Reducing attributes using the '-' suffix """
        child = self.merge.find('/parent/reduced')
        assert ('General' in child.data['description'])
        assert ('description' not in child.data['description'])
        assert (child.data['tags'] == ['Tier1'])
        assert (child.data['time'] == 5)
        assert (child.data['vars'] == dict(x=1, y=2))
        assert ('time+' not in child.data)
        with pytest.raises(utils.MergeError):
            child.data["disabled-"] = True
            child.inherit()
        child.data.pop('disabled-')
        with pytest.raises(utils.MergeError):
            child.data["time-"] = "bad"
            child.inherit()

    def test_get(self):
        """ Get attributes """
        assert (isinstance(self.wget.get(), dict))
        assert ('Petr' in self.wget.get('tester'))

    def test_show(self):
        """ Show metadata """
        assert (isinstance(self.wget.show(brief=True), type("")))
        assert (self.wget.show(brief=True).endswith("\n"))
        assert (isinstance(self.wget.show(), type("")))
        assert (self.wget.show().endswith("\n"))
        assert ('tester' in self.wget.show())

    def test_update(self):
        """ Update data """
        data = self.wget.get()
        self.wget.update(None)
        assert (self.wget.data == data)

    def test_find_node(self):
        """ Find node by name """
        assert (self.wget.find("non-existent") == None)
        protocols = self.wget.find('/protocols')
        assert (isinstance(protocols, Tree))

    def test_find_root(self):
        """ Find metadata tree root """
        tree = Tree(os.path.join(EXAMPLES, "wget", "protocols"))
        assert (tree.find("/download/test"))

    def test_yaml_syntax_errors(self):
        """ Handle YAML syntax errors """
        path = tempfile.mkdtemp()
        fmf.cli.main("fmf init", path)
        with open(os.path.join(path, "main.fmf"), "w") as main:
            main.write("missing\ncolon:")
        with pytest.raises(utils.FileError):
            tree = fmf.Tree(path)
        rmtree(path)
Example #23
0
 def setUp(self):
     self.wget_path = EXAMPLES + "wget"
     self.wget = Tree(self.wget_path)
Example #24
0
 def target():
     Tree.node({
         'url': 'localhost',
         'name': '/',
     })
Example #25
0
 def test_deep_hierarchy(self):
     """ Deep hierarchy on one line """
     deep = Tree(EXAMPLES + "deep")
     assert len(deep.children) == 1
Example #26
0
 def test_none_key(self):
     """ Handle None keys """
     with pytest.raises(utils.FormatError):
         tree = Tree({None: "weird key"})
Example #27
0
 def test_empty(self):
     """ Empty structures should be ignored """
     child = Tree(EXAMPLES + "empty")
     assert child.find("/nothing") is None
     assert child.find("/zero") is None
Example #28
0
 def test_find_root(self):
     """ Find metadata tree root """
     tree = Tree(os.path.join(EXAMPLES, "wget", "protocols"))
     assert (tree.find("/download/test"))
Example #29
0
 def test_subtrees(self):
     """ Subtrees should be ignored """
     child = Tree(EXAMPLES + "child")
     assert child.find("/nobody") is None
Example #30
0
 def setup_method(self, method):
     """ Load examples """
     self.wget = Tree(EXAMPLES + "wget")
     self.merge = Tree(EXAMPLES + "merge")