예제 #1
0
    def testActions(self):
        """Test that InsertCLActions accepts 0-, 1-, and multi-item lists."""
        db = self._PrepareDatabase()
        build_id = db.InsertBuild('my builder', 'chromiumos', _random(),
                                  'my config', 'my bot hostname')

        a1 = clactions.CLAction.FromGerritPatchAndAction(
            metadata_lib.GerritPatchTuple(1, 1, True),
            constants.CL_ACTION_PICKED_UP)
        a2 = clactions.CLAction.FromGerritPatchAndAction(
            metadata_lib.GerritPatchTuple(1, 1, True),
            constants.CL_ACTION_PICKED_UP)
        a3 = clactions.CLAction.FromGerritPatchAndAction(
            metadata_lib.GerritPatchTuple(1, 1, True),
            constants.CL_ACTION_PICKED_UP)

        db.InsertCLActions(build_id, [])
        db.InsertCLActions(build_id, [a1])
        db.InsertCLActions(build_id, [a2, a3])

        action_count = db._GetEngine().execute(
            'select count(*) from clActionTable').fetchall()[0][0]
        self.assertEqual(action_count, 3)

        # Test that all known CL action types can be inserted
        fakepatch = metadata_lib.GerritPatchTuple(1, 1, True)
        all_actions_list = [
            clactions.CLAction.FromGerritPatchAndAction(fakepatch, action)
            for action in constants.CL_ACTIONS
        ]
        db.InsertCLActions(build_id, all_actions_list)
예제 #2
0
  def testGetRequeuedOrSpeculative(self):
    """Tests GetRequeuedOrSpeculative function."""
    change = metadata_lib.GerritPatchTuple(1, 1, False)
    speculative_change = metadata_lib.GerritPatchTuple(2, 2, False)
    changes = [change, speculative_change]

    build_id = self.fake_db.InsertBuild('n', 'w', 1, 'c', 'h')

    # A fresh change should not be marked requeued. A fresh specualtive
    # change should be marked as speculative.
    action_history = self.fake_db.GetActionsForChanges(changes)
    a = clactions.GetRequeuedOrSpeculative(change, action_history, False)
    self.assertEqual(a, None)
    a = clactions.GetRequeuedOrSpeculative(speculative_change, action_history,
                                           True)
    self.assertEqual(a, constants.CL_ACTION_SPECULATIVE)
    self._Act(build_id, speculative_change, a)

    # After picking up either change, neither should need an additional
    # requeued or speculative action.
    self._Act(build_id, speculative_change, constants.CL_ACTION_PICKED_UP)
    self._Act(build_id, change, constants.CL_ACTION_PICKED_UP)
    action_history = self.fake_db.GetActionsForChanges(changes)
    a = clactions.GetRequeuedOrSpeculative(change, action_history, False)
    self.assertEqual(a, None)
    a = clactions.GetRequeuedOrSpeculative(speculative_change, action_history,
                                           True)
    self.assertEqual(a, None)

    # After being rejected, both changes need an action (requeued and
    # speculative accordingly).
    self._Act(build_id, speculative_change, constants.CL_ACTION_KICKED_OUT)
    self._Act(build_id, change, constants.CL_ACTION_KICKED_OUT)
    action_history = self.fake_db.GetActionsForChanges(changes)
    a = clactions.GetRequeuedOrSpeculative(change, action_history, False)
    self.assertEqual(a, constants.CL_ACTION_REQUEUED)
    self._Act(build_id, change, a)
    a = clactions.GetRequeuedOrSpeculative(speculative_change, action_history,
                                           True)
    self.assertEqual(a, constants.CL_ACTION_SPECULATIVE)
    self._Act(build_id, speculative_change, a)

    # Once a speculative change becomes un-speculative, it needs a REQUEUD
    # action.
    action_history = self.fake_db.GetActionsForChanges(changes)
    a = clactions.GetRequeuedOrSpeculative(speculative_change, action_history,
                                           False)
    self.assertEqual(a, constants.CL_ACTION_REQUEUED)
    self._Act(build_id, speculative_change, a)
