Пример #1
0
    def test_get_build_failure_reasons_multiple_failures(self):
        project = self.create_project(name='test', slug='project-slug')
        build = self.create_build(project,
                                  result=Result.failed,
                                  target='D1',
                                  label='Some sweet diff')
        job = self.create_job(build=build, result=Result.failed)
        jobphase = self.create_jobphase(job)
        jobstep = self.create_jobstep(jobphase,
                                      status=Status.finished,
                                      result=Result.failed)
        for reason in ('missing_tests', 'timeout', 'aborted'):
            db.session.add(
                FailureReason(step_id=jobstep.id,
                              job_id=job.id,
                              build_id=build.id,
                              project_id=project.id,
                              reason=reason))
        jobstep2 = self.create_jobstep(jobphase,
                                       status=Status.finished,
                                       result=Result.failed)
        for reason in ('timeout', 'insufficient_politeness'):
            db.session.add(
                FailureReason(step_id=jobstep2.id,
                              job_id=job.id,
                              build_id=build.id,
                              project_id=project.id,
                              reason=reason))
        db.session.commit()

        self.assertEquals(
            _get_build_failure_reasons(build),
            ['aborted', 'insufficient_politeness', 'missing_tests', 'timeout'])
Пример #2
0
    def test_simple(self):
        project = self.create_project()
        previous_build = self.create_build(project,
                                           date_created=datetime(
                                               2013, 9, 19, 22, 15, 23),
                                           status=Status.finished)
        build = self.create_build(project,
                                  date_created=datetime(
                                      2013, 9, 19, 22, 15, 24))
        job1 = self.create_job(build)
        job2 = self.create_job(build)
        phase = self.create_jobphase(job1)
        step = self.create_jobstep(phase)
        db.session.add(
            Event(
                item_id=build.id,
                type='green_build_notification',
            ))
        db.session.add(
            ItemStat(
                item_id=build.id,
                name='test_failures',
                value=2,
            ))
        db.session.add(
            FailureReason(project_id=project.id,
                          build_id=build.id,
                          job_id=job1.id,
                          step_id=step.id,
                          reason='test_failures'))
        db.session.commit()

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

        resp = self.client.get(path)
        assert resp.status_code == 200
        data = self.unserialize(resp)
        assert data['id'] == build.id.hex
        assert len(data['jobs']) == 2
        assert data['jobs'][0]['id'] == job1.id.hex
        assert data['jobs'][1]['id'] == job2.id.hex
        assert data['seenBy'] == []
        assert data['testFailures']['total'] == 0
        assert data['testFailures']['tests'] == []
        assert data['testChanges'] == []
        assert len(data['events']) == 1
        assert len(data['failures']) == 1
        assert data['failures'][0] == {
            'id':
            'test_failures',
            'reason':
            'There were <a href="http://example.com/projects/{0}/builds/{1}/tests/?result=failed">2 failing tests</a>.'
            .format(
                project.slug,
                build.id.hex,
            ),
            'count':
            1,
        }
