Example #1
0
    def testRevertCulprit(self, mock_revert, *_):
        repo_name = 'chromium'
        revision = 'rev1'
        build_key = 'm/b/123'

        revert_cl = RevertCL()
        revert_cl.revert_cl_url = 'url'
        revert_cl.created_time = datetime.datetime(2018, 6, 20, 0, 0, 0)

        mock_revert.return_value = (constants.CREATED_BY_FINDIT, revert_cl,
                                    None)

        culprit = WfSuspectedCL.Create(repo_name, revision, 1)
        culprit.put()

        pipeline_input = CreateRevertCLParameters(
            cl_key=culprit.key.urlsafe(),
            build_key=build_key,
            failure_type=failure_type.COMPILE)
        self.assertEqual(
            constants.CREATED_BY_FINDIT,
            culprit_action.RevertCulprit(pipeline_input, 'pipeline_id'))
        culprit = WfSuspectedCL.Get(repo_name, revision)
        self.assertEqual(revert_cl, culprit.revert_cl)
        self.assertEqual(analysis_status.COMPLETED, culprit.revert_status)
    def testSubmitRevertSucceed(self, mock_fn, mock_commit, *_):
        repo_name = 'chromium'
        revision = 'rev1'
        commit_position = 123

        cl_info = ClInfo(self.review_server_host, self.review_change_id)
        cl_info.commits.append(
            Commit('20001', 'rev1', [], datetime(2017, 2, 1, 0, 0, 0)))
        mock_fn.return_value = cl_info
        mock_commit.return_value = True

        culprit = WfSuspectedCL.Create(repo_name, revision, commit_position)
        revert = RevertCL()
        revert_change_id = '54321'
        revert.revert_cl_url = 'https://%s/q/%s' % (self.review_server_host,
                                                    revert_change_id)
        culprit.revert_cl = revert
        culprit.revert_status = status.COMPLETED
        culprit.put()
        revert_status = constants.CREATED_BY_FINDIT
        pipeline_input = SubmitRevertCLParameters(
            cl_key=culprit.key.urlsafe(),
            revert_status=revert_status,
            failure_type=failure_type.COMPILE)
        pipeline = SubmitRevertCLPipeline(pipeline_input)
        self.assertEqual(constants.COMMITTED, pipeline.run(pipeline_input))

        culprit = WfSuspectedCL.Get(repo_name, revision)
        self.assertEqual(culprit.revert_submission_status, status.COMPLETED)

        mock_commit.assert_called_with(revert_change_id)
Example #3
0
    def testAddedReviewerFailedBefore(self, mock_fn, mock_send, *_):
        repo_name = 'chromium'
        revision = 'rev1'

        cl_info = ClInfo(self.review_server_host, self.review_change_id)
        cl_info.commits.append(
            Commit('20001', 'rev1', [], datetime(2017, 2, 1, 0, 0, 0)))
        cl_info.owner_email = '*****@*****.**'
        revert_cl = ClInfo('revert_review_host', '123V3127')
        revert_cl.url = 'https://chromium-review.googlesource.com/54321'
        cl_info.reverts.append(
            Revert('20001', revert_cl, constants.DEFAULT_SERVICE_ACCOUNT,
                   datetime(2017, 2, 1, 1, 0, 0)))
        mock_fn.return_value = cl_info

        culprit = WfSuspectedCL.Create(repo_name, revision, 123)
        culprit.revert_cl = RevertCL()
        culprit.revert_status = status.RUNNING
        culprit.cr_notification_status = status.COMPLETED
        culprit.put()
        revert_status, _, _ = gerrit.RevertCulprit(culprit.key.urlsafe(),
                                                   'm/b/1',
                                                   failure_type.COMPILE,
                                                   'compile',
                                                   self.codereview_info)

        self.assertEquals(revert_status, services_constants.CREATED_BY_FINDIT)
Example #4
0
    def testLatestBuildSucceeded(self, mock_fn, *_):
        repo_name = 'chromium'
        revision = 'rev1'

        cl_info = ClInfo(self.review_server_host, self.review_change_id)
        cl_info.owner_email = '*****@*****.**'
        cl_info.commits.append(
            Commit('20001', 'rev1', datetime(2017, 2, 1, 0, 0, 0)))
        revert_cl = ClInfo('revert_review_host', '123V3127')
        revert_cl.url = 'https://codereview.chromium.org/54321'
        cl_info.reverts.append(
            Revert('20001', revert_cl, constants.DEFAULT_SERVICE_ACCOUNT,
                   datetime(2017, 2, 1, 1, 0, 0)))
        mock_fn.return_value = cl_info

        culprit = WfSuspectedCL.Create(repo_name, revision, 123)
        culprit.revert_cl = RevertCL()
        culprit.revert_status = status.RUNNING
        culprit.put()
        pipeline = CreateRevertCLPipeline('m', 'b', 123, repo_name, revision)
        revert_status = pipeline.run('m', 'b', 123, repo_name, revision)

        self.assertEquals(revert_status, create_revert_cl_pipeline.SKIPPED)

        culprit = WfSuspectedCL.Get(repo_name, revision)
        self.assertEqual(culprit.revert_status, status.SKIPPED)
        self.assertIsNotNone(culprit.revert_cl)
        self.assertEqual(culprit.skip_revert_reason,
                         create_revert_cl_pipeline.NEWEST_BUILD_GREEN)
    def testCheckRevertStatusOfSuspectedCLFalsePositive(self, mock_fn, *_):
        mock_fn.return_value = {
            'commit_position': 1,
            'code_review_url': 'codereview.chromium.org/123',
            'review_server_host': 'codereview.chromium.org',
            'review_change_id': '123'
        }
        suspected_cl = WfSuspectedCL.Create('chromium', 'a1b2c3d4', 1)
        suspected_cl.revert_cl = RevertCL()

        check_reverted_cls._CheckRevertStatusOfSuspectedCL(suspected_cl)
        self.assertEqual(revert_cl_status.FALSE_POSITIVE,
                         suspected_cl.revert_cl.status)
    def testCheckRevertStatusOfSuspectedCLRevertedNoCodeReview(
            self, mock_fn, _):
        mock_fn.return_value = {
            'commit_position': 1,
            'code_review_url': 'badhost.org/123',
            'review_server_host': 'badhost.org/123',
            'review_change_id': '123'
        }
        suspected_cl = WfSuspectedCL.Create('chromium', 'a1b2c3d4', 1)
        suspected_cl.revert_cl = RevertCL()

        self.assertEqual(
            (None, None, None),
            check_reverted_cls._CheckRevertStatusOfSuspectedCL(suspected_cl))
