blob: 1d128007011fd9340aa65b10ca27b1ffbccf8179 [file] [log] [blame]
Kuang-che Wu1fcc0222018-07-07 16:43:22 +08001#!/usr/bin/env python2
2# -*- coding: utf-8 -*-
3# Copyright 2018 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 autotest regressions.
7
8This is integrated bisection utility. Given ChromeOS, Chrome, Android source
Kuang-che Wu927231f2018-07-24 14:21:56 +08009tree, and necessary parameters, this script can determine which components to
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080010bisect, 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
16import argparse
17import fnmatch
18import glob
19import logging
20import os
21
22from bisect_kit import cli
23from bisect_kit import common
24from bisect_kit import configure
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080025from bisect_kit import cros_lab_util
26from bisect_kit import cros_util
27from bisect_kit import diagnoser_cros
Kuang-che Wue121fae2018-11-09 16:18:39 +080028from bisect_kit import errors
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080029from bisect_kit import util
Kuang-che Wud8fc9572018-10-03 21:00:41 +080030import setup_cros_bisect
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080031
32logger = logging.getLogger(__name__)
33
34# What chrome binaries to build for given autotest.
35# This dict is created manually by inspecting output of
36# 'grep -r ChromeBinaryTest autotest/files/client/site_tests'
37# If you change this dict, build_and_deploy_chrome_helper.sh may need update
38# as well.
39CHROME_BINARIES_OF_TEST = {
40 'graphics_Chrome.ozone_gl_unittests': ['ozone_gl_unittests'],
41 'security_SandboxLinuxUnittests': ['sandbox_linux_unittests'],
42 'video_HangoutHardwarePerf*': [
43 'video_decode_accelerator_unittest',
44 'video_encode_accelerator_unittest',
45 ],
46 'video_JDAPerf*': ['jpeg_decode_accelerator_unittest'],
47 'video_JEAPerf': ['jpeg_encode_accelerator_unittest'],
48 'video_JpegDecodeAccelerator': ['jpeg_decode_accelerator_unittest'],
49 'video_JpegEncodeAccelerator': ['jpeg_encode_accelerator_unittest'],
Kuang-che Wu17cdeb52019-01-30 17:58:46 +080050 'video_VDAPerf*': ['video_decode_accelerator_unittest'],
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080051 'video_VDASanity': ['video_decode_accelerator_unittest'],
Kuang-che Wu17cdeb52019-01-30 17:58:46 +080052 'video_VEAPerf*': ['video_encode_accelerator_unittest'],
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080053 'video_VideoDecodeAccelerator*': ['video_decode_accelerator_unittest'],
54 'video_VideoEncodeAccelerator*': ['video_encode_accelerator_unittest'],
55}
56
57
Kuang-che Wu22aa9d42019-01-25 10:35:33 +080058def get_test_dependency_labels(config):
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080059 # Assume "DEPENDENCIES" is identical between the period of
60 # `old` and `new` version.
Kuang-che Wua41525a2018-10-17 23:52:24 +080061 autotest_dir = os.path.join(config['chromeos_root'],
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080062 cros_util.prebuilt_autotest_dir)
Kuang-che Wua41525a2018-10-17 23:52:24 +080063 info = cros_util.get_autotest_test_info(autotest_dir, config['test_name'])
Kuang-che Wu0f1c3b02019-01-10 01:21:01 +080064 assert info, 'incorrect test name? %s' % config['test_name']
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080065
Kuang-che Wu22aa9d42019-01-25 10:35:33 +080066 extra_labels = []
67 dependencies = info.variables.get('DEPENDENCIES', '')
68 for label in dependencies.split(','):
69 label = label.strip()
70 # Skip non-machine labels
71 if not label or label in ['cleanup-reboot']:
72 continue
73 extra_labels.append(label)
74
75 return extra_labels
76
77
78def grab_dut(config):
79 reason = cros_lab_util.make_lock_reason(config['session'])
Kuang-che Wuf65c61d2018-10-19 17:48:30 +080080 if config.get('allocated_dut'):
81 host_name = cros_lab_util.dut_host_name(config['allocated_dut'])
Kuang-che Wu22aa9d42019-01-25 10:35:33 +080082 logger.info('try to lock the same host (%s) as last run', host_name)
83 candidates = cros_lab_util.list_host(host=host_name).values()
Kuang-che Wuf65c61d2018-10-19 17:48:30 +080084 else:
Kuang-che Wu22aa9d42019-01-25 10:35:33 +080085 extra_labels = get_test_dependency_labels(config)
86 candidates = cros_lab_util.seek_host(
87 pools=config.get('pools', '').split(','),
Kuang-che Wuf65c61d2018-10-19 17:48:30 +080088 model=config['model'],
89 sku=config['sku'],
90 extra_labels=extra_labels)
91
Kuang-che Wu22aa9d42019-01-25 10:35:33 +080092 if (not candidates or candidates[0]['Status'] != 'Ready' or
93 candidates[0]['Locked']):
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080094 logger.error('unable to allocate dut')
95 return None
96
Kuang-che Wu22aa9d42019-01-25 10:35:33 +080097 host_name = candidates[0]['Host']
98 info = cros_lab_util.lock_host(host_name, reason)
99 if info['Status'] != 'Ready':
100 cros_lab_util.unlock_host(host_name)
101 raise Exception(
102 'unexpected host status=%s, a race condition?' % info['Status'])
103
104 logger.info('allocated host %s', host_name)
105 return host_name
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800106
107
108def may_depend_on_extra_chrome_binaries(autotest_dir, test_name):
109 info = cros_util.get_autotest_test_info(autotest_dir, test_name)
Kuang-che Wu0f1c3b02019-01-10 01:21:01 +0800110 assert info, 'incorrect test name? %s' % test_name
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800111 dirpath = os.path.dirname(info.path)
112 for pypath in glob.glob(os.path.join(dirpath, '*.py')):
113 if 'ChromeBinaryTest' in open(pypath).read():
114 return True
115 return False
116
117
Kuang-che Wua41525a2018-10-17 23:52:24 +0800118def determine_chrome_binaries(chromeos_root, test_name):
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800119 chrome_binaries = None
120 for name_pattern, binaries in CHROME_BINARIES_OF_TEST.items():
Kuang-che Wua41525a2018-10-17 23:52:24 +0800121 if fnmatch.fnmatch(test_name, name_pattern):
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800122 chrome_binaries = binaries
123 break
124
Kuang-che Wua41525a2018-10-17 23:52:24 +0800125 autotest_dir = os.path.join(chromeos_root, cros_util.prebuilt_autotest_dir)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800126 if chrome_binaries:
127 logger.info('This test depends on chrome binary: %s', chrome_binaries)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800128 elif may_depend_on_extra_chrome_binaries(autotest_dir, test_name):
Kuang-che Wuaf7b06b2019-01-30 18:50:05 +0800129 raise errors.InternalError(
Kuang-che Wu74768d32018-09-07 12:03:24 +0800130 '%s code used ChromeBinaryTest but the binary is unknown; '
Kuang-che Wuaf7b06b2019-01-30 18:50:05 +0800131 'please update CHROME_BINARIES_OF_TEST table' % test_name)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800132 return chrome_binaries
133
134
Kuang-che Wua41525a2018-10-17 23:52:24 +0800135class DiagnoseCommandLine(object):
136 """Diagnose command line interface."""
Kuang-che Wud8fc9572018-10-03 21:00:41 +0800137
Kuang-che Wua41525a2018-10-17 23:52:24 +0800138 def __init__(self):
139 common.init()
140 self.argument_parser = self.create_argument_parser()
141 self.states = None
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800142
Kuang-che Wua41525a2018-10-17 23:52:24 +0800143 @property
144 def config(self):
145 return self.states.config
146
147 def check_options(self, opts, path_factory):
148 if not opts.chromeos_mirror:
149 opts.chromeos_mirror = path_factory.get_chromeos_mirror()
150 logger.info('chromeos_mirror = %s', opts.chromeos_mirror)
151 if not opts.chromeos_root:
152 opts.chromeos_root = path_factory.get_chromeos_tree()
153 logger.info('chromeos_root = %s', opts.chromeos_root)
154 if not opts.chrome_mirror:
155 opts.chrome_mirror = path_factory.get_chrome_cache()
156 logger.info('chrome_mirror = %s', opts.chrome_mirror)
157 if not opts.chrome_root:
158 opts.chrome_root = path_factory.get_chrome_tree()
159 logger.info('chrome_root = %s', opts.chrome_root)
160
Kuang-che Wu248c5182018-10-19 17:08:11 +0800161 if opts.dut == cros_lab_util.LAB_DUT:
162 if not opts.model and not opts.sku:
163 self.argument_parser.error(
164 'either --model or --sku need to be specified if DUT is "%s"' %
165 cros_lab_util.LAB_DUT)
166 # Board name cannot be deduced from auto allocated devices because they
167 # may be provisioned with image of unexpected board.
168 if not opts.board:
Kuang-che Wua41525a2018-10-17 23:52:24 +0800169 self.argument_parser.error('--board need to be specified if DUT is "%s"'
170 % cros_lab_util.LAB_DUT)
Kuang-che Wu248c5182018-10-19 17:08:11 +0800171 else:
172 if not opts.board:
Kuang-che Wua41525a2018-10-17 23:52:24 +0800173 opts.board = cros_util.query_dut_board(opts.dut)
174
175 if cros_util.is_cros_short_version(opts.old):
176 opts.old = cros_util.version_to_full(opts.board, opts.old)
177 if cros_util.is_cros_short_version(opts.new):
178 opts.new = cros_util.version_to_full(opts.board, opts.new)
179
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800180 is_cts = (
181 opts.cts_revision or opts.cts_abi or opts.cts_prefix or
182 opts.cts_module or opts.cts_test or opts.cts_timeout)
183 if is_cts:
184 if opts.test_name or opts.metric or opts.args:
185 self.argument_parser.error(
186 'do not specify --test_name, --metric, --args for CTS/GTS tests')
187 opts.test_name = '%s.tradefed-run-test' % opts.cts_prefix
188
Kuang-che Wua41525a2018-10-17 23:52:24 +0800189 if opts.metric:
190 if opts.old_value is None:
191 self.argument_parser.error('--old_value is not provided')
192 if opts.new_value is None:
193 self.argument_parser.error('--new_value is not provided')
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800194 if opts.fail_to_pass:
195 self.argument_parser.error(
196 '--fail_to_pass is not for benchmark test (--metric)')
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800197 else:
Kuang-che Wua41525a2018-10-17 23:52:24 +0800198 if opts.old_value is not None:
199 self.argument_parser.error(
200 '--old_value is provided but --metric is not')
201 if opts.new_value is not None:
202 self.argument_parser.error(
203 '--new_value is provided but --metric is not')
Kuang-che Wue4558242019-05-14 15:26:08 +0800204 if opts.recompute_init_values:
Kuang-che Wu4f6f9122019-04-23 17:44:46 +0800205 self.argument_parser.error(
206 '--recompute_init_values is provided but --metric is not')
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800207
Kuang-che Wua41525a2018-10-17 23:52:24 +0800208 def cmd_init(self, opts):
209 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
210 opts.mirror_base, opts.work_base, opts.session)
211 self.check_options(opts, path_factory)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800212
Kuang-che Wua41525a2018-10-17 23:52:24 +0800213 config = dict(
214 session=opts.session,
215 mirror_base=opts.mirror_base,
216 work_base=opts.work_base,
217 chromeos_root=opts.chromeos_root,
218 chromeos_mirror=opts.chromeos_mirror,
219 chrome_root=opts.chrome_root,
220 chrome_mirror=opts.chrome_mirror,
221 android_root=opts.android_root,
222 android_mirror=opts.android_mirror,
Kuang-che Wu248c5182018-10-19 17:08:11 +0800223 dut=opts.dut,
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800224 pools=opts.pools,
Kuang-che Wu248c5182018-10-19 17:08:11 +0800225 model=opts.model,
226 sku=opts.sku,
227 board=opts.board,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800228 old=opts.old,
229 new=opts.new,
230 test_name=opts.test_name,
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800231 fail_to_pass=opts.fail_to_pass,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800232 metric=opts.metric,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800233 old_value=opts.old_value,
234 new_value=opts.new_value,
Kuang-che Wu4f6f9122019-04-23 17:44:46 +0800235 recompute_init_values=opts.recompute_init_values,
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800236 cts_revision=opts.cts_revision,
237 cts_abi=opts.cts_abi,
238 cts_prefix=opts.cts_prefix,
239 cts_module=opts.cts_module,
240 cts_test=opts.cts_test,
241 cts_timeout=opts.cts_timeout,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800242 noisy=opts.noisy,
243 test_that_args=opts.args,
244 always_reflash=opts.always_reflash,
Kuang-che Wuda3abfe2019-03-21 14:48:12 +0800245 reboot_before_test=opts.reboot_before_test,
Kuang-che Wu9787fb82019-03-28 18:13:47 +0800246 bypass_chromeos_prebuilt=opts.bypass_chromeos_prebuilt,
247 bypass_chromeos_build=opts.bypass_chromeos_build,
248 bypass_chrome_build=opts.bypass_chrome_build,
249 bypass_android_prebuilt=opts.bypass_android_prebuilt,
250 bypass_android_build=opts.bypass_android_build,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800251 )
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800252
Kuang-che Wua41525a2018-10-17 23:52:24 +0800253 self.states.init(config)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800254
Kuang-che Wua41525a2018-10-17 23:52:24 +0800255 # Unpack old autotest prebuilt, assume following information don't change
256 # between versions:
257 # - what chrome binaries to run
258 # - dependency labels for DUT allocation
259 common_switch_cmd, _common_eval_cmd = self._build_cmds()
260 util.check_call(*(common_switch_cmd + [self.config['old']]))
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800261
Kuang-che Wua41525a2018-10-17 23:52:24 +0800262 self.states.save()
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800263
Kuang-che Wua41525a2018-10-17 23:52:24 +0800264 def _build_cmds(self):
265 # prebuilt version will be specified later.
266 common_switch_cmd = [
267 './switch_autotest_prebuilt.py',
268 '--chromeos_root', self.config['chromeos_root'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800269 '--board', self.config['board'],
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800270 ] # yapf: disable
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800271 if self.config['test_name'] and not self.config['cts_test']:
272 common_switch_cmd += ['--test_name', self.config['test_name']]
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800273
Kuang-che Wua41525a2018-10-17 23:52:24 +0800274 common_eval_cmd = [
275 './eval_cros_autotest.py',
276 '--chromeos_root', self.config['chromeos_root'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800277 ] # yapf: disable
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800278 if self.config['test_name'] and not self.config['cts_test']:
279 common_eval_cmd += ['--test_name', self.config['test_name']]
Kuang-che Wua41525a2018-10-17 23:52:24 +0800280 if self.config['metric']:
281 common_eval_cmd += [
282 '--metric', self.config['metric'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800283 ] # yapf: disable
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800284 elif self.config['fail_to_pass']:
285 common_eval_cmd.append('--fail_to_pass')
Kuang-che Wuda3abfe2019-03-21 14:48:12 +0800286 if self.config['reboot_before_test']:
287 common_eval_cmd.append('--reboot_before_test')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800288 if self.config['test_that_args']:
289 common_eval_cmd += ['--args', self.config['test_that_args']]
Kuang-che Wud4603d72018-11-29 17:51:21 +0800290 if self.config['test_name'].startswith('telemetry_'):
291 common_eval_cmd += ['--chrome_root', self.config['chrome_root']]
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800292
293 for arg_name in [
294 'cts_revision', 'cts_abi', 'cts_prefix', 'cts_module', 'cts_test',
295 'cts_timeout'
296 ]:
297 if self.config.get(arg_name) is not None:
298 common_eval_cmd += ['--%s' % arg_name, str(self.config[arg_name])]
299
Kuang-che Wua41525a2018-10-17 23:52:24 +0800300 return common_switch_cmd, common_eval_cmd
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800301
Kuang-che Wua41525a2018-10-17 23:52:24 +0800302 def cmd_run(self, opts):
303 del opts # unused
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800304
Kuang-che Wua41525a2018-10-17 23:52:24 +0800305 self.states.load()
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800306
Kuang-che Wu8b654092018-11-09 17:56:25 +0800307 try:
308 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
309 self.config['mirror_base'], self.config['work_base'],
310 self.config['session'])
311 common_switch_cmd, common_eval_cmd = self._build_cmds()
312
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800313 if self.config['test_name']:
314 chrome_binaries = determine_chrome_binaries(
315 self.config['chromeos_root'], self.config['test_name'])
316 else:
317 chrome_binaries = None
Kuang-che Wu8b654092018-11-09 17:56:25 +0800318
319 with cros_lab_util.dut_manager(self.config['dut'],
320 lambda: grab_dut(self.config)) as dut:
321 if not dut:
322 raise errors.NoDutAvailable('unable to allocate DUT')
323 assert cros_util.is_dut(dut)
324 if self.config['dut'] == cros_lab_util.LAB_DUT:
325 self.config['allocated_dut'] = dut
326 self.states.save()
327 common_eval_cmd.append(dut)
328
Kuang-che Wu186071a2019-03-28 17:11:41 +0800329 diagnoser = diagnoser_cros.CrosDiagnoser(self.states, path_factory,
330 self.config, dut)
Kuang-che Wu8b654092018-11-09 17:56:25 +0800331
332 eval_cmd = common_eval_cmd + ['--prebuilt', '--reinstall']
333 # Do not specify version for autotest prebuilt switching here. The trick
334 # is that version number is obtained via bisector's environment variable
335 # CROS_VERSION.
336 extra_switch_cmd = common_switch_cmd
337 diagnoser.narrow_down_chromeos_prebuilt(
338 self.config['old'],
339 self.config['new'],
340 eval_cmd,
341 extra_switch_cmd=extra_switch_cmd)
342
343 diagnoser.switch_chromeos_to_old(force=self.config['always_reflash'])
344 util.check_call(*(common_switch_cmd + [diagnoser.cros_old]))
Kuang-che Wu931e8822019-03-01 00:05:27 +0800345 # Now, the version of autotest on the DUT is unknown. This is harmless
346 # to the final diagnose result. Even if the culprit is inside autotest
347 # itself, the verification step of chrome bisection will know that
348 # chrome is not culprit and go on.
349 # Do not delete existing autotest folders on the DUT, so chrome custom
350 # binary tests can reuse them.
Kuang-che Wu8b654092018-11-09 17:56:25 +0800351
352 try:
353 if diagnoser.narrow_down_android(eval_cmd):
354 return
Kuang-che Wuec566f32019-03-07 16:53:32 +0800355 except errors.DiagnoseContradiction:
Kuang-che Wu8b654092018-11-09 17:56:25 +0800356 raise
357 except Exception:
358 logger.exception('exception in android bisector before verification; '
359 'assume culprit is not inside android and continue')
360 # Assume it's ok to leave random version of android prebuilt on DUT.
361
362 # Don't --reinstall to keep chrome binaries override.
363 eval_cmd = common_eval_cmd + ['--prebuilt']
364 try:
365 if diagnoser.narrow_down_chrome(
Kuang-che Wu50d8ff42018-11-26 12:48:30 +0800366 eval_cmd, chrome_binaries=chrome_binaries):
Kuang-che Wu8b654092018-11-09 17:56:25 +0800367 return
Kuang-che Wuec566f32019-03-07 16:53:32 +0800368 except errors.DiagnoseContradiction:
Kuang-che Wu8b654092018-11-09 17:56:25 +0800369 raise
370 except Exception:
371 logger.exception('exception in chrome bisector before verification; '
372 'assume culprit is not inside chrome and continue')
373
374 eval_cmd = common_eval_cmd + ['--reinstall']
375 diagnoser.narrow_down_chromeos_localbuild(eval_cmd)
376 logger.info('%s done', __file__)
377 except Exception as e:
378 logger.exception('got exception; stop')
379 exception_name = e.__class__.__name__
380 self.states.add_history(
381 'failed', '%s: %s' % (exception_name, e), exception=exception_name)
382
383 def cmd_log(self, opts):
384 self.states.load()
Kuang-che Wua41525a2018-10-17 23:52:24 +0800385 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
386 self.config['mirror_base'], self.config['work_base'],
387 self.config['session'])
Kuang-che Wu186071a2019-03-28 17:11:41 +0800388 diagnoser = diagnoser_cros.CrosDiagnoser(self.states, path_factory,
389 self.config, None)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800390
Kuang-che Wu8b654092018-11-09 17:56:25 +0800391 diagnoser.cmd_log(opts.json)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800392
Kuang-che Wue80bb872018-11-15 19:45:25 +0800393 def cmd_view(self, opts):
394 self.states.load()
395 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
396 self.config['mirror_base'], self.config['work_base'],
397 self.config['session'])
Kuang-che Wu186071a2019-03-28 17:11:41 +0800398 diagnoser = diagnoser_cros.CrosDiagnoser(self.states, path_factory,
399 self.config, None)
Kuang-che Wue80bb872018-11-15 19:45:25 +0800400 diagnoser.cmd_view(opts.json, opts.verbose)
401
Kuang-che Wua41525a2018-10-17 23:52:24 +0800402 def create_argument_parser(self):
403 parser = argparse.ArgumentParser()
404 common.add_common_arguments(parser)
405 parser.add_argument('--session_base', default='bisect.sessions')
406 parser.add_argument('--session', help='Session name', required=True)
407 subparsers = parser.add_subparsers(
408 dest='command', title='commands', metavar='<command>')
409
410 parser_init = subparsers.add_parser('init', help='Initialize')
411 group = parser_init.add_argument_group(
412 title='Source tree path options',
413 description='''
414 Specify the paths of chromeos/chrome/android mirror and checkout. They
415 have the same default values as setup_cros_bisect.py, so usually you can
416 omit them and it just works.
417 ''')
418 group.add_argument(
419 '--mirror_base',
420 metavar='MIRROR_BASE',
421 default=configure.get('MIRROR_BASE',
422 setup_cros_bisect.DEFAULT_MIRROR_BASE),
423 help='Directory for mirrors (default: %(default)s)')
424 group.add_argument(
425 '--work_base',
426 metavar='WORK_BASE',
427 default=configure.get('WORK_BASE', setup_cros_bisect.DEFAULT_WORK_BASE),
428 help='Directory for bisection working directories '
429 '(default: %(default)s)')
430 group.add_argument(
431 '--chromeos_root',
432 metavar='CHROMEOS_ROOT',
433 type=cli.argtype_dir_path,
434 default=configure.get('CHROMEOS_ROOT'),
435 help='ChromeOS tree root')
436 group.add_argument(
437 '--chromeos_mirror',
438 type=cli.argtype_dir_path,
439 default=configure.get('CHROMEOS_MIRROR'),
440 help='ChromeOS repo mirror path')
441 group.add_argument(
442 '--android_root',
443 metavar='ANDROID_ROOT',
444 type=cli.argtype_dir_path,
445 default=configure.get('ANDROID_ROOT'),
446 help='Android tree root')
447 group.add_argument(
448 '--android_mirror',
449 type=cli.argtype_dir_path,
450 default=configure.get('ANDROID_MIRROR'),
451 help='Android repo mirror path')
452 group.add_argument(
453 '--chrome_root',
454 metavar='CHROME_ROOT',
455 type=cli.argtype_dir_path,
456 default=configure.get('CHROME_ROOT'),
457 help='Chrome tree root')
458 group.add_argument(
459 '--chrome_mirror',
460 metavar='CHROME_MIRROR',
461 type=cli.argtype_dir_path,
462 default=configure.get('CHROME_MIRROR'),
463 help="chrome's gclient cache dir")
464
Kuang-che Wu248c5182018-10-19 17:08:11 +0800465 group = parser_init.add_argument_group(title='DUT allocation options')
466 group.add_argument(
467 '--dut',
468 metavar='DUT',
469 required=True,
470 help='Address of DUT (Device Under Test). If "%s", DUT will be '
471 'automatically allocated from the lab' % cros_lab_util.LAB_DUT)
472 group.add_argument(
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800473 '--pools',
474 type=cli.argtype_notempty,
Kuang-che Wu8c6d9dd2019-01-16 10:29:13 +0800475 default='suites',
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800476 help='Desired pools, comma separated and ordered by preference '
477 '(default: %(default)s)')
478 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800479 '--model',
480 metavar='MODEL',
481 help='"model" criteria if DUT is auto allocated from the lab')
482 group.add_argument(
483 '--sku',
484 metavar='SKU',
485 help='"sku" criteria if DUT is auto allocated from the lab')
486
Kuang-che Wua41525a2018-10-17 23:52:24 +0800487 group = parser_init.add_argument_group(title='Essential options')
488 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800489 '--board',
490 metavar='BOARD',
491 default=configure.get('BOARD'),
492 help='ChromeOS board name; auto detected if DUT is not auto allocated')
493 group.add_argument(
Kuang-che Wua41525a2018-10-17 23:52:24 +0800494 '--old',
495 type=cros_util.argtype_cros_version,
496 required=True,
497 help='ChromeOS version with old behavior')
498 group.add_argument(
499 '--new',
500 type=cros_util.argtype_cros_version,
501 required=True,
502 help='ChromeOS version with new behavior')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800503
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800504 group = parser_init.add_argument_group(
505 title='Options for normal autotest tests')
506 group.add_argument('--test_name', help='Test name')
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800507 group.add_argument(
508 '--fail_to_pass',
509 action='store_true',
510 help='For functional tests: bisect the CL fixed the regression (when '
511 'test became PASS). If not specified, the default is to bisect the CL '
512 'which broke the test (when test became FAIL)')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800513 group.add_argument('--metric', help='Metric name of benchmark test')
514 group.add_argument(
515 '--old_value',
516 type=float,
517 help='For benchmark test, old value of metric')
518 group.add_argument(
519 '--new_value',
520 type=float,
521 help='For benchmark test, new value of metric')
Kuang-che Wu4f6f9122019-04-23 17:44:46 +0800522 group.add_argument(
523 '--recompute_init_values',
524 action='store_true',
525 help='For performance test, recompute initial values')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800526
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800527 group = parser_init.add_argument_group(title='Options for CTS/GTS tests')
528 group.add_argument('--cts_revision', help='CTS revision, like "9.0_r3"')
Kuang-che Wu63f836a2019-02-21 16:33:32 +0000529 group.add_argument('--cts_abi', choices=['arm', 'x86'])
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800530 group.add_argument(
531 '--cts_prefix',
532 help='Prefix of autotest test name, '
533 'like cheets_CTS_N, cheets_CTS_P, cheets_GTS')
534 group.add_argument(
535 '--cts_module', help='CTS/GTS module name, like "CtsCameraTestCases"')
536 group.add_argument(
537 '--cts_test',
538 help='CTS/GTS test name, like '
539 '"android.hardware.cts.CameraTest#testDisplayOrientation"')
540 group.add_argument('--cts_timeout', type=float, help='timeout, in seconds')
541
Kuang-che Wua41525a2018-10-17 23:52:24 +0800542 group = parser_init.add_argument_group(title='Options passed to test_that')
543 group.add_argument(
544 '--args',
545 help='Extra args passed to "test_that --args"; Overrides the default')
546
547 group = parser_init.add_argument_group(title='Bisect behavior options')
548 group.add_argument(
549 '--noisy',
550 help='Enable noisy binary search. Example value: "old=1/10,new=2/3"')
551 group.add_argument(
552 '--always_reflash',
553 action='store_true',
554 help='Do not trust ChromeOS version number of DUT and always reflash. '
555 'This is usually only needed when resume because previous bisect was '
556 'interrupted and the DUT may be in an unexpected state')
Kuang-che Wuda3abfe2019-03-21 14:48:12 +0800557 group.add_argument(
558 '--reboot_before_test',
559 action='store_true',
560 help='Reboot before test run')
Kuang-che Wu9787fb82019-03-28 18:13:47 +0800561 group.add_argument(
562 '--bypass_chromeos_prebuilt',
563 action='store_true',
564 help='Bypass chromeos prebuilt image bisect')
565 group.add_argument(
566 '--bypass_chromeos_build',
567 action='store_true',
568 help='Bypass chromeos local build bisect')
569 group.add_argument(
570 '--bypass_chrome_build',
571 action='store_true',
572 help='Bypass chrome local build bisect')
573 group.add_argument(
574 '--bypass_android_prebuilt',
575 action='store_true',
576 help='Bypass android prebuilt image bisect')
577 group.add_argument(
578 '--bypass_android_build',
579 action='store_true',
580 help='Bypass chromeos local build bisect')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800581 parser_init.set_defaults(func=self.cmd_init)
582
583 parser_run = subparsers.add_parser('run', help='Start auto bisection')
584 parser_run.set_defaults(func=self.cmd_run)
585
Kuang-che Wu8b654092018-11-09 17:56:25 +0800586 parser_log = subparsers.add_parser(
587 'log', help='Prints what has been done so far')
588 parser_log.add_argument(
589 '--json', action='store_true', help='Machine readable output')
590 parser_log.set_defaults(func=self.cmd_log)
591
Kuang-che Wue80bb872018-11-15 19:45:25 +0800592 parser_view = subparsers.add_parser(
593 'view', help='Prints summary of current status')
594 parser_view.add_argument('--verbose', '-v', action='store_true')
595 parser_view.add_argument(
596 '--json', action='store_true', help='Machine readable output')
597 parser_view.set_defaults(func=self.cmd_view)
598
Kuang-che Wua41525a2018-10-17 23:52:24 +0800599 return parser
600
601 def main(self, args=None):
602 opts = self.argument_parser.parse_args(args)
603 common.config_logging(opts)
604
605 session_base = configure.get('SESSION_BASE', common.DEFAULT_SESSION_BASE)
606 session_file = os.path.join(session_base, opts.session,
607 self.__class__.__name__)
Kuang-che Wu8b654092018-11-09 17:56:25 +0800608 self.states = diagnoser_cros.DiagnoseStates(session_file)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800609 opts.func(opts)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800610
611
612if __name__ == '__main__':
Kuang-che Wua41525a2018-10-17 23:52:24 +0800613 DiagnoseCommandLine().main()