def setUp(self): self.cl1 = clactions.GerritChangeTuple(11111, True) self.cl1_patch1 = clactions.GerritPatchTuple(self.cl1.gerrit_number, 1, self.cl1.internal) self.cl1_patch2 = clactions.GerritPatchTuple(self.cl1.gerrit_number, 2, self.cl1.internal) self.cl2 = clactions.GerritChangeTuple(22222, True) self.cl2_patch1 = clactions.GerritPatchTuple(self.cl2.gerrit_number, 1, self.cl2.internal) self.cl2_patch2 = clactions.GerritPatchTuple(self.cl2.gerrit_number, 2, self.cl2.internal) self.cl3 = clactions.GerritChangeTuple(33333, True) self.cl3_patch1 = clactions.GerritPatchTuple(self.cl3.gerrit_number, 2, self.cl3.internal) # Expected actions in chronological order, most recent first. self.action1 = clactions.CLAction.FromGerritPatchAndAction( self.cl1_patch2, constants.CL_ACTION_SUBMITTED, timestamp=self._NDaysAgo(1)) self.action2 = clactions.CLAction.FromGerritPatchAndAction( self.cl1_patch2, constants.CL_ACTION_KICKED_OUT, timestamp=self._NDaysAgo(2)) self.action3 = clactions.CLAction.FromGerritPatchAndAction( self.cl2_patch2, constants.CL_ACTION_SUBMITTED, timestamp=self._NDaysAgo(3)) self.action4 = clactions.CLAction.FromGerritPatchAndAction( self.cl1_patch1, constants.CL_ACTION_SUBMIT_FAILED, timestamp=self._NDaysAgo(4)) self.action5 = clactions.CLAction.FromGerritPatchAndAction( self.cl1_patch1, constants.CL_ACTION_KICKED_OUT, timestamp=self._NDaysAgo(5)) self.action6 = clactions.CLAction.FromGerritPatchAndAction( self.cl3_patch1, constants.CL_ACTION_SUBMITTED, reason=constants.STRATEGY_NONMANIFEST, timestamp=self._NDaysAgo(6)) # CLActionHistory does not require the history to be given in chronological # order, so we provide them in reverse order, and expect them to be sorted # as appropriate. self.cl_action_stats = clactions.CLActionHistory([ self.action1, self.action2, self.action3, self.action4, self.action5, self.action6 ])
def GetActionHistory(self, *args, **kwargs): """Get all the actions for all changes.""" # pylint: disable=W0613 values = [] for item, action_id in zip(self.clActionTable, itertools.count()): row = (action_id, item['build_id'], item['action'], item['reason'], self.buildTable[item['build_id']]['build_config'], item['change_number'], item['patch_number'], item['change_source'], item['timestamp']) values.append(row) return clactions.CLActionHistory( clactions.CLAction(*row) for row in values)
def _RecordSubmissionMetrics(self): """Record CL handling statistics for submitted changes in monarch.""" if not self._run.config.master: return build_id, db = self._run.GetCIDBHandle() if db: my_actions = db.GetActionsForBuild(build_id) my_submit_actions = [m for m in my_actions if m.action == constants.CL_ACTION_SUBMITTED] # A dictionary mapping from every change that was submitted to the # submission reason. submitted_change_strategies = {m.patch : m.reason for m in my_submit_actions} submitted_changes_all_actions = db.GetActionsForChanges( submitted_change_strategies.keys()) action_history = clactions.CLActionHistory(submitted_changes_all_actions) clactions.RecordSubmissionMetrics(action_history, submitted_change_strategies)
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', constants.WATERFALL_INTERNAL, 1, constants.PRE_CQ_LAUNCHER_CONFIG, 'hostname') trybot_id = self.fake_db.InsertBuild('banana pre cq', constants.WATERFALL_INTERNAL, 1, 'banana-pre-cq', 'hostname') master_id = self.fake_db.InsertBuild('CQ master', constants.WATERFALL_INTERNAL, 1, constants.CQ_MASTER, 'hostname') slave_id = self.fake_db.InsertBuild('banana paladin', constants.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)) clactions.RecordSubmissionMetrics( clactions.CLActionHistory(action_history), strategies)