Example #7
0
    def testRevertHasCompleted(self):
        repo_name = 'chromium'
        revision = 'rev1'

        culprit = WfSuspectedCL.Create(repo_name, revision, 123)
        culprit.revert_cl = RevertCL()
        culprit.revert_status = status.COMPLETED
        culprit.put()

        pipeline = CreateRevertCLPipeline('m', 'b', 123, repo_name, revision)
        revert_status = pipeline.run('m', 'b', 123, repo_name, revision)

        self.assertEquals(revert_status,
                          create_revert_cl_pipeline.CREATED_BY_FINDIT)
Example #8
0
    def testSendNotification(self):
        repo_name = 'chromium'
        revision = 'rev'
        commit_position = 123
        revert_cl_url = 'revert_url'
        commit_status = constants.SKIPPED

        culprit = WfSuspectedCL.Create(repo_name, revision, 1)
        culprit.revert_cl = RevertCL()
        culprit.put()

        self.mock(irc, 'IRCClient', MockedIRCClient)
        self.assertTrue(
            irc.SendMessageToIrc(revert_cl_url, commit_position, revision,
                                 culprit.key.urlsafe(), commit_status))
Example #9
0
    def testRevertHasCompleted(self):
        repo_name = 'chromium'
        revision = 'rev1'

        culprit = WfSuspectedCL.Create(repo_name, revision, 123)
        culprit.revert_cl = RevertCL()
        culprit.revert_status = analysis_status.COMPLETED
        culprit.put()

        parameters = CreateRevertCLParameters(cl_key=culprit.key.urlsafe(),
                                              build_key='build_key')
        pipeline_id = 'pipeline_id'

        self.assertFalse(
            culprit_action._CanCreateRevertForCulprit(parameters, pipeline_id))
Example #10
0
    def testSubmitRevertSucceed(self, mock_fn, mock_commit, mock_add, *_):
        repo_name = 'chromium'
        revision = 'rev1'
        commit_position = 123

        cl_info = ClInfo(self.review_server_host, self.review_change_id)
        cl_info.commits.append(
            Commit('20001', 'rev1', [], datetime(2017, 2, 1, 0, 0, 0)))
        mock_fn.return_value = cl_info
        mock_commit.return_value = True

        culprit = WfSuspectedCL.Create(repo_name, revision, commit_position)
        revert_for_culprit = RevertCL()
        revert_change_id = '54321'
        revert_for_culprit.revert_cl_url = 'https://%s/q/%s' % (
            self.review_server_host, revert_change_id)
        culprit.revert_cl = revert_for_culprit
        culprit.revert_status = status.COMPLETED
        culprit.put()
        revert_status = services_constants.CREATED_BY_FINDIT
        commit_status = gerrit.CommitRevert(
            SubmitRevertCLParameters(cl_key=culprit.key.urlsafe(),
                                     revert_status=revert_status),
            self.codereview_info)

        self.assertEqual(services_constants.COMMITTED, commit_status)

        mock_commit.assert_called_once_with(revert_change_id)

        culprit_link = (
            'https://analysis.chromium.org/waterfall/culprit?key=%s' %
            (culprit.key.urlsafe()))
        false_positive_bug_link = gerrit.CreateFinditWrongBugLink(
            gerrit.FINDIT_BUILD_FAILURE_COMPONENT, culprit_link, revision)
        message = textwrap.dedent("""
        Sheriffs, CL owner or CL reviewers:
        Please confirm this revert if it is correct.
        If it is a false positive, please reland the original CL and report this
        false positive at %s.

        For more information about Findit auto-revert: %s.

        Sheriffs, it'll be much appreciated if you could take a couple minutes
        to fill out this survey: %s.""") % (
            false_positive_bug_link, gerrit._MANUAL_LINK, gerrit._SURVEY_LINK)
        mock_add.assert_called_once_with(revert_change_id, ['*****@*****.**'],
                                         message)
