blob: f8eb77880f8c837c7dfdc734a8585f0ea5ff0582 [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'],
50 'video_VDAPerf': ['video_decode_accelerator_unittest'],
51 'video_VDASanity': ['video_decode_accelerator_unittest'],
52 'video_VEAPerf': ['video_encode_accelerator_unittest'],
53 'video_VideoDecodeAccelerator*': ['video_decode_accelerator_unittest'],
54 'video_VideoEncodeAccelerator*': ['video_encode_accelerator_unittest'],
55}
56
57
Kuang-che Wua41525a2018-10-17 23:52:24 +080058def grab_dut(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 Wua41525a2018-10-17 23:52:24 +080066 reason = 'bisect-kit: %s' % config['session']
Kuang-che Wuf65c61d2018-10-19 17:48:30 +080067 if config.get('allocated_dut'):
68 host_name = cros_lab_util.dut_host_name(config['allocated_dut'])
69 logger.info('try to allocate the same host (%s) as last run', host_name)
70 host = cros_lab_util.allocate_host(reason, host=host_name)
71 else:
72 extra_labels = []
73 dependencies = info.variables.get('DEPENDENCIES', '')
74 for label in dependencies.split(','):
75 label = label.strip()
76 # Skip non-machine labels
77 if label in ['cleanup-reboot']:
78 continue
79 extra_labels.append(label)
80
81 host = cros_lab_util.allocate_host(
82 reason,
83 model=config['model'],
84 sku=config['sku'],
Kuang-che Wufcac3f22019-01-10 00:36:42 +080085 pools=config.get('pools', '').split(','),
Kuang-che Wuf65c61d2018-10-19 17:48:30 +080086 extra_labels=extra_labels)
87
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080088 if not host:
89 logger.error('unable to allocate dut')
90 return None
91
92 logger.info('allocated host %s', host)
93 return host
94
95
96def may_depend_on_extra_chrome_binaries(autotest_dir, test_name):
97 info = cros_util.get_autotest_test_info(autotest_dir, test_name)
Kuang-che Wu0f1c3b02019-01-10 01:21:01 +080098 assert info, 'incorrect test name? %s' % test_name
Kuang-che Wu1fcc0222018-07-07 16:43:22 +080099 dirpath = os.path.dirname(info.path)
100 for pypath in glob.glob(os.path.join(dirpath, '*.py')):
101 if 'ChromeBinaryTest' in open(pypath).read():
102 return True
103 return False
104
105
Kuang-che Wua41525a2018-10-17 23:52:24 +0800106def determine_chrome_binaries(chromeos_root, test_name):
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800107 chrome_binaries = None
108 for name_pattern, binaries in CHROME_BINARIES_OF_TEST.items():
Kuang-che Wua41525a2018-10-17 23:52:24 +0800109 if fnmatch.fnmatch(test_name, name_pattern):
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800110 chrome_binaries = binaries
111 break
112
Kuang-che Wua41525a2018-10-17 23:52:24 +0800113 autotest_dir = os.path.join(chromeos_root, cros_util.prebuilt_autotest_dir)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800114 if chrome_binaries:
115 logger.info('This test depends on chrome binary: %s', chrome_binaries)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800116 elif may_depend_on_extra_chrome_binaries(autotest_dir, test_name):
Kuang-che Wu74768d32018-09-07 12:03:24 +0800117 logger.warning(
118 '%s code used ChromeBinaryTest but the binary is unknown; '
Kuang-che Wua41525a2018-10-17 23:52:24 +0800119 'please update CHROME_BINARIES_OF_TEST table', test_name)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800120 return chrome_binaries
121
122
Kuang-che Wua41525a2018-10-17 23:52:24 +0800123class DiagnoseCommandLine(object):
124 """Diagnose command line interface."""
Kuang-che Wud8fc9572018-10-03 21:00:41 +0800125
Kuang-che Wua41525a2018-10-17 23:52:24 +0800126 def __init__(self):
127 common.init()
128 self.argument_parser = self.create_argument_parser()
129 self.states = None
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800130
Kuang-che Wua41525a2018-10-17 23:52:24 +0800131 @property
132 def config(self):
133 return self.states.config
134
135 def check_options(self, opts, path_factory):
136 if not opts.chromeos_mirror:
137 opts.chromeos_mirror = path_factory.get_chromeos_mirror()
138 logger.info('chromeos_mirror = %s', opts.chromeos_mirror)
139 if not opts.chromeos_root:
140 opts.chromeos_root = path_factory.get_chromeos_tree()
141 logger.info('chromeos_root = %s', opts.chromeos_root)
142 if not opts.chrome_mirror:
143 opts.chrome_mirror = path_factory.get_chrome_cache()
144 logger.info('chrome_mirror = %s', opts.chrome_mirror)
145 if not opts.chrome_root:
146 opts.chrome_root = path_factory.get_chrome_tree()
147 logger.info('chrome_root = %s', opts.chrome_root)
148
Kuang-che Wu248c5182018-10-19 17:08:11 +0800149 if opts.dut == cros_lab_util.LAB_DUT:
150 if not opts.model and not opts.sku:
151 self.argument_parser.error(
152 'either --model or --sku need to be specified if DUT is "%s"' %
153 cros_lab_util.LAB_DUT)
154 # Board name cannot be deduced from auto allocated devices because they
155 # may be provisioned with image of unexpected board.
156 if not opts.board:
Kuang-che Wua41525a2018-10-17 23:52:24 +0800157 self.argument_parser.error('--board need to be specified if DUT is "%s"'
158 % cros_lab_util.LAB_DUT)
Kuang-che Wu248c5182018-10-19 17:08:11 +0800159 else:
160 if not opts.board:
Kuang-che Wua41525a2018-10-17 23:52:24 +0800161 opts.board = cros_util.query_dut_board(opts.dut)
162
163 if cros_util.is_cros_short_version(opts.old):
164 opts.old = cros_util.version_to_full(opts.board, opts.old)
165 if cros_util.is_cros_short_version(opts.new):
166 opts.new = cros_util.version_to_full(opts.board, opts.new)
167
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800168 is_cts = (
169 opts.cts_revision or opts.cts_abi or opts.cts_prefix or
170 opts.cts_module or opts.cts_test or opts.cts_timeout)
171 if is_cts:
172 if opts.test_name or opts.metric or opts.args:
173 self.argument_parser.error(
174 'do not specify --test_name, --metric, --args for CTS/GTS tests')
175 opts.test_name = '%s.tradefed-run-test' % opts.cts_prefix
176
Kuang-che Wua41525a2018-10-17 23:52:24 +0800177 if opts.metric:
178 if opts.old_value is None:
179 self.argument_parser.error('--old_value is not provided')
180 if opts.new_value is None:
181 self.argument_parser.error('--new_value is not provided')
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800182 else:
Kuang-che Wua41525a2018-10-17 23:52:24 +0800183 if opts.old_value is not None:
184 self.argument_parser.error(
185 '--old_value is provided but --metric is not')
186 if opts.new_value is not None:
187 self.argument_parser.error(
188 '--new_value is provided but --metric is not')
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800189
Kuang-che Wua41525a2018-10-17 23:52:24 +0800190 def cmd_init(self, opts):
191 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
192 opts.mirror_base, opts.work_base, opts.session)
193 self.check_options(opts, path_factory)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800194
Kuang-che Wua41525a2018-10-17 23:52:24 +0800195 config = dict(
196 session=opts.session,
197 mirror_base=opts.mirror_base,
198 work_base=opts.work_base,
199 chromeos_root=opts.chromeos_root,
200 chromeos_mirror=opts.chromeos_mirror,
201 chrome_root=opts.chrome_root,
202 chrome_mirror=opts.chrome_mirror,
203 android_root=opts.android_root,
204 android_mirror=opts.android_mirror,
Kuang-che Wu248c5182018-10-19 17:08:11 +0800205 dut=opts.dut,
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800206 pools=opts.pools,
Kuang-che Wu248c5182018-10-19 17:08:11 +0800207 model=opts.model,
208 sku=opts.sku,
209 board=opts.board,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800210 old=opts.old,
211 new=opts.new,
212 test_name=opts.test_name,
213 metric=opts.metric,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800214 old_value=opts.old_value,
215 new_value=opts.new_value,
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800216 cts_revision=opts.cts_revision,
217 cts_abi=opts.cts_abi,
218 cts_prefix=opts.cts_prefix,
219 cts_module=opts.cts_module,
220 cts_test=opts.cts_test,
221 cts_timeout=opts.cts_timeout,
Kuang-che Wua41525a2018-10-17 23:52:24 +0800222 noisy=opts.noisy,
223 test_that_args=opts.args,
224 always_reflash=opts.always_reflash,
225 )
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800226
Kuang-che Wua41525a2018-10-17 23:52:24 +0800227 self.states.init(config)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800228
Kuang-che Wua41525a2018-10-17 23:52:24 +0800229 # Unpack old autotest prebuilt, assume following information don't change
230 # between versions:
231 # - what chrome binaries to run
232 # - dependency labels for DUT allocation
233 common_switch_cmd, _common_eval_cmd = self._build_cmds()
234 util.check_call(*(common_switch_cmd + [self.config['old']]))
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800235
Kuang-che Wua41525a2018-10-17 23:52:24 +0800236 self.states.save()
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800237
Kuang-che Wua41525a2018-10-17 23:52:24 +0800238 def _build_cmds(self):
239 # prebuilt version will be specified later.
240 common_switch_cmd = [
241 './switch_autotest_prebuilt.py',
242 '--chromeos_root', self.config['chromeos_root'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800243 '--board', self.config['board'],
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800244 ] # yapf: disable
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800245 if self.config['test_name'] and not self.config['cts_test']:
246 common_switch_cmd += ['--test_name', self.config['test_name']]
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800247
Kuang-che Wua41525a2018-10-17 23:52:24 +0800248 common_eval_cmd = [
249 './eval_cros_autotest.py',
250 '--chromeos_root', self.config['chromeos_root'],
Kuang-che Wua41525a2018-10-17 23:52:24 +0800251 ] # yapf: disable
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800252 if self.config['test_name'] and not self.config['cts_test']:
253 common_eval_cmd += ['--test_name', self.config['test_name']]
Kuang-che Wua41525a2018-10-17 23:52:24 +0800254 if self.config['metric']:
255 common_eval_cmd += [
256 '--metric', self.config['metric'],
257 '--old_value', str(self.config['old_value']),
258 '--new_value', str(self.config['new_value']),
259 ] # yapf: disable
260 if self.config['test_that_args']:
261 common_eval_cmd += ['--args', self.config['test_that_args']]
Kuang-che Wud4603d72018-11-29 17:51:21 +0800262 if self.config['test_name'].startswith('telemetry_'):
263 common_eval_cmd += ['--chrome_root', self.config['chrome_root']]
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800264
265 for arg_name in [
266 'cts_revision', 'cts_abi', 'cts_prefix', 'cts_module', 'cts_test',
267 'cts_timeout'
268 ]:
269 if self.config.get(arg_name) is not None:
270 common_eval_cmd += ['--%s' % arg_name, str(self.config[arg_name])]
271
Kuang-che Wua41525a2018-10-17 23:52:24 +0800272 return common_switch_cmd, common_eval_cmd
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800273
Kuang-che Wua41525a2018-10-17 23:52:24 +0800274 def cmd_run(self, opts):
275 del opts # unused
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800276
Kuang-che Wua41525a2018-10-17 23:52:24 +0800277 self.states.load()
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800278
Kuang-che Wu8b654092018-11-09 17:56:25 +0800279 try:
280 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
281 self.config['mirror_base'], self.config['work_base'],
282 self.config['session'])
283 common_switch_cmd, common_eval_cmd = self._build_cmds()
284
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800285 if self.config['test_name']:
286 chrome_binaries = determine_chrome_binaries(
287 self.config['chromeos_root'], self.config['test_name'])
288 else:
289 chrome_binaries = None
Kuang-che Wu8b654092018-11-09 17:56:25 +0800290
291 with cros_lab_util.dut_manager(self.config['dut'],
292 lambda: grab_dut(self.config)) as dut:
293 if not dut:
294 raise errors.NoDutAvailable('unable to allocate DUT')
295 assert cros_util.is_dut(dut)
296 if self.config['dut'] == cros_lab_util.LAB_DUT:
297 self.config['allocated_dut'] = dut
298 self.states.save()
299 common_eval_cmd.append(dut)
300
301 diagnoser = diagnoser_cros.CrosDiagnoser(
302 self.states, self.config['session'], path_factory,
303 self.config['chromeos_root'], self.config['chromeos_mirror'],
304 self.config['android_root'], self.config['android_mirror'],
305 self.config['chrome_root'], self.config['chrome_mirror'],
306 self.config['board'], self.config['noisy'], dut)
307
308 eval_cmd = common_eval_cmd + ['--prebuilt', '--reinstall']
309 # Do not specify version for autotest prebuilt switching here. The trick
310 # is that version number is obtained via bisector's environment variable
311 # CROS_VERSION.
312 extra_switch_cmd = common_switch_cmd
313 diagnoser.narrow_down_chromeos_prebuilt(
314 self.config['old'],
315 self.config['new'],
316 eval_cmd,
317 extra_switch_cmd=extra_switch_cmd)
318
319 diagnoser.switch_chromeos_to_old(force=self.config['always_reflash'])
320 util.check_call(*(common_switch_cmd + [diagnoser.cros_old]))
321 util.check_call('ssh', dut, 'rm', '-rf', '/usr/local/autotest')
322
323 try:
324 if diagnoser.narrow_down_android(eval_cmd):
325 return
326 except errors.VerificationFailed:
327 raise
328 except Exception:
329 logger.exception('exception in android bisector before verification; '
330 'assume culprit is not inside android and continue')
331 # Assume it's ok to leave random version of android prebuilt on DUT.
332
333 # Don't --reinstall to keep chrome binaries override.
334 eval_cmd = common_eval_cmd + ['--prebuilt']
335 try:
336 if diagnoser.narrow_down_chrome(
Kuang-che Wu50d8ff42018-11-26 12:48:30 +0800337 eval_cmd, chrome_binaries=chrome_binaries):
Kuang-che Wu8b654092018-11-09 17:56:25 +0800338 return
339 except errors.VerifyOldFailed:
340 logger.fatal('expect old chrome has old behavior but failed')
341 raise
342 except Exception:
343 logger.exception('exception in chrome bisector before verification; '
344 'assume culprit is not inside chrome and continue')
345
346 eval_cmd = common_eval_cmd + ['--reinstall']
347 diagnoser.narrow_down_chromeos_localbuild(eval_cmd)
348 logger.info('%s done', __file__)
349 except Exception as e:
350 logger.exception('got exception; stop')
351 exception_name = e.__class__.__name__
352 self.states.add_history(
353 'failed', '%s: %s' % (exception_name, e), exception=exception_name)
354
355 def cmd_log(self, opts):
356 self.states.load()
Kuang-che Wua41525a2018-10-17 23:52:24 +0800357 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
358 self.config['mirror_base'], self.config['work_base'],
359 self.config['session'])
Kuang-che Wu8b654092018-11-09 17:56:25 +0800360 diagnoser = diagnoser_cros.CrosDiagnoser(
361 self.states, self.config['session'], path_factory,
362 self.config['chromeos_root'], self.config['chromeos_mirror'],
363 self.config['android_root'], self.config['android_mirror'],
364 self.config['chrome_root'], self.config['chrome_mirror'],
365 self.config['board'], self.config['noisy'], None)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800366
Kuang-che Wu8b654092018-11-09 17:56:25 +0800367 diagnoser.cmd_log(opts.json)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800368
Kuang-che Wue80bb872018-11-15 19:45:25 +0800369 def cmd_view(self, opts):
370 self.states.load()
371 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
372 self.config['mirror_base'], self.config['work_base'],
373 self.config['session'])
374 diagnoser = diagnoser_cros.CrosDiagnoser(
375 self.states, self.config['session'], path_factory,
376 self.config['chromeos_root'], self.config['chromeos_mirror'],
377 self.config['android_root'], self.config['android_mirror'],
378 self.config['chrome_root'], self.config['chrome_mirror'],
379 self.config['board'], self.config['noisy'], None)
380 diagnoser.cmd_view(opts.json, opts.verbose)
381
Kuang-che Wua41525a2018-10-17 23:52:24 +0800382 def create_argument_parser(self):
383 parser = argparse.ArgumentParser()
384 common.add_common_arguments(parser)
385 parser.add_argument('--session_base', default='bisect.sessions')
386 parser.add_argument('--session', help='Session name', required=True)
387 subparsers = parser.add_subparsers(
388 dest='command', title='commands', metavar='<command>')
389
390 parser_init = subparsers.add_parser('init', help='Initialize')
391 group = parser_init.add_argument_group(
392 title='Source tree path options',
393 description='''
394 Specify the paths of chromeos/chrome/android mirror and checkout. They
395 have the same default values as setup_cros_bisect.py, so usually you can
396 omit them and it just works.
397 ''')
398 group.add_argument(
399 '--mirror_base',
400 metavar='MIRROR_BASE',
401 default=configure.get('MIRROR_BASE',
402 setup_cros_bisect.DEFAULT_MIRROR_BASE),
403 help='Directory for mirrors (default: %(default)s)')
404 group.add_argument(
405 '--work_base',
406 metavar='WORK_BASE',
407 default=configure.get('WORK_BASE', setup_cros_bisect.DEFAULT_WORK_BASE),
408 help='Directory for bisection working directories '
409 '(default: %(default)s)')
410 group.add_argument(
411 '--chromeos_root',
412 metavar='CHROMEOS_ROOT',
413 type=cli.argtype_dir_path,
414 default=configure.get('CHROMEOS_ROOT'),
415 help='ChromeOS tree root')
416 group.add_argument(
417 '--chromeos_mirror',
418 type=cli.argtype_dir_path,
419 default=configure.get('CHROMEOS_MIRROR'),
420 help='ChromeOS repo mirror path')
421 group.add_argument(
422 '--android_root',
423 metavar='ANDROID_ROOT',
424 type=cli.argtype_dir_path,
425 default=configure.get('ANDROID_ROOT'),
426 help='Android tree root')
427 group.add_argument(
428 '--android_mirror',
429 type=cli.argtype_dir_path,
430 default=configure.get('ANDROID_MIRROR'),
431 help='Android repo mirror path')
432 group.add_argument(
433 '--chrome_root',
434 metavar='CHROME_ROOT',
435 type=cli.argtype_dir_path,
436 default=configure.get('CHROME_ROOT'),
437 help='Chrome tree root')
438 group.add_argument(
439 '--chrome_mirror',
440 metavar='CHROME_MIRROR',
441 type=cli.argtype_dir_path,
442 default=configure.get('CHROME_MIRROR'),
443 help="chrome's gclient cache dir")
444
Kuang-che Wu248c5182018-10-19 17:08:11 +0800445 group = parser_init.add_argument_group(title='DUT allocation options')
446 group.add_argument(
447 '--dut',
448 metavar='DUT',
449 required=True,
450 help='Address of DUT (Device Under Test). If "%s", DUT will be '
451 'automatically allocated from the lab' % cros_lab_util.LAB_DUT)
452 group.add_argument(
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800453 '--pools',
454 type=cli.argtype_notempty,
Kuang-che Wu8c6d9dd2019-01-16 10:29:13 +0800455 default='suites',
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800456 help='Desired pools, comma separated and ordered by preference '
457 '(default: %(default)s)')
458 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800459 '--model',
460 metavar='MODEL',
461 help='"model" criteria if DUT is auto allocated from the lab')
462 group.add_argument(
463 '--sku',
464 metavar='SKU',
465 help='"sku" criteria if DUT is auto allocated from the lab')
466
Kuang-che Wua41525a2018-10-17 23:52:24 +0800467 group = parser_init.add_argument_group(title='Essential options')
468 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800469 '--board',
470 metavar='BOARD',
471 default=configure.get('BOARD'),
472 help='ChromeOS board name; auto detected if DUT is not auto allocated')
473 group.add_argument(
Kuang-che Wua41525a2018-10-17 23:52:24 +0800474 '--old',
475 type=cros_util.argtype_cros_version,
476 required=True,
477 help='ChromeOS version with old behavior')
478 group.add_argument(
479 '--new',
480 type=cros_util.argtype_cros_version,
481 required=True,
482 help='ChromeOS version with new behavior')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800483
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800484 group = parser_init.add_argument_group(
485 title='Options for normal autotest tests')
486 group.add_argument('--test_name', help='Test name')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800487 group.add_argument('--metric', help='Metric name of benchmark test')
488 group.add_argument(
489 '--old_value',
490 type=float,
491 help='For benchmark test, old value of metric')
492 group.add_argument(
493 '--new_value',
494 type=float,
495 help='For benchmark test, new value of metric')
496
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800497 group = parser_init.add_argument_group(title='Options for CTS/GTS tests')
498 group.add_argument('--cts_revision', help='CTS revision, like "9.0_r3"')
499 group.add_argument('--cts_abi', choices=['arm', 'x86'])
500 group.add_argument(
501 '--cts_prefix',
502 help='Prefix of autotest test name, '
503 'like cheets_CTS_N, cheets_CTS_P, cheets_GTS')
504 group.add_argument(
505 '--cts_module', help='CTS/GTS module name, like "CtsCameraTestCases"')
506 group.add_argument(
507 '--cts_test',
508 help='CTS/GTS test name, like '
509 '"android.hardware.cts.CameraTest#testDisplayOrientation"')
510 group.add_argument('--cts_timeout', type=float, help='timeout, in seconds')
511
Kuang-che Wua41525a2018-10-17 23:52:24 +0800512 group = parser_init.add_argument_group(title='Options passed to test_that')
513 group.add_argument(
514 '--args',
515 help='Extra args passed to "test_that --args"; Overrides the default')
516
517 group = parser_init.add_argument_group(title='Bisect behavior options')
518 group.add_argument(
519 '--noisy',
520 help='Enable noisy binary search. Example value: "old=1/10,new=2/3"')
521 group.add_argument(
522 '--always_reflash',
523 action='store_true',
524 help='Do not trust ChromeOS version number of DUT and always reflash. '
525 'This is usually only needed when resume because previous bisect was '
526 'interrupted and the DUT may be in an unexpected state')
527 parser_init.set_defaults(func=self.cmd_init)
528
529 parser_run = subparsers.add_parser('run', help='Start auto bisection')
530 parser_run.set_defaults(func=self.cmd_run)
531
Kuang-che Wu8b654092018-11-09 17:56:25 +0800532 parser_log = subparsers.add_parser(
533 'log', help='Prints what has been done so far')
534 parser_log.add_argument(
535 '--json', action='store_true', help='Machine readable output')
536 parser_log.set_defaults(func=self.cmd_log)
537
Kuang-che Wue80bb872018-11-15 19:45:25 +0800538 parser_view = subparsers.add_parser(
539 'view', help='Prints summary of current status')
540 parser_view.add_argument('--verbose', '-v', action='store_true')
541 parser_view.add_argument(
542 '--json', action='store_true', help='Machine readable output')
543 parser_view.set_defaults(func=self.cmd_view)
544
Kuang-che Wua41525a2018-10-17 23:52:24 +0800545 return parser
546
547 def main(self, args=None):
548 opts = self.argument_parser.parse_args(args)
549 common.config_logging(opts)
550
551 session_base = configure.get('SESSION_BASE', common.DEFAULT_SESSION_BASE)
552 session_file = os.path.join(session_base, opts.session,
553 self.__class__.__name__)
Kuang-che Wu8b654092018-11-09 17:56:25 +0800554 self.states = diagnoser_cros.DiagnoseStates(session_file)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800555 opts.func(opts)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800556
557
558if __name__ == '__main__':
Kuang-che Wua41525a2018-10-17 23:52:24 +0800559 DiagnoseCommandLine().main()