Ejemplo n.º 1
0
    def test_incremental_state_update_with_no_update(self):
        """Build updates to a non-finished state when update_on_success=True."""
        build_envs = [
            LocalEnvironment(
                version=self.version,
                project=self.project,
                build={'id': DUMMY_BUILD_ID},
            ),
            LocalEnvironment(
                version=self.version,
                project=self.project,
                build={'id': DUMMY_BUILD_ID},
                update_on_success=False,
            ),
        ]

        for build_env in build_envs:
            with build_env:
                build_env.update_build(BUILD_STATE_CLONING)
                self.mocks.mocks['api_v2.build']().put.assert_called_with({
                    'id': DUMMY_BUILD_ID,
                    'version': self.version.pk,
                    'success': True,
                    'project': self.project.pk,
                    'setup_error': u'',
                    'length': mock.ANY,
                    'error': '',
                    'setup': u'',
                    'output': u'',
                    'state': BUILD_STATE_CLONING,
                    'builder': mock.ANY,
                    'exit_code': 0,
                })
Ejemplo n.º 2
0
    def test_build_respects_epub_flag(self):
        '''Test build with epub enabled'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=False,
                      enable_epub_build=True,
                      versions=[fixture()])
        version = project.versions.all()[0]

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env,
                              project=project,
                              python_env=python_env,
                              version=version,
                              search=False,
                              localmedia=False,
                              config=config)
        task.build_docs()

        # The HTML and the Epub format were built.
        self.mocks.html_build.assert_called_once_with()
        self.mocks.epub_build.assert_called_once_with()
        # PDF however was disabled and therefore not built.
        self.assertFalse(self.mocks.pdf_build.called)
Ejemplo n.º 3
0
    def test_build_respects_pdf_flag(self):
        '''Build output format control'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        task = UpdateDocsTask(build_env=build_env,
                              version=version,
                              project=project,
                              search=False,
                              localmedia=False)
        built_docs = task.build_docs()

        # The HTML and the Epub format were built.
        self.mocks.html_build.assert_called_once_with()
        self.mocks.pdf_build.assert_called_once_with()
        # PDF however was disabled and therefore not built.
        self.assertFalse(self.mocks.epub_build.called)
Ejemplo n.º 4
0
    def test_failing_execution_with_unexpected_exception(self):
        """Build in failing state with exception from code."""
        build_env = LocalEnvironment(
            version=self.version,
            project=self.project,
            build={'id': DUMMY_BUILD_ID},
        )

        with build_env:
            raise ValueError('uncaught')

        self.assertFalse(self.mocks.process.communicate.called)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)

        # api() is not called anymore, we use api_v2 instead
        self.assertFalse(self.mocks.api()(DUMMY_BUILD_ID).put.called)
        self.mocks.mocks['api_v2.build']().put.assert_called_with({
            'id': DUMMY_BUILD_ID,
            'version': self.version.pk,
            'success': False,
            'project': self.project.pk,
            'setup_error': u'',
            'length': mock.ANY,
            'error': (
                'There was a problem with Read the Docs while building your '
                'documentation. Please report this to us with your build id (123).'
            ),
            'setup': u'',
            'output': u'',
            'state': u'finished',
            'builder': mock.ANY,
        })
Ejemplo n.º 5
0
    def test_failing_execution_with_caught_exception(self):
        """Build in failing state with BuildEnvironmentError exception."""
        build_env = LocalEnvironment(
            version=self.version,
            project=self.project,
            build={'id': DUMMY_BUILD_ID},
        )

        with build_env:
            raise BuildEnvironmentError('Foobar')

        self.assertFalse(self.mocks.process.communicate.called)
        self.assertEqual(len(build_env.commands), 0)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)

        # api() is not called anymore, we use api_v2 instead
        self.assertFalse(self.mocks.api()(DUMMY_BUILD_ID).put.called)
        self.mocks.mocks['api_v2.build']().put.assert_called_with({
            'id': DUMMY_BUILD_ID,
            'version': self.version.pk,
            'success': False,
            'project': self.project.pk,
            'setup_error': u'',
            'length': mock.ANY,
            'error': 'Foobar',
            'setup': u'',
            'output': u'',
            'state': u'finished',
            'builder': mock.ANY,
            'exit_code': 1,
        })