Example #11
0
    def testCanCommitRevert(self, *_):
        repo_name = 'chromium'
        revision = 'rev1'

        culprit = WfSuspectedCL.Create(repo_name, revision, 123)
        culprit.revert_cl = RevertCL()
        culprit.revert_status = analysis_status.COMPLETED
        culprit.put()

        parameters = SubmitRevertCLParameters(
            cl_key=culprit.key.urlsafe(),
            revert_status=constants.CREATED_BY_FINDIT)
        pipeline_id = 'pipeline_id'

        self.assertTrue(
            culprit_action._CanCommitRevert(parameters, pipeline_id,
                                            'codereview_info'))
    def testCheckRevertStatusOfSuspectedCLReverted(self, mock_fn, *_):
        mock_fn.return_value = {
            'commit_position': 1,
            'code_review_url': 'codereview.chromium.org/q/123',
            'review_server_host': 'codereview.chromium.org',
            'review_change_id': '123'
        }
        suspected_cl = WfSuspectedCL.Create('chromium', 'a1b2c3d4', 1)
        suspected_cl.revert_cl = RevertCL()

        result = check_reverted_cls._CheckRevertStatusOfSuspectedCL(
            suspected_cl)

        self.assertTrue(result[0])
        self.assertEqual(result[1], 'https://codereview.chromium.org/q/123')
        self.assertEqual(result[2], revert_cl_status.COMMITTED)
        self.assertEqual(revert_cl_status.COMMITTED,
                         suspected_cl.revert_cl.status)
Example #13
0
    def testSendNotificationException(self, mocked_logging, _):
        repo_name = 'chromium'
        revision = 'rev'
        commit_position = 123
        revert_cl_url = 'revert_url'
        commit_status = constants.SKIPPED

        culprit = WfSuspectedCL.Create(repo_name, revision, 1)
        culprit.revert_cl = RevertCL()
        culprit.put()

        self.mock(irc, 'IRCClient', MockedIRCClient)
        self.assertFalse(
            irc.SendMessageToIrc(revert_cl_url, commit_position, revision,
                                 culprit.key.urlsafe(), commit_status))

        expected_message = 'Sending message to IRC failed with An exception.'
        mocked_logging.assert_called_with(expected_message)
Example #14
0
    def testCannotCommitRevertByAnotherAnalysis(self):
        repo_name = 'chromium'
        revision = 'rev1'

        culprit = WfSuspectedCL.Create(repo_name, revision, 123)
        culprit.revert_cl = RevertCL()
        culprit.revert_status = analysis_status.COMPLETED
        culprit.revert_submission_status = analysis_status.RUNNING
        culprit.submit_revert_pipeline_id = 'pipeline_id'
        culprit.put()

        parameters = SubmitRevertCLParameters(
            cl_key=culprit.key.urlsafe(),
            revert_status=constants.CREATED_BY_FINDIT)
        pipeline_id = 'another_pipeline'

        self.assertFalse(
            culprit_action._CanCommitRevert(parameters, pipeline_id,
                                            'codereview_info'))
Example #15
0
    def testSendNotificationToIRC(self, mock_mo, _):
        repo_name = 'chromium'
        revision = 'rev'
        revert_status = constants.CREATED_BY_FINDIT
        commit_status = constants.SKIPPED

        culprit = WfSuspectedCL.Create(repo_name, revision, 1)
        culprit.revert_cl = RevertCL()
        culprit.revert_cl.revert_cl_url = 'revert_url'
        culprit.put()

        pipeline_input = SendNotificationToIrcParameters(
            cl_key=culprit.key.urlsafe(),
            revert_status=revert_status,
            commit_status=commit_status,
            failure_type=failure_type.COMPILE)
        self.assertTrue(culprit_action.SendMessageToIRC(pipeline_input))
        parameters = {'type': 'compile', 'action_taken': 'irc_notified'}
        mock_mo.assert_called_once_with(parameters)
