def testGetValidBoundingBuildsForStepCommitRightAtUpperBound(self, *_): upper_bound_build_number = 4 lower_bound, upper_bound = step_util.GetValidBoundingBuildsForStep( 'm', 'b', 's', None, upper_bound_build_number, 50) self.assertEqual(50, lower_bound.commit_position) self.assertEqual(50, upper_bound.commit_position)
def testGetValidBoundingBuildsForStepCommitBeforeEarliestBuild(self, *_): lower_bound_build_number = 3 lower_bound, upper_bound = step_util.GetValidBoundingBuildsForStep( 'm', 'b', 's', lower_bound_build_number, 100, 10) self.assertIsNone(lower_bound) self.assertEqual(lower_bound_build_number, upper_bound.build_number)
def testGetValidBoundingBuildsForStepCommitAfterLatestBuildInvalid(self, *_): upper_bound_build_number = 5 lower_bound, upper_bound = step_util.GetValidBoundingBuildsForStep( 'm', 'b', 's', None, upper_bound_build_number, 10000) self.assertIsNone(lower_bound) self.assertIsNone(upper_bound)
def testGetValidBoundingBuildsForStepExactMatch(self, *_): lower_bound, upper_bound = step_util.GetValidBoundingBuildsForStep( 'm', 'b', 's', 0, 100, 30) self.assertEqual(1, lower_bound.build_number) self.assertEqual(2, upper_bound.build_number)
def RunImpl(self, parameters): """Determines the Isolated sha to run in swarming given a commit position. If the requested commit position maps directly to a build, simply get that existing build's isolated sha. Otherwise, trigger a try job to compile and isolate at that revision and return the resulting sha. """ analysis = ndb.Key(urlsafe=parameters.analysis_urlsafe_key).get() assert analysis master_name = analysis.master_name builder_name = analysis.builder_name commit_position = parameters.commit_position step_name = analysis.step_name isolate_target_name = parameters.step_metadata.isolate_target_name reference_build_info = build_util.GetBuildInfo(master_name, builder_name, analysis.build_number) parent_mastername = (reference_build_info.parent_mastername or master_name) parent_buildername = (reference_build_info.parent_buildername or builder_name) targets = (IsolatedTarget.FindIsolateAtOrAfterCommitPositionByMaster( parent_mastername, parent_buildername, constants.GITILES_HOST, constants.GITILES_PROJECT, constants.GITILES_REF, isolate_target_name, commit_position)) # TODO(crbug.com/872992): Remove this entire branch's fallback logic once # LUCI migration is complete. if not targets: analysis.LogInfo(( 'No IsolatedTargets found for {}/{} with minimum commit position ' '{}. Falling back to searching buildbot').format( master_name, builder_name, commit_position)) _, earliest_containing_build = step_util.GetValidBoundingBuildsForStep( master_name, builder_name, step_name, None, parameters.upper_bound_build_number, commit_position) assert earliest_containing_build, ( 'Unable to find nearest build cycle with minimum commit position ' '{}'.format(commit_position)) build_commit_position = earliest_containing_build.commit_position assert build_commit_position >= commit_position, ( 'Upper bound build commit position {} is before {}'.format( build_commit_position, commit_position)) if build_commit_position == commit_position: # pragma: no branch get_build_sha_parameters = self.CreateInputObjectInstance( GetIsolateShaForBuildParameters, master_name=master_name, builder_name=builder_name, build_number=earliest_containing_build.build_number, step_name=step_name, url=buildbot.CreateBuildUrl( master_name, builder_name, earliest_containing_build.build_number)) yield GetIsolateShaForBuildPipeline(get_build_sha_parameters) return if targets: upper_bound_target = targets[0] if upper_bound_target.commit_position == commit_position: # The requested commit position is that of a found IsolatedTarget. get_target_input = GetIsolateShaForTargetInput( isolated_target_urlsafe_key=upper_bound_target.key.urlsafe( )) yield GetIsolateShaForTargetPipeline(get_target_input) return # The requested commit position needs to be compiled. cache_name = swarmbot_util.GetCacheName( parent_mastername, parent_buildername, suffix=flake_constants.FLAKE_CACHE_SUFFIX) test_name = analysis.test_name try_job = flake_try_job.GetTryJob(master_name, builder_name, step_name, test_name, parameters.revision) run_flake_try_job_parameters = self.CreateInputObjectInstance( RunFlakeTryJobParameters, analysis_urlsafe_key=parameters.analysis_urlsafe_key, revision=parameters.revision, flake_cache_name=cache_name, dimensions=parameters.dimensions, isolate_target_name=isolate_target_name, urlsafe_try_job_key=try_job.key.urlsafe()) with pipeline.InOrder(): try_job_result = yield RunFlakeTryJobPipeline( run_flake_try_job_parameters) get_isolate_sha_from_try_job_input = self.CreateInputObjectInstance( GetIsolateShaForTryJobParameters, try_job_result=try_job_result, step_name=step_name) yield GetIsolateShaForTryJobPipeline( get_isolate_sha_from_try_job_input)
def RunImpl(self, parameters): """Pipeline for determining the next commit position to analyze.""" analysis_urlsafe_key = parameters.analysis_urlsafe_key analysis = ndb.Key(urlsafe=analysis_urlsafe_key).get() assert analysis master_name = analysis.master_name builder_name = analysis.builder_name specified_lower_bound = parameters.commit_position_range.lower specified_upper_bound = parameters.commit_position_range.upper data_points = analysis.GetDataPointsWithinCommitPositionRange( IntRange(lower=specified_lower_bound, upper=specified_upper_bound)) # Data points must be sorted in reverse order by commit position before. data_points = sorted(data_points, key=lambda k: k.commit_position, reverse=True) # A suspected build id is available when there is a regression range that # spans a single build cycle. During this time, bisect is preferred to # exponential search. use_bisect = (analysis.suspected_flake_build_number is not None or analysis.suspected_build_id is not None) latest_regression_range = analysis.GetLatestRegressionRange() calculated_next_commit_id, culprit_commit_id = ( lookback_algorithm.GetNextCommitId(data_points, use_bisect, latest_regression_range)) if calculated_next_commit_id is None: # The analysis is finished according to the lookback algorithm. return NextCommitPositionOutput( next_commit_id=None, culprit_commit_id=culprit_commit_id) cutoff_commit_position = ( next_commit_position_utils.GetEarliestCommitPosition( specified_lower_bound, specified_upper_bound)) if calculated_next_commit_id.commit_position < cutoff_commit_position: # Long-standing flake. Do not continue the analysis. return NextCommitPositionOutput(next_commit_id=None, culprit_commit_id=None) # Try the analysis' heuristic results first, if any. next_commit_id = ( next_commit_position_utils.GetNextCommitIdFromHeuristicResults( analysis_urlsafe_key)) if next_commit_id is not None: # Heuristic results are available and should be tried first. assert not analysis.FindMatchingDataPointWithCommitPosition( next_commit_id.commit_position ), ('Existing heuristic results suggest commit position {} which has ' 'already been run'.format(next_commit_id.commit_position)) return NextCommitPositionOutput(next_commit_id=next_commit_id, culprit_commit_id=None) # Round off the next calculated commit position to the nearest builds on # both sides. reference_build_info = build_util.GetBuildInfo(master_name, builder_name, analysis.build_number) parent_mastername = reference_build_info.parent_mastername or master_name parent_buildername = (reference_build_info.parent_buildername or builder_name) target_name = parameters.step_metadata.isolate_target_name try: lower_bound_target, upper_bound_target = ( step_util.GetBoundingIsolatedTargets( parent_mastername, parent_buildername, target_name, calculated_next_commit_id.commit_position)) # Update the analysis' suspected build cycle if identified. analysis.UpdateSuspectedBuild(lower_bound_target, upper_bound_target) lower_bound_commit_id, upper_bound_commit_id = ( next_commit_position_utils.GenerateCommitIDsForBoundingTargets( data_points, lower_bound_target, upper_bound_target)) except AssertionError as e: # Fallback to searching buildbot in case builds aren't indexed as # IsolatedTargets. # TODO(crbug.com/872992): Remove fallback logic. analysis.LogError(e.message) analysis.LogWarning(( 'Failed to determine isolated targets surrounding {}. Falling back ' 'to searching buildbot').format( calculated_next_commit_id.commit_position)) upper_bound_build_number = analysis.GetLowestUpperBoundBuildNumber( calculated_next_commit_id) lower_bound_build, upper_bound_build = ( step_util.GetValidBoundingBuildsForStep( master_name, builder_name, analysis.step_name, None, upper_bound_build_number, calculated_next_commit_id.commit_position)) # Update the analysis' suspected build cycle if identified. analysis.UpdateSuspectedBuildUsingBuildInfo( lower_bound_build, upper_bound_build) lower_bound_commit_id = CommitID( commit_position=lower_bound_build.commit_position, revision=lower_bound_build.chromium_revision ) if lower_bound_build else None upper_bound_commit_id = CommitID( commit_position=upper_bound_build.commit_position, revision=upper_bound_build.chromium_revision ) if upper_bound_build else None # When identifying the neighboring builds of the requested commit position, # heuristic analysis may become eligible if the neighboring builds are # adjacent to one another. if analysis.CanRunHeuristicAnalysis(): # Run heuristic analysis if eligible and not yet already done. heuristic_analysis.RunHeuristicAnalysis(analysis) # Try the newly computed heuristic results if any were identified. next_commit_id = ( next_commit_position_utils.GetNextCommitIdFromHeuristicResults( analysis_urlsafe_key)) if next_commit_id is not None: # pragma: no branch assert not analysis.FindMatchingDataPointWithCommitPosition( next_commit_id.commit_position ), ('Newly run heuristic results suggest commit position {} which has ' 'already been run'.format(next_commit_id)) return NextCommitPositionOutput(next_commit_id=next_commit_id, culprit_commit_id=None) # Pick the commit position of the returned neighboring builds that has not # yet been analyzed if possible, or the commit position itself when not. build_range = CommitIDRange(lower=lower_bound_commit_id, upper=upper_bound_commit_id) actual_next_commit_id = ( next_commit_position_utils.GetNextCommitIDFromBuildRange( analysis, build_range, calculated_next_commit_id)) assert not analysis.FindMatchingDataPointWithCommitPosition( actual_next_commit_id.commit_position), ( 'Rounded-off commit position {} has already been run'.format( actual_next_commit_id.commit_position)) return NextCommitPositionOutput(next_commit_id=actual_next_commit_id, culprit_commit_id=culprit_commit_id)