Пример #3
0
    def test_failed_build(self, post_fn):
        URL = "https://analytics.example.com/report?source=changes"
        self._set_config_url(URL)
        project = self.create_project(name='test', slug='project-slug')
        self.assertEquals(post_fn.call_count, 0)
        duration = 1234
        created = 1424998888
        started = created + 10
        finished = started + duration

        build = self.create_build(project,
                                  result=Result.failed,
                                  target='D1',
                                  label='Some sweet diff',
                                  duration=duration,
                                  date_created=ts_to_datetime(created),
                                  date_started=ts_to_datetime(started),
                                  date_finished=ts_to_datetime(finished))

        job = self.create_job(build=build, result=Result.failed)
        jobphase = self.create_jobphase(job)
        jobstep = self.create_jobstep(jobphase,
                                      status=Status.finished,
                                      result=Result.failed)
        db.session.add(
            FailureReason(step_id=jobstep.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='missing_tests'))
        db.session.commit()

        with mock.patch(
                'changes.listeners.analytics_notifier._get_phabricator_revision_url'
        ) as mock_get_phab:
            mock_get_phab.return_value = 'https://example.com/D1'
            with mock.patch(
                    'changes.listeners.analytics_notifier._get_build_failure_reasons'
            ) as mock_get_failures:
                mock_get_failures.return_value = ['aborted', 'missing_tests']
                build_finished_handler(build_id=build.id.hex)

        expected_data = {
            'build_id': build.id.hex,
            'number': 1,
            'target': 'D1',
            'project_slug': 'project-slug',
            'result': 'Failed',
            'label': 'Some sweet diff',
            'is_commit': True,
            'duration': 1234,
            'date_created': created,
            'date_started': started,
            'date_finished': finished,
            'phab_revision_url': 'https://example.com/D1',
            'failure_reasons': ['aborted', 'missing_tests'],
        }
        post_fn.assert_called_once_with(URL, [expected_data])
Пример #4
0
 def _add_failure_reason(self):
     db.session.add(
         FailureReason(step_id=self.step.id,
                       job_id=self.step.job_id,
                       build_id=self.step.job.build_id,
                       project_id=self.step.project_id,
                       reason='malformed_manifest_json'))
     self.step.result = Result.infra_failed
     db.session.add(self.step)
     db.session.commit()
Пример #5
0
    def test_get_job_failure_reasons_by_jobstep_failures(self):
        project = self.create_project(name='test', slug='project-slug')

        build = self.create_build(project,
                                  result=Result.failed,
                                  target='D1',
                                  label='Some sweet diff')
        job = self.create_job(build=build, result=Result.failed)
        jobphase = self.create_jobphase(job)
        jobstep_a = self.create_jobstep(jobphase,
                                        status=Status.finished,
                                        result=Result.failed,
                                        label='Step A')
        jobstep_b = self.create_jobstep(jobphase,
                                        status=Status.finished,
                                        result=Result.failed,
                                        label='Step B')

        db.session.add(
            FailureReason(step_id=jobstep_a.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='missing_tests'))
        db.session.add(
            FailureReason(step_id=jobstep_a.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='aborted'))
        db.session.add(
            FailureReason(step_id=jobstep_b.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='aborted'))
        db.session.commit()

        expected_data = defaultdict(list)
        expected_data[jobstep_a.id] = ['aborted', 'missing_tests']
        expected_data[jobstep_b.id] = ['aborted']
        self.assertEquals(_get_job_failure_reasons_by_jobstep(job),
                          expected_data)
Пример #6
0
 def verify_final_artifacts(self, step, artifacts):
     # If the Jenkins run was aborted or timed out, we don't expect a manifest file.
     if (step.result != Result.aborted and
         not step.data.get('timed_out', False) and
             not any(ManifestJsonHandler.can_process(a.name) for a in artifacts)):
         db.session.add(FailureReason(
             step_id=step.id,
             job_id=step.job.id,
             build_id=step.job.build_id,
             project_id=step.job.project_id,
             reason='missing_manifest_json',
         ))
         step.result = Result.infra_failed
         db.session.add(step)
         db.session.commit()
Пример #7
0
    def test_failure_reasons(self, get_implementation):
        # 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

        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,
                                   status=Status.finished,
                                   result=Result.passed)

        db.session.add(
            FailureReason(step_id=step.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='missing_manifest_json'))
        db.session.commit()

        with mock.patch.object(sync_job_step, 'allow_absent_from_db', True):
            sync_job_step(step_id=step.id.hex,
                          task_id=step.id.hex,
                          parent_task_id=job.id.hex)

        assert step.result == Result.infra_failed