Example #16
0
    def testCommitRevertNoCodeReview(self, _):
        repo_name = 'chromium'
        revision = 'rev1'
        commit_position = 123

        cl_info = ClInfo(self.review_server_host, self.review_change_id)
        cl_info.commits.append(
            Commit('20001', 'rev1', [], datetime(2017, 2, 1, 0, 0, 0)))

        culprit = WfSuspectedCL.Create(repo_name, revision, commit_position)
        revert_for_culprit = RevertCL()
        revert_change_id = '54321'
        revert_for_culprit.revert_cl_url = 'https://%s/q/%s' % (
            self.review_server_host, revert_change_id)
        culprit.revert_cl = revert_for_culprit
        culprit.revert_status = status.COMPLETED
        culprit.put()
        revert_status = services_constants.CREATED_BY_FINDIT
        self.assertEquals(
            services_constants.ERROR,
            gerrit.CommitRevert(
                SubmitRevertCLParameters(cl_key=culprit.key.urlsafe(),
                                         revert_status=revert_status), None))
    def testGenerateFinditMetrics(self):
        reverted_suspected_cl = WfSuspectedCL.Create('chromium', 'r1', 1)
        reverted_revert_cl = RevertCL()
        reverted_revert_cl.status = revert_cl_status.COMMITTED
        reverted_suspected_cl.revert_cl = reverted_revert_cl

        duplicate_fast_suspected_cl = WfSuspectedCL.Create('chromium', 'r2', 2)
        duplicate_revert_cl = RevertCL()
        duplicate_revert_cl.created_time = datetime(2017, 3, 15, 1)
        duplicate_revert_cl.status = revert_cl_status.DUPLICATE
        duplicate_fast_suspected_cl.revert_cl = duplicate_revert_cl
        duplicate_fast_suspected_cl.sheriff_action_time = datetime(
            2017, 3, 15, 2)

        duplicate_slow_suspected_cl = WfSuspectedCL.Create('chromium', 'r3', 3)
        duplicate_revert_cl = RevertCL()
        duplicate_revert_cl.created_time = datetime(2017, 3, 15, 2)
        duplicate_revert_cl.status = revert_cl_status.DUPLICATE
        duplicate_slow_suspected_cl.revert_cl = duplicate_revert_cl
        duplicate_slow_suspected_cl.sheriff_action_time = datetime(
            2017, 3, 15, 1)

        false_positive_suspected_cl = WfSuspectedCL.Create('chromium', 'r4', 4)
        false_positive_revert_cl = RevertCL()
        false_positive_revert_cl.status = revert_cl_status.FALSE_POSITIVE
        false_positive_suspected_cl.revert_cl = false_positive_revert_cl

        slow_suspected_cl = WfSuspectedCL.Create('chromium', 'r5', 5)
        slow_suspected_cl.cr_notification_time = datetime(2017, 3, 15, 2)
        slow_suspected_cl.should_be_reverted = True
        slow_suspected_cl.sheriff_action_time = datetime(2017, 3, 15, 1)

        false_positive_suspected_cl_no_revert = WfSuspectedCL.Create(
            'chromium', 'r6', 6)

        expected_metrics = {
            'revert_cls_detected': 5,
            'revert_cls_created': 4,
            'revert_cls_committed': 1,
            'duplicate_revert_cls': 2,
            'sheriffs_faster': 2,
            'false_positives': 1,
            'findit_faster': 1,
            'faster_than_sheriff_metrics': {
                'ninetieth_percentile': '01:00:00',
                'average': '01:00:00',
                'total': 1,
                'fiftieth_percentile': '01:00:00',
                'seventieth_percentile': '01:00:00'
            },
            'slower_than_sheriff_metrics': {
                'ninetieth_percentile': '01:00:00',
                'average': '01:00:00',
                'total': 2,
                'fiftieth_percentile': '01:00:00',
                'seventieth_percentile': '01:00:00'
            }
        }

        metrics = auto_revert_metrics._GenerateFinditMetrics([
            reverted_suspected_cl, duplicate_fast_suspected_cl,
            duplicate_slow_suspected_cl, false_positive_suspected_cl,
            slow_suspected_cl, false_positive_suspected_cl_no_revert
        ])

        self.assertEqual(expected_metrics, metrics)