예제 #3
0
  def testMultiprocessSafety(self):
    m = multiprocessing.Manager()
    metadata = metadata_lib.CBuildbotMetadata(multiprocess_manager=m)
    key_dict = {'key1': 1, 'key2': 2}
    starting_dict = {
        'key1': 1,
        'key2': '2',
        'key3': key_dict,
        'cl_actions': [('a', 1), ('b', 2)],
        'board-metadata': {
            'board-1': {'info': 432},
        },
    }

    # Test that UpdateWithDict is process-safe
    parallel.RunParallelSteps([lambda: metadata.UpdateWithDict(starting_dict)])
    ending_dict = metadata.GetDict()
    self.assertEqual(starting_dict, ending_dict)

    # Test that UpdateKeyDictWithDict is process-safe
    parallel.RunParallelSteps([lambda: metadata.UpdateKeyDictWithDict(
        'key3', key_dict)])
    ending_dict = metadata.GetDict()
    self.assertEqual(starting_dict, ending_dict)

    # Test that RecordCLAction is process-safe
    fake_change = metadata_lib.GerritPatchTuple(12345, 1, False)
    fake_action = ('asdf,')
    parallel.RunParallelSteps([lambda: metadata.RecordCLAction(fake_change,
                                                               fake_action)])
    ending_dict = metadata.GetDict()
    # Assert that an action was recorded.
    self.assertEqual(len(starting_dict['cl_actions']) + 1,
                     len(ending_dict['cl_actions']))
예제 #4
0
    def testGetCLPreCQStatus(self):
        change = metadata_lib.GerritPatchTuple(1, 1, False)
        # Initial pre-CQ status of a change is None.
        self.assertEqual(self._GetCLStatus(change), None)

        # Builders can update the CL's pre-CQ status.
        build_id = self.fake_db.InsertBuild(constants.PRE_CQ_LAUNCHER_NAME,
                                            waterfall.WATERFALL_INTERNAL, 1,
                                            constants.PRE_CQ_LAUNCHER_CONFIG,
                                            'bot-hostname')

        self._Act(build_id, change, constants.CL_ACTION_PRE_CQ_WAITING)
        self.assertEqual(self._GetCLStatus(change),
                         constants.CL_STATUS_WAITING)

        self._Act(build_id, change, constants.CL_ACTION_PRE_CQ_INFLIGHT)
        self.assertEqual(self._GetCLStatus(change),
                         constants.CL_STATUS_INFLIGHT)

        # Recording a cl action that is not a valid pre-cq status should leave
        # pre-cq status unaffected.
        self._Act(build_id, change, 'polenta')
        self.assertEqual(self._GetCLStatus(change),
                         constants.CL_STATUS_INFLIGHT)

        self._Act(build_id, change, constants.CL_ACTION_PRE_CQ_RESET)
        self.assertEqual(self._GetCLStatus(change), None)
