| # -*- coding: utf-8 -*- |
| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Module that contains unittests for triage_lib module.""" |
| |
| from __future__ import print_function |
| |
| import json |
| import mock |
| |
| from chromite.lib import build_failure_message |
| from chromite.lib import config_lib |
| from chromite.lib import constants |
| from chromite.lib import cq_config |
| from chromite.lib import cros_test_lib |
| from chromite.lib import failure_message_lib_unittest |
| from chromite.lib import gerrit |
| from chromite.lib import patch as cros_patch |
| from chromite.lib import patch_unittest |
| from chromite.lib import portage_util |
| from chromite.lib import triage_lib |
| |
| |
| failure_msg_helper = failure_message_lib_unittest.FailureMessageHelper() |
| |
| |
| class MessageHelper(object): |
| """Helper class to create failure messages for tests.""" |
| |
| @staticmethod |
| def GetFailedMessage(failure_messages, stage='Build', internal=False, |
| bot='daisy_spring-paladin'): |
| """Returns a build_failure_message.BuildFailureMessage object.""" |
| return build_failure_message.BuildFailureMessage( |
| 'Stage %s failed' % stage, failure_messages, internal, |
| 'failure reason string', bot) |
| |
| @staticmethod |
| def GetGeneralFailure(stage='Build'): |
| return failure_msg_helper.GetStageFailureMessage(stage_name=stage) |
| |
| @staticmethod |
| def GetTestLabFailure(stage='Build'): |
| return failure_msg_helper.GetStageFailureMessage( |
| exception_type='TestLabFailure', |
| exception_category=constants.EXCEPTION_CATEGORY_LAB, |
| stage_name=stage) |
| |
| @staticmethod |
| def GetInfraFailure(stage='Build'): |
| return failure_msg_helper.GetStageFailureMessage( |
| exception_type='InfrastructureFailure', |
| exception_category=constants.EXCEPTION_CATEGORY_INFRA, |
| stage_name=stage) |
| |
| @staticmethod |
| def GetPackageStageBuildFailure(extra_info=None, stage='Build'): |
| return failure_msg_helper.GetPackageBuildFailureMessage( |
| extra_info=extra_info, |
| stage_name=stage) |
| |
| # pylint: disable=protected-access |
| class TestFindSuspects(cros_test_lib.MockTestCase): |
| """Tests CalculateSuspects.""" |
| |
| def setUp(self): |
| site_params = config_lib.GetSiteParams() |
| overlay = 'chromiumos/overlays/chromiumos-overlay' |
| self._patch_factory = patch_unittest.MockPatchFactory() |
| self.overlay_patch = self._patch_factory.GetPatches(project=overlay) |
| chromite = 'chromiumos/chromite' |
| self.chromite_patch = self._patch_factory.GetPatches(project=chromite) |
| self.power_manager = 'chromiumos/platform2/power_manager' |
| self.power_manager_pkg = 'chromeos-base/power_manager' |
| self.power_manager_patch = self._patch_factory.GetPatches( |
| project=self.power_manager) |
| self.kernel = 'chromiumos/third_party/kernel/foo' |
| self.kernel_pkg = 'sys-kernel/chromeos-kernel-foo' |
| self.kernel_patch = self._patch_factory.GetPatches(project=self.kernel) |
| self.secret = 'chromeos/secret' |
| self.secret_patch = self._patch_factory.GetPatches( |
| project=self.secret, remote=site_params.INTERNAL_REMOTE) |
| self.PatchObject(cros_patch.GitRepoPatch, 'GetCheckout') |
| self.PatchObject(cros_patch.GitRepoPatch, 'GetDiffStatus') |
| self.PatchObject(gerrit, 'GetGerritPatchInfoWithPatchQueries', |
| side_effect=lambda x: x) |
| self.changes = [self.overlay_patch, self.chromite_patch, |
| self.power_manager_patch, self.kernel_patch, |
| self.secret_patch] |
| |
| @staticmethod |
| def _GetBuildFailure(pkg): |
| """Create a PackageBuildFailure for the specified |pkg|. |
| |
| Args: |
| pkg: Package that failed to build. |
| """ |
| extra_info_dict = {'shortname': './build_image', |
| 'failed_packages': [pkg]} |
| extra_info = json.dumps(extra_info_dict) |
| return MessageHelper.GetPackageStageBuildFailure(extra_info=extra_info) |
| |
| def _AssertSuspects(self, patches, suspects, pkgs=(), exceptions=(), |
| internal=False, infra_fail=False, lab_fail=False, |
| sanity=True): |
| """Run _FindSuspects and verify its output. |
| |
| Args: |
| patches: List of patches to look at. |
| suspects: Expected list of suspects returned by _FindSuspects. |
| pkgs: List of packages that failed with exceptions in the build. |
| exceptions: List of other failure messages (instances of |
| failure_message_lib.StageFailureMessage) that occurred during the build. |
| internal: Whether the failures occurred on an internal bot. |
| infra_fail: Whether the build failed due to infrastructure issues. |
| lab_fail: Whether the build failed due to lab infrastructure issues. |
| sanity: The sanity checker builder passed and the tree was open when |
| the build started. |
| """ |
| all_exceptions = list(exceptions) + [self._GetBuildFailure(x) for x in pkgs] |
| message = MessageHelper.GetFailedMessage(all_exceptions, internal=internal) |
| results = triage_lib.CalculateSuspects.FindSuspects( |
| patches, [message], lab_fail=lab_fail, infra_fail=infra_fail, |
| sanity=sanity) |
| self.assertItemsEqual(suspects, results.keys()) |
| |
| def testFailSameProject(self): |
| """Patches to the package that failed should be marked as failing.""" |
| suspects = [self.kernel_patch] |
| patches = suspects + [self.power_manager_patch, self.secret_patch] |
| with self.PatchObject(portage_util, 'FindWorkonProjects', |
| return_value=self.kernel): |
| self._AssertSuspects(patches, suspects, [self.kernel_pkg]) |
| self._AssertSuspects(patches, suspects, [self.kernel_pkg], sanity=False) |
| |
| def testFailSameProjectPlusOverlay(self): |
| """Patches to the overlay should be marked as failing.""" |
| suspects = [self.overlay_patch, self.kernel_patch] |
| patches = suspects + [self.power_manager_patch, self.secret_patch] |
| with self.PatchObject(portage_util, 'FindWorkonProjects', |
| return_value=self.kernel): |
| self._AssertSuspects(patches, suspects, [self.kernel_pkg]) |
| self._AssertSuspects(patches, [self.kernel_patch], [self.kernel_pkg], |
| sanity=False) |
| |
| def testFailUnknownPackage(self): |
| """If no patches changed the package, all patches should fail.""" |
| changes = [self.overlay_patch, self.power_manager_patch, self.secret_patch] |
| self._AssertSuspects(changes, changes, [self.kernel_pkg]) |
| self._AssertSuspects(changes, [], [self.kernel_pkg], sanity=False) |
| |
| def testFailUnknownException(self): |
| """An unknown exception should cause all patches to fail.""" |
| changes = [self.kernel_patch, self.power_manager_patch, self.secret_patch] |
| self._AssertSuspects(changes, changes, |
| exceptions=[MessageHelper.GetGeneralFailure()]) |
| self._AssertSuspects(changes, [], |
| exceptions=[MessageHelper.GetGeneralFailure()], |
| sanity=False) |
| |
| def testFailUnknownInternalException(self): |
| """An unknown exception should cause all patches to fail.""" |
| suspects = [self.kernel_patch, self.power_manager_patch, self.secret_patch] |
| self._AssertSuspects( |
| suspects, suspects, exceptions=[MessageHelper.GetGeneralFailure()], |
| internal=True) |
| self._AssertSuspects( |
| suspects, [], exceptions=[MessageHelper.GetGeneralFailure()], |
| internal=True, sanity=False) |
| |
| def testFailUnknownCombo(self): |
| """Unknown exceptions should cause all patches to fail. |
| |
| Even if there are also build failures that we can explain. |
| """ |
| suspects = [self.kernel_patch, self.power_manager_patch, self.secret_patch] |
| with self.PatchObject(portage_util, 'FindWorkonProjects', |
| return_value=self.kernel): |
| self._AssertSuspects(suspects, suspects, [self.kernel_pkg], |
| [MessageHelper.GetGeneralFailure()]) |
| self._AssertSuspects(suspects, [self.kernel_patch], [self.kernel_pkg], |
| [MessageHelper.GetGeneralFailure()], sanity=False) |
| |
| def testFailNone(self): |
| """If a message is just 'None', it should cause all patches to fail.""" |
| patches = [self.kernel_patch, self.power_manager_patch, self.secret_patch] |
| results = triage_lib.CalculateSuspects.FindSuspects(patches, [None]) |
| self.assertItemsEqual(results.keys(), patches) |
| |
| results = triage_lib.CalculateSuspects.FindSuspects( |
| patches, [None], sanity=False) |
| self.assertItemsEqual(results.keys(), []) |
| |
| def testFailNoExceptions(self): |
| """If there are no exceptions, all patches should be failed.""" |
| suspects = [self.kernel_patch, self.power_manager_patch, self.secret_patch] |
| self._AssertSuspects(suspects, suspects) |
| self._AssertSuspects(suspects, [], sanity=False) |
| |
| def testLabFail(self): |
| """If there are only lab failures, no suspect is chosen.""" |
| suspects = [] |
| changes = [self.kernel_patch, self.power_manager_patch] |
| self._AssertSuspects(changes, suspects, lab_fail=True, infra_fail=True) |
| self._AssertSuspects(changes, suspects, lab_fail=True, infra_fail=True, |
| sanity=False) |
| |
| def testInfraFail(self): |
| """If there are only non-lab infra failures, pick chromite changes.""" |
| suspects = [self.chromite_patch] |
| changes = [self.kernel_patch, self.power_manager_patch] + suspects |
| self._AssertSuspects(changes, suspects, lab_fail=False, infra_fail=True) |
| self._AssertSuspects(changes, suspects, lab_fail=False, infra_fail=True, |
| sanity=False) |
| |
| def testManualBlame(self): |
| """If there are changes that were manually blamed, pick those changes.""" |
| approvals1 = [{'type': 'VRIF', 'value': '-1', 'grantedOn': 1391733002}, |
| {'type': 'CRVW', 'value': '2', 'grantedOn': 1391733002}, |
| {'type': 'COMR', 'value': '1', 'grantedOn': 1391733002},] |
| approvals2 = [{'type': 'VRIF', 'value': '1', 'grantedOn': 1391733002}, |
| {'type': 'CRVW', 'value': '-2', 'grantedOn': 1391733002}, |
| {'type': 'COMR', 'value': '1', 'grantedOn': 1391733002},] |
| suspects = [self._patch_factory.MockPatch(approvals=approvals1), |
| self._patch_factory.MockPatch(approvals=approvals2)] |
| changes = [self.kernel_patch, self.chromite_patch] + suspects |
| self._AssertSuspects(changes, suspects, lab_fail=False, infra_fail=False) |
| self._AssertSuspects(changes, suspects, lab_fail=True, infra_fail=False) |
| self._AssertSuspects(changes, suspects, lab_fail=True, infra_fail=True) |
| self._AssertSuspects(changes, suspects, lab_fail=False, infra_fail=True) |
| self._AssertSuspects(changes, suspects, lab_fail=False, infra_fail=False, |
| sanity=False) |
| self._AssertSuspects(changes, suspects, lab_fail=True, infra_fail=False, |
| sanity=False) |
| self._AssertSuspects(changes, suspects, lab_fail=True, infra_fail=True, |
| sanity=False) |
| self._AssertSuspects(changes, suspects, lab_fail=False, infra_fail=True, |
| sanity=False) |
| |
| def _GetMessages(self, lab_fail=0, infra_fail=0, other_fail=0): |
| """Returns a list ofbuild_failure_message.BuildFailureMessage objects.""" |
| messages = [] |
| messages.extend( |
| [MessageHelper.GetFailedMessage([MessageHelper.GetTestLabFailure()]) |
| for _ in range(lab_fail)]) |
| messages.extend( |
| [MessageHelper.GetFailedMessage([MessageHelper.GetInfraFailure()]) |
| for _ in range(infra_fail)]) |
| messages.extend( |
| [MessageHelper.GetFailedMessage([MessageHelper.GetGeneralFailure()]) |
| for _ in range(other_fail)]) |
| |
| return messages |
| |
| def testMatchesExceptionCategories(self): |
| """Test MatchesExceptionCategories.""" |
| messages = self._GetMessages(lab_fail=1, infra_fail=1) |
| messages.append(None) |
| self.assertFalse( |
| triage_lib.CalculateSuspects._MatchesExceptionCategories( |
| messages, [constants.EXCEPTION_CATEGORY_LAB])) |
| self.assertFalse( |
| triage_lib.CalculateSuspects._MatchesExceptionCategories( |
| messages, [constants.EXCEPTION_CATEGORY_LAB], strict=False)) |
| self.assertTrue( |
| triage_lib.CalculateSuspects._MatchesExceptionCategories( |
| messages, |
| {constants.EXCEPTION_CATEGORY_INFRA, |
| constants.EXCEPTION_CATEGORY_LAB}, |
| strict=False)) |
| |
| def testMatchesExceptionCategoriesWithEmptyMessages(self): |
| """Test MatchesExceptionCategoriesWithEmptyMessages.""" |
| messages = self._GetMessages() |
| self.assertFalse( |
| triage_lib.CalculateSuspects._MatchesExceptionCategories( |
| messages, {constants.EXCEPTION_CATEGORY_LAB})) |
| |
| def testOnlyLabFailures(self): |
| """Tests the OnlyLabFailures function.""" |
| messages = self._GetMessages(lab_fail=2) |
| no_stat = [] |
| self.assertTrue( |
| triage_lib.CalculateSuspects.OnlyLabFailures(messages, no_stat)) |
| |
| no_stat = ['foo', 'bar'] |
| # Some builders did not start. This is not a lab failure. |
| self.assertFalse( |
| triage_lib.CalculateSuspects.OnlyLabFailures(messages, no_stat)) |
| |
| messages = self._GetMessages(lab_fail=1, infra_fail=1) |
| no_stat = [] |
| # Non-lab infrastructure failures are present. |
| self.assertFalse( |
| triage_lib.CalculateSuspects.OnlyLabFailures(messages, no_stat)) |
| |
| def testOnlyInfraFailures(self): |
| """Tests the OnlyInfraFailures function.""" |
| messages = self._GetMessages(infra_fail=2) |
| no_stat = [] |
| self.assertTrue( |
| triage_lib.CalculateSuspects.OnlyInfraFailures(messages, no_stat)) |
| |
| messages = self._GetMessages(lab_fail=2) |
| no_stat = [] |
| # Lab failures are infrastructure failures. |
| self.assertTrue( |
| triage_lib.CalculateSuspects.OnlyInfraFailures(messages, no_stat)) |
| |
| messages = self._GetMessages(lab_fail=1, infra_fail=1) |
| no_stat = [] |
| # Lab failures are infrastructure failures. |
| self.assertTrue( |
| triage_lib.CalculateSuspects.OnlyInfraFailures(messages, no_stat)) |
| |
| messages = self._GetMessages(other_fail=1, infra_fail=1) |
| no_stat = [] |
| self.assertFalse( |
| triage_lib.CalculateSuspects.OnlyInfraFailures(messages, no_stat)) |
| |
| no_stat = ['orange'] |
| messages = [] |
| # 'Builders failed to report statuses' belong to infrastructure failures. |
| self.assertTrue( |
| triage_lib.CalculateSuspects.OnlyInfraFailures(messages, no_stat)) |
| |
| 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 testFindSuspectsForFailuresWithNoneMessage(self): |
| """Test FindSuspectsForFailuresWith None message.""" |
| build_root = mock.Mock() |
| failed_hwtests = mock.Mock() |
| messages = [None] |
| |
| suspects = triage_lib.CalculateSuspects.FindSuspectsForFailures( |
| self.changes, messages, build_root, failed_hwtests, False) |
| self.assertItemsEqual(suspects.keys(), set()) |
| |
| suspects = triage_lib.CalculateSuspects.FindSuspectsForFailures( |
| self.changes, messages, build_root, failed_hwtests, True) |
| self.assertItemsEqual(suspects.keys(), self.changes) |
| |
| |
| class TestGetFullyVerifiedChanges(cros_test_lib.MockTestCase): |
| """Tests GetFullyVerifiedChanges() and related functions.""" |
| |
| def setUp(self): |
| self.build_root = '/foo/build/root' |
| self._patch_factory = patch_unittest.MockPatchFactory() |
| self.changes = self._patch_factory.GetPatches(how_many=5) |
| |
| def testChangesNoAllTested(self): |
| """Tests that those changes are fully verified.""" |
| no_stat = failing = messages = [] |
| inflight = ['foo-paladin'] |
| changes_by_config = {'foo-paladin': []} |
| |
| verified_results = triage_lib.CalculateSuspects.GetFullyVerifiedChanges( |
| self.changes, changes_by_config, {}, failing, |
| inflight, no_stat, messages, self.build_root) |
| verified_changes = set(verified_results.keys()) |
| self.assertEquals(verified_changes, set(self.changes)) |
| |
| def testChangesOnNotCompletedBuilds(self): |
| """Test changes on not completed builds.""" |
| failing = messages = [] |
| inflight = ['foo-paladin'] |
| no_stat = ['puppy-paladin'] |
| changes_by_config = {'foo-paladin': set(self.changes[:2]), |
| 'bar-paladin': set(self.changes), |
| 'puppy-paladin': set(self.changes[-2:])} |
| |
| verified_results = triage_lib.CalculateSuspects.GetFullyVerifiedChanges( |
| self.changes, changes_by_config, {}, failing, |
| inflight, no_stat, messages, self.build_root) |
| verified_changes = set(verified_results.keys()) |
| self.assertEquals(verified_changes, set(self.changes[2:-2])) |
| |
| def testChangesOnNotCompletedBuildsWithCQHistory(self): |
| """Tests changes on not completed builds with builds passed in history.""" |
| failing = messages = [] |
| inflight = ['foo-paladin'] |
| no_stat = ['puppy-paladin'] |
| changes_by_config = {'foo-paladin': set(self.changes[:2]), |
| 'bar-paladin': set(self.changes), |
| 'puppy-paladin': set(self.changes[-2:])} |
| passed_slave_by_change = { |
| self.changes[1]: {'foo-paladin'}, |
| self.changes[3]: {'puppy-paladin'} |
| } |
| |
| verified_results = triage_lib.CalculateSuspects.GetFullyVerifiedChanges( |
| self.changes, changes_by_config, passed_slave_by_change, |
| failing, inflight, no_stat, messages, self.build_root) |
| verified_changes = set(verified_results.keys()) |
| self.assertEquals(verified_changes, set(self.changes[1:-1])) |
| |
| def testChangesNotVerifiedOnFailures(self): |
| """Tests that changes are not verified if failures cannot be ignored.""" |
| messages = no_stat = inflight = [] |
| failing = ['cub-paladin'] |
| changes_by_config = {'bar-paladin': set(self.changes), |
| 'cub-paladin': set(self.changes[:2])} |
| |
| self.PatchObject( |
| triage_lib.CalculateSuspects, 'CanIgnoreFailures', |
| return_value=(False, None)) |
| verified_results = triage_lib.CalculateSuspects.GetFullyVerifiedChanges( |
| self.changes, changes_by_config, {}, failing, |
| inflight, no_stat, messages, self.build_root) |
| verified_changes = set(verified_results.keys()) |
| self.assertEquals(verified_changes, set(self.changes[2:])) |
| |
| def testChangesNotVerifiedOnFailuresWithCQHistory(self): |
| """Tests on not ignorable faiulres with CQ history.""" |
| messages = no_stat = inflight = [] |
| failing = ['cub-paladin'] |
| changes_by_config = {'bar-paladin': set(self.changes), |
| 'cub-paladin': set(self.changes[:2])} |
| passed_slave_by_change = { |
| self.changes[1]: {'cub-paladin'}, |
| } |
| |
| self.PatchObject( |
| triage_lib.CalculateSuspects, 'CanIgnoreFailures', |
| return_value=(False, None)) |
| verified_results = triage_lib.CalculateSuspects.GetFullyVerifiedChanges( |
| self.changes, changes_by_config, passed_slave_by_change, failing, |
| inflight, no_stat, messages, self.build_root) |
| verified_changes = set(verified_results.keys()) |
| self.assertEquals(verified_changes, set(self.changes[1:])) |
| |
| def testChangesVerifiedWhenFailuresCanBeIgnored(self): |
| """Tests that changes are verified if failures can be ignored.""" |
| messages = no_stat = inflight = [] |
| failing = ['cub-paladin'] |
| changes_by_config = {'bar-paladin': set(self.changes), |
| 'cub-paladin': set(self.changes[:2])} |
| |
| self.PatchObject( |
| triage_lib.CalculateSuspects, 'CanIgnoreFailures', |
| return_value=(True, constants.STRATEGY_CQ_PARTIAL_IGNORED_STAGES)) |
| verified_results = triage_lib.CalculateSuspects.GetFullyVerifiedChanges( |
| self.changes, changes_by_config, {}, failing, |
| inflight, no_stat, messages, self.build_root) |
| verified_changes = set(verified_results.keys()) |
| self.assertEquals(verified_changes, set(self.changes)) |
| |
| def testCanIgnoreFailures(self): |
| """Tests CanIgnoreFailures().""" |
| # pylint: disable=protected-access |
| change = self.changes[0] |
| messages = [ |
| MessageHelper.GetFailedMessage( |
| [MessageHelper.GetGeneralFailure(stage='HWTest')], stage='HWTest'), |
| MessageHelper.GetFailedMessage( |
| [MessageHelper.GetGeneralFailure(stage='VMTest')], stage='VMTest')] |
| self.PatchObject(cq_config.CQConfigParser, 'GetCommonConfigFileForChange') |
| m = self.PatchObject(cq_config.CQConfigParser, 'GetStagesToIgnore') |
| |
| m.return_value = ('HWTest',) |
| self.assertEqual(triage_lib.CalculateSuspects.CanIgnoreFailures( |
| messages, change, self.build_root), (False, None)) |
| |
| m.return_value = ('HWTest', 'VMTest', 'Foo') |
| self.assertEqual(triage_lib.CalculateSuspects.CanIgnoreFailures( |
| messages, change, self.build_root), |
| (True, constants.STRATEGY_CQ_PARTIAL_IGNORED_STAGES)) |
| |
| m.return_value = None |
| self.assertEqual(triage_lib.CalculateSuspects.CanIgnoreFailures( |
| messages, change, self.build_root), (False, None)) |
| |
| # pylint: disable=protected-access |
| def testGetVerifiedReason(self): |
| """Test _GetVerifiedReason.""" |
| verified_reasons = set() |
| self.assertEqual( |
| triage_lib.CalculateSuspects._GetVerifiedReason(verified_reasons), None) |
| |
| verified_reasons = {constants.STRATEGY_CQ_PARTIAL_BUILDS_PASSED, |
| constants.STRATEGY_CQ_PARTIAL_IGNORED_STAGES} |
| self.assertEqual( |
| triage_lib.CalculateSuspects._GetVerifiedReason(verified_reasons), |
| constants.STRATEGY_CQ_PARTIAL_IGNORED_STAGES) |
| |
| |
| class SuspectChangesTest(cros_test_lib.MockTestCase): |
| """Tests for SuspectChanges.""" |
| |
| def setUp(self): |
| self._patch_factory = patch_unittest.MockPatchFactory() |
| self.patches = self._patch_factory.GetPatches(how_many=3) |
| |
| def _CreateSuspectChanges(self, suspect_dict=None): |
| return triage_lib.SuspectChanges(suspect_dict) |
| |
| def testSetitem(self): |
| """Test __setitem__.""" |
| suspects = self._CreateSuspectChanges() |
| |
| suspects[self.patches[0]] = constants.SUSPECT_REASON_BAD_CHANGE |
| suspects[self.patches[1]] = constants.SUSPECT_REASON_UNKNOWN |
| |
| self.assertEqual(len(suspects), 2) |
| self.assertEqual(suspects[self.patches[0]], |
| constants.SUSPECT_REASON_BAD_CHANGE) |
| self.assertEqual(suspects[self.patches[1]], |
| constants.SUSPECT_REASON_UNKNOWN) |
| |
| suspects[self.patches[0]] = constants.SUSPECT_REASON_UNKNOWN |
| suspects[self.patches[1]] = constants.SUSPECT_REASON_BUILD_FAIL |
| |
| self.assertEqual(len(suspects), 2) |
| self.assertEqual(suspects[self.patches[0]], |
| constants.SUSPECT_REASON_BAD_CHANGE) |
| self.assertEqual(suspects[self.patches[1]], |
| constants.SUSPECT_REASON_BUILD_FAIL) |
| |
| suspects[self.patches[2]] = constants.SUSPECT_REASON_OVERLAY_CHANGE |
| self.assertEqual(len(suspects), 3) |
| self.assertEqual(suspects[self.patches[2]], |
| constants.SUSPECT_REASON_OVERLAY_CHANGE) |
| |
| def testSetdefault(self): |
| """Test setdefault.""" |
| suspects = self._CreateSuspectChanges() |
| self.assertRaises(Exception, suspects.setdefault, self.patches[0], None) |
| |
| suspects.setdefault(self.patches[0], constants.SUSPECT_REASON_BAD_CHANGE) |
| suspects.setdefault(self.patches[1], constants.SUSPECT_REASON_UNKNOWN) |
| |
| self.assertEqual(len(suspects), 2) |
| self.assertEqual(suspects[self.patches[0]], |
| constants.SUSPECT_REASON_BAD_CHANGE) |
| self.assertEqual(suspects[self.patches[1]], |
| constants.SUSPECT_REASON_UNKNOWN) |
| |
| suspects.setdefault(self.patches[0], constants.SUSPECT_REASON_UNKNOWN) |
| suspects.setdefault(self.patches[1], constants.SUSPECT_REASON_BUILD_FAIL) |
| |
| self.assertEqual(len(suspects), 2) |
| self.assertEqual(suspects[self.patches[0]], |
| constants.SUSPECT_REASON_BAD_CHANGE) |
| self.assertEqual(suspects[self.patches[1]], |
| constants.SUSPECT_REASON_BUILD_FAIL) |
| |
| suspects.setdefault(self.patches[2], |
| constants.SUSPECT_REASON_OVERLAY_CHANGE) |
| self.assertEqual(len(suspects), 3) |
| self.assertEqual(suspects[self.patches[2]], |
| constants.SUSPECT_REASON_OVERLAY_CHANGE) |
| |
| def testUpdate(self): |
| """Test update.""" |
| suspects = self._CreateSuspectChanges({ |
| self.patches[0]: constants.SUSPECT_REASON_BAD_CHANGE, |
| self.patches[1]: constants.SUSPECT_REASON_UNKNOWN}) |
| suspects.update({ |
| self.patches[0]: constants.SUSPECT_REASON_UNKNOWN, |
| self.patches[1]: constants.SUSPECT_REASON_BUILD_FAIL}) |
| expected = self._CreateSuspectChanges({ |
| self.patches[0]: constants.SUSPECT_REASON_BAD_CHANGE, |
| self.patches[1]: constants.SUSPECT_REASON_BUILD_FAIL}) |
| |
| self.assertEqual(suspects, expected) |