Example #18
0
    def testSubmitRevertFailed(self, mock_fn, mock_commit, mock_add, *_):
        repo_name = 'chromium'
        revision = 'rev1'
        commit_position = 123

        cl_info = ClInfo(self.review_server_host, self.review_change_id)
        cl_info.commits.append(
            Commit('20001', 'rev1', [], datetime(2017, 2, 1, 0, 0, 0)))
        mock_fn.return_value = cl_info
        mock_commit.return_value = False

        culprit = WfSuspectedCL.Create(repo_name, revision, commit_position)
        revert_for_culprit = RevertCL()
        revert_change_id = '54321'
        revert_for_culprit.revert_cl_url = 'https://%s/q/%s' % (
            self.review_server_host, revert_change_id)
        culprit.revert_cl = revert_for_culprit
        culprit.revert_status = status.COMPLETED
        culprit.put()

        revert_status = services_constants.CREATED_BY_FINDIT
        commit_status = gerrit.CommitRevert(
            SubmitRevertCLParameters(cl_key=culprit.key.urlsafe(),
                                     revert_status=revert_status),
            self.codereview_info)

        self.assertEqual(services_constants.ERROR, commit_status)
        mock_commit.assert_called_once_with(revert_change_id)

        culprit_link = (
            'https://analysis.chromium.org/waterfall/culprit?key=%s' %
            culprit.key.urlsafe())
        false_positive_bug_link = gerrit.CreateFinditWrongBugLink(
            gerrit.FINDIT_BUILD_FAILURE_COMPONENT, culprit_link, revision)

        auto_revert_bug_query = urllib.urlencode({
            'status':
            'Available',
            'components':
            'Tools>Test>FindIt>Autorevert',
            'summary':
            'Auto Revert failed on %s' % revision,
            'comment':
            'Detail is %s' % culprit_link
        })
        auto_revert_bug_link = (
            'https://bugs.chromium.org/p/chromium/issues/entry?%s') % (
                auto_revert_bug_query)
        message = textwrap.dedent("""
        Sheriffs, CL owner or CL reviewers:
        Please submit this revert if it is correct.
        If it is a false positive, please abandon and report it
        at %s.
        If failed to submit the revert, please abandon it and report the failure
        at %s.

        For more information about Findit auto-revert: %s.

        Sheriffs, it'll be much appreciated if you could take a couple minutes
        to fill out this survey: %s.""") % (
            false_positive_bug_link, auto_revert_bug_link, gerrit._MANUAL_LINK,
            gerrit._SURVEY_LINK)
        mock_add.assert_called_once_with('54321', ['*****@*****.**'], message)
    def testTestLevelResultIsReturned(self, mock_fn):
        master_name = 'm'
        builder_name = 'b'
        build_number = 5

        master_url = 'https://build.chromium.org/p/%s' % master_name
        builds = {
            'builds': [{
                'master_url': master_url,
                'builder_name': builder_name,
                'build_number': build_number,
                'failed_steps': ['a', 'b on platform']
            }]
        }

        task = WfSwarmingTask.Create(master_name, builder_name, 4,
                                     'b on platform')
        task.parameters['ref_name'] = 'b'
        task.status = analysis_status.COMPLETED
        task.put()

        try_job = WfTryJob.Create(master_name, builder_name, 4)
        try_job.status = analysis_status.COMPLETED
        try_job.test_results = [{
            'culprit': {
                'a': {
                    'repo_name': 'chromium',
                    'revision': 'r4_2',
                    'commit_position': 42,
                    'url': None,
                },
                'b': {
                    'tests': {
                        'Unittest3.Subtest1': {
                            'repo_name': 'chromium',
                            'revision': 'r4_10',
                            'commit_position': 410,
                            'url': None,
                        },
                    }
                }
            },
        }]
        try_job.put()

        analysis = WfAnalysis.Create(master_name, builder_name, build_number)
        analysis.status = analysis_status.COMPLETED
        analysis.failure_result_map = {
            'a': '/'.join([master_name, builder_name, '4']),
            'b on platform': {
                'Unittest1.Subtest1':
                '/'.join([master_name, builder_name, '3']),
                'Unittest2.Subtest1':
                '/'.join([master_name, builder_name, '4']),
                'Unittest3.Subtest1':
                '/'.join([master_name, builder_name, '4']),
            },
        }
        analysis.result = {
            'failures': [{
                'step_name':
                'a',
                'first_failure':
                4,
                'last_pass':
                3,
                'supported':
                True,
                'suspected_cls': [{
                    'build_number': 4,
                    'repo_name': 'chromium',
                    'revision': 'r4_2_failed',
                    'commit_position': None,
                    'url': None,
                    'score': 2,
                    'hints': {
                        'modified f4_2.cc (and it was in log)': 2,
                    },
                }],
            }, {
                'step_name':
                'b on platform',
                'first_failure':
                3,
                'last_pass':
                2,
                'supported':
                True,
                'suspected_cls': [{
                    'build_number': 3,
                    'repo_name': 'chromium',
                    'revision': 'r3_1',
                    'commit_position': None,
                    'url': None,
                    'score': 5,
                    'hints': {
                        'added x/y/f3_1.cc (and it was in log)': 5,
                    },
                }, {
                    'build_number': 4,
                    'repo_name': 'chromium',
                    'revision': 'r4_1',
                    'commit_position': None,
                    'url': None,
                    'score': 2,
                    'hints': {
                        'modified f4.cc (and it was in log)': 2,
                    },
                }],
                'tests': [{
                    'test_name':
                    'Unittest1.Subtest1',
                    'first_failure':
                    3,
                    'last_pass':
                    2,
                    'suspected_cls': [{
                        'build_number': 2,
                        'repo_name': 'chromium',
                        'revision': 'r2_1',
                        'commit_position': None,
                        'url': None,
                        'score': 5,
                        'hints': {
                            'added x/y/f99_1.cc (and it was in log)': 5,
                        },
                    }]
                }, {
                    'test_name':
                    'Unittest2.Subtest1',
                    'first_failure':
                    4,
                    'last_pass':
                    2,
                    'suspected_cls': [{
                        'build_number': 2,
                        'repo_name': 'chromium',
                        'revision': 'r2_1',
                        'commit_position': None,
                        'url': None,
                        'score': 5,
                        'hints': {
                            'added x/y/f99_1.cc (and it was in log)': 5,
                        },
                    }]
                }, {
                    'test_name': 'Unittest3.Subtest1',
                    'first_failure': 4,
                    'last_pass': 2,
                    'suspected_cls': []
                }]
            }, {
                'step_name': 'c',
                'first_failure': 4,
                'last_pass': 3,
                'supported': False,
                'suspected_cls': [],
            }]
        }
        analysis.put()

        suspected_cl_42 = WfSuspectedCL.Create('chromium', 'r4_2', 42)
        suspected_cl_42.builds = {
            build_util.CreateBuildId(master_name, builder_name, 5): {
                'approaches': [analysis_approach_type.TRY_JOB]
            }
        }
        suspected_cl_42.put()

        suspected_cl_21 = WfSuspectedCL.Create('chromium', 'r2_1', None)
        suspected_cl_21.builds = {
            build_util.CreateBuildId(master_name, builder_name, 3): {
                'approaches': [analysis_approach_type.HEURISTIC],
                'top_score': 5
            },
            build_util.CreateBuildId(master_name, builder_name, 4): {
                'approaches': [analysis_approach_type.HEURISTIC],
                'top_score': 5
            },
            build_util.CreateBuildId(master_name, builder_name, build_number):
            {
                'approaches': [analysis_approach_type.HEURISTIC],
                'top_score': 5
            }
        }
        suspected_cl_21.put()

        suspected_cl_410 = WfSuspectedCL.Create('chromium', 'r4_10', None)
        suspected_cl_410.builds = {
            build_util.CreateBuildId(master_name, builder_name, 4): {
                'approaches': [
                    analysis_approach_type.HEURISTIC,
                    analysis_approach_type.TRY_JOB
                ],
                'top_score':
                5
            },
            build_util.CreateBuildId(master_name, builder_name, build_number):
            {
                'approaches': [analysis_approach_type.HEURISTIC],
                'top_score': 5
            }
        }
        revert_cl = RevertCL()
        revert_cl.revert_cl_url = 'revert_cl_url'
        suspected_cl_410.revert_cl = revert_cl
        suspected_cl_410.put()

        def confidence_side_effect(_, build_info, first_build_info):
            if (first_build_info and first_build_info.get('approaches') == [
                    analysis_approach_type.HEURISTIC,
                    analysis_approach_type.TRY_JOB
            ]):
                return 100, analysis_approach_type.TRY_JOB
            if build_info and build_info.get('top_score'):
                return 90, analysis_approach_type.HEURISTIC
            return 98, analysis_approach_type.TRY_JOB

        mock_fn.side_effect = confidence_side_effect

        expected_results = [{
            'master_url':
            master_url,
            'builder_name':
            builder_name,
            'build_number':
            build_number,
            'step_name':
            'a',
            'is_sub_test':
            False,
            'first_known_failed_build_number':
            4,
            'suspected_cls': [{
                'repo_name': 'chromium',
                'revision': 'r4_2',
                'commit_position': 42,
                'confidence': 98,
                'analysis_approach': 'TRY_JOB'
            }],
            'analysis_approach':
            'TRY_JOB',
            'is_flaky_test':
            False,
            'try_job_status':
            'FINISHED',
            'has_findings':
            True,
            'is_finished':
            True,
            'is_supported':
            True,
        }, {
            'master_url':
            master_url,
            'builder_name':
            builder_name,
            'build_number':
            build_number,
            'step_name':
            'b on platform',
            'is_sub_test':
            True,
            'test_name':
            'Unittest1.Subtest1',
            'first_known_failed_build_number':
            3,
            'suspected_cls': [{
                'repo_name': 'chromium',
                'revision': 'r2_1',
                'confidence': 90,
                'analysis_approach': 'HEURISTIC'
            }],
            'analysis_approach':
            'HEURISTIC',
            'is_flaky_test':
            False,
            'try_job_status':
            'FINISHED',
            'has_findings':
            True,
            'is_finished':
            True,
            'is_supported':
            True,
        }, {
            'master_url':
            master_url,
            'builder_name':
            builder_name,
            'build_number':
            build_number,
            'step_name':
            'b on platform',
            'is_sub_test':
            True,
            'test_name':
            'Unittest2.Subtest1',
            'first_known_failed_build_number':
            4,
            'suspected_cls': [{
                'repo_name': 'chromium',
                'revision': 'r2_1',
                'confidence': 90,
                'analysis_approach': 'HEURISTIC'
            }],
            'analysis_approach':
            'HEURISTIC',
            'is_flaky_test':
            False,
            'try_job_status':
            'FINISHED',
            'has_findings':
            True,
            'is_finished':
            True,
            'is_supported':
            True,
        }, {
            'master_url':
            master_url,
            'builder_name':
            builder_name,
            'build_number':
            build_number,
            'step_name':
            'b on platform',
            'is_sub_test':
            True,
            'test_name':
            'Unittest3.Subtest1',
            'first_known_failed_build_number':
            4,
            'suspected_cls': [{
                'repo_name': 'chromium',
                'revision': 'r4_10',
                'commit_position': 410,
                'analysis_approach': 'TRY_JOB',
                'confidence': 100,
                'revert_cl_url': 'revert_cl_url'
            }],
            'analysis_approach':
            'TRY_JOB',
            'is_flaky_test':
            False,
            'try_job_status':
            'FINISHED',
            'has_findings':
            True,
            'is_finished':
            True,
            'is_supported':
            True,
        }, {
            'master_url': master_url,
            'builder_name': builder_name,
            'build_number': build_number,
            'step_name': 'c',
            'is_sub_test': False,
            'analysis_approach': 'HEURISTIC',
            'is_flaky_test': False,
            'has_findings': False,
            'is_finished': True,
            'is_supported': False,
        }]

        self._MockMasterIsSupported(supported=True)

        response = self.call_api('AnalyzeBuildFailures', body=builds)
        self.assertEqual(200, response.status_int)
        self.assertItemsEqual(expected_results,
                              response.json_body.get('results'))
