blob: c458a8b41853e2dc2373d79bb0d022b483f103f2 [file] [log] [blame]
Kuang-che Wu875c89a2020-01-08 14:30:55 +08001#!/usr/bin/env python3
Kuang-che Wu32f27242019-05-16 17:34:50 +08002# -*- 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
8This is integrated bisection utility. Given ChromeOS, Chrome, Android source
9tree, and necessary parameters, this script can determine which components to
10bisect, and hopefully output the culprit CL of regression.
11
12Sometimes the script failed to figure out the final CL for various reasons, it
13will cut down the search range as narrow as it can.
14"""
15from __future__ import print_function
Kuang-che Wu32f27242019-05-16 17:34:50 +080016import logging
17
18from bisect_kit import cros_lab_util
19from bisect_kit import cros_util
20from bisect_kit import diagnoser_cros
21from bisect_kit import errors
22import setup_cros_bisect
23
24logger = logging.getLogger(__name__)
25
Kuang-che Wu32f27242019-05-16 17:34:50 +080026
27class DiagnoseTastCommandLine(diagnoser_cros.DiagnoseCommandLineBase):
28 """Diagnose command line interface."""
29
30 def check_options(self, opts, path_factory):
31 super(DiagnoseTastCommandLine, self).check_options(opts, path_factory)
32 if not opts.test_name:
33 self.argument_parser.error('argument --test_name is required')
34
35 def init_hook(self, opts):
36 pass
37
38 def _build_cmds(self):
Kuang-che Wu5963ebf2020-10-21 09:01:04 +080039 # prebuilt version will be specified later.
40 common_switch_cmd = [
41 './switch_tast_prebuilt.py',
42 '--chromeos_root',
43 self.config['chromeos_root'],
44 '--board',
45 self.config['board'],
46 ]
Kuang-che Wu32f27242019-05-16 17:34:50 +080047 common_eval_cmd = [
48 './eval_cros_tast.py',
Kuang-che Wu4fc0f1c2019-08-02 21:56:49 +080049 '--with_private_bundles',
Kuang-che Wu32f27242019-05-16 17:34:50 +080050 '--chromeos_root', self.config['chromeos_root'],
51 '--test_name', self.config['test_name'],
52 ] # yapf: disable
53 if self.config['metric']:
54 common_eval_cmd += [
55 '--metric', self.config['metric'],
56 ] # yapf: disable
57 if self.config['fail_to_pass']:
58 common_eval_cmd.append('--fail_to_pass')
59 if self.config['reboot_before_test']:
60 common_eval_cmd.append('--reboot_before_test')
61
Kuang-che Wu5963ebf2020-10-21 09:01:04 +080062 return common_switch_cmd, common_eval_cmd
Kuang-che Wu32f27242019-05-16 17:34:50 +080063
64 def cmd_run(self, opts):
65 del opts # unused
66
67 self.states.load()
68
69 try:
70 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
71 self.config['mirror_base'], self.config['work_base'],
72 self.config['session'])
Kuang-che Wu5963ebf2020-10-21 09:01:04 +080073 common_switch_cmd, common_eval_cmd = self._build_cmds()
Kuang-che Wu32f27242019-05-16 17:34:50 +080074
Kuang-che Wu0c9b7942019-10-30 16:55:39 +080075 with cros_lab_util.dut_manager(
Kuang-che Wud1b74152020-05-20 08:46:46 +080076 self.config['dut'], lambda: diagnoser_cros.grab_dut(self.config)
77 ) as dut:
Kuang-che Wu32f27242019-05-16 17:34:50 +080078 if not dut:
79 raise errors.NoDutAvailable('unable to allocate DUT')
Kuang-che Wu7cb08df2019-06-04 19:12:29 +080080 if not cros_util.is_good_dut(dut):
81 if not cros_lab_util.repair(dut):
82 raise errors.ExternalError('Not a good DUT and unable to repair')
Kuang-che Wu32f27242019-05-16 17:34:50 +080083 assert cros_util.is_dut(dut)
84 if self.config['dut'] == cros_lab_util.LAB_DUT:
85 self.config['allocated_dut'] = dut
86 self.states.save()
87 common_eval_cmd.append(dut)
88
89 diagnoser = diagnoser_cros.CrosDiagnoser(self.states, path_factory,
90 self.config, dut)
91
Kuang-che Wu5963ebf2020-10-21 09:01:04 +080092 eval_cmd = common_eval_cmd + ['--prebuilt']
93 extra_switch_cmd = common_switch_cmd
94 diagnoser.narrow_down_chromeos_prebuilt(
95 self.config['old'],
96 self.config['new'],
97 eval_cmd,
98 extra_switch_cmd=extra_switch_cmd)
Kuang-che Wu32f27242019-05-16 17:34:50 +080099
100 diagnoser.switch_chromeos_to_old(force=self.config['always_reflash'])
Kuang-che Wu5963ebf2020-10-21 09:01:04 +0800101 util.check_call(*(common_switch_cmd + [diagnoser.cros_old]))
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800102 dut_os_version = cros_util.query_dut_short_version(dut)
Kuang-che Wu32f27242019-05-16 17:34:50 +0800103
104 try:
105 if diagnoser.narrow_down_android(common_eval_cmd):
106 return
107 except errors.DiagnoseContradiction:
108 raise
109 except Exception:
Kuang-che Wuc93d0f92020-05-20 20:55:23 +0800110 diagnoser.make_decision(
Kuang-che Wue4435b42020-05-21 20:06:24 +0800111 'Exception in Android bisector before verification; '
112 'assume the culprit is not inside Android and continue')
Kuang-che Wu32f27242019-05-16 17:34:50 +0800113 # Assume it's ok to leave random version of android prebuilt on DUT.
114
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800115 # Sanity check. The OS version should not change after android bisect.
Kuang-che Wu523bdf22019-08-20 12:11:09 +0800116 assert dut_os_version == cros_util.query_dut_short_version(dut), \
117 'Someone else reflashed the DUT. ' \
118 'DUT locking is not respected? b/126141102'
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800119
Kuang-che Wu32f27242019-05-16 17:34:50 +0800120 try:
Zheng-Jie Chang7a076a52020-05-31 13:03:37 +0800121 buildbucket_build = (
122 cros_util.is_buildbucket_buildable(self.config['old']) and
123 self.config['enable_buildbucket_chrome'])
Kuang-che Wude5bfc32019-09-12 21:56:48 +0800124 if self.config['chrome_deploy_image']:
125 eval_cmd = common_eval_cmd + ['--tast_build']
126 else:
Kuang-che Wu5963ebf2020-10-21 09:01:04 +0800127 eval_cmd = common_eval_cmd + ['--prebuilt']
Zheng-Jie Chang7a076a52020-05-31 13:03:37 +0800128 if diagnoser.narrow_down_chrome(
129 eval_cmd, buildbucket_build=buildbucket_build):
Kuang-che Wu32f27242019-05-16 17:34:50 +0800130 return
131 except errors.DiagnoseContradiction:
132 raise
133 except Exception:
Kuang-che Wuc93d0f92020-05-20 20:55:23 +0800134 diagnoser.make_decision(
Kuang-che Wue4435b42020-05-21 20:06:24 +0800135 'Exception in Chrome bisector before verification; '
136 'assume the culprit is not inside Chrome and continue')
Kuang-che Wu32f27242019-05-16 17:34:50 +0800137
Zheng-Jie Chang7a076a52020-05-31 13:03:37 +0800138 if not self.config['chrome_deploy_image'] and not buildbucket_build:
Kuang-che Wude5bfc32019-09-12 21:56:48 +0800139 # Sanity check. The OS version should not change after chrome bisect.
140 assert dut_os_version == cros_util.query_dut_short_version(dut), \
141 'Someone else reflashed the DUT. ' \
142 'DUT locking is not respected? b/126141102'
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800143
Zheng-Jie Chang61a645a2020-04-29 10:12:13 +0800144 buildbucket_build = (
145 cros_util.is_buildbucket_buildable(self.config['old']) and
146 not self.config['disable_buildbucket_chromeos'])
147
148 if not buildbucket_build:
Zheng-Jie Chang181be6f2020-03-17 16:16:08 +0800149 eval_cmd = common_eval_cmd + ['--tast_build']
Kuang-che Wu5963ebf2020-10-21 09:01:04 +0800150 extra_switch_cmd = None
Zheng-Jie Changd3fd8f12020-04-14 11:41:06 +0800151 else:
Kuang-che Wu5963ebf2020-10-21 09:01:04 +0800152 eval_cmd = common_eval_cmd + ['--prebuilt']
153 extra_switch_cmd = common_switch_cmd
Zheng-Jie Chang61a645a2020-04-29 10:12:13 +0800154 diagnoser.narrow_down_chromeos_localbuild(eval_cmd, buildbucket_build)
Kuang-che Wu32f27242019-05-16 17:34:50 +0800155 logger.info('%s done', __file__)
156 except Exception as e:
157 logger.exception('got exception; stop')
158 exception_name = e.__class__.__name__
159 self.states.add_history(
Kuang-che Wu0c2cb922020-06-16 23:34:53 +0800160 'failed',
161 text='%s: %s' % (exception_name, e),
162 exception=exception_name)
Kuang-che Wu32f27242019-05-16 17:34:50 +0800163
164
165if __name__ == '__main__':
166 DiagnoseTastCommandLine().main()