예제 #5
0
 def testGetCancelledPreCQBuilds(self):
     """Test GetCancelledPreCQBuilds."""
     c1 = metadata_lib.GerritPatchTuple(1, 1, False)
     build_id = self.fake_db.InsertBuild('n', 'w', 1, 'c', 'h')
     a1 = clactions.CLAction.FromGerritPatchAndAction(
         c1, constants.CL_ACTION_TRYBOT_CANCELLED, reason='binhost-pre-cq')
     a2 = clactions.CLAction.FromGerritPatchAndAction(
         c1,
         constants.CL_ACTION_TRYBOT_LAUNCHING,
         reason='binhost-pre-cq',
         buildbucket_id='1')
     a3 = clactions.CLAction.FromGerritPatchAndAction(
         c1,
         constants.CL_ACTION_TRYBOT_CANCELLED,
         reason='binhost-pre-cq',
         buildbucket_id='2')
     cl_actions = [a1, a2, a3]
     self.fake_db.InsertCLActions(build_id, cl_actions)
     action_history = self.fake_db.GetActionsForChanges([c1])
     builds = clactions.GetCancelledPreCQBuilds(action_history)
     self.assertEqual(len(builds), 1)
     self.assertEqual(builds.pop().buildbucket_id, '2')
    def _PopulateFakeCidbWithTestData(self, cq):
        """Generate test data and insert it in the the fake cidb object.

    Args:
      cq: Whether this is a CQ run. If False, this is a Pre-CQ run.
    """
        # Mock patches for test data.
        c1p1 = metadata_lib.GerritPatchTuple(1, 1, False)
        c2p1 = metadata_lib.GerritPatchTuple(2, 1, True)
        c2p2 = metadata_lib.GerritPatchTuple(2, 2, True)
        c3p1 = metadata_lib.GerritPatchTuple(3, 1, True)
        c3p2 = metadata_lib.GerritPatchTuple(3, 2, True)
        c4p1 = metadata_lib.GerritPatchTuple(4, 1, True)
        c4p2 = metadata_lib.GerritPatchTuple(4, 2, True)

        # Mock builder status dictionaries
        passed_status = {'status': constants.BUILDER_STATUS_PASSED}
        failed_status = {'status': constants.BUILDER_STATUS_FAILED}

        t = datetime.datetime.now()
        delta = datetime.timedelta(hours=1)
        bot_config = (constants.CQ_MASTER
                      if cq else constants.PRE_CQ_DEFAULT_CONFIGS[0])

        # pylint: disable=bad-continuation
        test_metadata = [
            # Build 1 picks up no patches.
            metadata_lib.CBuildbotMetadata().UpdateWithDict({
                'build-number':
                1,
                'bot-config':
                bot_config,
                'results': [],
                'status':
                passed_status
            }),
            # Build 2 picks up c1p1 and does nothing.
            metadata_lib.CBuildbotMetadata().UpdateWithDict({
                'build-number':
                2,
                'bot-config':
                bot_config,
                'results': [],
                'status':
                failed_status,
                'changes': [c1p1._asdict()]
            }).RecordCLAction(c1p1, constants.CL_ACTION_PICKED_UP, t + delta),
            # Build 3 picks up c1p1 and c2p1 and rejects both.
            # c3p1 is not included in the run because it fails to apply.
            metadata_lib.CBuildbotMetadata().UpdateWithDict({
                'build-number':
                3,
                'bot-config':
                bot_config,
                'results': [],
                'status':
                failed_status,
                'changes': [c1p1._asdict(), c2p1._asdict()]
            }).RecordCLAction(c1p1, constants.CL_ACTION_PICKED_UP,
                              t + delta).RecordCLAction(
                                  c2p1, constants.CL_ACTION_PICKED_UP,
                                  t + delta).RecordCLAction(
                                      c1p1, constants.CL_ACTION_KICKED_OUT,
                                      t + delta).RecordCLAction(
                                          c2p1, constants.CL_ACTION_KICKED_OUT,
                                          t + delta).RecordCLAction(
                                              c3p1,
                                              constants.CL_ACTION_KICKED_OUT,
                                              t + delta),
            # Build 4 picks up c4p1 and does nothing with it.
            # c4p2 isn't picked up because it fails to apply.
            metadata_lib.CBuildbotMetadata().UpdateWithDict({
                'build-number':
                3,
                'bot-config':
                bot_config,
                'results': [],
                'status':
                failed_status,
                'changes': [c4p1._asdict()]
            }).RecordCLAction(c4p1, constants.CL_ACTION_PICKED_UP,
                              t + delta).RecordCLAction(
                                  c4p2, constants.CL_ACTION_KICKED_OUT,
                                  t + delta),
        ]
        if cq:
            test_metadata += [
                # Build 4 picks up c1p1, c2p2, c3p2, c4p1 and submits the first three.
                # c4p2 is submitted without being tested.
                # So  c1p1 should be detected as a 1-time rejected good patch,
                # and c2p1 should be detected as a possibly bad patch.
                metadata_lib.CBuildbotMetadata().UpdateWithDict({
                    'build-number':
                    4,
                    'bot-config':
                    bot_config,
                    'results': [],
                    'status':
                    passed_status,
                    'changes': [c1p1._asdict(), c2p2._asdict()]
                }).RecordCLAction(
                    c1p1,
                    constants.CL_ACTION_PICKED_UP, t + delta).RecordCLAction(
                        c2p2, constants.CL_ACTION_PICKED_UP,
                        t + delta).RecordCLAction(
                            c3p2, constants.CL_ACTION_PICKED_UP,
                            t + delta).RecordCLAction(
                                c4p1, constants.CL_ACTION_PICKED_UP,
                                t + delta).RecordCLAction(
                                    c1p1, constants.CL_ACTION_SUBMITTED,
                                    t + delta).RecordCLAction(
                                        c2p2, constants.CL_ACTION_SUBMITTED,
                                        t + delta).RecordCLAction(
                                            c3p2,
                                            constants.CL_ACTION_SUBMITTED,
                                            t + delta).RecordCLAction(
                                                c4p2,
                                                constants.CL_ACTION_SUBMITTED,
                                                t + delta),
            ]
        else:
            test_metadata += [
                metadata_lib.CBuildbotMetadata().UpdateWithDict({
                    'build-number':
                    5,
                    'bot-config':
                    bot_config,
                    'results': [],
                    'status':
                    failed_status,
                    'changes': [c4p1._asdict()]
                }).RecordCLAction(c4p1, constants.CL_ACTION_PICKED_UP,
                                  t + delta).RecordCLAction(
                                      c4p1, constants.CL_ACTION_KICKED_OUT,
                                      t + delta),
                metadata_lib.CBuildbotMetadata().UpdateWithDict({
                    'build-number':
                    6,
                    'bot-config':
                    bot_config,
                    'results': [],
                    'status':
                    failed_status,
                    'changes': [c4p1._asdict()]
                }).RecordCLAction(c1p1, constants.CL_ACTION_PICKED_UP,
                                  t + delta).RecordCLAction(
                                      c1p1, constants.CL_ACTION_KICKED_OUT,
                                      t + delta)
            ]
        # pylint: enable=bad-continuation

        # test_metadata should not be guaranteed to be ordered by build number
        # so shuffle it, but use the same seed each time so that unit test is
        # deterministic.
        random.seed(0)
        random.shuffle(test_metadata)

        for m in test_metadata:
            build_id = self.fake_db.InsertBuild(m.GetValue('bot-config'),
                                                waterfall.WATERFALL_INTERNAL,
                                                m.GetValue('build-number'),
                                                m.GetValue('bot-config'),
                                                'bot-hostname')
            m.UpdateWithDict({'build_id': build_id})
            actions = []
            for action_metadata in m.GetDict()['cl_actions']:
                actions.append(
                    clactions.CLAction.FromMetadataEntry(action_metadata))
            self.fake_db.InsertCLActions(build_id, actions)