Ejemplo n.º 6
0
    def test_build(self):
        '''Test full build'''
        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      versions=[fixture()])
        version = project.versions.all()[0]
        self.mocks.configure_mock('api_versions', {'return_value': [version]})
        self.mocks.configure_mock(
            'api', {'get.return_value': {
                'downloads': "no_url_here"
            }})
        self.mocks.patches['html_build'].stop()

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env,
                              project=project,
                              python_env=python_env,
                              version=version,
                              search=False,
                              localmedia=False,
                              config=config)
        task.build_docs()

        # Get command and check first part of command list is a call to sphinx
        self.assertEqual(self.mocks.popen.call_count, 1)
        cmd = self.mocks.popen.call_args_list[0][0]
        self.assertRegexpMatches(cmd[0][0], r'python')
        self.assertRegexpMatches(cmd[0][1], r'sphinx-build')
Ejemplo n.º 7
0
    def __init__(self, project, version_slug, environment=None, **kwargs):
        self.default_branch = project.default_branch
        self.name = project.name
        self.repo_url = project.clean_repo
        self.working_dir = project.checkout_path(version_slug)

        from readthedocs.doc_builder.environments import LocalEnvironment
        self.environment = environment or LocalEnvironment(project)

        # Update the env variables with the proper VCS env variables
        self.environment.environment.update(self.env)
Ejemplo n.º 8
0
 def __init__(self, project):
     self.project = project
     self.project_root = os.path.join(
         self.WEB_ROOT,
         project.slug,
     )
     self.subproject_root = os.path.join(
         self.project_root,
         'projects',
     )
     self.environment = LocalEnvironment(project)
     self.sanity_check()
Ejemplo n.º 9
0
    def test_failing_execution_with_caught_exception(self):
        '''Build in failing state with BuildEnvironmentError exception'''
        build_env = LocalEnvironment(version=self.version, project=self.project,
                                     build={})

        with build_env:
            raise BuildEnvironmentError('Foobar')

        self.assertFalse(self.mocks.process.communicate.called)
        self.assertEqual(len(build_env.commands), 0)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)
Ejemplo n.º 10
0
 def test_builder_comments(self):
     '''Normal build with comments'''
     project = get(Project,
                   documentation_type='sphinx',
                   allow_comments=True,
                   versions=[fixture()])
     version = project.versions.all()[0]
     build_env = LocalEnvironment(version=version, project=project, build={})
     python_env = Virtualenv(version=version, build_env=build_env)
     builder_class = get_builder_class(project.documentation_type)
     builder = builder_class(build_env, python_env)
     self.assertEqual(builder.sphinx_builder, 'readthedocs-comments')
Ejemplo n.º 11
0
    def test_failing_execution_with_uncaught_exception(self):
        '''Build in failing state with exception from code'''
        build_env = LocalEnvironment(version=self.version, project=self.project,
                                     build={})

        def _inner():
            with build_env:
                raise Exception()

        self.assertRaises(Exception, _inner)
        self.assertFalse(self.mocks.process.communicate.called)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)
Ejemplo n.º 12
0
 def test_builder_no_comments(self):
     '''Test builder without comments'''
     project = get(Project,
                   documentation_type='sphinx',
                   allow_comments=False,
                   versions=[fixture()])
     version = project.versions.all()[0]
     build_env = LocalEnvironment(version=version,
                                  project=project,
                                  build={})
     builder_class = get_builder_class(project.documentation_type)
     builder = builder_class(build_env)
     self.assertEqual(builder.sphinx_builder, 'readthedocs')
    def test_failing_execution_with_unexpected_exception(self):
        '''Build in failing state with exception from code'''
        build_env = LocalEnvironment(version=self.version,
                                     project=self.project,
                                     build={'id': DUMMY_BUILD_ID})

        with build_env:
            raise ValueError('uncaught')

        self.assertFalse(self.mocks.process.communicate.called)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)
        self.assertFalse(self.mocks.api()(DUMMY_BUILD_ID).put.called)
