blob: e3f737ca4a44a620dfccf133b901e3526e7e3dfa [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 Wu1fcc0222018-07-07 16:43:22 +0800204
Kuang-che Wua41525a2018-10-17 23:52:24 +0800205 def cmd_init(self, opts):
206 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
207 opts.mirror_base, opts.work_base, opts.session)
208 self.check_options(opts, path_factory)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800209
Kuang-che Wua41525a2018-10-17 23:52:24 +0800210 config = dict(
211 session=opts.session,
212 mirror_base=opts.mirror_base,
213 work_base=opts.work_base,
214 chromeos_root=opts.chromeos_root,
215 chromeos_mirror=opts.chromeos_mirror,
216 chrome_root=opts.chrome_root,
217 chrome_mirror=opts.chrome_mirror,
218 android_root=opts.android_root,
219 android_mirror=opts.android_mirror,
Kuang-che Wu248c5182018-10-19 17:08:11 +0800220 dut=opts.dut,
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800221 pools=opts.pools,
Kuang-che Wu248c5182018-10-19 17:08:11 +0800222 model=opts.model,
223 sku=opts.sku,
224 board=opts.board,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800225 old=opts.old,
226 new=opts.new,
227 test_name=opts.test_name,
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800228 fail_to_pass=opts.fail_to_pass,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800229 metric=opts.metric,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800230 old_value=opts.old_value,
231 new_value=opts.new_value,
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800232 cts_revision=opts.cts_revision,
233 cts_abi=opts.cts_abi,
234 cts_prefix=opts.cts_prefix,
235 cts_module=opts.cts_module,
236 cts_test=opts.cts_test,
237 cts_timeout=opts.cts_timeout,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800238 noisy=opts.noisy,
239 test_that_args=opts.args,
240 always_reflash=opts.always_reflash,
241 )
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800242
Kuang-che Wua41525a2018-10-17 23:52:24 +0800243 self.states.init(config)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800244
Kuang-che Wua41525a2018-10-17 23:52:24 +0800245 # Unpack old autotest prebuilt, assume following information don't change
246 # between versions:
247 # - what chrome binaries to run
248 # - dependency labels for DUT allocation
249 common_switch_cmd, _common_eval_cmd = self._build_cmds()
250 util.check_call(*(common_switch_cmd + [self.config['old']]))
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800251
Kuang-che Wua41525a2018-10-17 23:52:24 +0800252 self.states.save()
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800253
Kuang-che Wua41525a2018-10-17 23:52:24 +0800254 def _build_cmds(self):
255 # prebuilt version will be specified later.
256 common_switch_cmd = [
257 './switch_autotest_prebuilt.py',
258 '--chromeos_root', self.config['chromeos_root'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800259 '--board', self.config['board'],
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800260 ] # yapf: disable
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800261 if self.config['test_name'] and not self.config['cts_test']:
262 common_switch_cmd += ['--test_name', self.config['test_name']]
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800263
Kuang-che Wua41525a2018-10-17 23:52:24 +0800264 common_eval_cmd = [
265 './eval_cros_autotest.py',
266 '--chromeos_root', self.config['chromeos_root'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800267 ] # yapf: disable
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800268 if self.config['test_name'] and not self.config['cts_test']:
269 common_eval_cmd += ['--test_name', self.config['test_name']]
Kuang-che Wua41525a2018-10-17 23:52:24 +0800270 if self.config['metric']:
271 common_eval_cmd += [
272 '--metric', self.config['metric'],
273 '--old_value', str(self.config['old_value']),
274 '--new_value', str(self.config['new_value']),
275 ] # yapf: disable
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800276 elif self.config['fail_to_pass']:
277 common_eval_cmd.append('--fail_to_pass')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800278 if self.config['test_that_args']:
279 common_eval_cmd += ['--args', self.config['test_that_args']]
Kuang-che Wud4603d72018-11-29 17:51:21 +0800280 if self.config['test_name'].startswith('telemetry_'):
281 common_eval_cmd += ['--chrome_root', self.config['chrome_root']]
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800282
283 for arg_name in [
284 'cts_revision', 'cts_abi', 'cts_prefix', 'cts_module', 'cts_test',
285 'cts_timeout'
286 ]:
287 if self.config.get(arg_name) is not None:
288 common_eval_cmd += ['--%s' % arg_name, str(self.config[arg_name])]
289
Kuang-che Wua41525a2018-10-17 23:52:24 +0800290 return common_switch_cmd, common_eval_cmd
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800291
Kuang-che Wua41525a2018-10-17 23:52:24 +0800292 def cmd_run(self, opts):
293 del opts # unused
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800294
Kuang-che Wua41525a2018-10-17 23:52:24 +0800295 self.states.load()
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800296
Kuang-che Wu8b654092018-11-09 17:56:25 +0800297 try:
298 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
299 self.config['mirror_base'], self.config['work_base'],
300 self.config['session'])
301 common_switch_cmd, common_eval_cmd = self._build_cmds()
302
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800303 if self.config['test_name']:
304 chrome_binaries = determine_chrome_binaries(
305 self.config['chromeos_root'], self.config['test_name'])
306 else:
307 chrome_binaries = None
Kuang-che Wu8b654092018-11-09 17:56:25 +0800308
309 with cros_lab_util.dut_manager(self.config['dut'],
310 lambda: grab_dut(self.config)) as dut:
311 if not dut:
312 raise errors.NoDutAvailable('unable to allocate DUT')
313 assert cros_util.is_dut(dut)
314 if self.config['dut'] == cros_lab_util.LAB_DUT:
315 self.config['allocated_dut'] = dut
316 self.states.save()
317 common_eval_cmd.append(dut)
318
319 diagnoser = diagnoser_cros.CrosDiagnoser(
320 self.states, self.config['session'], path_factory,
321 self.config['chromeos_root'], self.config['chromeos_mirror'],
322 self.config['android_root'], self.config['android_mirror'],
323 self.config['chrome_root'], self.config['chrome_mirror'],
324 self.config['board'], self.config['noisy'], dut)
325
326 eval_cmd = common_eval_cmd + ['--prebuilt', '--reinstall']
327 # Do not specify version for autotest prebuilt switching here. The trick
328 # is that version number is obtained via bisector's environment variable
329 # CROS_VERSION.
330 extra_switch_cmd = common_switch_cmd
331 diagnoser.narrow_down_chromeos_prebuilt(
332 self.config['old'],
333 self.config['new'],
334 eval_cmd,
335 extra_switch_cmd=extra_switch_cmd)
336
337 diagnoser.switch_chromeos_to_old(force=self.config['always_reflash'])
338 util.check_call(*(common_switch_cmd + [diagnoser.cros_old]))
Kuang-che Wu931e8822019-03-01 00:05:27 +0800339 # Now, the version of autotest on the DUT is unknown. This is harmless
340 # to the final diagnose result. Even if the culprit is inside autotest
341 # itself, the verification step of chrome bisection will know that
342 # chrome is not culprit and go on.
343 # Do not delete existing autotest folders on the DUT, so chrome custom
344 # binary tests can reuse them.
Kuang-che Wu8b654092018-11-09 17:56:25 +0800345
346 try:
347 if diagnoser.narrow_down_android(eval_cmd):
348 return
Kuang-che Wuec566f32019-03-07 16:53:32 +0800349 except errors.DiagnoseContradiction:
Kuang-che Wu8b654092018-11-09 17:56:25 +0800350 raise
351 except Exception:
352 logger.exception('exception in android bisector before verification; '
353 'assume culprit is not inside android and continue')
354 # Assume it's ok to leave random version of android prebuilt on DUT.
355
356 # Don't --reinstall to keep chrome binaries override.
357 eval_cmd = common_eval_cmd + ['--prebuilt']
358 try:
359 if diagnoser.narrow_down_chrome(
Kuang-che Wu50d8ff42018-11-26 12:48:30 +0800360 eval_cmd, chrome_binaries=chrome_binaries):
Kuang-che Wu8b654092018-11-09 17:56:25 +0800361 return
Kuang-che Wuec566f32019-03-07 16:53:32 +0800362 except errors.DiagnoseContradiction:
Kuang-che Wu8b654092018-11-09 17:56:25 +0800363 raise
364 except Exception:
365 logger.exception('exception in chrome bisector before verification; '
366 'assume culprit is not inside chrome and continue')
367
368 eval_cmd = common_eval_cmd + ['--reinstall']
369 diagnoser.narrow_down_chromeos_localbuild(eval_cmd)
370 logger.info('%s done', __file__)
371 except Exception as e:
372 logger.exception('got exception; stop')
373 exception_name = e.__class__.__name__
374 self.states.add_history(
375 'failed', '%s: %s' % (exception_name, e), exception=exception_name)
376
377 def cmd_log(self, opts):
378 self.states.load()
Kuang-che Wua41525a2018-10-17 23:52:24 +0800379 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
380 self.config['mirror_base'], self.config['work_base'],
381 self.config['session'])
Kuang-che Wu8b654092018-11-09 17:56:25 +0800382 diagnoser = diagnoser_cros.CrosDiagnoser(
383 self.states, self.config['session'], path_factory,
384 self.config['chromeos_root'], self.config['chromeos_mirror'],
385 self.config['android_root'], self.config['android_mirror'],
386 self.config['chrome_root'], self.config['chrome_mirror'],
387 self.config['board'], self.config['noisy'], None)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800388
Kuang-che Wu8b654092018-11-09 17:56:25 +0800389 diagnoser.cmd_log(opts.json)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800390
Kuang-che Wue80bb872018-11-15 19:45:25 +0800391 def cmd_view(self, opts):
392 self.states.load()
393 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
394 self.config['mirror_base'], self.config['work_base'],
395 self.config['session'])
396 diagnoser = diagnoser_cros.CrosDiagnoser(
397 self.states, self.config['session'], path_factory,
398 self.config['chromeos_root'], self.config['chromeos_mirror'],
399 self.config['android_root'], self.config['android_mirror'],
400 self.config['chrome_root'], self.config['chrome_mirror'],
401 self.config['board'], self.config['noisy'], None)
402 diagnoser.cmd_view(opts.json, opts.verbose)
403
Kuang-che Wua41525a2018-10-17 23:52:24 +0800404 def create_argument_parser(self):
405 parser = argparse.ArgumentParser()
406 common.add_common_arguments(parser)
407 parser.add_argument('--session_base', default='bisect.sessions')
408 parser.add_argument('--session', help='Session name', required=True)
409 subparsers = parser.add_subparsers(
410 dest='command', title='commands', metavar='<command>')
411
412 parser_init = subparsers.add_parser('init', help='Initialize')
413 group = parser_init.add_argument_group(
414 title='Source tree path options',
415 description='''
416 Specify the paths of chromeos/chrome/android mirror and checkout. They
417 have the same default values as setup_cros_bisect.py, so usually you can
418 omit them and it just works.
419 ''')
420 group.add_argument(
421 '--mirror_base',
422 metavar='MIRROR_BASE',
423 default=configure.get('MIRROR_BASE',
424 setup_cros_bisect.DEFAULT_MIRROR_BASE),
425 help='Directory for mirrors (default: %(default)s)')
426 group.add_argument(
427 '--work_base',
428 metavar='WORK_BASE',
429 default=configure.get('WORK_BASE', setup_cros_bisect.DEFAULT_WORK_BASE),
430 help='Directory for bisection working directories '
431 '(default: %(default)s)')
432 group.add_argument(
433 '--chromeos_root',
434 metavar='CHROMEOS_ROOT',
435 type=cli.argtype_dir_path,
436 default=configure.get('CHROMEOS_ROOT'),
437 help='ChromeOS tree root')
438 group.add_argument(
439 '--chromeos_mirror',
440 type=cli.argtype_dir_path,
441 default=configure.get('CHROMEOS_MIRROR'),
442 help='ChromeOS repo mirror path')
443 group.add_argument(
444 '--android_root',
445 metavar='ANDROID_ROOT',
446 type=cli.argtype_dir_path,
447 default=configure.get('ANDROID_ROOT'),
448 help='Android tree root')
449 group.add_argument(
450 '--android_mirror',
451 type=cli.argtype_dir_path,
452 default=configure.get('ANDROID_MIRROR'),
453 help='Android repo mirror path')
454 group.add_argument(
455 '--chrome_root',
456 metavar='CHROME_ROOT',
457 type=cli.argtype_dir_path,
458 default=configure.get('CHROME_ROOT'),
459 help='Chrome tree root')
460 group.add_argument(
461 '--chrome_mirror',
462 metavar='CHROME_MIRROR',
463 type=cli.argtype_dir_path,
464 default=configure.get('CHROME_MIRROR'),
465 help="chrome's gclient cache dir")
466
Kuang-che Wu248c5182018-10-19 17:08:11 +0800467 group = parser_init.add_argument_group(title='DUT allocation options')
468 group.add_argument(
469 '--dut',
470 metavar='DUT',
471 required=True,
472 help='Address of DUT (Device Under Test). If "%s", DUT will be '
473 'automatically allocated from the lab' % cros_lab_util.LAB_DUT)
474 group.add_argument(
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800475 '--pools',
476 type=cli.argtype_notempty,
Kuang-che Wu8c6d9dd2019-01-16 10:29:13 +0800477 default='suites',
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800478 help='Desired pools, comma separated and ordered by preference '
479 '(default: %(default)s)')
480 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800481 '--model',
482 metavar='MODEL',
483 help='"model" criteria if DUT is auto allocated from the lab')
484 group.add_argument(
485 '--sku',
486 metavar='SKU',
487 help='"sku" criteria if DUT is auto allocated from the lab')
488
Kuang-che Wua41525a2018-10-17 23:52:24 +0800489 group = parser_init.add_argument_group(title='Essential options')
490 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800491 '--board',
492 metavar='BOARD',
493 default=configure.get('BOARD'),
494 help='ChromeOS board name; auto detected if DUT is not auto allocated')
495 group.add_argument(
Kuang-che Wua41525a2018-10-17 23:52:24 +0800496 '--old',
497 type=cros_util.argtype_cros_version,
498 required=True,
499 help='ChromeOS version with old behavior')
500 group.add_argument(
501 '--new',
502 type=cros_util.argtype_cros_version,
503 required=True,
504 help='ChromeOS version with new behavior')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800505
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800506 group = parser_init.add_argument_group(
507 title='Options for normal autotest tests')
508 group.add_argument('--test_name', help='Test name')
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800509 group.add_argument(
510 '--fail_to_pass',
511 action='store_true',
512 help='For functional tests: bisect the CL fixed the regression (when '
513 'test became PASS). If not specified, the default is to bisect the CL '
514 'which broke the test (when test became FAIL)')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800515 group.add_argument('--metric', help='Metric name of benchmark test')
516 group.add_argument(
517 '--old_value',
518 type=float,
519 help='For benchmark test, old value of metric')
520 group.add_argument(
521 '--new_value',
522 type=float,
523 help='For benchmark test, new value of metric')
524
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800525 group = parser_init.add_argument_group(title='Options for CTS/GTS tests')
526 group.add_argument('--cts_revision', help='CTS revision, like "9.0_r3"')
Kuang-che Wu63f836a2019-02-21 16:33:32 +0000527 group.add_argument('--cts_abi', choices=['arm', 'x86'])
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800528 group.add_argument(
529 '--cts_prefix',
530 help='Prefix of autotest test name, '
531 'like cheets_CTS_N, cheets_CTS_P, cheets_GTS')
532 group.add_argument(
533 '--cts_module', help='CTS/GTS module name, like "CtsCameraTestCases"')
534 group.add_argument(
535 '--cts_test',
536 help='CTS/GTS test name, like '
537 '"android.hardware.cts.CameraTest#testDisplayOrientation"')
538 group.add_argument('--cts_timeout', type=float, help='timeout, in seconds')
539
Kuang-che Wua41525a2018-10-17 23:52:24 +0800540 group = parser_init.add_argument_group(title='Options passed to test_that')
541 group.add_argument(
542 '--args',
543 help='Extra args passed to "test_that --args"; Overrides the default')
544
545 group = parser_init.add_argument_group(title='Bisect behavior options')
546 group.add_argument(
547 '--noisy',
548 help='Enable noisy binary search. Example value: "old=1/10,new=2/3"')
549 group.add_argument(
550 '--always_reflash',
551 action='store_true',
552 help='Do not trust ChromeOS version number of DUT and always reflash. '
553 'This is usually only needed when resume because previous bisect was '
554 'interrupted and the DUT may be in an unexpected state')
555 parser_init.set_defaults(func=self.cmd_init)
556
557 parser_run = subparsers.add_parser('run', help='Start auto bisection')
558 parser_run.set_defaults(func=self.cmd_run)
559
Kuang-che Wu8b654092018-11-09 17:56:25 +0800560 parser_log = subparsers.add_parser(
561 'log', help='Prints what has been done so far')
562 parser_log.add_argument(
563 '--json', action='store_true', help='Machine readable output')
564 parser_log.set_defaults(func=self.cmd_log)
565
Kuang-che Wue80bb872018-11-15 19:45:25 +0800566 parser_view = subparsers.add_parser(
567 'view', help='Prints summary of current status')
568 parser_view.add_argument('--verbose', '-v', action='store_true')
569 parser_view.add_argument(
570 '--json', action='store_true', help='Machine readable output')
571 parser_view.set_defaults(func=self.cmd_view)
572
Kuang-che Wua41525a2018-10-17 23:52:24 +0800573 return parser
574
575 def main(self, args=None):
576 opts = self.argument_parser.parse_args(args)
577 common.config_logging(opts)
578
579 session_base = configure.get('SESSION_BASE', common.DEFAULT_SESSION_BASE)
580 session_file = os.path.join(session_base, opts.session,
581 self.__class__.__name__)
Kuang-che Wu8b654092018-11-09 17:56:25 +0800582 self.states = diagnoser_cros.DiagnoseStates(session_file)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800583 opts.func(opts)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800584
585
586if __name__ == '__main__':
Kuang-che Wua41525a2018-10-17 23:52:24 +0800587 DiagnoseCommandLine().main()