def testGetFailedRevisionFromCompileResult(self):
   self.assertIsNone(
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromCompileResult(
           None))
   self.assertIsNone(
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromCompileResult(
           {'report': {}}))
   self.assertIsNone(
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromCompileResult(
           {
               'report': {
                   'result': {
                       'rev1': 'passed'
                   }
               }
           }))
   self.assertEqual(
       'rev2',
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromCompileResult(
           {
               'report': {
                   'result': {
                       'rev1': 'passed',
                       'rev2': 'failed'
                   }
               }
           }))
  def testFindCulpritForEachTestFailureCulpritsReturned(self):
    result = {
        'report': {
            'culprits': {
                'a_tests': {
                    'Test1': 'rev1'
                }
            }
        }
    }

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit_map, failed_revisions = pipeline._FindCulpritForEachTestFailure(
        result)

    expected_culprit_map = {
        'a_tests': {
            'tests': {
                'Test1': {
                    'revision': 'rev1'
                }
            }
        }
    }

    self.assertEqual(culprit_map, expected_culprit_map)
    self.assertEqual(failed_revisions, ['rev1'])
  def testIdentifyCulpritForCompileTryJobNoCulprit(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    self._CreateEntities(master_name, builder_name, build_number, try_job_id)

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     None, [], failure_type.COMPILE])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.COMPILE, '1', None)
    pipeline.start()
    self.execute_queued_tasks()

    try_job = WfTryJob.Get(master_name, builder_name, build_number)
    try_job_data = WfTryJobData.Get(try_job_id)

    self.assertEqual(analysis_status.COMPLETED, try_job.status)
    self.assertEqual([], try_job.compile_results)
    self.assertIsNone(try_job_data.culprits)
    self.assertIsNone(analysis.result_status)
    self.assertIsNone(analysis.suspected_cls)
  def testIdentifyCulpritForTestTryJobNoTryJobResultNoHeuristicResult(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING)

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     None, [], failure_type.TEST])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.TEST, '1', None)
    pipeline.start()
    self.execute_queued_tasks()

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)
    self.assertIsNone(analysis.result_status)
    self.assertIsNone(analysis.suspected_cls)
  def testIdentifyCulpritForCompileReturnNoneIfAllPassed(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    compile_result = {
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'passed'
            }
        },
        'url': 'url',
        'try_job_id': try_job_id,
    }

    WfTryJobData.Create(try_job_id).put()
    WfTryJob.Create(master_name, builder_name, build_number).put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, ['rev1'],
        TryJobType.COMPILE, '1', compile_result)
    try_job = WfTryJob.Get(master_name, builder_name, build_number)

    self.assertIsNone(culprit)
    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)
  def testIdentifyCulpritForFlakyCompile(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    compile_result = {
        'report': {
            'result': {
                'rev1': 'failed',
                'rev2': 'failed'
            },
            'metadata': {
                'sub_ranges': [
                  [
                      None,
                      'rev2'
                  ]
                ]
            }
        },
        'url': 'url',
        'try_job_id': try_job_id,
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id)

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.result = {
        'failures': [
            {
                'step_name': 'compile',
                'suspected_cls': []
            }
        ]
    }
    analysis.put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     {}, [], failure_type.COMPILE])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.COMPILE, '1', compile_result)
    pipeline.start()
    self.execute_queued_tasks()

    try_job = WfTryJob.Get(master_name, builder_name, build_number)

    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)

    analysis = WfAnalysis.Get(master_name, builder_name, build_number)
    self.assertEqual(result_status.FLAKY, analysis.result_status)
    self.assertEqual([], analysis.suspected_cls)
  def testIdentifyCulpritForTestTryJobReturnRevisionIfNoCulpritInfo(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    test_result = {
        'report': {
            'result': {
                'rev3': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    }
                }
            }
        },
        'url': 'url',
        'try_job_id': try_job_id
    }

    WfTryJobData.Create(try_job_id).put()
    try_job = WfTryJob.Create(master_name, builder_name, build_number)
    try_job.status = analysis_status.RUNNING
    try_job.put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, ['rev3'], TryJobType.TEST,
        '1', test_result)

    expected_culprit = {
        'a_test': {
            'tests': {
                'a_test1': {
                    'revision': 'rev3'
                }
            }
        }
    }
    self.assertEqual(expected_culprit, culprit)

    try_job_data = WfTryJobData.Get(try_job_id)
    expected_culprit_data = {
        'a_test': {
            'a_test1': 'rev3'
        }
    }
    self.assertEqual(expected_culprit_data, try_job_data.culprits)
  def testFindCulpritForEachTestFailureRevisionNotRun(self):
    result = {
        'report': {
            'result': {
                'rev2': 'passed'
            }
        }
    }

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit_map, failed_revisions = pipeline._FindCulpritForEachTestFailure(
        result)
    self.assertEqual(culprit_map, {})
    self.assertEqual(failed_revisions, [])
 def testGetFailedRevisionFromResultsDict(self):
   self.assertIsNone(
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict({}))
   self.assertEqual(
       None,
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict(
           {'rev1': 'passed'}))
   self.assertEqual(
       'rev1',
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict(
           {'rev1': 'failed'}))
   self.assertEqual(
       'rev2',
       IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict(
           {'rev1': 'passed', 'rev2': 'failed'}))
  def testIdentifyCulpritForTestTryJobReturnNoneIfNoRevisionToCheck(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    test_result = {
        'report': {
            'result': {
                'rev1': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    }
                }
            }
        },
        'url': 'url',
        'try_job_id': try_job_id
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING)

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     {}, [], failure_type.TEST])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number, failure_type.TEST, '1',
        test_result)
    pipeline.start()
    self.execute_queued_tasks()

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)

    self.assertIsNone(analysis.result_status)
    self.assertIsNone(analysis.suspected_cls)
  def testReturnNoneIfNoTryJob(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 8

    WfTryJob.Create(master_name, builder_name, build_number).put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     None, [], failure_type.TEST])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.TEST, None, None)
    pipeline.start()
    self.execute_queued_tasks()

    try_job = WfTryJob.Get(master_name, builder_name, build_number)
    self.assertEqual(try_job.test_results, [])
    self.assertEqual(try_job.status, analysis_status.COMPLETED)
  def testIdentifyCulpritForTestTryJobReturnNoneIfNoTryJobResult(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    WfTryJobData.Create(try_job_id).put()
    try_job = WfTryJob.Create(master_name, builder_name, build_number)
    try_job.status = analysis_status.RUNNING
    try_job.put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, ['rev1', 'rev2'],
        TryJobType.TEST, '1', None)

    self.assertIsNone(culprit)

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)
  def testIdentifyCulpritForCompileReturnNoneIfAllPassed(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    compile_result = {
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'passed'
            }
        },
        'url': 'url',
        'try_job_id': try_job_id,
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id)

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     {}, [], failure_type.COMPILE])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.COMPILE, '1', compile_result)
    pipeline.start()
    self.execute_queued_tasks()

    try_job = WfTryJob.Get(master_name, builder_name, build_number)

    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)

    self.assertIsNone(analysis.result_status)
    self.assertIsNone(analysis.suspected_cls)
  def testIdentifyCulpritForCompileTryJobNoCulprit(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    try_job = WfTryJob.Create(master_name, builder_name, build_number)
    try_job.put()
    try_job_data = WfTryJobData.Create(try_job_id)
    try_job_data.put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, ['rev1'],
        TryJobType.COMPILE, '1', None)
    try_job = WfTryJob.Get(master_name, builder_name, build_number)

    self.assertEqual(analysis_status.COMPLETED, try_job.status)
    self.assertEqual([], try_job.compile_results)
    self.assertIsNone(culprit)
    self.assertIsNone(try_job_data.culprits)
  def testIdentifyCulpritForTestTryJobNoTryJobResultWithHeuristicResult(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    suspected_cl = {
        'revision': 'rev1',
        'commit_position': 1,
        'url': 'url_1',
        'repo_name': 'chromium'
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING)

    # Heuristic analysis already provided some results.
    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.result_status = result_status.FOUND_UNTRIAGED
    analysis.suspected_cls = [suspected_cl]
    analysis.put()

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     None, [['chromium', 'rev1']],
                                     failure_type.TEST])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.TEST, '1', None)
    pipeline.start()
    self.execute_queued_tasks()

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)

    # Ensure analysis results are not updated since no culprit from try job.
    self.assertEqual(analysis.result_status, result_status.FOUND_UNTRIAGED)
    self.assertEqual(analysis.suspected_cls, [suspected_cl])
  def testIdentifyCulpritForTestTryJobReturnNoneIfNoRevisionToCheck(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    test_result = {
        'report': {
            'result': {
                'rev1': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    }
                }
            }
        },
        'url': 'url',
        'try_job_id': try_job_id
    }

    WfTryJobData.Create(try_job_id).put()
    try_job = WfTryJob.Create(master_name, builder_name, build_number)
    try_job.status = analysis_status.RUNNING
    try_job.put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, [], TryJobType.TEST, '1',
        test_result)

    self.assertIsNone(culprit)

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertIsNone(try_job_data.culprits)
  def testAnalysisIsUpdatedOnlyIfStatusOrSuspectedCLsChanged(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'
    repo_name = 'chromium'
    revision = 'rev1'
    commit_position = 1

    heuristic_suspected_cl = {
        'revision': revision,
        'commit_position': commit_position,
        'url': 'url_1',
        'repo_name': repo_name
    }

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.suspected_cls = [heuristic_suspected_cl]
    analysis.result_status = result_status.FOUND_UNTRIAGED
    analysis.put()
    version = analysis.version

    build_key = build_util.CreateBuildId(
        master_name, builder_name, build_number)
    suspected_cl = WfSuspectedCL.Create(repo_name, revision, commit_position)
    suspected_cl.approaches = [analysis_approach_type.HEURISTIC]
    suspected_cl.builds = {
        build_key: {
            'approaches': [analysis_approach_type.HEURISTIC],
            'failure_type': failure_type.COMPILE,
            'failures': {'compile': []},
            'status': None,
            'top_score': 4
        }
    }
    suspected_cl.put()

    compile_result = {
        'report': {
            'result': {
                revision: 'failed',
            },
            'culprit': revision
        },
        'try_job_id': try_job_id,
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING,
                         compile_results=[compile_result])

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     {revision: heuristic_suspected_cl},
                                     [[repo_name, revision]],
                                     failure_type.COMPILE])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.COMPILE, '1', compile_result)
    pipeline.start()
    self.execute_queued_tasks()

    self.assertEqual(analysis.result_status,
                     result_status.FOUND_UNTRIAGED)
    self.assertEqual(analysis.suspected_cls, [heuristic_suspected_cl])
    self.assertEqual(version, analysis.version)  # No update to analysis.

    expected_approaches = [
        analysis_approach_type.HEURISTIC, analysis_approach_type.TRY_JOB]
    expected_builds = {
        build_key: {
            'approaches': expected_approaches,
            'failure_type': failure_type.COMPILE,
            'failures': {'compile': []},
            'status': None,
            'top_score': 4
        }
    }
    suspected_cl = WfSuspectedCL.Get(repo_name, revision)
    self.assertEqual(expected_approaches, suspected_cl.approaches)
    self.assertEqual(expected_builds, suspected_cl.builds)
  def testIdentifyCulpritForCompileTryJobSuccess(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    compile_result = {
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'failed'
            },
            'culprit': 'rev2'
        },
        'try_job_id': try_job_id,
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING,
                         compile_results=[compile_result])
    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    expected_culprit = 'rev2'
    expected_suspected_cl = {
        'revision': 'rev2',
        'commit_position': 2,
        'url': 'url_2',
        'repo_name': 'chromium'
    }
    expected_compile_result = {
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'failed'
            },
            'culprit': 'rev2'
        },
        'try_job_id': try_job_id,
        'culprit': {
            'compile': expected_suspected_cl
        }
    }
    expected_analysis_suspected_cls = [{
        'revision': 'rev2',
        'commit_position': 2,
        'url': 'url_2',
        'repo_name': 'chromium',
        'failures': {'compile': []},
        'top_score': None
    }]

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     {expected_culprit: expected_suspected_cl},
                                     [], failure_type.COMPILE])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.COMPILE, '1', compile_result)
    pipeline.start()
    self.execute_queued_tasks()

    try_job = WfTryJob.Get(master_name, builder_name, build_number)
    self.assertEqual(expected_compile_result, try_job.compile_results[-1])
    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    analysis = WfAnalysis.Get(master_name, builder_name, build_number)
    self.assertEqual({'compile': expected_culprit}, try_job_data.culprits)
    self.assertEqual(analysis.result_status,
                     result_status.FOUND_UNTRIAGED)
    self.assertEqual(analysis.suspected_cls, expected_analysis_suspected_cls)
  def testIdentifyCulpritForTestTryJobSuccess(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    test_result = {
        'report': {
            'result': {
                'rev1': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    },
                    'c_test': {
                        'status': 'passed',
                        'valid': True
                    }
                },
                'rev2': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1', 'a_test2']
                    },
                    'b_test': {
                        'status': 'passed',
                        'valid': True
                    },
                    'c_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': []
                    }
                }
            }
        },
        'url': 'url',
        'try_job_id': try_job_id
    }

    WfTryJobData.Create(try_job_id).put()
    try_job = WfTryJob.Create(master_name, builder_name, build_number)
    try_job.status = analysis_status.RUNNING
    try_job.test_results = [test_result]
    try_job.put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, ['rev1', 'rev2'],
        TryJobType.TEST, '1', test_result)

    expected_test_result = {
        'report': {
            'result': {
                'rev1': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    },
                    'c_test': {
                        'status': 'passed',
                        'valid': True
                    }
                },
                'rev2': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1', 'a_test2']
                    },
                    'b_test': {
                        'status': 'passed',
                        'valid': True
                    },
                    'c_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': []
                    }
                }
            }
        },
        'url': 'url',
        'try_job_id': try_job_id,
        'culprit': {
            'a_test': {
                'tests': {
                    'a_test1': {
                        'revision': 'rev1',
                        'commit_position': '1',
                        'review_url': 'url_1'
                    },
                    'a_test2': {
                        'revision': 'rev2',
                        'commit_position': '2',
                        'review_url': 'url_2'
                    }
                }
            },
            'b_test': {
                'tests': {
                    'b_test1': {
                        'revision': 'rev1',
                        'commit_position': '1',
                        'review_url': 'url_1'
                    }
                }
            },
            'c_test': {
                'revision': 'rev2',
                'commit_position': '2',
                'review_url': 'url_2',
                'tests': {}
            }
        }
    }

    self.assertEqual(expected_test_result['culprit'], culprit)

    try_job = WfTryJob.Get(master_name, builder_name, build_number)
    self.assertEqual(expected_test_result, try_job.test_results[-1])
    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    expected_culprit_data = {
        'a_test': {
            'a_test1': 'rev1',
            'a_test2': 'rev2',
        },
        'b_test': {
            'b_test1': 'rev1',
        },
        'c_test': 'rev2'
        }
    self.assertEqual(expected_culprit_data, try_job_data.culprits)
    def run(self, master_name, builder_name, build_number, failure_info,
            signals, heuristic_result, build_completed, force_try_job):
        """Starts a try job if one is needed for the given failure."""

        if not build_completed:  # Only start try-jobs for completed builds.
            return

        need_try_job, try_job_key = try_job_util.NeedANewWaterfallTryJob(
            master_name, builder_name, build_number, failure_info, signals,
            heuristic_result, force_try_job)

        if not need_try_job:
            return

        try_job_type = failure_info['failure_type']
        last_pass = _GetLastPass(build_number, failure_info, try_job_type)
        if last_pass is None:  # pragma: no cover
            logging.warning(
                'Couldn"t start try job for build %s, %s, %d because'
                ' last_pass is not found.', master_name, builder_name,
                build_number)
            return

        good_revision = failure_info['builds'][str(
            last_pass)]['chromium_revision']
        bad_revision = failure_info['builds'][str(
            build_number)]['chromium_revision']
        suspected_revisions = _GetSuspectsFromHeuristicResult(heuristic_result)

        if try_job_type == failure_type.COMPILE:
            compile_targets = try_job_util.GetFailedTargetsFromSignals(
                signals, master_name, builder_name)
            dimensions = waterfall_config.GetTrybotDimensions(
                master_name, builder_name)
            cache_name = swarming_util.GetCacheName(master_name, builder_name)
            try_job_id = yield ScheduleCompileTryJobPipeline(
                master_name, builder_name, build_number, good_revision,
                bad_revision, try_job_type, compile_targets,
                suspected_revisions, cache_name, dimensions)
        else:
            # If try_job_type is other type, the pipeline has returned.
            # So here the try_job_type is failure_type.TEST.

            # Waits and gets the swarming tasks' results.
            task_results = []
            for step_name, step_failure in failure_info[
                    'failed_steps'].iteritems():
                step_has_first_time_failure = _HasFirstTimeFailure(
                    step_failure.get('tests', {}), build_number)
                if not step_has_first_time_failure:
                    continue
                task_result = yield ProcessSwarmingTaskResultPipeline(
                    master_name, builder_name, build_number, step_name)
                task_results.append(task_result)

            yield UpdateAnalysisWithFlakeInfoPipeline(master_name,
                                                      builder_name,
                                                      build_number,
                                                      *task_results)

            parent_mastername = failure_info.get(
                'parent_mastername') or master_name
            parent_buildername = failure_info.get('parent_buildername') or (
                builder_name)
            dimensions = waterfall_config.GetTrybotDimensions(
                parent_mastername, parent_buildername)
            cache_name = swarming_util.GetCacheName(parent_mastername,
                                                    parent_buildername)

            try_job_id = yield ScheduleTestTryJobPipeline(
                master_name, builder_name, build_number, good_revision,
                bad_revision, try_job_type, suspected_revisions, cache_name,
                dimensions, *task_results)

        try_job_result = yield MonitorTryJobPipeline(try_job_key.urlsafe(),
                                                     try_job_type, try_job_id)

        yield IdentifyTryJobCulpritPipeline(master_name, builder_name,
                                            build_number, try_job_type,
                                            try_job_id, try_job_result)
  def testIdentifyCulpritForTestTryJobReturnRevisionIfNoCulpritInfo(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    test_result = {
        'report': {
            'result': {
                'rev3': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    }
                }
            },
            'culprits': {
                'a_test': {
                    'a_test1': 'rev3'
                }
            }
        },
        'url': 'url',
        'try_job_id': try_job_id
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING)

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    expected_suspected_cl = {
        'revision': 'rev3',
        'repo_name': 'chromium'
    }

    expected_analysis_suspected_cls = [
        {
            'revision': 'rev3',
            'repo_name': 'chromium',
            'failures': {'a_test': ['a_test1']},
            'top_score': None
        }
    ]

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     {'rev3': expected_suspected_cl}, [],
                                     failure_type.TEST])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number, failure_type.TEST,
        '1', test_result)
    pipeline.start()
    self.execute_queued_tasks()

    try_job_data = WfTryJobData.Get(try_job_id)
    analysis = WfAnalysis.Get(master_name, builder_name, build_number)
    expected_culprit_data = {
        'a_test': {
            'a_test1': 'rev3'
        }
    }
    self.assertEqual(expected_culprit_data, try_job_data.culprits)
    self.assertEqual(analysis.result_status,
                     result_status.FOUND_UNTRIAGED)
    self.assertEqual(analysis.suspected_cls, expected_analysis_suspected_cls)
  def testIdentifyCulpritForTestTryJobSuccess(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    test_result = {
        'report': {
            'result': {
                'rev0': {
                    'a_test': {
                        'status': 'passed',
                        'valid': True,
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    }
                },
                'rev1': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    }
                },
                'rev2': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1', 'a_test2']
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    }
                }
            },
            'culprits': {
                'a_test': {
                    'a_test1': 'rev1',
                    'a_test2': 'rev2'
                },
            },
            'flakes': {
                'b_test': ['b_test1']
            }
        },
        'url': 'url',
        'try_job_id': try_job_id
    }

    self._CreateEntities(master_name, builder_name, build_number, try_job_id,
                         try_job_status=analysis_status.RUNNING,
                         test_results=[test_result])

    analysis = WfAnalysis.Create(master_name, builder_name, build_number)
    analysis.put()

    a_test1_suspected_cl = {
        'revision': 'rev1',
        'commit_position': 1,
        'url': 'url_1',
        'repo_name': 'chromium'
    }
    a_test2_suspected_cl = {
        'revision': 'rev2',
        'commit_position': 2,
        'url': 'url_2',
        'repo_name': 'chromium'
    }

    expected_test_result = {
        'report': {
            'result': {
                'rev0': {
                    'a_test': {
                        'status': 'passed',
                        'valid': True,
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    }
                },
                'rev1': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1']
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    }
                },
                'rev2': {
                    'a_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['a_test1', 'a_test2']
                    },
                    'b_test': {
                        'status': 'failed',
                        'valid': True,
                        'failures': ['b_test1']
                    }
                }
            },
            'culprits': {
                'a_test': {
                    'a_test1': 'rev1',
                    'a_test2': 'rev2'
                },
            },
            'flakes': {
                'b_test': ['b_test1']
            }
        },
        'url': 'url',
        'try_job_id': try_job_id,
        'culprit': {
            'a_test': {
                'tests': {
                    'a_test1': a_test1_suspected_cl,
                    'a_test2': a_test2_suspected_cl
                }
            }
        }
    }

    expected_culprits = {
      'rev1': a_test1_suspected_cl,
      'rev2': a_test2_suspected_cl
    }

    self.MockPipeline(RevertAndNotifyCulpritPipeline,
                      None,
                      expected_args=[master_name, builder_name, build_number,
                                     expected_culprits, [], failure_type.TEST])
    pipeline = IdentifyTryJobCulpritPipeline(
        master_name, builder_name, build_number,
        failure_type.TEST, '1', test_result)
    pipeline.start()
    self.execute_queued_tasks()

    try_job = WfTryJob.Get(master_name, builder_name, build_number)
    self.assertEqual(expected_test_result, try_job.test_results[-1])
    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    analysis = WfAnalysis.Get(master_name, builder_name, build_number)
    expected_culprit_data = {
        'a_test': {
            'a_test1': 'rev1',
            'a_test2': 'rev2',
        }
    }

    expected_cls = [
        {
            'revision': 'rev1',
            'commit_position': 1,
            'url': 'url_1',
            'repo_name': 'chromium',
            'failures': {
                'a_test': ['a_test1'],
                'b_test': ['b_test1'],
            },
            'top_score': None
        },
        {
            'revision': 'rev2',
            'commit_position': 2,
            'url': 'url_2',
            'repo_name': 'chromium',
            'failures': {
                'a_test': ['a_test1', 'a_test2'],
                'b_test': ['b_test1'],
            },
            'top_score': None
        }
    ]
    self.assertEqual(expected_culprit_data, try_job_data.culprits)
    self.assertEqual(analysis.result_status,
                     result_status.FOUND_UNTRIAGED)
    self.assertEqual(analysis.suspected_cls, expected_cls)
  def testIdentifyCulpritForCompileTryJobSuccess(self):
    master_name = 'm'
    builder_name = 'b'
    build_number = 1
    try_job_id = '1'

    compile_result = {
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'failed'
            },
        },
    }

    try_job_data = WfTryJobData.Create(try_job_id)
    try_job_data.put()

    try_job = WfTryJob.Create(master_name, builder_name, build_number)
    try_job.status = analysis_status.RUNNING
    try_job.compile_results = [{
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'failed'
            },
        },
        'try_job_id': try_job_id,
    }]
    try_job.put()

    pipeline = IdentifyTryJobCulpritPipeline()
    culprit = pipeline.run(
        master_name, builder_name, build_number, ['rev1'],
        TryJobType.COMPILE, '1', compile_result)

    expected_culprit = 'rev2'
    expected_compile_result = {
        'report': {
            'result': {
                'rev1': 'passed',
                'rev2': 'failed'
            }
        },
        'try_job_id': try_job_id,
        'culprit': {
            'compile': {
                'revision': 'rev2',
                'commit_position': '2',
                'review_url': 'url_2'
            }
        }
    }

    self.assertEqual(expected_compile_result['culprit'], culprit)

    try_job = WfTryJob.Get(master_name, builder_name, build_number)
    self.assertEqual(expected_compile_result, try_job.compile_results[-1])
    self.assertEqual(analysis_status.COMPLETED, try_job.status)

    try_job_data = WfTryJobData.Get(try_job_id)
    self.assertEqual({'compile': expected_culprit}, try_job_data.culprits)