Ejemplo n.º 14
0
    def run_setup(self, record=True):
        """
        Run setup in the local environment.

        Return True if successful.
        """
        self.setup_env = LocalEnvironment(
            project=self.project,
            version=self.version,
            build=self.build,
            record=record,
            update_on_success=False,
        )

        # Environment used for code checkout & initial configuration reading
        with self.setup_env:
            if self.project.skip:
                raise BuildEnvironmentError(
                    _('Builds for this project are temporarily disabled'))
            try:
                self.setup_vcs()
            except vcs_support_utils.LockTimeout as e:
                self.retry(exc=e, throw=False)
                raise BuildEnvironmentError(
                    'Version locked, retrying in 5 minutes.',
                    status_code=423
                )

            try:
                self.config = load_yaml_config(version=self.version)
            except ConfigError as e:
                raise BuildEnvironmentError(
                    'Problem parsing YAML configuration. {0}'.format(str(e))
                )

        if self.setup_env.failure or self.config is None:
            self._log('Failing build because of setup failure: %s' % self.setup_env.failure)

            # Send notification to users only if the build didn't fail because of
            # LockTimeout: this exception occurs when a build is triggered before the previous
            # one has finished (e.g. two webhooks, one after the other)
            if not isinstance(self.setup_env.failure, vcs_support_utils.LockTimeout):
                self.send_notifications()

            return False

        if self.setup_env.successful and not self.project.has_valid_clone:
            self.set_valid_clone()

        return True
Ejemplo n.º 15
0
    def test_build_pdf_latex_not_failure(self):
        '''Test pass during PDF builds and bad latex failure status code'''
        self.mocks.patches['html_build'].stop()
        self.mocks.patches['pdf_build'].stop()

        project = get(Project,
                      slug='project-2',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]
        assert project.conf_dir() == '/tmp/rtd'

        build_env = LocalEnvironment(project=project,
                                     version=version,
                                     build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        yaml_config = get_build_config({})
        config = ConfigWrapper(version=version, yaml_config=yaml_config)
        task = UpdateDocsTask(build_env=build_env,
                              project=project,
                              python_env=python_env,
                              version=version,
                              search=False,
                              localmedia=False,
                              config=config)

        # Mock out the separate calls to Popen using an iterable side_effect
        returns = [
            (('', ''), 0),  # sphinx-build html
            (('', ''), 0),  # sphinx-build pdf
            (('Output written on foo.pdf', ''), 1),  # latex
            (('', ''), 0),  # makeindex
            (('', ''), 0),  # latex
        ]
        mock_obj = mock.Mock()
        mock_obj.communicate.side_effect = [
            output for (output, status) in returns
        ]
        type(mock_obj).returncode = mock.PropertyMock(
            side_effect=[status for (output, status) in returns])
        self.mocks.popen.return_value = mock_obj

        with build_env:
            task.build_docs()
        self.assertEqual(self.mocks.popen.call_count, 5)
        self.assertTrue(build_env.successful)
Ejemplo n.º 16
0
    def test_failing_execution(self):
        """Build in failing state."""
        self.mocks.configure_mock(
            'process', {'communicate.return_value': (b'This is not okay', '')})
        type(self.mocks.process).returncode = PropertyMock(return_value=1)

        build_env = LocalEnvironment(
            version=self.version,
            project=self.project,
            build={'id': DUMMY_BUILD_ID},
        )

        with build_env:
            build_env.run('echo', 'test')
            self.fail('This should be unreachable')
        self.assertTrue(self.mocks.process.communicate.called)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)
        self.assertEqual(len(build_env.commands), 1)
        self.assertEqual(build_env.commands[0].output, u'This is not okay')

        # api() is not called anymore, we use api_v2 instead
        self.assertFalse(self.mocks.api()(DUMMY_BUILD_ID).put.called)
        self.mocks.mocks['api_v2.build']().put.assert_called_with({
            'id':
            DUMMY_BUILD_ID,
            'version':
            self.version.pk,
            'success':
            False,
            'project':
            self.project.pk,
            'setup_error':
            u'',
            'length':
            mock.ANY,
            'error':
            '',
            'setup':
            u'',
            'output':
            u'',
            'state':
            u'finished',
            'builder':
            mock.ANY,
            'exit_code':
            1,
        })
