Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python2 |
| 2 | # -*- coding: utf-8 -*- |
| 3 | # Copyright 2019 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | """Diagnose ChromeOS tast regressions. |
| 7 | |
| 8 | This is integrated bisection utility. Given ChromeOS, Chrome, Android source |
| 9 | tree, and necessary parameters, this script can determine which components to |
| 10 | bisect, and hopefully output the culprit CL of regression. |
| 11 | |
| 12 | Sometimes the script failed to figure out the final CL for various reasons, it |
| 13 | will cut down the search range as narrow as it can. |
| 14 | """ |
| 15 | from __future__ import print_function |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 16 | import logging |
Kuang-che Wu | 568c84d | 2019-11-06 17:23:53 +0800 | [diff] [blame] | 17 | import os |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 18 | |
| 19 | from bisect_kit import cros_lab_util |
| 20 | from bisect_kit import cros_util |
Kuang-che Wu | 568c84d | 2019-11-06 17:23:53 +0800 | [diff] [blame] | 21 | from bisect_kit import cr_util |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 22 | from bisect_kit import diagnoser_cros |
| 23 | from bisect_kit import errors |
| 24 | import setup_cros_bisect |
| 25 | |
| 26 | logger = logging.getLogger(__name__) |
| 27 | |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 28 | |
| 29 | class DiagnoseTastCommandLine(diagnoser_cros.DiagnoseCommandLineBase): |
| 30 | """Diagnose command line interface.""" |
| 31 | |
| 32 | def check_options(self, opts, path_factory): |
| 33 | super(DiagnoseTastCommandLine, self).check_options(opts, path_factory) |
| 34 | if not opts.test_name: |
| 35 | self.argument_parser.error('argument --test_name is required') |
| 36 | |
| 37 | def init_hook(self, opts): |
| 38 | pass |
| 39 | |
| 40 | def _build_cmds(self): |
| 41 | common_eval_cmd = [ |
| 42 | './eval_cros_tast.py', |
Kuang-che Wu | 4fc0f1c | 2019-08-02 21:56:49 +0800 | [diff] [blame] | 43 | '--with_private_bundles', |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 44 | '--chromeos_root', self.config['chromeos_root'], |
| 45 | '--test_name', self.config['test_name'], |
| 46 | ] # yapf: disable |
| 47 | if self.config['metric']: |
| 48 | common_eval_cmd += [ |
| 49 | '--metric', self.config['metric'], |
| 50 | ] # yapf: disable |
| 51 | if self.config['fail_to_pass']: |
| 52 | common_eval_cmd.append('--fail_to_pass') |
| 53 | if self.config['reboot_before_test']: |
| 54 | common_eval_cmd.append('--reboot_before_test') |
| 55 | |
| 56 | return common_eval_cmd |
| 57 | |
| 58 | def cmd_run(self, opts): |
| 59 | del opts # unused |
| 60 | |
| 61 | self.states.load() |
| 62 | |
| 63 | try: |
| 64 | path_factory = setup_cros_bisect.DefaultProjectPathFactory( |
| 65 | self.config['mirror_base'], self.config['work_base'], |
| 66 | self.config['session']) |
| 67 | common_eval_cmd = self._build_cmds() |
| 68 | |
Kuang-che Wu | 568c84d | 2019-11-06 17:23:53 +0800 | [diff] [blame] | 69 | chrome_src = os.path.join(self.config['chrome_root'], 'src') |
| 70 | chrome_binaries = ( |
| 71 | cr_util.CHROME_BINARIES + cr_util.get_chrome_test_binaries( |
| 72 | chrome_src, self.config['board'])) |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 73 | |
Kuang-che Wu | 0c9b794 | 2019-10-30 16:55:39 +0800 | [diff] [blame] | 74 | with cros_lab_util.dut_manager( |
| 75 | self.config['dut'], |
| 76 | lambda: diagnoser_cros.grab_dut(self.config)) as dut: |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 77 | if not dut: |
| 78 | raise errors.NoDutAvailable('unable to allocate DUT') |
Kuang-che Wu | 7cb08df | 2019-06-04 19:12:29 +0800 | [diff] [blame] | 79 | if not cros_util.is_good_dut(dut): |
| 80 | if not cros_lab_util.repair(dut): |
| 81 | raise errors.ExternalError('Not a good DUT and unable to repair') |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 82 | assert cros_util.is_dut(dut) |
| 83 | if self.config['dut'] == cros_lab_util.LAB_DUT: |
| 84 | self.config['allocated_dut'] = dut |
| 85 | self.states.save() |
| 86 | common_eval_cmd.append(dut) |
| 87 | |
| 88 | diagnoser = diagnoser_cros.CrosDiagnoser(self.states, path_factory, |
| 89 | self.config, dut) |
| 90 | |
| 91 | diagnoser.narrow_down_chromeos_prebuilt( |
| 92 | self.config['old'], self.config['new'], common_eval_cmd) |
| 93 | |
| 94 | diagnoser.switch_chromeos_to_old(force=self.config['always_reflash']) |
Kuang-che Wu | c8c495d | 2019-08-19 17:48:58 +0800 | [diff] [blame] | 95 | dut_os_version = cros_util.query_dut_short_version(dut) |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 96 | |
| 97 | try: |
| 98 | if diagnoser.narrow_down_android(common_eval_cmd): |
| 99 | return |
| 100 | except errors.DiagnoseContradiction: |
| 101 | raise |
| 102 | except Exception: |
| 103 | logger.exception('exception in android bisector before verification; ' |
| 104 | 'assume culprit is not inside android and continue') |
| 105 | # Assume it's ok to leave random version of android prebuilt on DUT. |
| 106 | |
Kuang-che Wu | c8c495d | 2019-08-19 17:48:58 +0800 | [diff] [blame] | 107 | # Sanity check. The OS version should not change after android bisect. |
Kuang-che Wu | 523bdf2 | 2019-08-20 12:11:09 +0800 | [diff] [blame] | 108 | assert dut_os_version == cros_util.query_dut_short_version(dut), \ |
| 109 | 'Someone else reflashed the DUT. ' \ |
| 110 | 'DUT locking is not respected? b/126141102' |
Kuang-che Wu | c8c495d | 2019-08-19 17:48:58 +0800 | [diff] [blame] | 111 | |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 112 | try: |
Kuang-che Wu | de5bfc3 | 2019-09-12 21:56:48 +0800 | [diff] [blame] | 113 | if self.config['chrome_deploy_image']: |
| 114 | eval_cmd = common_eval_cmd + ['--tast_build'] |
| 115 | else: |
| 116 | eval_cmd = common_eval_cmd |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 117 | if diagnoser.narrow_down_chrome( |
Kuang-che Wu | de5bfc3 | 2019-09-12 21:56:48 +0800 | [diff] [blame] | 118 | eval_cmd, chrome_binaries=chrome_binaries): |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 119 | return |
| 120 | except errors.DiagnoseContradiction: |
| 121 | raise |
| 122 | except Exception: |
| 123 | logger.exception('exception in chrome bisector before verification; ' |
| 124 | 'assume culprit is not inside chrome and continue') |
| 125 | |
Kuang-che Wu | de5bfc3 | 2019-09-12 21:56:48 +0800 | [diff] [blame] | 126 | if not self.config['chrome_deploy_image']: |
| 127 | # Sanity check. The OS version should not change after chrome bisect. |
| 128 | assert dut_os_version == cros_util.query_dut_short_version(dut), \ |
| 129 | 'Someone else reflashed the DUT. ' \ |
| 130 | 'DUT locking is not respected? b/126141102' |
Kuang-che Wu | c8c495d | 2019-08-19 17:48:58 +0800 | [diff] [blame] | 131 | |
Kuang-che Wu | 32f2724 | 2019-05-16 17:34:50 +0800 | [diff] [blame] | 132 | eval_cmd = common_eval_cmd + ['--tast_build'] |
| 133 | diagnoser.narrow_down_chromeos_localbuild(eval_cmd) |
| 134 | logger.info('%s done', __file__) |
| 135 | except Exception as e: |
| 136 | logger.exception('got exception; stop') |
| 137 | exception_name = e.__class__.__name__ |
| 138 | self.states.add_history( |
| 139 | 'failed', '%s: %s' % (exception_name, e), exception=exception_name) |
| 140 | |
| 141 | |
| 142 | if __name__ == '__main__': |
| 143 | DiagnoseTastCommandLine().main() |