def _RevertCulprit(master_name, builder_name, build_number, repo_name,
                   revision):

    culprit = _UpdateCulprit(repo_name, revision)

    if culprit.revert_cl and culprit.revert_status == status.COMPLETED:
        return CREATED_BY_FINDIT

    # 0. Gets information about this culprit.
    culprit_info = (suspected_cl_util.GetCulpritInfo(repo_name, revision))

    culprit_commit_position = culprit_info['commit_position']
    culprit_change_id = culprit_info['review_change_id']
    culprit_host = culprit_info['review_server_host']

    codereview = codereview_util.GetCodeReviewForReview(culprit_host)

    if not codereview or not culprit_change_id:  # pragma: no cover
        logging.error('Failed to get change id for %s/%s' %
                      (repo_name, revision))
        return ERROR

    culprit_cl_info = codereview.GetClDetails(culprit_change_id)
    if not culprit_cl_info:  # pragma: no cover
        logging.error('Failed to get cl_info for %s/%s' %
                      (repo_name, revision))
        return ERROR

    # Checks if the culprit is a revert created by Findit. If yes, bail out.
    if _IsOwnerFindit(culprit_cl_info.owner_email):
        _UpdateCulprit(repo_name,
                       revision,
                       status.SKIPPED,
                       skip_revert_reason=CULPRIT_OWNED_BY_FINDIT)
        return SKIPPED

    if culprit_cl_info.auto_revert_off:
        _UpdateCulprit(repo_name,
                       revision,
                       status.SKIPPED,
                       skip_revert_reason=AUTO_REVERT_OFF)
        return SKIPPED

    # 1. Checks if a revert CL by sheriff has been created.
    reverts = culprit_cl_info.GetRevertCLsByRevision(revision)

    if reverts is None:  # pragma: no cover
        # if no reverts, reverts should be [], only when some error happens it will
        # be None.
        logging.error('Failed to find patchset_id for %s/%s' %
                      (repo_name, revision))
        return ERROR

    findit_revert = None
    for revert in reverts:
        if _IsOwnerFindit(revert.reverting_user_email):
            findit_revert = revert
            break

    if reverts and not findit_revert:
        # Sheriff(s) created the revert CL(s).
        return CREATED_BY_SHERIFF

    # 2. Reverts the culprit.
    if not _LatestBuildFailed(master_name, builder_name, build_number):
        # The latest build didn't fail, skip.
        _UpdateCulprit(repo_name,
                       revision,
                       status.SKIPPED,
                       skip_revert_reason=NEWEST_BUILD_GREEN)
        return SKIPPED

    revert_change_id = None
    if findit_revert:
        revert_change_id = findit_revert.reverting_cl.change_id

    # TODO (chanli): Better handle cases where 2 analyses are trying to revert
    # at the same time.
    if not revert_change_id:
        _UpdateCulprit(repo_name, revision, status.RUNNING)
        revert_reason = textwrap.dedent("""
        Findit (https://goo.gl/kROfz5) identified CL at revision %s as the
        culprit for failures in the build cycles as shown on:
        https://findit-for-me.appspot.com/waterfall/culprit?key=%s""") % (
            culprit_commit_position or revision, culprit.key.urlsafe())

        revert_change_id = codereview.CreateRevert(
            revert_reason, culprit_change_id,
            culprit_cl_info.GetPatchsetIdByRevision(revision))

        if not revert_change_id:  # pragma: no cover
            _UpdateCulprit(repo_name, revision, status.ERROR)
            logging.error('Revert for culprit %s/%s failed.' %
                          (repo_name, revision))
            culprit.put()
            return ERROR

    # Save revert CL info and notification info to culprit.
    if not culprit.revert_cl:
        revert_cl = RevertCL()
        revert_cl.revert_cl_url = codereview.GetCodeReviewUrl(revert_change_id)
        revert_cl.created_time = time_util.GetUTCNow()
        _UpdateCulprit(repo_name, revision, None, revert_cl=revert_cl)

    # 3. Add reviewers.
    sheriffs = rotations.current_sheriffs()
    message = textwrap.dedent("""
      Sheriffs:

      Please confirm and "Quick L-G-T-M & CQ" this revert if it is correct.
      If it is a false positive, please close it.

      Findit (https://goo.gl/kROfz5) identified the original CL as the culprit
      for failures in the build cycles as shown on:
      https://findit-for-me.appspot.com/waterfall/culprit?key=%s""") % (
        culprit.key.urlsafe())
    success = codereview.AddReviewers(revert_change_id, sheriffs, message)

    if not success:  # pragma: no cover
        _UpdateCulprit(repo_name, revision, status.ERROR)
        logging.error('Failed to add reviewers for revert of culprit %s/%s' %
                      (repo_name, revision))
        return ERROR

    _UpdateCulprit(repo_name, revision, revert_status=status.COMPLETED)
    return CREATED_BY_FINDIT