예제 #7
0
  def testRecordSubmissionMetrics(self):
    """Test that we correctly compute a CL's handling time."""
    change = metadata_lib.GerritPatchTuple(1, 1, False)
    launcher_id = self.fake_db.InsertBuild(
        'launcher', waterfall.WATERFALL_INTERNAL, 1,
        constants.PRE_CQ_LAUNCHER_CONFIG, 'hostname')
    trybot_id = self.fake_db.InsertBuild(
        'banana pre cq', waterfall.WATERFALL_INTERNAL, 1,
        'banana-pre-cq', 'hostname')
    master_id = self.fake_db.InsertBuild(
        'CQ master', waterfall.WATERFALL_INTERNAL, 1,
        constants.CQ_MASTER, 'hostname')
    slave_id = self.fake_db.InsertBuild(
        'banana paladin', waterfall.WATERFALL_INTERNAL, 1,
        'banana-paladin', 'hostname')

    start_time = datetime.datetime.now()
    c = itertools.count()

    def next_time():
      return start_time + datetime.timedelta(seconds=c.next())

    def a(build_id, action, reason=None):
      self._Act(build_id, change, action, reason=reason, timestamp=next_time())

    strategies = {}

    # Change is screened, picked up, and rejected by the pre-cq,
    # non-speculatively.
    a(launcher_id, constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
      reason='banana-pre-cq')
    a(launcher_id, constants.CL_ACTION_SCREENED_FOR_PRE_CQ)
    a(launcher_id, constants.CL_ACTION_TRYBOT_LAUNCHING,
      reason='banana-pre-cq')
    a(trybot_id, constants.CL_ACTION_PICKED_UP)
    a(trybot_id, constants.CL_ACTION_KICKED_OUT)

    # Change is re-marked by developer, picked up again by pre-cq, verified,
    # and marked as passed.
    a(launcher_id, constants.CL_ACTION_REQUEUED)
    a(launcher_id, constants.CL_ACTION_TRYBOT_LAUNCHING,
      reason='banana-pre-cq')
    a(trybot_id, constants.CL_ACTION_PICKED_UP)
    a(trybot_id, constants.CL_ACTION_VERIFIED)
    a(launcher_id, constants.CL_ACTION_PRE_CQ_FULLY_VERIFIED)
    a(launcher_id, constants.CL_ACTION_PRE_CQ_PASSED)

    # Change is picked up by the CQ and rejected.
    a(master_id, constants.CL_ACTION_PICKED_UP)
    a(slave_id, constants.CL_ACTION_PICKED_UP)
    a(master_id, constants.CL_ACTION_KICKED_OUT)

    # Change is re-marked, picked up by the CQ, and forgiven.
    a(launcher_id, constants.CL_ACTION_REQUEUED)
    a(master_id, constants.CL_ACTION_PICKED_UP)
    a(slave_id, constants.CL_ACTION_PICKED_UP)
    a(master_id, constants.CL_ACTION_FORGIVEN)

    # Change is re-marked, picked up by the CQ, and forgiven.
    a(master_id, constants.CL_ACTION_PICKED_UP)
    a(slave_id, constants.CL_ACTION_PICKED_UP)
    a(master_id, constants.CL_ACTION_SUBMITTED)
    strategies[change] = constants.STRATEGY_CQ_SUCCESS

    action_history = self.fake_db.GetActionsForChanges([change])
    clactions_metrics.RecordSubmissionMetrics(
        clactions.CLActionHistory(action_history), strategies)
