Esempio n. 1
0
    def test_fetch_concurrent_timeout(self, monkeypatch, tmpdir):
        # Much shorter timeout
        monkeypatch.setattr('fmf.utils.FETCH_LOCK_TIMEOUT', 2)

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

        # Patch run to use sleep instead
        monkeypatch.setattr('fmf.utils.run', long_run)

        # Background thread to fetch() the same destination acquiring lock
        def target():
            utils.fetch(GIT_REPO, '0.10', destination=str(tmpdir))

        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):
            utils.fetch(GIT_REPO, '0.10', destination=str(tmpdir))

        # Wait on parallel thread to finish
        thread.join()
Esempio n. 2
0
 def test_env(self):
     # Nonexistent repo on github makes git to ask for password
     # Set handler for user input as echo to return immediately
     with pytest.raises(utils.GeneralError) as error:
         utils.fetch('https://github.com/psss/fmf-nope-nope.git',
                     env={"GIT_ASKPASS": "******"})
     # Assert 'git clone' string in exception's message
     assert "git clone" in error.value.args[0]
Esempio n. 3
0
 def test_fetch_default_branch(self):
     # On GitHub 'master' is the default
     repo = utils.fetch(GIT_REPO)
     output, _ = run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], repo)
     assert 'master' in output
     # Fedora uses 'rawide'
     repo = utils.fetch(GIT_REPO_FEDORA)
     output, _ = run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], repo)
     assert 'rawhide' in output
Esempio n. 4
0
    def test_destination(self, tmpdir, trailing):
        # Does not exist
        dest = str(tmpdir.join('branch_new' + trailing))
        repo = utils.fetch(GIT_REPO, destination=dest)
        assert repo == dest
        assert os.path.isfile(os.path.join(repo, 'fmf.spec'))

        # Is an empty directory
        dest = str(tmpdir.mkdir('another' + trailing))
        repo = utils.fetch(GIT_REPO, destination=dest)
        assert repo == dest
        assert os.path.isfile(os.path.join(repo, 'fmf.spec'))
Esempio n. 5
0
 def test_out_of_sync_ref(self, ref):
     """ Solve Your branch is behind ... """
     repo = utils.fetch(GIT_REPO, ref)
     out, err = run(["git", "rev-parse", "HEAD"], repo)
     old_ref = out
     # Move head one commit back, doesn't invalidate FETCH!
     out, err = run(["git", "reset", "--hard", "HEAD^1"], repo)
     out, err = run(["git", "rev-parse", "HEAD"], repo)
     assert out != old_ref
     # Fetch again, it should move the head back to origin/master
     repo = utils.fetch(GIT_REPO, ref)
     out, err = run(["git", "rev-parse", "HEAD"], repo)
     assert out == old_ref
Esempio n. 6
0
 def test_switch_branches(self):
     # Default branch
     repo = utils.fetch(GIT_REPO)
     output, _ = run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], repo)
     assert 'master' in output
     # Custom commit
     repo = utils.fetch(GIT_REPO, '0.12')
     output, _ = run(['git', 'rev-parse', 'HEAD'], repo)
     assert '6570aa5' in output
     # Back to the default branch
     repo = utils.fetch(GIT_REPO)
     output, _ = run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], repo)
     assert 'master' in output
Esempio n. 7
0
    def test_fetch_concurrent(self):
        def do_fetch():
            try:
                repo = utils.fetch(GIT_REPO, '0.10')
                q.put(True)
            except Exception as error:
                q.put(error)

        # make sure cache is empty (is there a better way how to target repo?)
        repo = utils.fetch(GIT_REPO, '0.10')
        shutil.rmtree(repo)

        q = queue.Queue()
        threads = []
        for i in range(10):
            threads.append(threading.Thread(target=do_fetch))
        for t in threads:
            t.start()
        for t in threads:
            t.join()
        # for number of threads check their results
        all_good = True
        for t in threads:
            value = q.get()
            if isinstance(value, Exception):
                print(value)  # so it is visible in the output
                all_good = False
        assert all_good
