def testAnalyzeBuildFailurePipelineAbortedWithoutAnalysis(self): master_name = 'm' builder_name = 'b' build_number = 124 root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number) root_pipeline._LogUnexpectedAborting(True) analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNone(analysis)
def testBuildFailurePipelineFlow(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number) self.MockPipeline( analyze_build_failure_pipeline.DetectFirstFailurePipeline, 'failure_info', expected_args=[master_name, builder_name, build_number], expected_kwargs={}) self.MockPipeline(analyze_build_failure_pipeline.PullChangelogPipeline, 'change_logs', expected_args=['failure_info'], expected_kwargs={}) self.MockPipeline( analyze_build_failure_pipeline.ExtractDEPSInfoPipeline, 'deps_info', expected_args=['failure_info', 'change_logs'], expected_kwargs={}) self.MockPipeline(analyze_build_failure_pipeline.ExtractSignalPipeline, 'signals', expected_args=['failure_info'], expected_kwargs={}) self.MockPipeline( analyze_build_failure_pipeline.IdentifyCulpritPipeline, 'heuristic_result', expected_args=[ 'failure_info', 'change_logs', 'deps_info', 'signals', False ], expected_kwargs={}) self.MockPipeline( analyze_build_failure_pipeline.TriggerSwarmingTasksPipeline, None, expected_args=[ master_name, builder_name, build_number, 'failure_info', False ], expected_kwargs={}) self.MockPipeline( analyze_build_failure_pipeline.StartTryJobOnDemandPipeline, 'try_job_result', expected_args=[ master_name, builder_name, build_number, 'failure_info', 'signals', 'heuristic_result', False, False ], expected_kwargs={}) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number, False, False) root_pipeline.start(queue_name=constants.DEFAULT_QUEUE) self.execute_queued_tasks()
def testBuildFailurePipelineStartWithNoneResultStatus(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number, False, False) root_pipeline._ResetAnalysis(master_name, builder_name, build_number) analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNotNone(analysis) self.assertEqual(analysis_status.RUNNING, analysis.status) self.assertIsNone(analysis.result_status)
def testAnalyzeBuildFailurePipelineNotAborted(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number) root_pipeline._LogUnexpectedAborting(False) analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNotNone(analysis) self.assertNotEqual(wf_analysis_status.ERROR, analysis.status)
def testBuildFailurePipelineStartWithNoneResultStatus(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number) root_pipeline._ResetAnalysis(master_name, builder_name, build_number) analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNotNone(analysis) self.assertEqual(wf_analysis_status.ANALYZING, analysis.status) self.assertIsNone(analysis.result_status)
def testAnalyzeBuildFailurePipelineNotAbortedIfWithoutError(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number, status=analysis_status.COMPLETED) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number, False, False) root_pipeline._LogUnexpectedAborting(True) analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNotNone(analysis) self.assertNotEqual(analysis_status.ERROR, analysis.status)
def testBuildFailurePipeline(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number) root_pipeline.start(queue_name='default') self.execute_queued_tasks() expected_analysis_result = { 'failures': [{ 'step_name': 'a', 'first_failure': 124, 'last_pass': 123, 'suspected_cls': [{ 'build_number': 124, 'repo_name': 'chromium', 'revision': 'some_git_hash', 'commit_position': 8888, 'url': ('https://chromium.googlesource.com/chromium' '/src.git/+/some_git_hash'), 'score': 2, 'hints': { 'modified x.cc (and it was in log)': 2, }, }], }] } analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNotNone(analysis) self.assertEqual(wf_analysis_status.ANALYZED, analysis.status) self.assertEqual(expected_analysis_result, analysis.result) self.assertIsNotNone(analysis.result_status)
def testBuildFailurePipeline(self): master_name = 'm' builder_name = 'b' build_number = 124 self._Setup(master_name, builder_name, build_number) root_pipeline = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number, False) root_pipeline.start(queue_name=constants.DEFAULT_QUEUE) self.execute_queued_tasks() expected_analysis_result = { 'failures': [ { 'step_name': 'a', 'supported': True, 'first_failure': 124, 'last_pass': 123, 'suspected_cls': [ { 'build_number': 124, 'repo_name': 'chromium', 'revision': 'some_git_hash', 'commit_position': 8888, 'url': ('https://chromium.googlesource.com/chromium' '/src.git/+/some_git_hash'), 'score': 2, 'hints': { 'modified x.cc (and it was in log)': 2, }, } ], } ] } analysis = WfAnalysis.Get(master_name, builder_name, build_number) self.assertIsNotNone(analysis) self.assertEqual(analysis_status.COMPLETED, analysis.status) self.assertEqual(expected_analysis_result, analysis.result) self.assertIsNotNone(analysis.result_status)
def ScheduleAnalysisIfNeeded(master_name, builder_name, build_number, failed_steps=None, build_completed=False, force=False, queue_name=constants.DEFAULT_QUEUE): """Schedules an analysis if needed and returns the build analysis. When the build failure was already analyzed and a new analysis is scheduled, the returned WfAnalysis will still have the result of last completed analysis. Args: master_name (str): The master name of the failed build. builder_name (str): The builder name of the failed build. build_number (int): The build number of the failed build. failed_steps (list): The names of all failed steps reported for the build. build_completed (bool): Indicate whether the build is completed. force (bool): If True, a fresh new analysis will be triggered even when an old one was completed already; otherwise bail out. queue_name (str): The task queue to be used for pipeline tasks. Returns: A WfAnalysis instance. """ if NeedANewAnalysis(master_name, builder_name, build_number, failed_steps, build_completed, force): pipeline_job = AnalyzeBuildFailurePipeline(master_name, builder_name, build_number, build_completed, force) # Explicitly run analysis in the backend module "waterfall-backend". # Note: Just setting the target in queue.yaml does NOT work for pipeline # when deployed to App Engine, but it does work in dev-server locally. # A possible reason is that pipeline will pick a default target if none is # specified explicitly, and the default target is used rather than the one # in the queue.yaml file, but this contradicts the documentation in # https://cloud.google.com/appengine/docs/python/taskqueue/tasks#Task. pipeline_job.target = appengine_util.GetTargetNameForModule( constants.WATERFALL_BACKEND) pipeline_job.start(queue_name=queue_name) logging.info('An analysis was scheduled for build %s, %s, %s: %s', master_name, builder_name, build_number, pipeline_job.pipeline_status_path()) else: logging.info('An analysis is not needed for build %s, %s, %s', master_name, builder_name, build_number) return WfAnalysis.Get(master_name, builder_name, build_number)