예제 #8
0
  def testGetCLActionCount(self):
    c1p1 = metadata_lib.GerritPatchTuple(1, 1, False)
    c1p2 = metadata_lib.GerritPatchTuple(1, 2, False)
    precq_build_id = self.fake_db.InsertBuild(
        constants.PRE_CQ_LAUNCHER_NAME, constants.WATERFALL_INTERNAL, 1,
        constants.PRE_CQ_LAUNCHER_CONFIG, 'bot-hostname')
    melon_build_id = self.fake_db.InsertBuild(
        'melon builder name', constants.WATERFALL_INTERNAL, 1,
        'melon-config-name', 'grape-bot-hostname')

    # Count should be zero before any actions are recorded.

    action_history = self.fake_db.GetActionsForChanges([c1p1])
    self.assertEqual(
        0,
        clactions.GetCLActionCount(
            c1p1, validation_pool.CQ_PIPELINE_CONFIGS,
            constants.CL_ACTION_KICKED_OUT, action_history))

    # Record 3 failures for c1p1, and some other actions. Only count the
    # actions from builders in validation_pool.CQ_PIPELINE_CONFIGS.
    self.fake_db.InsertCLActions(
        precq_build_id,
        [clactions.CLAction.FromGerritPatchAndAction(
            c1p1, constants.CL_ACTION_KICKED_OUT)])
    self.fake_db.InsertCLActions(
        precq_build_id,
        [clactions.CLAction.FromGerritPatchAndAction(
            c1p1, constants.CL_ACTION_PICKED_UP)])
    self.fake_db.InsertCLActions(
        precq_build_id,
        [clactions.CLAction.FromGerritPatchAndAction(
            c1p1, constants.CL_ACTION_KICKED_OUT)])
    self.fake_db.InsertCLActions(
        melon_build_id,
        [clactions.CLAction.FromGerritPatchAndAction(
            c1p1, constants.CL_ACTION_KICKED_OUT)])

    action_history = self.fake_db.GetActionsForChanges([c1p1])
    self.assertEqual(
        2,
        clactions.GetCLActionCount(
            c1p1, validation_pool.CQ_PIPELINE_CONFIGS,
            constants.CL_ACTION_KICKED_OUT, action_history))

    # Record a failure for c1p2. Now the latest patches failure count should be
    # 1 (true weather we pass c1p1 or c1p2), whereas the total failure count
    # should be 3.
    self.fake_db.InsertCLActions(
        precq_build_id,
        [clactions.CLAction.FromGerritPatchAndAction(
            c1p2, constants.CL_ACTION_KICKED_OUT)])

    action_history = self.fake_db.GetActionsForChanges([c1p1])
    self.assertEqual(
        1,
        clactions.GetCLActionCount(
            c1p1, validation_pool.CQ_PIPELINE_CONFIGS,
            constants.CL_ACTION_KICKED_OUT, action_history))
    self.assertEqual(
        1,
        clactions.GetCLActionCount(
            c1p2, validation_pool.CQ_PIPELINE_CONFIGS,
            constants.CL_ACTION_KICKED_OUT, action_history))
    self.assertEqual(
        3,
        clactions.GetCLActionCount(
            c1p2, validation_pool.CQ_PIPELINE_CONFIGS,
            constants.CL_ACTION_KICKED_OUT, action_history,
            latest_patchset_only=False))