Esempio n. 8
0
    def test_invalid_destination(self, tmpdir):
        # Is a file
        dest = tmpdir.join('file')
        dest.write('content')
        with pytest.raises(utils.GeneralError):
            repo = utils.fetch(GIT_REPO, destination=str(dest))

        # Is a directory, but not empty
        dest = tmpdir.mkdir('yet_another')
        dest.join('some_file').write('content')
        with pytest.raises(utils.GeneralError) as error:
            repo = utils.fetch(GIT_REPO, destination=str(dest))
        # Git's error message
        assert ("already exists and is not an empty"
                in error.value.args[1].stderr)
        # We report same error message as before
        assert str(error.value) == str(error.value.args[1])
Esempio n. 9
0
    def node(reference):
        """
        Return Tree node referenced by the fmf identifier

        Keys supported in the reference:

        url .... git repository url (optional)
        ref .... branch, tag or commit (default branch if not provided)
        path ... metadata tree root ('.' by default)
        name ... tree node name ('/' by default)

        See the documentation for the full fmf id specification:
        https://fmf.readthedocs.io/en/latest/concept.html#identifiers
        Raises ReferenceError if referenced node does not exist.
        """

        # Fetch remote git repository
        if 'url' in reference:
            path = reference.get('path', '.').lstrip('/')
            # Create lock path to fetch/read git from URL to the cache
            cache_dir = utils.get_cache_directory()
            # Use .read.lock suffix (different from the inner fetch lock)
            lock_path = os.path.join(
                cache_dir, reference["url"].replace('/', '_')) + '.read.lock'
            try:
                with FileLock(lock_path, timeout=NODE_LOCK_TIMEOUT) as lock:
                    # Write PID to lockfile so we know which process got it
                    with open(lock.lock_file, 'w') as lock_file:
                        lock_file.write(str(os.getpid()))
                    repository = utils.fetch(
                        reference.get('url'), reference.get('ref'))
                    root = os.path.join(repository, path)
                    tree = Tree(root)
            except Timeout:
                raise utils.GeneralError(
                    "Failed to acquire lock for {0} within {1} seconds".format(
                    lock_path, NODE_LOCK_TIMEOUT))
        # Use local files
        else:
            root = reference.get('path', '.')
            if not root.startswith('/') and root != '.':
                raise utils.ReferenceError(
                    'Relative path "%s" specified.' % root)
            tree = Tree(root)
        found_node = tree.find(reference.get('name', '/'))
        if found_node is None:
            raise utils.ReferenceError(
                "No tree node found for '{0}' reference".format(reference))
        # FIXME Should be able to remove .cache if required
        return found_node
Esempio n. 10
0
 def test_fetch_deprecation(self):
     with pytest.warns(FutureWarning):
         repo = utils.fetch(GIT_REPO, '0.10')
     assert utils.os.path.isfile(utils.os.path.join(repo, 'fmf.spec'))
Esempio n. 11
0
 def test_fetch_valid_id(self):
     repo = utils.fetch(GIT_REPO, '0.10')
     assert utils.os.path.isfile(utils.os.path.join(repo, 'fmf.spec'))
Esempio n. 12
0
 def target():
     utils.fetch(GIT_REPO, '0.10', destination=str(tmpdir))
Esempio n. 13
0
 def do_fetch():
     try:
         repo = utils.fetch(GIT_REPO, '0.10')
         q.put(True)
     except Exception as error:
         q.put(error)
Esempio n. 14
0
 def test_fetch_invalid_url(self):
     with pytest.raises(utils.GeneralError):
         utils.fetch('invalid')
Esempio n. 15
0
 def test_fetch_invalid_ref(self):
     with pytest.raises(utils.GeneralError):
         utils.fetch(GIT_REPO, 'invalid')
Esempio n. 16
0
 def test_cache_expiration(self):
     repo = utils.fetch(GIT_REPO)
     fetch_head = (os.path.join(repo, '.git', 'FETCH_HEAD'))
     os.remove(fetch_head)
     repo = utils.fetch(GIT_REPO)
     assert os.path.isfile(fetch_head)
Esempio n. 17
0
 def test_invalid_cache_directory(self, monkeypatch):
     with pytest.raises(utils.GeneralError):
         monkeypatch.setenv("XDG_CACHE_HOME", "/etc")
         utils.fetch(GIT_REPO)