blob: 5a1e45a4203c9f352f99cf3395314c5d59edcede [file]
#!/usr/bin/env python3
# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Diagnose ChromeOS tast regressions.
This is integrated bisection utility. Given ChromeOS, Chrome, Android source
tree, and necessary parameters, this script can determine which components to
bisect, and hopefully output the culprit CL of regression.
Sometimes the script failed to figure out the final CL for various reasons, it
will cut down the search range as narrow as it can.
"""
import logging
from bisect_kit import cros_util
from bisect_kit import diagnoser_cros
from bisect_kit import errors
from bisect_kit import util
logger = logging.getLogger(__name__)
class DiagnoseTastCommandLine(diagnoser_cros.DiagnoseCommandLineBase):
"""Diagnose command line interface."""
def check_options(self, opts):
super().check_options(opts)
if not opts.test_name:
self.argument_parser.error('argument --test-name is required')
def init_hook(self, opts):
pass
def _build_cmds(self):
# prebuilt version will be specified later.
switch_test_harness_cmd = [
'./switch_tast_prebuilt.py',
'--rich-result',
'--chromeos-root',
self.config.get('chromeos_root'),
]
common_eval_cmd = [
'./eval_cros_tast.py',
'--rich-result',
'--chromeos-root',
self.config.get('chromeos_root'),
'--test-name',
self.config.get('test_name'),
]
if not self.config.get('is_public_build'):
common_eval_cmd.append('--with-private-bundles')
if self.config.get('metric'):
common_eval_cmd += [
'--metric',
self.config.get('metric'),
]
if self.config.get('tast_patch_cls'):
for patch_cl in self.config.get('tast_patch_cls'):
common_eval_cmd += ['--tast-patch-cl', patch_cl]
# With tast_patch_cls switch tast harness cmd is redundant
switch_test_harness_cmd = None
if self.config.get('tast_revision'):
common_eval_cmd += [
'--tast-revision',
self.config.get('tast_revision'),
]
switch_test_harness_cmd = None
if self.config.get('tast_private_revision'):
common_eval_cmd += [
'--tast-private-revision',
self.config.get('tast_private_revision'),
]
switch_test_harness_cmd = None
if self.config.get('tast_runtime_revision'):
common_eval_cmd += [
'--tast-runtime-revision',
self.config.get('tast_runtime_revision'),
]
switch_test_harness_cmd = None
if self.config.get('fail_to_pass'):
common_eval_cmd.append('--fail-to-pass')
if self.config.get('reboot_before_test'):
common_eval_cmd.append('--reboot-before-test')
for var in self.config.get('extra_test_variables'):
common_eval_cmd.append('--args')
common_eval_cmd.append(var)
if self.config.get('consider_test_crash_as_failure'):
common_eval_cmd.append('--consider-test-crash-as-failure')
return switch_test_harness_cmd, common_eval_cmd
def do_run(self):
diagnoser = diagnoser_cros.CrosDiagnoser(self.states, self.config)
switch_test_harness_cmd, common_eval_cmd = self._build_cmds()
cros_prebuilt_eval_cmd = common_eval_cmd[:]
android_prebuilt_eval_cmd = common_eval_cmd
if self.config.get('chrome_deploy_image'):
chrome_localbuild_eval_cmd = common_eval_cmd + ['--tast-build']
else:
chrome_localbuild_eval_cmd = common_eval_cmd + ['--prebuilt']
cros_buildbucket_build = cros_util.is_buildbucket_buildable(
self.config.get('cros_prebuilt_old')
) and not self.config.get('disable_buildbucket_chromeos')
if not cros_buildbucket_build:
cros_localbuild_eval_cmd = common_eval_cmd + ['--tast-build']
else:
cros_localbuild_eval_cmd = common_eval_cmd + ['--prebuilt']
diagnoser.diagnose(
is_autotest=False,
switch_test_harness_cmd=switch_test_harness_cmd,
cros_prebuilt_eval_cmd=cros_prebuilt_eval_cmd,
android_prebuilt_eval_cmd=android_prebuilt_eval_cmd,
chrome_localbuild_eval_cmd=chrome_localbuild_eval_cmd,
should_build_chrome_localbuild_with_tests=True,
cros_localbuild_eval_cmd=cros_localbuild_eval_cmd,
)
@util.MethodTimer(
diagnoser_cros.DiagnoseCommandLineBase.write_total_execution_time
)
def cmd_run(self, opts):
del opts # unused
self.states.load_states()
try:
logger.info('experiments: %s', self.config.get('experiments'))
self.do_run()
logger.info('%s done', __file__)
except Exception as e:
logger.exception('got exception; stop')
exception_name = e.__class__.__name__
self.states.add_history(
'failed',
text='%s: %s' % (exception_name, e),
exception=exception_name,
error_type=errors.error_type(e),
)
if __name__ == '__main__':
DiagnoseTastCommandLine().main()