예제 #9
0
  def testGetCLPreCQCategoriesAndPendingCLs(self):
    c1 = metadata_lib.GerritPatchTuple(1, 1, False)
    c2 = metadata_lib.GerritPatchTuple(2, 2, False)
    c3 = metadata_lib.GerritPatchTuple(3, 3, False)
    c4 = metadata_lib.GerritPatchTuple(4, 4, False)
    c5 = metadata_lib.GerritPatchTuple(5, 5, False)

    launcher_build_id = self.fake_db.InsertBuild(
        constants.PRE_CQ_LAUNCHER_NAME, constants.WATERFALL_INTERNAL,
        1, constants.PRE_CQ_LAUNCHER_CONFIG, 'bot hostname 1')
    pineapple_build_id = self.fake_db.InsertBuild(
        'pineapple', constants.WATERFALL_TRYBOT, 87, 'pineapple-pre-cq',
        'pineapple hostname')
    guava_build_id = self.fake_db.InsertBuild(
        'guava', constants.WATERFALL_TRYBOT, 7, 'guava-pre-cq',
        'guava hostname')

    # c1 has 3 pending verifications, but only 1 inflight and 1
    # launching, so it is not busy/inflight.
    self._Act(launcher_build_id, c1,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'pineapple-pre-cq')
    self._Act(launcher_build_id, c1,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'banana-pre-cq')
    self._Act(launcher_build_id, c1,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'guava-pre-cq')
    self._Act(launcher_build_id, c1,
              constants.CL_ACTION_TRYBOT_LAUNCHING,
              'banana-pre-cq')
    self._Act(pineapple_build_id, c1, constants.CL_ACTION_PICKED_UP)

    # c2 has 3 pending verifications, 1 inflight and 1 launching, and 1 passed,
    # so it is busy.
    self._Act(launcher_build_id, c2,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'pineapple-pre-cq')
    self._Act(launcher_build_id, c2,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'banana-pre-cq')
    self._Act(launcher_build_id, c2,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'guava-pre-cq')
    self._Act(launcher_build_id, c2, constants.CL_ACTION_TRYBOT_LAUNCHING,
              'banana-pre-cq')
    self._Act(pineapple_build_id, c2, constants.CL_ACTION_PICKED_UP)
    self._Act(guava_build_id, c2, constants.CL_ACTION_VERIFIED)

    # c3 has 2 pending verifications, both passed, so it is passed.
    self._Act(launcher_build_id, c3,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'pineapple-pre-cq')
    self._Act(launcher_build_id, c3,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'guava-pre-cq')
    self._Act(pineapple_build_id, c3, constants.CL_ACTION_VERIFIED)
    self._Act(guava_build_id, c3, constants.CL_ACTION_VERIFIED)

    # c4 has 2 pending verifications: one is inflight and the other
    # passed. It is considered inflight and busy.
    self._Act(launcher_build_id, c4,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'pineapple-pre-cq')
    self._Act(launcher_build_id, c4,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'guava-pre-cq')
    self._Act(pineapple_build_id, c4, constants.CL_ACTION_PICKED_UP)
    self._Act(guava_build_id, c4, constants.CL_ACTION_VERIFIED)

    # c5 has not even been screened.

    changes = [c1, c2, c3, c4, c5]
    action_history = self.fake_db.GetActionsForChanges(changes)
    progress_map = clactions.GetPreCQProgressMap(changes, action_history)

    self.assertEqual(({c2, c4}, {c4}, {c3}),
                     clactions.GetPreCQCategories(progress_map))

    # Among changes c1, c2, c3, only the guava-pre-cq config is pending. The
    # other configs are either inflight, launching, or passed everywhere.
    screened_changes = set(changes).intersection(progress_map)
    self.assertEqual({'guava-pre-cq'},
                     clactions.GetPreCQConfigsToTest(screened_changes,
                                                     progress_map))
예제 #10
0
  def testGetCLPreCQProgress(self):
    change = metadata_lib.GerritPatchTuple(1, 1, False)
    s = lambda: clactions.GetCLPreCQProgress(
        change, self.fake_db.GetActionsForChanges([change]))

    self.assertEqual({}, s())

    # Simulate the pre-cq-launcher screening changes for pre-cq configs
    # to test with.
    launcher_build_id = self.fake_db.InsertBuild(
        constants.PRE_CQ_LAUNCHER_NAME, constants.WATERFALL_INTERNAL,
        1, constants.PRE_CQ_LAUNCHER_CONFIG, 'bot hostname 1')

    self._Act(launcher_build_id, change,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'pineapple-pre-cq')
    self._Act(launcher_build_id, change,
              constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
              'banana-pre-cq')

    configs = ['banana-pre-cq', 'pineapple-pre-cq']

    self.assertEqual(configs, sorted(s().keys()))
    for c in configs:
      self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_PENDING,
                       s()[c][0])

    # Simulate a prior build rejecting change
    self._Act(launcher_build_id, change,
              constants.CL_ACTION_KICKED_OUT,
              'pineapple-pre-cq')
    self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_FAILED,
                     s()['pineapple-pre-cq'][0])

    # Simulate the pre-cq-launcher launching tryjobs for all pending configs.
    for c in configs:
      self._Act(launcher_build_id, change,
                constants.CL_ACTION_TRYBOT_LAUNCHING, c)
    for c in configs:
      self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_LAUNCHED,
                       s()[c][0])

    # Simulate the tryjobs launching, and picking up the changes.
    banana_build_id = self.fake_db.InsertBuild(
        'banana', constants.WATERFALL_TRYBOT, 12, 'banana-pre-cq',
        'banana hostname')
    pineapple_build_id = self.fake_db.InsertBuild(
        'pineapple', constants.WATERFALL_TRYBOT, 87, 'pineapple-pre-cq',
        'pineapple hostname')

    self._Act(banana_build_id, change, constants.CL_ACTION_PICKED_UP)
    self._Act(pineapple_build_id, change, constants.CL_ACTION_PICKED_UP)
    for c in configs:
      self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_INFLIGHT,
                       s()[c][0])

    # Simulate the changes being retried.
    self._Act(banana_build_id, change, constants.CL_ACTION_FORGIVEN)
    self._Act(launcher_build_id, change, constants.CL_ACTION_FORGIVEN,
              'pineapple-pre-cq')
    for c in configs:
      self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_PENDING,
                       s()[c][0])
    # Simulate the changes being rejected, either by the configs themselves
    # or by the pre-cq-launcher.
    self._Act(banana_build_id, change, constants.CL_ACTION_KICKED_OUT)
    self._Act(launcher_build_id, change, constants.CL_ACTION_KICKED_OUT,
              'pineapple-pre-cq')
    for c in configs:
      self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_FAILED,
                       s()[c][0])
    # Simulate the tryjobs verifying the changes.
    self._Act(banana_build_id, change, constants.CL_ACTION_VERIFIED)
    self._Act(pineapple_build_id, change, constants.CL_ACTION_VERIFIED)
    for c in configs:
      self.assertEqual(constants.CL_PRECQ_CONFIG_STATUS_VERIFIED,
                       s()[c][0])

    # Simulate the pre-cq status being reset.
    self._Act(launcher_build_id, change, constants.CL_ACTION_PRE_CQ_RESET)
    self.assertEqual({}, s())
