def test_simple(self):
        fake_project_id = uuid4()

        project = self.create_project()
        build = self.create_build(project)
        self.create_job(build)

        project2 = self.create_project()
        build = self.create_build(project2,
                                  status=Status.finished,
                                  result=Result.passed)
        job = self.create_job(build)
        phase = self.create_jobphase(job)
        step = self.create_jobstep(phase)

        db.session.add(
            FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=project2.id,
                lines_covered=5,
                lines_uncovered=7,
                filename="foo/bar.py",
            ))
        db.session.add(
            FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=project2.id,
                lines_covered=0,
                lines_uncovered=5,
                filename="foo/baz.py",
            ))
        db.session.add(
            FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=project2.id,
                lines_covered=6,
                lines_uncovered=23,
                filename="blah/blah.py",
            ))
        db.session.commit()

        path = '/api/0/projects/{0}/coverage/'.format(fake_project_id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 404

        path = '/api/0/projects/{0}/coverage/'.format(project2.id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert len(data) == 3
        assert data[0] == {
            'filename': 'blah/blah.py',
            'linesCovered': 6,
            'linesUncovered': 23,
        }
    def test_merging(self):
        project = self.create_project()
        build = self.create_build(project,
                                  status=Status.finished,
                                  result=Result.passed)
        # One build with two jobs.
        job1 = self.create_job(build)
        phase1 = self.create_jobphase(job1)
        step1 = self.create_jobstep(phase1)
        job2 = self.create_job(build)
        phase2 = self.create_jobphase(job2)
        step2 = self.create_jobstep(phase2)

        # Two jobs contribute to coverage for foo.py.
        db.session.add(
            FileCoverage(
                step_id=step1.id,
                job_id=job1.id,
                project_id=project.id,
                lines_covered=1,
                lines_uncovered=1,
                filename="foo.py",
                data="NNUC",
            ))
        db.session.add(
            FileCoverage(
                step_id=step1.id,
                job_id=job1.id,
                project_id=project.id,
                lines_covered=1,
                lines_uncovered=1,
                filename="bar.py",
                data="CNNU",
            ))
        db.session.add(
            FileCoverage(
                step_id=step2.id,
                job_id=job2.id,
                project_id=project.id,
                lines_covered=1,
                lines_uncovered=1,
                filename="foo.py",
                data="NUCN",
            ))
        db.session.commit()

        path = '/api/0/builds/{0}/coverage/'.format(build.id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert data == {
            "foo.py": "NUCC",  # Merged.
            "bar.py": "CNNU",
        }
示例#3
0
    def test_process(self, process_diff, get_coverage):
        project = self.create_project()
        build = self.create_build(project)
        job = self.create_job(build)
        jobphase = self.create_jobphase(job)
        jobstep = self.create_jobstep(jobphase)

        handler = CoverageHandler(jobstep)

        process_diff.return_value = {
            'setup.py': set([1, 2, 3, 4, 5]),
        }

        # now try with some duplicate coverage
        get_coverage.return_value = [FileCoverage(
            job_id=job.id,
            step_id=jobstep.id,
            project_id=project.id,
            filename='setup.py',
            data='CUNNNNCCNNNUNNNUUUUUU'
        )]

        fp = StringIO()
        handler.process(fp)
        get_coverage.assert_called_once_with(fp)

        get_coverage.reset_mock()

        get_coverage.return_value = [FileCoverage(
            job_id=job.id,
            step_id=jobstep.id,
            project_id=project.id,
            filename='setup.py',
            data='NUUNNNNNNNNUCCNU'
        )]

        fp = StringIO()
        handler.process(fp)
        get_coverage.assert_called_once_with(fp)

        file_cov = list(FileCoverage.query.filter(
            FileCoverage.job_id == job.id,
        ))
        assert len(file_cov) == 1
        assert file_cov[0].filename == 'setup.py'
        assert file_cov[0].data == 'CUUNNNCCNNNUCCNUUUUUU'
        assert file_cov[0].lines_covered == 5
        assert file_cov[0].lines_uncovered == 9
        assert file_cov[0].diff_lines_covered == 1
        assert file_cov[0].diff_lines_uncovered == 2
示例#4
0
    def end(self, tag):
        if tag == 'class':
            if self.in_file:
                result = FileCoverage(
                    step_id=self.step.id,
                    job_id=self.job.id,
                    project_id=self.job.project_id,
                    filename=self.filename,
                    data=''.join(self.file_coverage),
                )
                self.coverage_handler.add_file_stats(result)
                self.results.append(result)

                self.in_file = False
示例#5
0
    def get_coverage(self, fp):
        """
        Return a phabricator-capable coverage mapping.

        >>> {
        >>>     'foo.py': 'NNNUUUUUUUUUUUUCCCUUUUUCCCCCCCCCNNCNCNCCCNNNN',
        >>> }

        Line flags consists of a single character coverage indicator for each line in the file.

        - N: no coverage available
        - U: uncovered
        - C: covered
        """
        step = self.step
        job = self.step.job

        root = etree.fromstring(fp.read())

        results = []
        for node in root.iter('class'):
            filename = node.get('filename')
            file_coverage = []
            for lineset in node.iterchildren('lines'):
                lineno = 0
                for line in lineset.iterchildren('line'):
                    number, hits = int(line.get('number')), int(line.get('hits'))
                    if lineno < number - 1:
                        for lineno in range(lineno, number - 1):
                            file_coverage.append('N')
                    if hits > 0:
                        file_coverage.append('C')
                    else:
                        file_coverage.append('U')
                    lineno = number

            result = FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=job.project_id,
                filename=filename,
                data=''.join(file_coverage),
            )
            self.add_file_stats(result)

            results.append(result)

        return results
示例#6
0
def file_coverage(project, job, patch):
    file_cov = _generate_sample_coverage_data(patch.diff)

    for file, coverage in file_cov.iteritems():
        file_coverage = FileCoverage(
            project_id=project.id,
            job_id=job.id,
            filename=file,
            data=coverage,
            lines_covered=5,
            lines_uncovered=8,
            diff_lines_covered=3,
            diff_lines_uncovered=5,
        )
        db.session.add(file_coverage)

    return file_coverage
示例#7
0
    def get_jacoco_coverage(self, root):
        step = self.step
        job = self.step.job

        results = []
        for package in root.iter('package'):
            package_path = 'src/main/java/{}'.format(package.get('name'))
            for sourcefile in package.iter('sourcefile'):
                # node name resembles 'com/example/foo/bar/Resource'
                filename = '{filepath}/{filename}'.format(
                    filepath=package_path,
                    filename=sourcefile.get('name'),
                )

                file_coverage = []
                lineno = 0
                for line in sourcefile.iterchildren('line'):
                    number, hits = int(line.get('nr')), int(line.get('ci'))
                    if lineno < number - 1:
                        for lineno in range(lineno, number - 1):
                            file_coverage.append('N')
                    if hits > 0:
                        file_coverage.append('C')
                    else:
                        file_coverage.append('U')
                    lineno = number

                result = FileCoverage(
                    step_id=step.id,
                    job_id=job.id,
                    project_id=job.project_id,
                    filename=filename,
                    data=''.join(file_coverage),
                )
                self.add_file_stats(result)

                results.append(result)

        return results
示例#8
0
    def get_cobertura_coverage(self, root):
        step = self.step
        job = self.step.job

        results = []
        for node in root.iter('class'):
            filename = node.get('filename')
            if not filename:
                self.logger.warn('Unable to determine filename for node: %s',
                                 node)
                continue

            file_coverage = []
            for lineset in node.iterchildren('lines'):
                lineno = 0
                for line in lineset.iterchildren('line'):
                    number, hits = int(line.get('number')), int(
                        line.get('hits'))
                    if lineno < number - 1:
                        for lineno in range(lineno, number - 1):
                            file_coverage.append('N')
                    if hits > 0:
                        file_coverage.append('C')
                    else:
                        file_coverage.append('U')
                    lineno = number

            result = FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=job.project_id,
                filename=filename,
                data=''.join(file_coverage),
            )
            self.add_file_stats(result)

            results.append(result)

        return results
    def test_finished(self, get_implementation, queue_delay):
        # Simulate test type which doesn't interact with artifacts store.
        responses.add(responses.GET,
                      SyncJobStepTest.ARTIFACTSTORE_REQUEST_RE,
                      body='',
                      status=404)

        implementation = mock.Mock()
        get_implementation.return_value = implementation

        def mark_finished(step):
            step.status = Status.finished
            step.result = Result.failed

        implementation.update_step.side_effect = mark_finished

        project = self.create_project()
        build = self.create_build(project=project)
        job = self.create_job(build=build)

        plan = self.create_plan(project)
        self.create_step(plan, implementation='test', order=0)
        self.create_job_plan(job, plan)

        phase = self.create_jobphase(job)
        step = self.create_jobstep(phase)
        task = self.create_task(
            parent_id=job.id,
            task_id=step.id,
            task_name='sync_job_step',
            status=Status.finished,
        )

        db.session.add(
            TestCase(
                name='test',
                step_id=step.id,
                job_id=job.id,
                project_id=project.id,
                result=Result.failed,
            ))

        db.session.add(
            FileCoverage(
                job=job,
                step=step,
                project=job.project,
                filename='foo.py',
                data='CCCUUUCCCUUNNN',
                lines_covered=6,
                lines_uncovered=5,
                diff_lines_covered=3,
                diff_lines_uncovered=2,
            ))
        db.session.commit()

        sync_job_step(
            step_id=step.id.hex,
            task_id=step.id.hex,
            parent_task_id=job.id.hex,
        )

        implementation.update_step.assert_called_once_with(step=step)

        db.session.expire(step)
        db.session.expire(task)

        step = JobStep.query.get(step.id)

        assert step.status == Status.finished

        task = Task.query.get(task.id)

        assert task.status == Status.finished

        assert len(queue_delay.mock_calls) == 0

        stat = ItemStat.query.filter(
            ItemStat.item_id == step.id,
            ItemStat.name == 'tests_missing',
        ).first()
        assert stat.value == 0

        stat = ItemStat.query.filter(
            ItemStat.item_id == step.id,
            ItemStat.name == 'lines_covered',
        ).first()
        assert stat.value == 6

        stat = ItemStat.query.filter(
            ItemStat.item_id == step.id,
            ItemStat.name == 'lines_uncovered',
        ).first()
        assert stat.value == 5

        stat = ItemStat.query.filter(
            ItemStat.item_id == step.id,
            ItemStat.name == 'diff_lines_covered',
        ).first()
        assert stat.value == 3

        stat = ItemStat.query.filter(
            ItemStat.item_id == step.id,
            ItemStat.name == 'diff_lines_uncovered',
        ).first()
        assert stat.value == 2

        assert FailureReason.query.filter(
            FailureReason.step_id == step.id,
            FailureReason.reason == 'test_failures',
        )
示例#10
0
    def test_simple(self):
        fake_project_id = uuid4()

        project = self.create_project()
        build = self.create_build(project)
        self.create_job(build)

        project2 = self.create_project()
        build = self.create_build(project2,
                                  status=Status.finished,
                                  result=Result.passed)
        job = self.create_job(build)
        phase = self.create_jobphase(job)
        step = self.create_jobstep(phase)

        db.session.add(
            FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=project2.id,
                lines_covered=5,
                lines_uncovered=7,
                filename="foo/bar.py",
            ))
        db.session.add(
            FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=project2.id,
                lines_covered=0,
                lines_uncovered=5,
                filename="foo/baz.py",
            ))
        db.session.add(
            FileCoverage(
                step_id=step.id,
                job_id=job.id,
                project_id=project2.id,
                lines_covered=6,
                lines_uncovered=23,
                filename="blah/blah.py",
            ))
        db.session.commit()

        path = '/api/0/projects/{0}/coveragegroups/'.format(
            fake_project_id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 404

        path = '/api/0/projects/{0}/coveragegroups/'.format(project2.id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert len(data['groups']) == 2
        assert data['groups'][0]['filename'] == 'blah/blah.py'
        assert data['groups'][0]['path'] == 'blah/blah.py'
        assert data['groups'][0]['numFiles'] == 1
        assert data['groups'][0]['totalLinesCovered'] == 6
        assert data['groups'][0]['totalLinesUncovered'] == 23
        assert data['groups'][1]['filename'] == 'foo'
        assert data['groups'][1]['path'] == 'foo'
        assert data['groups'][1]['numFiles'] == 2
        assert data['groups'][1]['totalLinesCovered'] == 5
        assert data['groups'][1]['totalLinesUncovered'] == 12
        assert len(data['trail']) == 0

        path = '/api/0/projects/{0}/coveragegroups/?parent=foo'.format(
            project2.id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert len(data['groups']) == 2
        assert data['groups'][0]['filename'] == 'bar.py'
        assert data['groups'][0]['path'] == 'foo/bar.py'
        assert data['groups'][0]['numFiles'] == 1
        assert data['groups'][0]['totalLinesCovered'] == 5
        assert data['groups'][0]['totalLinesUncovered'] == 7
        assert data['groups'][1]['filename'] == 'baz.py'
        assert data['groups'][1]['path'] == 'foo/baz.py'
        assert data['groups'][1]['numFiles'] == 1
        assert data['groups'][1]['totalLinesCovered'] == 0
        assert data['groups'][1]['totalLinesUncovered'] == 5
        assert len(data['trail']) == 1
        assert data['trail'][0] == {
            'name': 'foo',
            'path': 'foo',
        }
示例#11
0
    def test_simple(self, generate_diff):
        project = self.create_project()
        build = self.create_build(
            project, date_created=datetime(2013, 9, 19, 22, 15, 24),
            status=Status.finished)
        job1 = self.create_job(build)
        job2 = self.create_job(build)

        db.session.add(FileCoverage(
            project_id=project.id,
            job_id=job1.id, filename='ci/run_with_retries.py',
            lines_covered=4, lines_uncovered=5, diff_lines_covered=2, diff_lines_uncovered=3,
            data='NNCCUU' + 'N' * 50 + 'CCUUU',  # Matches sample.diff
        ))
        db.session.add(FileCoverage(
            project_id=project.id,
            job_id=job2.id, filename='foobar.py',
            lines_covered=4, lines_uncovered=5, diff_lines_covered=2, diff_lines_uncovered=3,
            data='NNCCUU' + 'N' * 50 + 'CCUUU',  # Matches sample.diff
        ))
        # Two more not in sample.diff, same filename but different job ids
        db.session.add(FileCoverage(
            project_id=project.id,
            job_id=job1.id, filename='booh.py',
            lines_covered=4, lines_uncovered=5, diff_lines_covered=3, diff_lines_uncovered=2,
        ))
        db.session.add(FileCoverage(
            project_id=project.id,
            job_id=job2.id, filename='booh.py',
            lines_covered=5, lines_uncovered=4, diff_lines_covered=2, diff_lines_uncovered=3,
        ))
        db.session.commit()

        path = '/api/0/builds/{0}/stats/coverage/'.format(build.id.hex)

        resp = self.client.get(path)
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert len(data) == 3
        assert data['ci/run_with_retries.py'] == {
            'linesCovered': 4,
            'linesUncovered': 5,
            'diffLinesCovered': 2,
            'diffLinesUncovered': 3,
        }
        assert data['foobar.py'] == {
            'linesCovered': 4,
            'linesUncovered': 5,
            'diffLinesCovered': 2,
            'diffLinesUncovered': 3,
        }
        assert data['booh.py'] == {
            'linesCovered': 5,
            'linesUncovered': 4,
            'diffLinesCovered': 3,
            'diffLinesUncovered': 2,
        }

        generate_diff.return_value = None

        resp = self.client.get(path + '?diff=1')
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert len(data) == 0

        generate_diff.return_value = SAMPLE_DIFF

        resp = self.client.get(path + '?diff=1')
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert len(data) == 1
        assert data['ci/run_with_retries.py'] == {
            'linesCovered': 4,
            'linesUncovered': 5,
            'diffLinesCovered': 2,
            'diffLinesUncovered': 3,
        }