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", }
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
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
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
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
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
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', )
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', }
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, }