blob: 6c6d859da0112364b1c8db76e09c68459299636d [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
349 except errors.VerificationFailed:
350 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 Wu1dc5bd72019-01-19 00:14:46 +0800362 except errors.VerifyOldBehaviorFailed:
Kuang-che Wu8b654092018-11-09 17:56:25 +0800363 logger.fatal('expect old chrome has old behavior but failed')
364 raise
365 except Exception:
366 logger.exception('exception in chrome bisector before verification; '
367 'assume culprit is not inside chrome and continue')
368
369 eval_cmd = common_eval_cmd + ['--reinstall']
370 diagnoser.narrow_down_chromeos_localbuild(eval_cmd)
371 logger.info('%s done', __file__)
372 except Exception as e:
373 logger.exception('got exception; stop')
374 exception_name = e.__class__.__name__
375 self.states.add_history(
376 'failed', '%s: %s' % (exception_name, e), exception=exception_name)
377
378 def cmd_log(self, opts):
379 self.states.load()
Kuang-che Wua41525a2018-10-17 23:52:24 +0800380 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
381 self.config['mirror_base'], self.config['work_base'],
382 self.config['session'])
Kuang-che Wu8b654092018-11-09 17:56:25 +0800383 diagnoser = diagnoser_cros.CrosDiagnoser(
384 self.states, self.config['session'], path_factory,
385 self.config['chromeos_root'], self.config['chromeos_mirror'],
386 self.config['android_root'], self.config['android_mirror'],
387 self.config['chrome_root'], self.config['chrome_mirror'],
388 self.config['board'], self.config['noisy'], None)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800389
Kuang-che Wu8b654092018-11-09 17:56:25 +0800390 diagnoser.cmd_log(opts.json)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800391
Kuang-che Wue80bb872018-11-15 19:45:25 +0800392 def cmd_view(self, opts):
393 self.states.load()
394 path_factory = setup_cros_bisect.DefaultProjectPathFactory(
395 self.config['mirror_base'], self.config['work_base'],
396 self.config['session'])
397 diagnoser = diagnoser_cros.CrosDiagnoser(
398 self.states, self.config['session'], path_factory,
399 self.config['chromeos_root'], self.config['chromeos_mirror'],
400 self.config['android_root'], self.config['android_mirror'],
401 self.config['chrome_root'], self.config['chrome_mirror'],
402 self.config['board'], self.config['noisy'], None)
403 diagnoser.cmd_view(opts.json, opts.verbose)
404
Kuang-che Wua41525a2018-10-17 23:52:24 +0800405 def create_argument_parser(self):
406 parser = argparse.ArgumentParser()
407 common.add_common_arguments(parser)
408 parser.add_argument('--session_base', default='bisect.sessions')
409 parser.add_argument('--session', help='Session name', required=True)
410 subparsers = parser.add_subparsers(
411 dest='command', title='commands', metavar='<command>')
412
413 parser_init = subparsers.add_parser('init', help='Initialize')
414 group = parser_init.add_argument_group(
415 title='Source tree path options',
416 description='''
417 Specify the paths of chromeos/chrome/android mirror and checkout. They
418 have the same default values as setup_cros_bisect.py, so usually you can
419 omit them and it just works.
420 ''')
421 group.add_argument(
422 '--mirror_base',
423 metavar='MIRROR_BASE',
424 default=configure.get('MIRROR_BASE',
425 setup_cros_bisect.DEFAULT_MIRROR_BASE),
426 help='Directory for mirrors (default: %(default)s)')
427 group.add_argument(
428 '--work_base',
429 metavar='WORK_BASE',
430 default=configure.get('WORK_BASE', setup_cros_bisect.DEFAULT_WORK_BASE),
431 help='Directory for bisection working directories '
432 '(default: %(default)s)')
433 group.add_argument(
434 '--chromeos_root',
435 metavar='CHROMEOS_ROOT',
436 type=cli.argtype_dir_path,
437 default=configure.get('CHROMEOS_ROOT'),
438 help='ChromeOS tree root')
439 group.add_argument(
440 '--chromeos_mirror',
441 type=cli.argtype_dir_path,
442 default=configure.get('CHROMEOS_MIRROR'),
443 help='ChromeOS repo mirror path')
444 group.add_argument(
445 '--android_root',
446 metavar='ANDROID_ROOT',
447 type=cli.argtype_dir_path,
448 default=configure.get('ANDROID_ROOT'),
449 help='Android tree root')
450 group.add_argument(
451 '--android_mirror',
452 type=cli.argtype_dir_path,
453 default=configure.get('ANDROID_MIRROR'),
454 help='Android repo mirror path')
455 group.add_argument(
456 '--chrome_root',
457 metavar='CHROME_ROOT',
458 type=cli.argtype_dir_path,
459 default=configure.get('CHROME_ROOT'),
460 help='Chrome tree root')
461 group.add_argument(
462 '--chrome_mirror',
463 metavar='CHROME_MIRROR',
464 type=cli.argtype_dir_path,
465 default=configure.get('CHROME_MIRROR'),
466 help="chrome's gclient cache dir")
467
Kuang-che Wu248c5182018-10-19 17:08:11 +0800468 group = parser_init.add_argument_group(title='DUT allocation options')
469 group.add_argument(
470 '--dut',
471 metavar='DUT',
472 required=True,
473 help='Address of DUT (Device Under Test). If "%s", DUT will be '
474 'automatically allocated from the lab' % cros_lab_util.LAB_DUT)
475 group.add_argument(
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800476 '--pools',
477 type=cli.argtype_notempty,
Kuang-che Wu8c6d9dd2019-01-16 10:29:13 +0800478 default='suites',
Kuang-che Wufcac3f22019-01-10 00:36:42 +0800479 help='Desired pools, comma separated and ordered by preference '
480 '(default: %(default)s)')
481 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800482 '--model',
483 metavar='MODEL',
484 help='"model" criteria if DUT is auto allocated from the lab')
485 group.add_argument(
486 '--sku',
487 metavar='SKU',
488 help='"sku" criteria if DUT is auto allocated from the lab')
489
Kuang-che Wua41525a2018-10-17 23:52:24 +0800490 group = parser_init.add_argument_group(title='Essential options')
491 group.add_argument(
Kuang-che Wu248c5182018-10-19 17:08:11 +0800492 '--board',
493 metavar='BOARD',
494 default=configure.get('BOARD'),
495 help='ChromeOS board name; auto detected if DUT is not auto allocated')
496 group.add_argument(
Kuang-che Wua41525a2018-10-17 23:52:24 +0800497 '--old',
498 type=cros_util.argtype_cros_version,
499 required=True,
500 help='ChromeOS version with old behavior')
501 group.add_argument(
502 '--new',
503 type=cros_util.argtype_cros_version,
504 required=True,
505 help='ChromeOS version with new behavior')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800506
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800507 group = parser_init.add_argument_group(
508 title='Options for normal autotest tests')
509 group.add_argument('--test_name', help='Test name')
Kuang-che Wu0a4304a2019-01-19 01:32:11 +0800510 group.add_argument(
511 '--fail_to_pass',
512 action='store_true',
513 help='For functional tests: bisect the CL fixed the regression (when '
514 'test became PASS). If not specified, the default is to bisect the CL '
515 'which broke the test (when test became FAIL)')
Kuang-che Wua41525a2018-10-17 23:52:24 +0800516 group.add_argument('--metric', help='Metric name of benchmark test')
517 group.add_argument(
518 '--old_value',
519 type=float,
520 help='For benchmark test, old value of metric')
521 group.add_argument(
522 '--new_value',
523 type=float,
524 help='For benchmark test, new value of metric')
525
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800526 group = parser_init.add_argument_group(title='Options for CTS/GTS tests')
527 group.add_argument('--cts_revision', help='CTS revision, like "9.0_r3"')
Kuang-che Wu63f836a2019-02-21 16:33:32 +0000528 group.add_argument('--cts_abi', choices=['arm', 'x86'])
Kuang-che Wu85c613c2019-01-09 15:46:11 +0800529 group.add_argument(
530 '--cts_prefix',
531 help='Prefix of autotest test name, '
532 'like cheets_CTS_N, cheets_CTS_P, cheets_GTS')
533 group.add_argument(
534 '--cts_module', help='CTS/GTS module name, like "CtsCameraTestCases"')
535 group.add_argument(
536 '--cts_test',
537 help='CTS/GTS test name, like '
538 '"android.hardware.cts.CameraTest#testDisplayOrientation"')
539 group.add_argument('--cts_timeout', type=float, help='timeout, in seconds')
540
Kuang-che Wua41525a2018-10-17 23:52:24 +0800541 group = parser_init.add_argument_group(title='Options passed to test_that')
542 group.add_argument(
543 '--args',
544 help='Extra args passed to "test_that --args"; Overrides the default')
545
546 group = parser_init.add_argument_group(title='Bisect behavior options')
547 group.add_argument(
548 '--noisy',
549 help='Enable noisy binary search. Example value: "old=1/10,new=2/3"')
550 group.add_argument(
551 '--always_reflash',
552 action='store_true',
553 help='Do not trust ChromeOS version number of DUT and always reflash. '
554 'This is usually only needed when resume because previous bisect was '
555 'interrupted and the DUT may be in an unexpected state')
556 parser_init.set_defaults(func=self.cmd_init)
557
558 parser_run = subparsers.add_parser('run', help='Start auto bisection')
559 parser_run.set_defaults(func=self.cmd_run)
560
Kuang-che Wu8b654092018-11-09 17:56:25 +0800561 parser_log = subparsers.add_parser(
562 'log', help='Prints what has been done so far')
563 parser_log.add_argument(
564 '--json', action='store_true', help='Machine readable output')
565 parser_log.set_defaults(func=self.cmd_log)
566
Kuang-che Wue80bb872018-11-15 19:45:25 +0800567 parser_view = subparsers.add_parser(
568 'view', help='Prints summary of current status')
569 parser_view.add_argument('--verbose', '-v', action='store_true')
570 parser_view.add_argument(
571 '--json', action='store_true', help='Machine readable output')
572 parser_view.set_defaults(func=self.cmd_view)
573
Kuang-che Wua41525a2018-10-17 23:52:24 +0800574 return parser
575
576 def main(self, args=None):
577 opts = self.argument_parser.parse_args(args)
578 common.config_logging(opts)
579
580 session_base = configure.get('SESSION_BASE', common.DEFAULT_SESSION_BASE)
581 session_file = os.path.join(session_base, opts.session,
582 self.__class__.__name__)
Kuang-che Wu8b654092018-11-09 17:56:25 +0800583 self.states = diagnoser_cros.DiagnoseStates(session_file)
Kuang-che Wua41525a2018-10-17 23:52:24 +0800584 opts.func(opts)
Kuang-che Wu1fcc0222018-07-07 16:43:22 +0800585
586
587if __name__ == '__main__':
Kuang-che Wua41525a2018-10-17 23:52:24 +0800588 DiagnoseCommandLine().main()