예제 #1
0
    def testExtractSignal(self):
        class DummyGeneralExtractor(Extractor):
            def Extract(self, *_):
                return '0'

        class DummyExtractor1(Extractor):
            def Extract(self, *_):
                return '1'

        class DummyExtractor2(Extractor):
            def Extract(self, *_):
                return '2'

        DUMMY_EXTRACTORS = {'1': DummyExtractor1, '2': DummyExtractor2}

        self.mock(extractors, 'GeneralExtractor', DummyGeneralExtractor)
        self.mock(extractors, 'EXTRACTORS', DUMMY_EXTRACTORS)

        cases = {
            # step_name: result
            '1': '1',
            '2': '2',
            '32434': '0'
        }

        for step_name, expected_result in cases.iteritems():
            result = extractors.ExtractSignal('master', 'bot', step_name,
                                              'test', '')
            self.assertEqual(expected_result, result)
예제 #2
0
def ExtractSignalsForCompileFailure(failure_info, http_client):
    signals = {}

    master_name = failure_info.master_name
    builder_name = failure_info.builder_name
    build_number = failure_info.build_number
    step_name = 'compile'

    if step_name not in (failure_info.failed_steps or {}):
        logging.debug(
            'No compile failure found when extracting signals for failed '
            'build %s/%s/%d', master_name, builder_name, build_number)
        return signals

    if not failure_info.failed_steps[step_name].supported:
        # Bail out if the step is not supported.
        logging.info('Findit could not analyze compile failure for master %s.',
                     master_name)
        return signals

    failure_log = None

    # 1. Tries to get stored failure log from step.
    step = (WfStep.Get(master_name, builder_name, build_number, step_name) or
            WfStep.Create(master_name, builder_name, build_number, step_name))
    if step.log_data:
        failure_log = step.log_data
    else:
        # 2. Tries to get ninja_output as failure log.
        from_ninja_output = False
        use_ninja_output_log = (waterfall_config.GetDownloadBuildDataSettings(
        ).get('use_ninja_output_log'))
        if use_ninja_output_log:
            failure_log = step_util.GetWaterfallBuildStepLog(
                master_name, builder_name, build_number, step_name,
                http_client, 'json.output[ninja_info]')
            from_ninja_output = True

        if not failure_log:
            # 3. Tries to get stdout log for compile step.
            from_ninja_output = False
            failure_log = extract_signal.GetStdoutLog(master_name,
                                                      builder_name,
                                                      build_number, step_name,
                                                      http_client)

        try:
            if not failure_log:
                raise extract_signal.FailedToGetFailureLogError(
                    'Failed to pull failure log (stdio or ninja output) of step %s of'
                    ' %s/%s/%d' %
                    (step_name, master_name, builder_name, build_number))
        except extract_signal.FailedToGetFailureLogError:
            return {}

        # Save step log in datastore and avoid downloading again during retry.
        step.log_data = extract_signal.ExtractStorablePortionOfLog(
            failure_log, from_ninja_output)
        try:
            step.put()
        except Exception as e:  # pragma: no cover
            # Sometimes, the step log is too large to save in datastore.
            logging.exception(e)

    signals[step_name] = extractors.ExtractSignal(
        master_name,
        builder_name,
        step_name,
        test_name=None,
        failure_log=failure_log).ToDict()

    extract_signal.SaveSignalInAnalysis(master_name, builder_name,
                                        build_number, signals)

    return signals
    def run(self, failure_info):
        """Extracts failure signals from failed steps.

    Args:
      failure_info (dict): Output of pipeline DetectFirstFailurePipeline.run().

    Returns:
      A dict like below:
      {
        'step_name1': waterfall.failure_signal.FailureSignal.ToDict(),
        ...
      }
    """
        signals = {}
        if not failure_info['failed'] or not failure_info['chromium_revision']:
            # Bail out if no failed step or no chromium revision.
            return signals

        # Bail out on infra failure
        if failure_info.get('failure_type') == failure_type.INFRA:
            return signals

        master_name = failure_info['master_name']
        builder_name = failure_info['builder_name']
        build_number = failure_info['build_number']

        for step_name in failure_info.get('failed_steps', []):
            if not waterfall_config.StepIsSupportedForMaster(
                    step_name, master_name):
                # Bail out if the step is not supported.
                continue

            step = WfStep.Get(master_name, builder_name, build_number,
                              step_name)
            if step and step.log_data:
                failure_log = step.log_data
            else:
                # TODO: do test-level analysis instead of step-level.
                # TODO: Use swarming test result instead of archived gtest results
                gtest_result = buildbot.GetGtestResultLog(
                    master_name, builder_name, build_number, step_name)
                if gtest_result:
                    failure_log = _GetReliableTestFailureLog(gtest_result)

                if gtest_result is None or failure_log == 'invalid':
                    if not lock_util.WaitUntilDownloadAllowed(
                            master_name):  # pragma: no cover
                        raise pipeline.Retry(
                            'Failed to pull log of step %s of master %s' %
                            (step_name, master_name))
                    try:
                        failure_log = buildbot.GetStepLog(
                            master_name, builder_name, build_number, step_name,
                            self.HTTP_CLIENT)
                    except ResponseTooLargeError:  # pragma: no cover.
                        logging.exception(
                            'Log of step "%s" is too large for urlfetch.',
                            step_name)
                        # If the stdio log of a step is too large, we don't want to pull it
                        # again in next run, because that might lead to DDoS to the master.
                        # TODO: Use archived stdio logs in Google Storage instead.
                        failure_log = 'Stdio log is too large for urlfetch.'

                    if not failure_log:  # pragma: no cover
                        raise pipeline.Retry(
                            'Failed to pull stdio of step %s of master %s' %
                            (step_name, master_name))

                # Save step log in datastore and avoid downloading again during retry.
                if not step:  # pragma: no cover
                    step = WfStep.Create(master_name, builder_name,
                                         build_number, step_name)

                step.log_data = _ExtractStorablePortionOfLog(failure_log)

                try:
                    step.put()
                except Exception as e:  # pragma: no cover
                    # Sometimes, the step log is too large to save in datastore.
                    logging.exception(e)

            # TODO: save result in datastore?
            if step.isolated:
                try:
                    json_failure_log = (json.loads(failure_log)
                                        if failure_log != 'flaky' else {})
                except ValueError:  # pragma: no cover
                    json_failure_log = {}
                    logging.warning('failure_log %s is not valid JSON.' %
                                    failure_log)

                signals[step_name] = {'tests': {}}
                step_signal = FailureSignal()

                for test_name, test_failure_log in json_failure_log.iteritems(
                ):
                    signals[step_name]['tests'][
                        test_name] = extractors.ExtractSignal(
                            master_name, builder_name, step_name, test_name,
                            base64.b64decode(test_failure_log)).ToDict()

                    # Save signals in test failure log to step level.
                    step_signal.MergeFrom(
                        signals[step_name]['tests'][test_name])

                signals[step_name]['files'] = step_signal.files
                signals[step_name]['keywords'] = step_signal.keywords
            else:
                signals[step_name] = extractors.ExtractSignal(
                    master_name, builder_name, step_name, None,
                    failure_log).ToDict()

        return signals