Пример #8
0
    def post(self, step_id):
        jobstep = JobStep.query.options(joinedload(
            'project', innerjoin=True), ).get(step_id)
        if jobstep is None:
            return '', 404

        args = self.post_parser.parse_args()

        current_datetime = args.date or datetime.utcnow()

        if args.result:
            jobstep.result = Result[args.result]

        if args.status:
            jobstep.status = Status[args.status]

            # if we've finished this job, lets ensure we have set date_finished
            if jobstep.status == Status.finished and jobstep.date_finished is None:
                jobstep.date_finished = current_datetime
            elif jobstep.status != Status.finished and jobstep.date_finished:
                jobstep.date_finished = None

            if jobstep.status != Status.queued and jobstep.date_started is None:
                jobstep.date_started = current_datetime
            elif jobstep.status == Status.queued and jobstep.date_started:
                jobstep.date_started = None

        if args.node:
            node, _ = get_or_create(Node, where={
                'label': args.node,
            })
            jobstep.node_id = node.id

        # we want to guarantee that even if the jobstep seems to succeed, that
        # we accurately reflect what we internally would consider a success state
        if jobstep.result == Result.passed and jobstep.status == Status.finished:
            last_command = Command.query.filter(
                Command.jobstep_id == jobstep.id, ).order_by(
                    Command.order.desc()).first()

            if not last_command:
                pass

            elif last_command.status != Status.finished:
                jobstep.result = Result.failed

            elif last_command.return_code != 0:
                jobstep.result = Result.failed

            # are we missing an expansion step? it must happen before reporting
            # the result, and would falsely give us a success metric
            elif last_command.type.is_collector() and self._is_final_jobphase(
                    jobstep.phase):
                jobstep.result = Result.failed
                job = jobstep.job
                # TODO(dcramer): we should add a better failure reason
                db.session.add(
                    FailureReason(
                        step_id=jobstep.id,
                        job_id=job.id,
                        build_id=job.build_id,
                        project_id=job.project_id,
                        reason='missing_artifact',
                    ))

        db.session.add(jobstep)
        if db.session.is_modified(jobstep):
            db.session.commit()

            # TODO(dcramer): this is a little bit hacky, but until we can entirely
            # move to push APIs we need a good way to handle the existing sync
            job = jobstep.job
            sync_job.delay_if_needed(
                task_id=job.id.hex,
                parent_task_id=job.id.hex,
                job_id=job.build_id.hex,
            )

        return self.respond(jobstep)
Пример #9
0
def job(build, change=None, **kwargs):
    kwargs.setdefault('project', build.project)
    kwargs.setdefault('label', get_sentences(1)[0][:128])
    kwargs.setdefault('status', Status.finished)
    kwargs.setdefault('result', Result.passed)
    kwargs.setdefault('duration', random.randint(10000, 100000))
    kwargs['source'] = build.source

    kwargs['source_id'] = kwargs['source'].id
    kwargs['project_id'] = kwargs['project'].id
    kwargs['build_id'] = build.id
    if change:
        kwargs['change_id'] = change.id

    job = Job(
        build=build,
        change=change,
        **kwargs
    )
    db.session.add(job)

    node, created = get_or_create(Node, where={
        'label': get_sentences(1)[0][:32],
    })

    if created:
        cluster, _ = get_or_create(Cluster, where={
            'label': get_sentences(1)[0][:32],
        })

        clusternode = ClusterNode(cluster=cluster, node=node)
        db.session.add(clusternode)

    jobplan = JobPlan.build_jobplan(plan(build.project), job)
    db.session.add(jobplan)

    phase1_setup = JobPhase(
        project=job.project, job=job,
        date_started=job.date_started,
        date_finished=job.date_finished,
        status=Status.finished, result=Result.passed, label='Setup',
    )
    db.session.add(phase1_setup)

    phase1_compile = JobPhase(
        project=job.project, job=job,
        date_started=job.date_started,
        date_finished=job.date_finished,
        status=Status.finished, result=Result.passed, label='Compile',
    )
    db.session.add(phase1_compile)

    phase1_test = JobPhase(
        project=job.project, job=job,
        date_started=job.date_started,
        date_finished=job.date_finished,
        status=kwargs['status'], result=kwargs['result'], label='Test',
    )
    db.session.add(phase1_test)

    step = JobStep(
        project=job.project, job=job,
        phase=phase1_setup, status=phase1_setup.status, result=phase1_setup.result,
        label='Setup', node=node,
    )
    db.session.add(step)
    command = Command(
        jobstep=step,
        script="echo 1",
        label="echo 1",
    )
    db.session.add(command)

    step = JobStep(
        project=job.project, job=job,
        phase=phase1_compile, status=phase1_compile.status, result=phase1_compile.result,
        label='Compile', node=node,
    )
    db.session.add(step)
    command = Command(
        jobstep=step,
        script="echo 2",
        label="echo 2",
    )
    db.session.add(command)

    step = JobStep(
        project=job.project, job=job,
        phase=phase1_test, status=phase1_test.status, result=phase1_test.result,
        label=TEST_STEP_LABELS.next(), node=node,
    )
    db.session.add(step)
    command = Command(
        jobstep=step,
        script="echo 3",
        label="echo 3",
    )
    db.session.add(command)

    step = JobStep(
        project=job.project, job=job,
        phase=phase1_test, status=phase1_test.status, result=phase1_test.result,
        label=TEST_STEP_LABELS.next(), node=node,
    )
    db.session.add(step)
    command = Command(
        jobstep=step,
        script="echo 4",
        label="echo 4",
    )
    db.session.add(command)

    if phase1_test.result == Result.failed:
        db.session.add(FailureReason(
            reason='test_failures',
            build_id=build.id,
            job_id=job.id,
            step_id=step.id,
            project_id=job.project_id
        ))

    return job
