| |
@@ -0,0 +1,303 @@
|
| |
+ # -*- coding: utf-8 -*-
|
| |
+ # Copyright (c) 2017 Red Hat, Inc.
|
| |
+ #
|
| |
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
|
| |
+ # of this software and associated documentation files (the "Software"), to deal
|
| |
+ # in the Software without restriction, including without limitation the rights
|
| |
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| |
+ # copies of the Software, and to permit persons to whom the Software is
|
| |
+ # furnished to do so, subject to the following conditions:
|
| |
+ #
|
| |
+ # The above copyright notice and this permission notice shall be included in all
|
| |
+ # copies or substantial portions of the Software.
|
| |
+ #
|
| |
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| |
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| |
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| |
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| |
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| |
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| |
+ # SOFTWARE.
|
| |
+ #
|
| |
+ # Written by Chenxiong Qi <cqi@redhat.com>
|
| |
+
|
| |
+ import six
|
| |
+ import unittest
|
| |
+ import errno
|
| |
+ from mock import call, patch, Mock
|
| |
+
|
| |
+ import freshmaker
|
| |
+ from freshmaker import utils
|
| |
+
|
| |
+
|
| |
+ class TestMakeDirs(unittest.TestCase):
|
| |
+ """Test makedirs"""
|
| |
+
|
| |
+ @patch('os.makedirs', side_effect=OSError(errno.EEXIST, '...'))
|
| |
+ def test_ignore_error_if_dir_exists(self, makedirs):
|
| |
+ try:
|
| |
+ utils.makedirs('/some-dir')
|
| |
+ except OSError:
|
| |
+ self.fail('Should not raise any error from makedirs.')
|
| |
+
|
| |
+ @patch('os.makedirs', side_effect=OSError(errno.EPERM, '...'))
|
| |
+ def test_raise_error_if_other_os_error_is_raised(self, makedirs):
|
| |
+ self.assertRaises(OSError, utils.makedirs, '/some-dir')
|
| |
+
|
| |
+
|
| |
+ class TestCloneDistgitRepo(unittest.TestCase):
|
| |
+ """Test clone_distgit_repo"""
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'git_user', new='someone')
|
| |
+ @patch.object(freshmaker.conf, 'git_ssh_base_url', new='ssh://%s@localhost/')
|
| |
+ @patch('freshmaker.utils.clone_repo')
|
| |
+ def test_clone_via_ssh_using_configured_user(self, clone_repo):
|
| |
+ utils.clone_distgit_repo('modules', 'testmodule', '/some-destdir')
|
| |
+ expected_repo_url = 'ssh://someone@localhost/modules/testmodule'
|
| |
+ clone_repo.assert_called_once_with(
|
| |
+ expected_repo_url, '/some-destdir',
|
| |
+ branch='master', logger=None, commit=None)
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'git_user', new='')
|
| |
+ @patch.object(freshmaker.conf, 'git_ssh_base_url', new='ssh://%s@localhost/')
|
| |
+ @patch('freshmaker.utils.clone_repo')
|
| |
+ @patch('getpass.getuser', return_value='cqi')
|
| |
+ def test_clone_via_ssh_using_user_got_from_system(self, getuser, clone_repo):
|
| |
+ utils.clone_distgit_repo('modules', 'testmodule', '/some-destdir')
|
| |
+ expected_repo_url = 'ssh://cqi@localhost/modules/testmodule'
|
| |
+ clone_repo.assert_called_once_with(
|
| |
+ expected_repo_url, '/some-destdir',
|
| |
+ branch='master', logger=None, commit=None)
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'git_base_url', new='https://localhost/')
|
| |
+ @patch('freshmaker.utils.clone_repo')
|
| |
+ def test_clone_via_anonymous(self, clone_repo):
|
| |
+ utils.clone_distgit_repo(
|
| |
+ 'modules', 'testmodule', '/some-destdir', ssh=False)
|
| |
+ expected_repo_url = 'https://localhost/modules/testmodule'
|
| |
+ clone_repo.assert_called_once_with(
|
| |
+ expected_repo_url, '/some-destdir',
|
| |
+ branch='master', logger=None, commit=None)
|
| |
+
|
| |
+
|
| |
+ class TestRunCommand(unittest.TestCase):
|
| |
+ """Test _run_command"""
|
| |
+
|
| |
+ @patch('subprocess.Popen')
|
| |
+ @patch('tempfile.gettempdir')
|
| |
+ def test_use_system_tmp_dir_as_rundir(self, gettempdir, Popen):
|
| |
+ Popen.return_value.returncode = 0
|
| |
+ Popen.return_value.communicate.return_value = ['stdout', 'stderr']
|
| |
+ utils._run_command(['git', 'status'], rundir=None)
|
| |
+ gettempdir.assert_called_once()
|
| |
+
|
| |
+ @patch('subprocess.Popen')
|
| |
+ def test_log_stdout(self, Popen):
|
| |
+ Popen.return_value.returncode = 0
|
| |
+ Popen.return_value.communicate.return_value = ['stdout', 'stderr']
|
| |
+ logger = Mock()
|
| |
+ utils._run_command(['git'], rundir='/some-rundir', logger=logger)
|
| |
+ logger.debug.assert_has_calls([call('stdout')])
|
| |
+
|
| |
+ @patch('subprocess.Popen')
|
| |
+ def test_log_error(self, Popen):
|
| |
+ Popen.return_value.returncode = 1
|
| |
+ Popen.return_value.communicate.return_value = ['stdout', 'stderr']
|
| |
+ logger = Mock()
|
| |
+ six.assertRaisesRegex(
|
| |
+ self, OSError, r'Got an error.+',
|
| |
+ utils._run_command, ['git'], rundir='/some-rundir', logger=logger)
|
| |
+ logger.error.assert_has_calls([
|
| |
+ call('Got an error from %s', 'git'),
|
| |
+ call('stderr'),
|
| |
+ ])
|
| |
+
|
| |
+ @patch('subprocess.Popen')
|
| |
+ def test_get_output_from_stdout(self, Popen):
|
| |
+ Popen.return_value.returncode = 0
|
| |
+ Popen.return_value.communicate.return_value = ['stdout', 'stderr']
|
| |
+ result = utils._run_command(
|
| |
+ ['git'], rundir='/some-rundir', return_output=True)
|
| |
+ self.assertEqual('stdout', result)
|
| |
+
|
| |
+
|
| |
+ class TestBumpDistgitRepo(unittest.TestCase):
|
| |
+ """Test bump_distgit_repo"""
|
| |
+
|
| |
+ @patch('tempfile.mkdtemp')
|
| |
+ @patch('shutil.rmtree')
|
| |
+ @patch('freshmaker.utils.clone_distgit_repo')
|
| |
+ @patch('freshmaker.utils.add_empty_commit')
|
| |
+ @patch('freshmaker.utils.push_repo')
|
| |
+ def test_bump_repo(self, push_repo, add_empty_commit, clone_distgit_repo,
|
| |
+ rmtree, mkdtemp):
|
| |
+ rev = utils.bump_distgit_repo('modules', 'testmodule')
|
| |
+ self.assertEqual(add_empty_commit.return_value, rev)
|
| |
+ clone_distgit_repo.assert_called_once_with(
|
| |
+ 'modules', 'testmodule', mkdtemp.return_value, branch='master',
|
| |
+ ssh=True, user=None, logger=None)
|
| |
+ add_empty_commit.assert_called_once_with(
|
| |
+ mkdtemp.return_value, msg='Bump', author=None, logger=None)
|
| |
+
|
| |
+ @patch('freshmaker.utils.clone_distgit_repo', side_effect=ValueError)
|
| |
+ def test_fail_to_bump(self, bump_distgit_repo):
|
| |
+ logger = Mock()
|
| |
+ rev = utils.bump_distgit_repo('modules', 'testmodule', logger=logger)
|
| |
+ self.assertIsNone(rev)
|
| |
+ logger.error.assert_called_once()
|
| |
+
|
| |
+
|
| |
+ class TestCloneRepo(unittest.TestCase):
|
| |
+ """Test clone_repo"""
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=True)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_dry_run_clone_only(self, run_command):
|
| |
+ result = utils.clone_repo('http://remote-gitweb/testmodule.git',
|
| |
+ '/some-dest-dir')
|
| |
+ self.assertEqual('/some-dest-dir', result)
|
| |
+ run_command.assert_not_called()
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=True)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_dry_run_both_clone_and_checkout(self, run_command):
|
| |
+ result = utils.clone_repo('http://remote-gitweb/testmodule.git',
|
| |
+ '/some-dest-dir',
|
| |
+ commit='some-commit')
|
| |
+ self.assertEqual('/some-dest-dir', result)
|
| |
+ run_command.assert_not_called()
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=False)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_clone_only(self, run_command):
|
| |
+ git_url = 'http://remote-gitweb/testmodule.git'
|
| |
+ dest_dir = '/some-dest-dir'
|
| |
+ result = utils.clone_repo(git_url, dest_dir)
|
| |
+ self.assertEqual(dest_dir, result)
|
| |
+ run_command.assert_called_once_with(
|
| |
+ ['git', 'clone', '-b', 'master', git_url, dest_dir],
|
| |
+ logger=None)
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=False)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_both_clone_and_checkout(self, run_command):
|
| |
+ git_url = 'http://remote-gitweb/testmodule.git'
|
| |
+ dest_dir = '/some-dest-dir'
|
| |
+ result = utils.clone_repo(git_url, dest_dir, commit='some-commit')
|
| |
+ self.assertEqual(dest_dir, result)
|
| |
+ self.assertEqual(2, run_command.call_count)
|
| |
+ run_command.assert_has_calls([
|
| |
+ call(['git', 'clone', '-b', 'master', git_url, dest_dir],
|
| |
+ logger=None),
|
| |
+ call(['git', 'checkout', 'some-commit'],
|
| |
+ logger=None, rundir=dest_dir)
|
| |
+ ])
|
| |
+
|
| |
+
|
| |
+ class TestAddEmptyCommit(unittest.TestCase):
|
| |
+ """Test add_empty_commit"""
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=True)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ @patch('freshmaker.utils.get_commit_hash')
|
| |
+ def test_dry_run(self, get_commit_hash, run_command):
|
| |
+ repo_dir = '/some-repo'
|
| |
+ commit_hash = utils.add_empty_commit(repo_dir)
|
| |
+ self.assertEqual(get_commit_hash.return_value, commit_hash)
|
| |
+ get_commit_hash.assert_called_once_with(repo_dir)
|
| |
+ run_command.assert_not_called()
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=False)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ @patch('freshmaker.utils.get_commit_hash')
|
| |
+ def test_add_emtpy_commit(self, get_commit_hash, run_command):
|
| |
+ repo_dir = '/some-repo'
|
| |
+ commit_hash = utils.add_empty_commit(repo_dir, author='cqi')
|
| |
+ self.assertEqual(get_commit_hash.return_value, commit_hash)
|
| |
+ get_commit_hash.assert_called_once_with(repo_dir)
|
| |
+ run_command.assert_called_once_with(
|
| |
+ ['git', 'commit', '--allow-empty', '-m', 'bump', '--author=cqi'],
|
| |
+ logger=None, rundir=repo_dir)
|
| |
+
|
| |
+
|
| |
+ class TestPushRepo(unittest.TestCase):
|
| |
+ """Test push_repo"""
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=True)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_dry_run(self, run_command):
|
| |
+ utils.push_repo('/some-repo')
|
| |
+ run_command.assert_not_called()
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=False)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_push_a_repo(self, run_command):
|
| |
+ repo_dir = '/some-repo'
|
| |
+ utils.push_repo(repo_dir)
|
| |
+ run_command.assert_called_once_with(
|
| |
+ ['git', 'push'], logger=None, rundir=repo_dir)
|
| |
+
|
| |
+
|
| |
+ class TestGetCommitHash(unittest.TestCase):
|
| |
+ """Test get_commit_hash"""
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=True)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ @patch('random.choice')
|
| |
+ def test_dry_run_from_a_cloned_repo(self, choice, run_command):
|
| |
+ choice.return_value = '0'
|
| |
+ commit_hash = utils.get_commit_hash('/some-repo')
|
| |
+ self.assertEqual(choice.return_value * 40, commit_hash)
|
| |
+ run_command.assert_not_called()
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=True)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ @patch('freshmaker.utils.clone_repo')
|
| |
+ @patch('tempfile.mkdtemp')
|
| |
+ @patch('shutil.rmtree')
|
| |
+ @patch('random.choice')
|
| |
+ def test_dry_run_from_remote_repo(
|
| |
+ self, choice, rmtree, mkdtemp, clone_repo, run_command):
|
| |
+ choice.return_value = '0'
|
| |
+ mkdtemp.return_value = '/some-dir'
|
| |
+ git_url = 'http://remote-gitweb/modules/testmodule.git'
|
| |
+
|
| |
+ commit_hash = utils.get_commit_hash(git_url)
|
| |
+
|
| |
+ self.assertEqual(choice.return_value * 40, commit_hash)
|
| |
+ clone_repo.assert_called_once_with(
|
| |
+ git_url, mkdtemp.return_value, branch='master', logger=None)
|
| |
+ run_command.assert_not_called()
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=False)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ def test_get_from_a_cloned_repo(self, run_command):
|
| |
+ run_command.return_value = '123456'
|
| |
+
|
| |
+ commit_hash = utils.get_commit_hash('/some-repo')
|
| |
+
|
| |
+ self.assertEqual(run_command.return_value, commit_hash)
|
| |
+ run_command.assert_called_once_with(
|
| |
+ ['git', 'rev-parse', 'HEAD'],
|
| |
+ rundir='/some-repo',
|
| |
+ return_output=True)
|
| |
+
|
| |
+ @patch.object(freshmaker.conf, 'dry_run', new=False)
|
| |
+ @patch('freshmaker.utils._run_command')
|
| |
+ @patch('freshmaker.utils.clone_repo')
|
| |
+ @patch('tempfile.mkdtemp')
|
| |
+ @patch('shutil.rmtree')
|
| |
+ def test_get_from_remote_repo(self, rmtree, mkdtemp, clone_repo, run_command):
|
| |
+ run_command.return_value = '123456'
|
| |
+ mkdtemp.return_value = '/some-dir'
|
| |
+ git_url = 'http://remote-gitweb/modules/testmodule.git'
|
| |
+
|
| |
+ commit_hash = utils.get_commit_hash(git_url)
|
| |
+
|
| |
+ self.assertEqual(run_command.return_value, commit_hash)
|
| |
+ clone_repo.assert_called_once_with(
|
| |
+ git_url, mkdtemp.return_value, branch='master', logger=None)
|
| |
+ run_command.assert_called_once_with(
|
| |
+ ['git', 'rev-parse', 'HEAD'],
|
| |
+ rundir=mkdtemp.return_value,
|
| |
+ return_output=True)
|
| |
Why not to clone the repo in dry_run mode? It does not change the remote repo anyhow, so it is safe to do it and it can help finding out some misconfiguration or missing permissions.