예제 #4
0
    def run(self, failure_info):
        """
    Args:
      failure_info (dict): Output of pipeline DetectFirstFailurePipeline.run().

    Returns:
      A dict like below:
      {
        'step_name1': waterfall.failure_signal.FailureSignal.ToDict(),
        ...
      }
    """
        signals = {}
        if not failure_info['failed'] or not failure_info['chromium_revision']:
            # Bail out if no failed step or no chromium revision.
            return signals

        master_name = failure_info['master_name']
        builder_name = failure_info['builder_name']
        build_number = failure_info['build_number']
        for step_name in failure_info.get('failed_steps', []):
            step = WfStep.Get(master_name, builder_name, build_number,
                              step_name)
            if step and step.log_data:
                failure_log = step.log_data
            else:
                # TODO: do test-level analysis instead of step-level.
                gtest_result = buildbot.GetGtestResultLog(
                    master_name, builder_name, build_number, step_name)
                if gtest_result:
                    failure_log = self._GetReliableTestFailureLog(gtest_result)

                if gtest_result is None or failure_log == 'invalid':
                    if not lock_util.WaitUntilDownloadAllowed(
                            master_name):  # pragma: no cover
                        raise pipeline.Retry(
                            'Failed to pull log of step %s of master %s' %
                            (step_name, master_name))
                    try:
                        failure_log = buildbot.GetStepStdio(
                            master_name, builder_name, build_number, step_name,
                            self.HTTP_CLIENT)
                    except ResponseTooLargeError:  # pragma: no cover.
                        logging.exception(
                            'Log of step "%s" is too large for urlfetch.',
                            step_name)
                        # If the stdio log of a step is too large, we don't want to pull it
                        # again in next run, because that might lead to DDoS to the master.
                        # TODO: Use archived stdio logs in Google Storage instead.
                        failure_log = 'Stdio log is too large for urlfetch.'

                    if not failure_log:  # pragma: no cover
                        raise pipeline.Retry(
                            'Failed to pull stdio of step %s of master %s' %
                            (step_name, master_name))

                # Save step log in datastore and avoid downloading again during retry.
                if not step:  # pragma: no cover
                    step = WfStep.Create(master_name, builder_name,
                                         build_number, step_name)

                step.log_data = self._ExtractStorablePortionOfLog(failure_log)

                try:
                    step.put()
                except Exception as e:  # pragma: no cover
                    # Sometimes, the step log is too large to save in datastore.
                    logging.exception(e)

            # TODO: save result in datastore?
            signals[step_name] = extractors.ExtractSignal(
                master_name, builder_name, step_name, None,
                failure_log).ToDict()
        return signals