Пример #10
0
    def test_failed_job(self, post_fn):
        URL = "https://analytics.example.com/report?source=changes_jobstep"
        self._set_config_url(build_url=None, jobstep_url=URL)
        project = self.create_project(name='test', slug='project-slug')
        self.assertEquals(post_fn.call_count, 0)
        duration = 1234
        created = 1424998888
        started = created + 10
        finished = started + duration

        build = self.create_build(project,
                                  result=Result.failed,
                                  target='D1',
                                  label='Some sweet diff',
                                  duration=duration,
                                  date_created=ts_to_datetime(created),
                                  date_started=ts_to_datetime(started),
                                  date_finished=ts_to_datetime(finished))
        job = self.create_job(build=build, result=Result.failed)
        jobphase = self.create_jobphase(job)
        node = self.create_node()
        jobstep = self.create_jobstep(jobphase,
                                      status=Status.finished,
                                      result=Result.failed,
                                      label='Step 1',
                                      date_created=ts_to_datetime(created),
                                      date_started=ts_to_datetime(started),
                                      date_finished=ts_to_datetime(finished),
                                      node_id=node.id)
        db.session.add(
            FailureReason(step_id=jobstep.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='missing_tests'))
        db.session.add(
            FailureReason(step_id=jobstep.id,
                          job_id=job.id,
                          build_id=build.id,
                          project_id=project.id,
                          reason='aborted'))
        db.session.commit()

        with mock.patch(
                'changes.listeners.analytics_notifier._get_job_failure_reasons_by_jobstep'
        ) as mock_get_failures:
            mock_get_failures.return_value = defaultdict(list)
            mock_get_failures.return_value[jobstep.id] = [
                'aborted', 'missing_tests'
            ]
            job_finished_handler(job_id=job.id.hex)

        expected_data = {
            'jobstep_id': jobstep.id.hex,
            'phase_id': jobphase.id.hex,
            'build_id': build.id.hex,
            'job_id': job.id.hex,
            'result': 'Failed',
            'label': 'Step 1',
            'data': {},
            'date_created': created,
            'date_started': started,
            'date_finished': finished,
            'failure_reasons': ['aborted', 'missing_tests'],
            'log_categories': [],
        }
        post_fn.assert_called_once_with(URL, [expected_data])
        json.dumps(post_fn.call_args[0][1])