예제 #11
0
  def testGetOldPreCQBuildActions(self):
    """Test GetOldPreCQBuildActions."""
    c1 = metadata_lib.GerritPatchTuple(1, 1, False)
    c2 = metadata_lib.GerritPatchTuple(1, 2, False)
    changes = [c1, c2]

    build_id = self.fake_db.InsertBuild('n', 'w', 1, 'c', 'h')


    a1 = clactions.CLAction.FromGerritPatchAndAction(
        c1, constants.CL_ACTION_TRYBOT_LAUNCHING,
        reason='binhost-pre-cq',
        timestamp=datetime.datetime.now() - datetime.timedelta(hours=5))
    a2 = clactions.CLAction.FromGerritPatchAndAction(
        c1, constants.CL_ACTION_TRYBOT_LAUNCHING,
        reason='binhost-pre-cq',
        timestamp=datetime.datetime.now() - datetime.timedelta(hours=4),
        buildbucket_id='1')
    a3 = clactions.CLAction.FromGerritPatchAndAction(
        c1, constants.CL_ACTION_TRYBOT_LAUNCHING,
        reason='binhost-pre-cq',
        timestamp=datetime.datetime.now() - datetime.timedelta(hours=3),
        buildbucket_id='2')
    a4 = clactions.CLAction.FromGerritPatchAndAction(
        c1, constants.CL_ACTION_TRYBOT_LAUNCHING,
        reason='pbinhost-pre-cq',
        timestamp=datetime.datetime.now() - datetime.timedelta(hours=3),
        buildbucket_id='3')
    a5 = clactions.CLAction.FromGerritPatchAndAction(
        c1, constants.CL_ACTION_TRYBOT_CANCELLED,
        reason='binhost-pre-cq',
        timestamp=datetime.datetime.now() - datetime.timedelta(hours=3),
        buildbucket_id='3')
    a6 = clactions.CLAction.FromGerritPatchAndAction(
        c1, constants.CL_ACTION_TRYBOT_LAUNCHING,
        reason='binhost-pre-cq',
        timestamp=datetime.datetime.now() - datetime.timedelta(hours=1),
        buildbucket_id='4')
    a7 = clactions.CLAction.FromGerritPatchAndAction(
        c2, constants.CL_ACTION_TRYBOT_LAUNCHING,
        reason='binhost-pre-cq',
        timestamp=datetime.datetime.now(),
        buildbucket_id='5')

    cl_actions = [a1, a2, a3, a4, a5, a6, a7]

    self.fake_db.InsertCLActions(build_id, cl_actions)
    action_history = self.fake_db.GetActionsForChanges(changes)

    timestamp = datetime.datetime.now() - datetime.timedelta(hours=2)
    c1_old_actions = clactions.GetOldPreCQBuildActions(
        c1, action_history, timestamp)
    c2_old_actions = clactions.GetOldPreCQBuildActions(
        c2, action_history, timestamp)
    self.assertTrue(len(c1_old_actions) == 0)
    self.assertTrue(len(c2_old_actions) == 1)
    self.assertEqual([c.buildbucket_id for c in c2_old_actions],
                     [a6.buildbucket_id])

    c1_old_actions = clactions.GetOldPreCQBuildActions(
        c1, action_history)
    c2_old_actions = clactions.GetOldPreCQBuildActions(
        c2, action_history)
    self.assertTrue(len(c1_old_actions) == 0)
    self.assertTrue(len(c2_old_actions) == 3)
    self.assertEqual([c.buildbucket_id for c in c2_old_actions],
                     [a2.buildbucket_id, a3.buildbucket_id,
                      a6.buildbucket_id])