예제 #5
0
def ExtractSignalsForTestFailure(failure_info, http_client):
    signals = {}

    master_name = failure_info.master_name
    builder_name = failure_info.builder_name
    build_number = failure_info.build_number
    failed_steps = failure_info.failed_steps or {}

    for step_name in failed_steps:
        failure_log = None
        if not failed_steps[step_name].supported:
            # Bail out if the step is not supported.
            continue

        # 1. Tries to get stored failure log from step.
        step = (WfStep.Get(master_name, builder_name, build_number, step_name)
                or WfStep.Create(master_name, builder_name, build_number,
                                 step_name))
        if step.log_data and step.log_data != constants.TOO_LARGE_LOG:
            failure_log = step.log_data
        else:
            json_formatted_log = True
            # 2. Gets test results.
            list_isolated_data = failed_steps[step_name].list_isolated_data
            list_isolated_data = (list_isolated_data.ToSerializable()
                                  if list_isolated_data else [])
            merged_test_results = (
                swarmed_test_util.RetrieveShardedTestResultsFromIsolatedServer(
                    list_isolated_data, http_client))
            if merged_test_results:
                test_results = test_results_util.GetTestResultObject(
                    merged_test_results)
                if test_results:
                    failure_log, _ = (
                        test_results_service.
                        GetFailedTestsInformationFromTestResult(test_results))
                    failure_log = json.dumps(
                        failure_log
                    ) if failure_log else constants.FLAKY_FAILURE_LOG
                else:
                    failure_log = constants.WRONG_FORMAT_LOG

            if not merged_test_results or failure_log in [
                    constants.INVALID_FAILURE_LOG, constants.WRONG_FORMAT_LOG
            ]:
                # 3. Gets stdout log.
                json_formatted_log = False
                failure_log = extract_signal.GetStdoutLog(
                    master_name, builder_name, build_number, step_name,
                    http_client)

            try:
                if not failure_log:
                    raise extract_signal.FailedToGetFailureLogError(
                        'Failed to pull failure log (stdio or ninja output) of step %s of'
                        ' %s/%s/%d' %
                        (step_name, master_name, builder_name, build_number))
            except extract_signal.FailedToGetFailureLogError:
                return {}

            # Save step log in datastore and avoid downloading again during retry.
            step.log_data = extract_signal.ExtractStorablePortionOfLog(
                failure_log, json_formatted_log
            ) if step.log_data != constants.TOO_LARGE_LOG else step.log_data
            step.isolated = step.isolated or json_formatted_log

            try:
                step.put()
            except Exception as e:  # pragma: no cover
                # Sometimes, the step log is too large to save in datastore.
                logging.exception(e)

        if step.isolated:
            try:
                json_failure_log = (json.loads(failure_log) if
                                    failure_log != constants.FLAKY_FAILURE_LOG
                                    else {})
            except ValueError:
                json_failure_log = {}
                logging.warning('failure_log %s is not valid JSON.' %
                                failure_log)

            signals[step_name] = {'tests': {}}
            step_signal = FailureSignal()

            for test_name, test_failure_log in json_failure_log.iteritems():
                signals[step_name]['tests'][
                    test_name] = extractors.ExtractSignal(
                        master_name, builder_name, step_name, test_name,
                        base64.b64decode(test_failure_log)).ToDict()

                # Save signals in test failure log to step level.
                step_signal.MergeFrom(signals[step_name]['tests'][test_name])

            signals[step_name]['files'] = step_signal.files
        else:
            signals[step_name] = extractors.ExtractSignal(
                master_name, builder_name, step_name, None,
                failure_log).ToDict()

    return signals