Пример #1
0
 def setup(self):
     self.bi = Mock(spec_set=BuildInfo)
     self.cls = LocalBuild('my/repo', self.bi)
Пример #2
0
class TestLocalBuild(object):

    def setup(self):
        self.bi = Mock(spec_set=BuildInfo)
        self.cls = LocalBuild('my/repo', self.bi)

    def test_run_ok(self):
        with patch('%s.clone_repo' % pb) as mock_clone, \
                patch('%s.run_build' % pb) as mock_run, \
                patch('%s.rmtree' % pbm) as mock_rmtree, \
                patch('%s.get_time' % pb) as mock_time:
            mock_clone.return_value = ('/my/clone/path', 'repostr')
            mock_run.return_value = 'my output'
            mock_time.side_effect = [
                datetime(2015, 1, 1, 1, 0, 0),
                datetime(2015, 1, 1, 2, 0, 0),
            ]
            self.cls.run()
        assert mock_clone.mock_calls == [call()]
        assert mock_run.mock_calls == [call('/my/clone/path')]
        assert self.bi.mock_calls == [
            call.set_local_build(return_code=0, output='my output',
                                 start_dt=datetime(2015, 1, 1, 1, 0, 0),
                                 end_dt=datetime(2015, 1, 1, 2, 0, 0),
                                 repo_str='repostr')
        ]
        assert mock_rmtree.mock_calls == [call('/my/clone/path')]

    def make_exc_info(self, is_called_proc_error=False):
        """generate an exception traceback"""
        try:
            if is_called_proc_error:
                raise subprocess.CalledProcessError(4, 'mycmd', 'my out')
            else:
                raise Exception("foo")
        except:
            ex_type, ex, tb = sys.exc_info()
        return (ex_type, ex, tb)

    def test_run_clone_exception(self):
        ex_t, ex, tb = self.make_exc_info()

        def clone_se():
            raise ex

        with patch('%s.clone_repo' % pb) as mock_clone, \
                patch('%s.run_build' % pb) as mock_run, \
                patch('%s.rmtree' % pbm) as mock_rmtree, \
                patch('%s.sys.exc_info' % pbm) as mock_excinfo, \
                patch('%s.get_time' % pb) as mock_time:
            mock_clone.side_effect = clone_se
            mock_run.return_value = 'my output'
            mock_time.side_effect = [
                datetime(2015, 1, 1, 1, 0, 0),
                datetime(2015, 1, 1, 2, 0, 0),
            ]
            mock_excinfo.return_value = ex_t, ex, tb
            self.cls.run()
        assert mock_clone.mock_calls == [call()]
        assert mock_run.mock_calls == []
        assert self.bi.mock_calls == [
            call.set_local_build(return_code=-1, excinfo=ex,
                                 ex_type=ex_t, traceback=tb)
        ]
        assert mock_rmtree.mock_calls == []

    def test_run_subprocess_error(self):
        ex_t, ex, tb = self.make_exc_info(True)

        def se_ex(foo):
            raise ex

        with patch('%s.clone_repo' % pb) as mock_clone, \
                patch('%s.run_build' % pb) as mock_run, \
                patch('%s.rmtree' % pbm) as mock_rmtree, \
                patch('%s.sys.exc_info' % pbm) as mock_excinfo, \
                patch('%s.get_time' % pb) as mock_time:
            mock_clone.return_value = ('/my/clone/path', 'repostr')
            mock_run.side_effect = se_ex
            mock_time.side_effect = [
                datetime(2015, 1, 1, 1, 0, 0),
                datetime(2015, 1, 1, 2, 0, 0),
            ]
            mock_excinfo.return_value = ex_t, ex, tb
            self.cls.run()
        assert mock_clone.mock_calls == [call()]
        assert mock_run.mock_calls == [call('/my/clone/path')]
        assert self.bi.mock_calls == [
            call.set_local_build(excinfo=ex, output='my out', return_code=4,
                                 ex_type=ex_t, traceback=tb,
                                 start_dt=datetime(2015, 1, 1, 1, 0, 0),
                                 end_dt=datetime(2015, 1, 1, 2, 0, 0),
                                 repo_str='repostr')
        ]
        assert mock_rmtree.mock_calls == [call('/my/clone/path')]

    def test_run_other_exception(self):
        ex_t, ex, tb = self.make_exc_info()

        def se_ex(foo):
            raise ex

        with patch('%s.clone_repo' % pb) as mock_clone, \
                patch('%s.run_build' % pb) as mock_run, \
                patch('%s.rmtree' % pbm) as mock_rmtree, \
                patch('%s.sys.exc_info' % pbm) as mock_excinfo, \
                patch('%s.get_time' % pb) as mock_time:
            mock_clone.return_value = ('/my/clone/path', 'repostr')
            mock_run.side_effect = se_ex
            mock_time.side_effect = [
                datetime(2015, 1, 1, 1, 0, 0),
                datetime(2015, 1, 1, 2, 0, 0),
            ]
            mock_excinfo.return_value = ex_t, ex, tb
            self.cls.run()
        assert mock_clone.mock_calls == [call()]
        assert mock_run.mock_calls == [call('/my/clone/path')]
        assert self.bi.mock_calls == [
            call.set_local_build(excinfo=ex, ex_type=ex_t, traceback=tb,
                                 start_dt=datetime(2015, 1, 1, 1, 0, 0),
                                 end_dt=datetime(2015, 1, 1, 2, 0, 0),
                                 repo_str='repostr')
        ]
        assert mock_rmtree.mock_calls == [call('/my/clone/path')]

    @freeze_time('2015-01-10 12:13:14')
    def test_get_time(self):
        res = self.cls.get_time()
        assert res == FakeDatetime(2015, 1, 10, 12, 13, 14)

    def test_clone_repo(self):
        type(self.bi).ssh_clone_url = 'ssh_url'
        type(self.bi).https_clone_url = 'https_url'

        mock_repo = Mock(name='mock_repo')
        mock_repo.head.ref.name = 'rname'
        mock_repo.head.ref.commit.hexsha = 'mysha'

        with patch('%s.path_for_repo' % pb) as mock_path, \
                patch('%s.Repo.clone_from' % pbm) as mock_clone:
            mock_path.return_value = '/repo/path'
            mock_clone.return_value = mock_repo
            res = self.cls.clone_repo()
        assert mock_path.mock_calls == [call()]
        assert mock_clone.mock_calls[0] == call(
            'ssh_url', '/repo/path', branch='master'
        )
        assert res == ('/repo/path', '<ssh_url> rname (mysha)')

    def test_clone_repo_ssh_fail(self):
        type(self.bi).ssh_clone_url = 'ssh_url'
        type(self.bi).https_clone_url = 'https_url'
        ex = Exception('foo')

        mock_repo = Mock(name='mock_repo')
        mock_repo.head.ref.name = 'rname'
        mock_repo.head.ref.commit.hexsha = 'mysha'

        def se_clone(url, path, branch=None):
            if url == 'ssh_url':
                raise ex
            return mock_repo

        with patch('%s.path_for_repo' % pb) as mock_path, \
                patch('%s.Repo.clone_from' % pbm) as mock_clone:
            mock_path.return_value = '/repo/path'
            mock_clone.side_effect = se_clone
            res = self.cls.clone_repo(branch='mybranch')
        assert mock_path.mock_calls == [call()]
        assert mock_clone.mock_calls[0] == call.clone_from(
            'ssh_url', '/repo/path', branch='mybranch'
        )
        assert mock_clone.mock_calls[1] == call.clone_from(
            'https_url', '/repo/path', branch='mybranch'
        )
        assert res == ('/repo/path', '<https_url> rname (mysha)')

    def test_clone_repo_all_fail(self):
        type(self.bi).ssh_clone_url = 'ssh_url'
        type(self.bi).https_clone_url = 'https_url'
        ex1 = Exception('foo')
        ex2 = Exception('bar')

        def se_clone(url, path, branch=None):
            if url == 'ssh_url':
                raise ex1
            raise ex2

        with patch('%s.path_for_repo' % pb) as mock_path, \
                patch('%s.Repo' % pbm) as mock_repo:
            mock_path.return_value = '/repo/path'
            mock_repo.clone_from.side_effect = se_clone
            with pytest.raises(Exception) as excinfo:
                self.cls.clone_repo(branch='mybranch')
        assert mock_path.mock_calls == [call()]
        assert mock_repo.mock_calls == [
            call.clone_from('ssh_url', '/repo/path', branch='mybranch'),
            call.clone_from('https_url', '/repo/path', branch='mybranch'),
        ]
        assert excinfo.value == ex2

    def test_clone_repo_dry_run(self):
        type(self.bi).ssh_clone_url = 'ssh_url'
        type(self.bi).https_clone_url = 'https_url'
        self.cls.dry_run = True
        ex = Exception('foo')

        def se_clone(url, path, branch=None):
            if url == 'ssh_url':
                raise ex
            return True

        with patch('%s.path_for_repo' % pb) as mock_path, \
                patch('%s.Repo' % pbm) as mock_repo, \
                patch('%s.logger' % pbm) as mock_logger:
            mock_path.return_value = '/repo/path'
            mock_repo.clone_from.side_effect = se_clone
            res = self.cls.clone_repo()
        assert mock_path.mock_calls == [call()]
        assert mock_repo.mock_calls == []
        assert mock_logger.mock_calls == [
            call.debug("Cloning %s branch %s into: %s", 'my/repo', 'master',
                       '/repo/path'),
            call.info("DRY RUN - not actually cloning %s into %s", 'my/repo',
                      '/repo/path')
        ]
        assert res == ('/repo/path', '(DRY RUN)')

    def test_path_for_repo(self):
        with patch('%s.mkdtemp' % pbm) as mock_mkdtemp:
            mock_mkdtemp.return_value = '/tmpdir'
            res = self.cls.path_for_repo()
        assert res == '/tmpdir'
        assert mock_mkdtemp.mock_calls == [call(prefix='rebuildbot_')]

    @pytest.mark.skipif(
        (
                sys.version_info[0] != 2 or
                (sys.version_info[0] == 2 and sys.version_info[1] != 7)
        ),
        reason='not running py27 test on %d.%d.%d' % (
                sys.version_info[0],
                sys.version_info[1],
                sys.version_info[2]
        ))
    def test_run_build_success_py27(self):
        with patch('%s.os.getcwd' % pbm) as mock_getcwd, \
                patch('%s.os.chdir' % pbm) as mock_chdir, \
                patch('%s.subprocess' % pbm, autospec=True) as mock_subprocess:
            mock_getcwd.return_value = '/my/pwd'
            res = self.cls.run_build('/repo/path')
        assert mock_getcwd.mock_calls == [call()]
        assert mock_chdir.mock_calls == [
            call('/repo/path'),
            call('/my/pwd')
        ]
        assert mock_subprocess.mock_calls == [
            call.check_output(
                ['./.rebuildbot.sh'],
                stderr=mock_subprocess.STDOUT
            )
        ]
        assert res == mock_subprocess.check_output.return_value

    @pytest.mark.skipif(
        (
                sys.version_info[0] != 2 or
                (sys.version_info[0] == 2 and sys.version_info[1] != 7)
        ),
        reason='not running py27 test on %d.%d.%d' % (
                sys.version_info[0],
                sys.version_info[1],
                sys.version_info[2]
        ))
    def test_run_build_exception_py27(self):
        ex = Exception('foo')

        def se_exc(foo, stderr=None):
            raise ex

        with patch('%s.os.getcwd' % pbm) as mock_getcwd, \
                patch('%s.os.chdir' % pbm) as mock_chdir, \
                patch('%s.subprocess' % pbm, autospec=True) as mock_subprocess:
            mock_getcwd.return_value = '/my/pwd'
            mock_subprocess.check_output.side_effect = se_exc
            with pytest.raises(Exception) as excinfo:
                self.cls.run_build('/repo/path')
        assert mock_getcwd.mock_calls == [call()]
        assert mock_chdir.mock_calls == [
            call('/repo/path'),
            call('/my/pwd')
        ]
        assert mock_subprocess.mock_calls == [
            call.check_output(
                ['./.rebuildbot.sh'],
                stderr=mock_subprocess.STDOUT
            )
        ]
        assert excinfo.value == ex

    @pytest.mark.skipif(
        (
                sys.version_info[0] != 2 or
                (sys.version_info[0] == 2 and sys.version_info[1] != 7)
        ),
        reason='not running py27 test on %d.%d.%d' % (
                sys.version_info[0],
                sys.version_info[1],
                sys.version_info[2]
        ))
    def test_run_build_dry_run_py27(self):
        self.cls.dry_run = True

        with patch('%s.os.getcwd' % pbm) as mock_getcwd, \
                patch('%s.os.chdir' % pbm) as mock_chdir, \
                patch('%s.subprocess' % pbm, autospec=True) as mock_subprocess:
            mock_getcwd.return_value = '/my/pwd'
            res = self.cls.run_build('/repo/path')
        assert mock_getcwd.mock_calls == []
        assert mock_chdir.mock_calls == []
        assert mock_subprocess.mock_calls == []
        assert res == 'DRY RUN'

    @pytest.mark.skipif(sys.version_info[0] < 3,
                        reason='not running py3 test on %d.%d.%d' % (
                            sys.version_info[0],
                            sys.version_info[1],
                            sys.version_info[2]
                        ))
    def test_run_build_success_py3(self):
        mock_res = Mock()
        with patch('%s.os.getcwd' % pbm) as mock_getcwd, \
                patch('%s.os.chdir' % pbm) as mock_chdir, \
                patch('%s.subprocess' % pbm, autospec=True) as mock_subprocess,\
                patch('%s.locale' % pbm, autospec=True) as mock_locale:
            mock_getcwd.return_value = '/my/pwd'
            mock_locale.getdefaultlocale.return_value = ['foo', 'bar']
            mock_locale.return_value = ['foo', 'bar']
            mock_subprocess.check_output.return_value = mock_res
            res = self.cls.run_build('/repo/path')
        assert mock_getcwd.mock_calls == [call()]
        assert mock_chdir.mock_calls == [
            call('/repo/path'),
            call('/my/pwd')
        ]
        assert mock_subprocess.mock_calls == [
            call.check_output(
                ['./.rebuildbot.sh'],
                stderr=mock_subprocess.STDOUT
            ),
            call.check_output().decode('bar')
        ]
        assert res == mock_res.decode.return_value
        assert mock_res.mock_calls == [
            call.decode('bar')
        ]

    @pytest.mark.skipif(sys.version_info[0] < 3,
                        reason='not running py3 test on %d.%d.%d' % (
                            sys.version_info[0],
                            sys.version_info[1],
                            sys.version_info[2]
                        ))
    def test_run_build_exception_py3(self):
        ex = Exception('foo')

        def se_exc(foo, stderr=None):
            raise ex

        with patch('%s.os.getcwd' % pbm) as mock_getcwd, \
                patch('%s.os.chdir' % pbm) as mock_chdir, \
                patch('%s.subprocess' % pbm, autospec=True) as mock_subprocess,\
                patch('%s.locale' % pbm) as mock_locale:
            mock_getcwd.return_value = '/my/pwd'
            mock_locale.getdefaultlocale.return_value = ['foo', 'bar']
            mock_subprocess.check_output.side_effect = se_exc
            with pytest.raises(Exception) as excinfo:
                self.cls.run_build('/repo/path')
        assert mock_getcwd.mock_calls == [call()]
        assert mock_chdir.mock_calls == [
            call('/repo/path'),
            call('/my/pwd')
        ]
        assert mock_subprocess.mock_calls == [
            call.check_output(
                ['./.rebuildbot.sh'],
                stderr=mock_subprocess.STDOUT
            )
        ]
        assert excinfo.value == ex

    @pytest.mark.skipif(sys.version_info[0] < 3,
                        reason='not running py3 test on %d.%d.%d' % (
                            sys.version_info[0],
                            sys.version_info[1],
                            sys.version_info[2]
                        ))
    def test_run_build_dry_run_py3(self):
        self.cls.dry_run = True

        with patch('%s.os.getcwd' % pbm) as mock_getcwd, \
                patch('%s.os.chdir' % pbm) as mock_chdir, \
                patch('%s.subprocess' % pbm, autospec=True) as mock_subprocess,\
                patch('%s.locale' % pbm) as mock_locale:
            mock_getcwd.return_value = '/my/pwd'
            mock_locale.getdefaultlocale.return_value = ['foo', 'bar']
            res = self.cls.run_build('/repo/path')
        assert mock_getcwd.mock_calls == []
        assert mock_chdir.mock_calls == []
        assert mock_subprocess.mock_calls == []
        assert res == 'DRY RUN'