예제 #12
0
    def testGetCLHandlingTime(self):
        """Test that we correctly compute a CL's handling time."""
        change = metadata_lib.GerritPatchTuple(1, 1, False)
        launcher_id = self.fake_db.InsertBuild(
            'launcher', waterfall.WATERFALL_INTERNAL, 1,
            constants.PRE_CQ_LAUNCHER_CONFIG, 'hostname')
        trybot_id = self.fake_db.InsertBuild('banana pre cq',
                                             waterfall.WATERFALL_INTERNAL, 1,
                                             'banana-pre-cq', 'hostname')
        master_id = self.fake_db.InsertBuild('CQ master',
                                             waterfall.WATERFALL_INTERNAL, 1,
                                             constants.CQ_MASTER, 'hostname')
        slave_id = self.fake_db.InsertBuild('banana paladin',
                                            waterfall.WATERFALL_INTERNAL, 1,
                                            'banana-paladin', 'hostname')

        start_time = datetime.datetime.now()
        c = itertools.count()

        def next_time():
            return start_time + datetime.timedelta(seconds=c.next())

        def a(build_id, action, reason=None):
            self._Act(build_id,
                      change,
                      action,
                      reason=reason,
                      timestamp=next_time())

        strategies = {}

        # Change is screened, picked up, and rejected by the pre-cq,
        # non-speculatively.
        a(launcher_id,
          constants.CL_ACTION_VALIDATION_PENDING_PRE_CQ,
          reason='banana-pre-cq')
        a(launcher_id, constants.CL_ACTION_SCREENED_FOR_PRE_CQ)
        a(launcher_id,
          constants.CL_ACTION_TRYBOT_LAUNCHING,
          reason='banana-pre-cq')
        a(trybot_id, constants.CL_ACTION_PICKED_UP)
        a(trybot_id, constants.CL_ACTION_KICKED_OUT)

        # Change is re-marked by developer, picked up again by pre-cq, verified, and
        # marked as passed.
        a(launcher_id, constants.CL_ACTION_REQUEUED)
        a(launcher_id,
          constants.CL_ACTION_TRYBOT_LAUNCHING,
          reason='banana-pre-cq')
        a(trybot_id, constants.CL_ACTION_PICKED_UP)
        a(trybot_id, constants.CL_ACTION_VERIFIED)
        a(launcher_id, constants.CL_ACTION_PRE_CQ_FULLY_VERIFIED)
        a(launcher_id, constants.CL_ACTION_PRE_CQ_PASSED)

        # Change is picked up by the CQ and rejected.
        a(master_id, constants.CL_ACTION_PICKED_UP)
        a(slave_id, constants.CL_ACTION_PICKED_UP)
        a(master_id, constants.CL_ACTION_KICKED_OUT)

        # Change is re-marked, picked up by the CQ, and forgiven.
        a(launcher_id, constants.CL_ACTION_REQUEUED)
        a(master_id, constants.CL_ACTION_PICKED_UP)
        a(slave_id, constants.CL_ACTION_PICKED_UP)
        a(master_id, constants.CL_ACTION_FORGIVEN)

        # Change is re-marked, picked up by the CQ, and forgiven.
        a(master_id, constants.CL_ACTION_PICKED_UP)
        a(slave_id, constants.CL_ACTION_PICKED_UP)
        a(master_id, constants.CL_ACTION_SUBMITTED)
        strategies[change] = constants.STRATEGY_CQ_SUCCESS

        action_history = self.fake_db.GetActionsForChanges([change])
        # Note: There are 2 ticks in the total handling time that are not accounted
        # for in the sub-times. These are the time between VALIDATION_PENDING and
        # SCREENED, and the time between FULLY_VERIFIED and PASSED.
        self.assertEqual(18,
                         clactions.GetCLHandlingTime(change, action_history))
        self.assertEqual(7, clactions.GetPreCQTime(change, action_history))
        self.assertEqual(3, clactions.GetCQWaitTime(change, action_history))
        self.assertEqual(6, clactions.GetCQRunTime(change, action_history))
        self.assertEqual(3,
                         clactions.GetCQAttemptsCount(change, action_history))