blob: e84c4dc3935e092b1e7cab62d1a500e25765e18a [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):
39 common_eval_cmd = [
40 './eval_cros_tast.py',
Kuang-che Wu4fc0f1c2019-08-02 21:56:49 +080041 '--with_private_bundles',
Kuang-che Wu32f27242019-05-16 17:34:50 +080042 '--chromeos_root', self.config['chromeos_root'],
43 '--test_name', self.config['test_name'],
44 ] # yapf: disable
45 if self.config['metric']:
46 common_eval_cmd += [
47 '--metric', self.config['metric'],
48 ] # yapf: disable
49 if self.config['fail_to_pass']:
50 common_eval_cmd.append('--fail_to_pass')
51 if self.config['reboot_before_test']:
52 common_eval_cmd.append('--reboot_before_test')
53
54 return common_eval_cmd
55
56 def cmd_run(self, opts):
57 del opts # unused
58
59 self.states.load()
60
61 try:
62 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
63 self.config['mirror_base'], self.config['work_base'],
64 self.config['session'])
65 common_eval_cmd = self._build_cmds()
66
Kuang-che Wu0c9b7942019-10-30 16:55:39 +080067 with cros_lab_util.dut_manager(
Kuang-che Wud1b74152020-05-20 08:46:46 +080068 self.config['dut'], lambda: diagnoser_cros.grab_dut(self.config)
69 ) as dut:
Kuang-che Wu32f27242019-05-16 17:34:50 +080070 if not dut:
71 raise errors.NoDutAvailable('unable to allocate DUT')
Kuang-che Wu7cb08df2019-06-04 19:12:29 +080072 if not cros_util.is_good_dut(dut):
73 if not cros_lab_util.repair(dut):
74 raise errors.ExternalError('Not a good DUT and unable to repair')
Kuang-che Wu32f27242019-05-16 17:34:50 +080075 assert cros_util.is_dut(dut)
76 if self.config['dut'] == cros_lab_util.LAB_DUT:
77 self.config['allocated_dut'] = dut
78 self.states.save()
79 common_eval_cmd.append(dut)
80
81 diagnoser = diagnoser_cros.CrosDiagnoser(self.states, path_factory,
82 self.config, dut)
83
Kuang-che Wud1b74152020-05-20 08:46:46 +080084 diagnoser.narrow_down_chromeos_prebuilt(self.config['old'],
85 self.config['new'],
86 common_eval_cmd)
Kuang-che Wu32f27242019-05-16 17:34:50 +080087
88 diagnoser.switch_chromeos_to_old(force=self.config['always_reflash'])
Kuang-che Wuc8c495d2019-08-19 17:48:58 +080089 dut_os_version = cros_util.query_dut_short_version(dut)
Kuang-che Wu32f27242019-05-16 17:34:50 +080090
91 try:
92 if diagnoser.narrow_down_android(common_eval_cmd):
93 return
94 except errors.DiagnoseContradiction:
95 raise
96 except Exception:
97 logger.exception('exception in android bisector before verification; '
98 'assume culprit is not inside android and continue')
99 # Assume it's ok to leave random version of android prebuilt on DUT.
100
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800101 # Sanity check. The OS version should not change after android bisect.
Kuang-che Wu523bdf22019-08-20 12:11:09 +0800102 assert dut_os_version == cros_util.query_dut_short_version(dut), \
103 'Someone else reflashed the DUT. ' \
104 'DUT locking is not respected? b/126141102'
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800105
Kuang-che Wu32f27242019-05-16 17:34:50 +0800106 try:
Kuang-che Wude5bfc32019-09-12 21:56:48 +0800107 if self.config['chrome_deploy_image']:
108 eval_cmd = common_eval_cmd + ['--tast_build']
109 else:
110 eval_cmd = common_eval_cmd
Kuang-che Wuda9cb702019-11-11 14:40:56 +0800111 if diagnoser.narrow_down_chrome(eval_cmd):
Kuang-che Wu32f27242019-05-16 17:34:50 +0800112 return
113 except errors.DiagnoseContradiction:
114 raise
115 except Exception:
116 logger.exception('exception in chrome bisector before verification; '
117 'assume culprit is not inside chrome and continue')
118
Kuang-che Wude5bfc32019-09-12 21:56:48 +0800119 if not self.config['chrome_deploy_image']:
120 # Sanity check. The OS version should not change after chrome bisect.
121 assert dut_os_version == cros_util.query_dut_short_version(dut), \
122 'Someone else reflashed the DUT. ' \
123 'DUT locking is not respected? b/126141102'
Kuang-che Wuc8c495d2019-08-19 17:48:58 +0800124
Zheng-Jie Chang61a645a2020-04-29 10:12:13 +0800125 buildbucket_build = (
126 cros_util.is_buildbucket_buildable(self.config['old']) and
127 not self.config['disable_buildbucket_chromeos'])
128
129 if not buildbucket_build:
Zheng-Jie Chang181be6f2020-03-17 16:16:08 +0800130 eval_cmd = common_eval_cmd + ['--tast_build']
Zheng-Jie Changd3fd8f12020-04-14 11:41:06 +0800131 else:
132 eval_cmd = common_eval_cmd
Zheng-Jie Chang61a645a2020-04-29 10:12:13 +0800133 diagnoser.narrow_down_chromeos_localbuild(eval_cmd, buildbucket_build)
Kuang-che Wu32f27242019-05-16 17:34:50 +0800134 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
142if __name__ == '__main__':
143 DiagnoseTastCommandLine().main()