def testFindSuspectedChangesOnHWTestFailuresBlameEverything(self): """Test FindSuspectedChanges on HWTestFailures and blame everything.""" changes = self._GetMockChanges() f_1 = failure_message_helper.GetTestFailureMessage(failure_id=1) build_failure = self.ConstructBuildFailureMessage( failure_messages=[f_1]) mock_find = self.PatchObject(hwtest_results.HWTestResultManager, 'FindHWTestFailureSuspects', return_value=({changes[2]}, True)) build_root = mock.Mock() failed_hwtests = mock.Mock() suspects = build_failure.FindSuspectedChanges(changes, build_root, failed_hwtests, True) expected = triage_lib.SuspectChanges({ changes[0]: constants.SUSPECT_REASON_UNKNOWN, changes[1]: constants.SUSPECT_REASON_UNKNOWN, changes[2]: constants.SUSPECT_REASON_TEST_FAIL, changes[3]: constants.SUSPECT_REASON_UNKNOWN }) self.assertEqual(suspects, expected) mock_find.assert_called_once_with(changes, build_root, failed_hwtests) mock_find.reset_mock() suspects = build_failure.FindSuspectedChanges(changes, build_root, failed_hwtests, False) expected = triage_lib.SuspectChanges( {changes[2]: constants.SUSPECT_REASON_TEST_FAIL}) self.assertEqual(suspects, expected) mock_find.assert_called_once_with(changes, build_root, failed_hwtests)
def testFindSuspectedChangesOnPackageBuildFailuresBlameEverything(self): """Test FindSuspectedChanges on PackageBuildFailures and BlameEverything.""" changes = self._GetMockChanges() f_1 = failure_message_helper.GetPackageBuildFailureMessage( failure_id=1) build_failure = self.ConstructBuildFailureMessage( failure_messages=[f_1]) mock_find = self.PatchObject(build_failure_message.BuildFailureMessage, 'FindPackageBuildFailureSuspects', return_value=({changes[2]}, True)) suspects = build_failure.FindSuspectedChanges(changes, mock.Mock(), mock.Mock(), True) expected = triage_lib.SuspectChanges({ changes[0]: constants.SUSPECT_REASON_UNKNOWN, changes[1]: constants.SUSPECT_REASON_UNKNOWN, changes[2]: constants.SUSPECT_REASON_BUILD_FAIL, changes[3]: constants.SUSPECT_REASON_UNKNOWN }) self.assertEqual(suspects, expected) mock_find.assert_called_once_with(changes, f_1) mock_find.reset_mock() suspects = build_failure.FindSuspectedChanges(changes, mock.Mock(), mock.Mock(), False) expected = triage_lib.SuspectChanges( {changes[2]: constants.SUSPECT_REASON_BUILD_FAIL}) self.assertEqual(suspects, expected) mock_find.assert_called_once_with(changes, f_1)
def testFindSuspectedChangesOnUnknownFailures(self): """Test FindSuspectedChanges on unknown failures.""" changes = self._GetMockChanges() f_1 = failure_message_helper.GetStageFailureMessage(failure_id=1) build_failure = self.ConstructBuildFailureMessage( failure_messages=[f_1]) mock_find_build_failure = self.PatchObject( build_failure_message.BuildFailureMessage, 'FindPackageBuildFailureSuspects', return_value=({changes[2]}, True)) mock_find_hwtest_failure = self.PatchObject( hwtest_results.HWTestResultManager, 'FindHWTestFailureSuspects', return_value=({changes[2]}, False)) build_root = mock.Mock() failed_hwtests = mock.Mock() suspects = build_failure.FindSuspectedChanges(changes, build_root, failed_hwtests, True) expected = triage_lib.SuspectChanges({ changes[0]: constants.SUSPECT_REASON_UNKNOWN, changes[1]: constants.SUSPECT_REASON_UNKNOWN, changes[2]: constants.SUSPECT_REASON_UNKNOWN, changes[3]: constants.SUSPECT_REASON_UNKNOWN }) self.assertEqual(suspects, expected) mock_find_build_failure.assert_not_called() mock_find_hwtest_failure.assert_not_called() suspects = build_failure.FindSuspectedChanges(changes, build_root, failed_hwtests, False) expected = triage_lib.SuspectChanges() self.assertEqual(suspects, expected) mock_find_build_failure.assert_not_called() mock_find_hwtest_failure.assert_not_called()
def _AssertMessage(self, change, suspects, messages, sanity=True, infra_fail=False, lab_fail=False, no_stat=None, xretry=False, pre_cq_trybot=False, cl_status_url=None): """Call the CreateValidationFailureMessage method. Args: change: The change we are commenting on. suspects: List of suspected changes. messages: List of messages should appear in the failure message. sanity: Bool indicating sanity of build, default: True. infra_fail: True if build failed due to infrastructure issues. lab_fail: True if build failed due to lab infrastructure issues. no_stat: List of builders that did not start. xretry: Whether we expect the change to be retried. pre_cq_trybot: Whether the builder is a Pre-CQ trybot. cl_status_url: URL of the CL status viewer for the change. """ suspects = triage_lib.SuspectChanges( {x: constants.SUSPECT_REASON_UNKNOWN for x in suspects}) msg = cl_messages.CreateValidationFailureMessage( pre_cq_trybot, change, suspects, [], sanity=sanity, infra_fail=infra_fail, lab_fail=lab_fail, no_stat=no_stat, retry=xretry, cl_status_url=cl_status_url) for x in messages: self.assertTrue(x in msg) self.assertEqual(xretry, 'retry your change automatically' in msg) return msg
def testFindSuspectsForFailuresWithMessages(self): """Test FindSuspectsForFailures with not None messages.""" build_root = mock.Mock() failed_hwtests = mock.Mock() messages = [] for _ in range(0, 3): m = mock.Mock() m.FindSuspectedChanges.return_value = triage_lib.SuspectChanges( {self.changes[0]: constants.SUSPECT_REASON_UNKNOWN}) messages.append(m) suspects = triage_lib.CalculateSuspects.FindSuspectsForFailures( self.changes, messages, build_root, failed_hwtests, False) self.assertItemsEqual(suspects.keys(), self.changes[0:1]) suspects = triage_lib.CalculateSuspects.FindSuspectsForFailures( self.changes, messages, build_root, failed_hwtests, True) self.assertItemsEqual(suspects.keys(), self.changes[0:1]) for index in range(0, 3): messages[index].FindSuspectedChanges.called_once_with( self.changes, build_root, failed_hwtests, True) messages[index].FindSuspectedChanges.called_once_with( self.changes, build_root, failed_hwtests, False)
def _CreateSuspectChanges(self, suspect_dict=None): return triage_lib.SuspectChanges(suspect_dict)
def FindSuspectedChanges(self, changes, build_root, failed_hwtests, sanity): """Find and return suspected changes. Suspected changes are CLs that probably caused failures and will be rejected. This method analyzes every failure message and returns a set of changes as suspects. 1) if a failure message is a PackageBuildFailure, get suspects for the build failure. If there're failed packages without assigned suspects, blame all changes when sanity is True. 2) if a failure message is a TEST failure, get suspects for the HWTest failure. If there're failed HWTests without assigned suspects, blame all changes when sanity is True. 3) If a failure message is neither PackagebuildFailure nor HWTestFailure, we can't explain the failure and so blame all changes when sanity is True. It is certainly possible to trick this algorithm: If one developer submits a change to libchromeos that breaks the power_manager, and another developer submits a change to the power_manager at the same time, only the power_manager change will be kicked out. That said, in that situation, the libchromeos change will likely be kicked out on the next run when the next run fails power_manager but dosen't include any changes from power_manager. Args: changes: A list of cros_patch.GerritPatch instances. build_root: The path to the build root. failed_hwtests: A list of name of failed hwtests got from CIDB (see the return type of HWTestResultManager.GetFailedHWTestsFromCIDB), or None. sanity: The sanity checker builder passed and the tree was open when the build started and ended. Returns: An instance of triage_lib.SuspectChanges. """ suspect_changes = triage_lib.SuspectChanges() blame_everything = False for failure in self.failure_messages: if (failure.exception_type in failure_message_lib.PACKAGE_BUILD_FAILURE_TYPES): # Find suspects for PackageBuildFailure build_suspects, no_assignee_packages = ( self.FindPackageBuildFailureSuspects(changes, failure)) suspect_changes.update( {x: constants.SUSPECT_REASON_BUILD_FAIL for x in build_suspects}) blame_everything = blame_everything or no_assignee_packages elif failure.exception_category == constants.EXCEPTION_CATEGORY_TEST: # Find suspects for HWTestFailure hwtest_suspects, no_assignee_hwtests = ( hwtest_results.HWTestResultManager.FindHWTestFailureSuspects( changes, build_root, failed_hwtests)) suspect_changes.update( {x: constants.SUSPECT_REASON_TEST_FAIL for x in hwtest_suspects}) blame_everything = blame_everything or no_assignee_hwtests else: # Unknown failures, blame everything blame_everything = True # Only do broad-brush blaming if the tree is sane. if sanity: if blame_everything or len(suspect_changes) == 0: suspect_changes.update( {x: constants.SUSPECT_REASON_UNKNOWN for x in changes}) else: # Never treat changes to overlays as innocent. overlay_changes = [x for x in changes if '/overlays/' in x.project] suspect_changes.update( {x: constants.SUSPECT_REASON_OVERLAY_CHANGE for x in overlay_changes}) return suspect_changes