Ejemplo n.º 17
0
    def test_normal_execution(self):
        '''Normal build in passing state'''
        self.mocks.configure_mock('process', {
            'communicate.return_value': ('This is okay', '')})
        type(self.mocks.process).returncode = PropertyMock(return_value=0)

        build_env = LocalEnvironment(version=self.version, project=self.project,
                                     build={})
        with build_env:
            build_env.run('echo', 'test')
        self.assertTrue(self.mocks.process.communicate.called)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.successful)
        self.assertEqual(len(build_env.commands), 1)
        self.assertEqual(build_env.commands[0].output, u'This is okay')
Ejemplo n.º 18
0
    def test_failing_execution(self):
        '''Build in failing state'''
        self.mocks.configure_mock('process', {
            'communicate.return_value': ('This is not okay', '')})
        type(self.mocks.process).returncode = PropertyMock(return_value=1)

        build_env = LocalEnvironment(version=self.version, project=self.project,
                                     build={})
        with build_env:
            build_env.run('echo', 'test')
            self.fail('This should be unreachable')
        self.assertTrue(self.mocks.process.communicate.called)
        self.assertTrue(build_env.done)
        self.assertTrue(build_env.failed)
        self.assertEqual(len(build_env.commands), 1)
        self.assertEqual(build_env.commands[0].output, u'This is not okay')
Ejemplo n.º 19
0
    def test_build_pdf_latex_failures(self):
        '''Build failure if latex fails'''
        if six.PY3:
            import pytest
            pytest.xfail(
                "test_build_pdf_latex_failures is known to fail on 3.6")

        self.mocks.patches['html_build'].stop()
        self.mocks.patches['pdf_build'].stop()

        project = get(Project,
                      slug='project-1',
                      documentation_type='sphinx',
                      conf_py_file='test_conf.py',
                      enable_pdf_build=True,
                      enable_epub_build=False,
                      versions=[fixture()])
        version = project.versions.all()[0]
        assert project.conf_dir() == '/tmp/rtd'

        build_env = LocalEnvironment(project=project, version=version, build={})
        python_env = Virtualenv(version=version, build_env=build_env)
        config = ConfigWrapper(version=version, yaml_config=create_load()()[0])
        task = UpdateDocsTask(build_env=build_env, project=project, python_env=python_env,
                              version=version, search=False, localmedia=False, config=config)

        # Mock out the separate calls to Popen using an iterable side_effect
        returns = [
            (('', ''), 0),  # sphinx-build html
            (('', ''), 0),  # sphinx-build pdf
            (('', ''), 1),  # latex
            (('', ''), 0),  # makeindex
            (('', ''), 0),  # latex
        ]
        mock_obj = mock.Mock()
        mock_obj.communicate.side_effect = [output for (output, status)
                                            in returns]
        type(mock_obj).returncode = mock.PropertyMock(
            side_effect=[status for (output, status) in returns])
        self.mocks.popen.return_value = mock_obj

        with build_env:
            task.build_docs()
        self.assertEqual(self.mocks.popen.call_count, 7)
        self.assertTrue(build_env.failed)