Example #21
0
 def testRevertCLUrl(self):
     culprit = BaseSuspectedCL.Create('chromium', 'r1', 123)
     revert_cl = RevertCL()
     revert_cl.revert_cl_url = 'review_url'
     culprit.revert_cl = revert_cl
     self.assertEqual('review_url', culprit.revert_cl_url)
Example #22
0
def RevertCulprit(urlsafe_key, build_id, build_failure_type, sample_step_name,
                  codereview_info):
    """Creates a revert of a culprit and adds reviewers.

  Args:
    urlsafe_key (str): Key to the ndb model.
    build_id (str): Id of the sample failed build.
    build_failure_type (int): Failure type: compile, test or flake.
    sample_step_name (str): Sample failed step in the failed build.
    codereview_info (dict): Code review information about the culprit.

  Returns:
    (int, string, string):
      - Status of the reverting;
      - change_id of the revert;
      - reason why revert is skipped if it is skipped.
  """

    culprit = entity_util.GetEntityFromUrlsafeKey(urlsafe_key)
    repo_name = culprit.repo_name
    revision = culprit.revision
    # 0. Gets information about this culprit.
    culprit_commit_position = codereview_info['commit_position']
    culprit_change_id = codereview_info['review_change_id']

    codereview = _GetCodeReview(codereview_info)
    print codereview

    if not codereview or not culprit_change_id:  # pragma: no cover
        logging.error('Failed to get change id for %s/%s', repo_name, revision)
        return services_constants.ERROR, None, None

    culprit_cl_info = codereview.GetClDetails(culprit_change_id)
    if not culprit_cl_info:  # pragma: no cover
        logging.error('Failed to get cl_info for %s/%s', repo_name, revision)
        return services_constants.ERROR, None, None

    # Checks if the culprit is a revert. If yes, bail out.
    if _IsCulpritARevert(culprit_cl_info):
        return (services_constants.SKIPPED, None,
                services_constants.CULPRIT_IS_A_REVERT)

    if culprit_cl_info.auto_revert_off:
        return services_constants.SKIPPED, None, services_constants.AUTO_REVERT_OFF

    # 1. Checks if a revert CL by sheriff has been created.
    reverts = culprit_cl_info.GetRevertCLsByRevision(revision)

    if reverts is None:  # pragma: no cover
        # if no reverts, reverts should be [], only when some error happens it will
        # be None.
        logging.error('Failed to find patchset_id for %s/%s' %
                      (repo_name, revision))
        return services_constants.ERROR, None, None

    findit_revert = None
    for revert in reverts:
        if _IsOwnerFindit(revert.reverting_user_email):
            findit_revert = revert
            break

    if reverts and not findit_revert:
        # Sheriff(s) created the revert CL(s).
        return (services_constants.CREATED_BY_SHERIFF, None,
                services_constants.REVERTED_BY_SHERIFF)

    revert_change_id = None
    if findit_revert:
        revert_change_id = findit_revert.reverting_cl.change_id

    # 2. Crreate revert CL.
    # TODO (chanli): Better handle cases where 2 analyses are trying to revert
    # at the same time.
    if not revert_change_id:
        revert_reason = culprit.GenerateRevertReason(build_id,
                                                     culprit_commit_position,
                                                     revision,
                                                     sample_step_name)
        if not revert_reason:  # pragma: no cover.
            logging.error('Failed to get the reason for revert culprit %s',
                          culprit.key.urlsafe() if culprit else '')
            return services_constants.ERROR, None, None
        bug_id = _GetBugIdForCulprit(culprit)
        revert_change_id = codereview.CreateRevert(
            revert_reason,
            culprit_change_id,
            culprit_cl_info.GetPatchsetIdByRevision(revision),
            bug_id=bug_id)

        if not revert_change_id:  # pragma: no cover
            return services_constants.ERROR, None, None

    # Save revert CL info and notification info to culprit.
    revert_cl = None
    if not culprit.revert_cl:
        revert_cl = RevertCL()
        revert_cl.revert_cl_url = codereview.GetCodeReviewUrl(revert_change_id)
        revert_cl.created_time = time_util.GetUTCNow()

    # 3. Add reviewers.
    # If Findit cannot commit the revert, add sheriffs as reviewers and ask them
    # to 'LGTM' and commit the revert.
    action_settings = waterfall_config.GetActionSettings()
    can_commit_revert = (action_settings.get('auto_commit_revert_compile')
                         if build_failure_type == failure_type.COMPILE else
                         action_settings.get('auto_commit_revert_test'))
    if not can_commit_revert:
        success = _AddReviewers(revision, culprit, codereview,
                                revert_change_id, False)
        if not success:  # pragma: no cover
            logging.error('Failed to add reviewers for revert of'
                          ' culprit %s/%s' % (repo_name, revision))
            return services_constants.ERROR, revert_cl, None
    return services_constants.CREATED_BY_FINDIT, revert_cl, None
Example #23
0
    def testTryJobResultReturnedForCompileFailure(self, _):
        master_name = 'm'
        builder_name = 'b'
        build_number = 8

        master_url = 'https://build.chromium.org/p/%s' % master_name
        builds = {
            'builds': [{
                'master_url': master_url,
                'builder_name': builder_name,
                'build_number': build_number,
                'failed_steps': ['compile']
            }]
        }

        try_job = WfTryJob.Create(master_name, builder_name, 3)
        try_job.status = analysis_status.COMPLETED
        try_job.compile_results = [{
            'culprit': {
                'compile': {
                    'repo_name': 'chromium',
                    'revision': 'r3',
                    'commit_position': 3,
                    'url': None,
                },
            },
        }]
        try_job.put()

        analysis = WfAnalysis.Create(master_name, builder_name, build_number)
        analysis.status = analysis_status.COMPLETED
        analysis.build_failure_type = failure_type.COMPILE
        analysis.failure_result_map = {
            'compile': '/'.join([master_name, builder_name, '3']),
        }
        analysis.result = {
            'failures': [{
                'step_name':
                'compile',
                'first_failure':
                3,
                'last_pass':
                1,
                'supported':
                True,
                'suspected_cls': [{
                    'build_number': 3,
                    'repo_name': 'chromium',
                    'revision': 'git_hash2',
                    'commit_position': 288,
                    'score': 1,
                    'hints': {
                        'modify d/e/f.cc': 1,
                    }
                }]
            }]
        }
        analysis.put()

        culprit = WfSuspectedCL.Create('chromium', 'r3', 3)
        culprit.revert_submission_status = analysis_status.COMPLETED
        revert = RevertCL()
        revert.revert_cl_url = 'revert_cl_url'
        culprit.revert_cl = revert
        culprit.put()

        expected_results = [{
            'master_url':
            master_url,
            'builder_name':
            builder_name,
            'build_number':
            build_number,
            'step_name':
            'compile',
            'is_sub_test':
            False,
            'first_known_failed_build_number':
            3,
            'suspected_cls': [
                {
                    'repo_name': 'chromium',
                    'revision': 'r3',
                    'commit_position': 3,
                    'analysis_approach': 'TRY_JOB',
                    'revert_cl_url': 'revert_cl_url',
                    'revert_committed': True
                },
            ],
            'analysis_approach':
            'TRY_JOB',
            'is_flaky_test':
            False,
            'try_job_status':
            'FINISHED',
            'has_findings':
            True,
            'is_finished':
            True,
            'is_supported':
            True,
        }]

        self._MockMasterIsSupported(supported=True)

        response = self.call_api('AnalyzeBuildFailures', body=builds)
        self.assertEqual(200, response.status_int)
        self.assertEqual(expected_results, response.json_body.get('results'))