blob: 99c4ad4f7317d2bca221cdcf668d387d6b01d6fa [file] [log] [blame]
Aviv Keshet021c19f2013-02-22 13:19:43 -08001#!/usr/bin/python
2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import argparse
Aviv Keshet0e5d5252013-04-26 16:01:36 -07007import os
Aviv Keshet1d991ea2013-06-12 17:24:23 -07008import signal
Aviv Keshet0e5d5252013-04-26 16:01:36 -07009import subprocess
Aviv Keshet021c19f2013-02-22 13:19:43 -080010import sys
11
Aviv Keshete43bccf2013-08-14 14:11:59 -070012import logging
13# Turn the logging level to INFO before importing other autotest
14# code, to avoid having failed import logging messages confuse the
15# test_that user.
16logging.basicConfig(level=logging.INFO)
17
Aviv Keshet021c19f2013-02-22 13:19:43 -080018import common
beeps4efdf032013-09-17 11:27:14 -070019from autotest_lib.client.common_lib import error, logging_manager
Aviv Keshete43bccf2013-08-14 14:11:59 -070020from autotest_lib.server import server_logging_config
Simran Basi14622bb2015-11-25 13:23:40 -080021from autotest_lib.server.cros.dynamic_suite import constants
22from autotest_lib.server.hosts import factory
23from autotest_lib.site_utils import test_runner_utils
Aviv Keshete43bccf2013-08-14 14:11:59 -070024
Aviv Keshetd4a04302013-04-30 15:48:30 -070025
Aviv Keshet0e5d5252013-04-26 16:01:36 -070026try:
27 from chromite.lib import cros_build_lib
28except ImportError:
29 print 'Unable to import chromite.'
30 print 'This script must be either:'
31 print ' - Be run in the chroot.'
32 print ' - (not yet supported) be run after running '
33 print ' ../utils/build_externals.py'
Aviv Keshet021c19f2013-02-22 13:19:43 -080034
Aviv Keshet2dc98932013-06-17 15:22:10 -070035_QUICKMERGE_SCRIPTNAME = '/mnt/host/source/chromite/bin/autotest_quickmerge'
beeps4efdf032013-09-17 11:27:14 -070036
37
38def _get_board_from_host(remote):
39 """Get the board of the remote host.
40
41 @param remote: string representing the IP of the remote host.
42
43 @return: A string representing the board of the remote host.
44 """
45 logging.info('Board unspecified, attempting to determine board from host.')
46 host = factory.create_host(remote)
47 try:
48 board = host.get_board().replace(constants.BOARD_PREFIX, '')
49 except error.AutoservRunError:
Simran Basi14622bb2015-11-25 13:23:40 -080050 raise test_runner_utils.TestThatRunError(
51 'Cannot determine board, please specify a --board option.')
beeps4efdf032013-09-17 11:27:14 -070052 logging.info('Detected host board: %s', board)
53 return board
54
55
Aviv Keshetd4a04302013-04-30 15:48:30 -070056def validate_arguments(arguments):
Aviv Keshet0e5d5252013-04-26 16:01:36 -070057 """
58 Validates parsed arguments.
59
60 @param arguments: arguments object, as parsed by ParseArguments
61 @raises: ValueError if arguments were invalid.
62 """
Aviv Keshetd4a04302013-04-30 15:48:30 -070063 if arguments.remote == ':lab:':
Aviv Keshet30322f92013-07-18 13:21:52 -070064 if arguments.args:
65 raise ValueError('--args flag not supported when running against '
66 ':lab:')
Aviv Keshetc5e46092013-07-19 10:15:40 -070067 if arguments.pretend:
68 raise ValueError('--pretend flag not supported when running '
69 'against :lab:')
Aviv Keshetc14951a2013-08-12 18:17:35 -070070 if arguments.ssh_verbosity:
71 raise ValueError('--ssh_verbosity flag not supported when running '
72 'against :lab:')
Prathmesh Prabhu68ee1c52017-07-05 10:21:18 -070073 if not arguments.board or arguments.build == test_runner_utils.NO_BUILD:
J. Richard Barnette7c556622015-12-07 13:36:22 -080074 raise ValueError('--board and --build are both required when '
75 'running against :lab:')
Laurence Goodby079312e2015-08-05 12:43:04 -070076 else:
77 if arguments.web:
78 raise ValueError('--web flag not supported when running locally')
Aviv Keshetc14951a2013-08-12 18:17:35 -070079
Aviv Keshetd4a04302013-04-30 15:48:30 -070080
81def parse_arguments(argv):
Aviv Keshet021c19f2013-02-22 13:19:43 -080082 """
83 Parse command line arguments
84
85 @param argv: argument list to parse
Laurence Goodbycbb5ba02015-08-11 11:26:53 -070086 @returns: parsed arguments
87 @raises SystemExit if arguments are malformed, or required arguments
88 are not present.
89 """
90 return _parse_arguments_internal(argv)[0]
91
92
93def _parse_arguments_internal(argv):
94 """
95 Parse command line arguments
96
97 @param argv: argument list to parse
Laurence Goodby079312e2015-08-05 12:43:04 -070098 @returns: tuple of parsed arguments and argv suitable for remote runs
Aviv Keshet7cd12312013-07-25 10:25:55 -070099 @raises SystemExit if arguments are malformed, or required arguments
100 are not present.
Aviv Keshet021c19f2013-02-22 13:19:43 -0800101 """
Laurence Goodby079312e2015-08-05 12:43:04 -0700102 local_parser, remote_argv = parse_local_arguments(argv)
103
104 parser = argparse.ArgumentParser(description='Run remote tests.',
105 parents=[local_parser])
Aviv Keshet021c19f2013-02-22 13:19:43 -0800106
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700107 parser.add_argument('remote', metavar='REMOTE',
Aviv Keshet021c19f2013-02-22 13:19:43 -0800108 help='hostname[:port] for remote device. Specify '
Aviv Keshet61078eb2015-11-18 09:14:12 -0800109 ':lab: to run in test lab. When tests are run in '
110 'the lab, test_that will use the client autotest '
111 'package for the build specified with --build, '
112 'and the lab server code rather than local '
113 'changes.')
Simran Basi14622bb2015-11-25 13:23:40 -0800114 test_runner_utils.add_common_args(parser)
Prathmesh Prabhu63f00aa2013-07-26 13:33:06 -0700115 default_board = cros_build_lib.GetDefaultBoard()
116 parser.add_argument('-b', '--board', metavar='BOARD', default=default_board,
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700117 action='store',
Prathmesh Prabhu63f00aa2013-07-26 13:33:06 -0700118 help='Board for which the test will run. Default: %s' %
119 (default_board or 'Not configured'))
C Shapirof0dda1b2017-10-31 11:50:33 -0600120 parser.add_argument('-m', '--model', metavar='MODEL', default='',
121 help='Specific model the test will run against. '
122 'Matches the model:FAKE_MODEL label for the host.')
Simran Basi14622bb2015-11-25 13:23:40 -0800123 parser.add_argument('-i', '--build', metavar='BUILD',
124 default=test_runner_utils.NO_BUILD,
Aviv Keshet021c19f2013-02-22 13:19:43 -0800125 help='Build to test. Device will be reimaged if '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700126 'necessary. Omit flag to skip reimage and test '
Aviv Keshet21137742014-01-10 14:52:38 -0800127 'against already installed DUT image. Examples: '
128 'link-paladin/R34-5222.0.0-rc2, '
129 'lumpy-release/R34-5205.0.0')
J. Richard Barnette789f87c2015-03-23 16:25:25 -0700130 parser.add_argument('-p', '--pool', metavar='POOL', default='suites',
Simran Basib723b1b2015-02-04 14:25:52 -0800131 help='Pool to use when running tests in the lab. '
J. Richard Barnette789f87c2015-03-23 16:25:25 -0700132 'Default is "suites"')
Fang Dengb3ee20b2013-09-17 10:34:13 -0700133 parser.add_argument('--autotest_dir', metavar='AUTOTEST_DIR',
134 help='Use AUTOTEST_DIR instead of normal board sysroot '
135 'copy of autotest, and skip the quickmerge step.')
Aviv Keshet8ea71df2013-07-19 10:49:36 -0700136 parser.add_argument('--no-quickmerge', action='store_true', default=False,
137 dest='no_quickmerge',
138 help='Skip the quickmerge step and use the sysroot '
139 'as it currently is. May result in un-merged '
Jorge Lucangeli Obesad7309b2014-02-12 09:57:37 -0800140 'source tree changes not being reflected in the '
141 'run. If using --autotest_dir, this flag is '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700142 'automatically applied.')
Aviv Keshetfd775912013-08-06 11:37:16 -0700143 parser.add_argument('--whitelist-chrome-crashes', action='store_true',
144 default=False, dest='whitelist_chrome_crashes',
145 help='Ignore chrome crashes when producing test '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700146 'report. This flag gets passed along to the '
147 'report generation tool.')
Daniel Wang48e51172015-06-24 11:20:32 -0700148 parser.add_argument('--ssh_private_key', action='store',
Simran Basi14622bb2015-11-25 13:23:40 -0800149 default=test_runner_utils.TEST_KEY_PATH,
150 help='Path to the private ssh key.')
Laurence Goodby079312e2015-08-05 12:43:04 -0700151 return parser.parse_args(argv), remote_argv
152
153
154def parse_local_arguments(argv):
155 """
156 Strips out arguments that are not to be passed through to runs.
157
158 Add any arguments that should not be passed to remote test_that runs here.
159
160 @param argv: argument list to parse.
161 @returns: tuple of local argument parser and remaining argv.
162 """
163 parser = argparse.ArgumentParser(add_help=False)
164 parser.add_argument('-w', '--web', dest='web', default=None,
165 help='Address of a webserver to receive test requests.')
Laurence Goodby60dfcef2016-02-12 18:17:36 -0800166 parser.add_argument('-x', '--max_runtime_mins', type=int,
167 dest='max_runtime_mins', default=20,
168 help='Default time allowed for the tests to complete.')
Allen Li02b46c52017-09-11 11:48:12 -0700169 # TODO(crbug.com/763207): This is to support calling old moblab RPC
170 # with ToT code. This does not need to be supported after M62.
171 parser.add_argument('--oldrpc', action='store_true',
172 help='Use old AFE RPC.')
Laurence Goodby079312e2015-08-05 12:43:04 -0700173 _, remaining_argv = parser.parse_known_args(argv)
174 return parser, remaining_argv
Aviv Keshet021c19f2013-02-22 13:19:43 -0800175
176
Simran Basi14622bb2015-11-25 13:23:40 -0800177def perform_bootstrap_into_autotest_root(arguments, autotest_path, argv):
Aviv Keshet021c19f2013-02-22 13:19:43 -0800178 """
Fang Dengb3ee20b2013-09-17 10:34:13 -0700179 Perfoms a bootstrap to run test_that from the |autotest_path|.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700180
181 This function is to be called from test_that's main() script, when
182 test_that is executed from the source tree location. It runs
Fang Dengb3ee20b2013-09-17 10:34:13 -0700183 autotest_quickmerge to update the sysroot unless arguments.no_quickmerge
184 is set. It then executes and waits on the version of test_that.py
185 in |autotest_path|.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700186
187 @param arguments: A parsed arguments object, as returned from
Simran Basi14622bb2015-11-25 13:23:40 -0800188 test_that.parse_arguments(...).
Fang Dengb3ee20b2013-09-17 10:34:13 -0700189 @param autotest_path: Full absolute path to the autotest root directory.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700190 @param argv: The arguments list, as passed to main(...)
191
Fang Dengb3ee20b2013-09-17 10:34:13 -0700192 @returns: The return code of the test_that script that was executed in
193 |autotest_path|.
Aviv Keshet021c19f2013-02-22 13:19:43 -0800194 """
Aviv Keshete10e8d02013-09-09 17:04:58 -0700195 logging_manager.configure_logging(
196 server_logging_config.ServerLoggingConfig(),
197 use_console=True,
198 verbose=arguments.debug)
199 if arguments.no_quickmerge:
Fang Dengb3ee20b2013-09-17 10:34:13 -0700200 logging.info('Skipping quickmerge step.')
Aviv Keshete10e8d02013-09-09 17:04:58 -0700201 else:
202 logging.info('Running autotest_quickmerge step.')
Simran Basi8bd6d482015-04-21 17:12:26 -0700203 command = [_QUICKMERGE_SCRIPTNAME, '--board='+arguments.board]
Aviv Keshet6c028392013-07-22 12:57:32 -0700204 s = subprocess.Popen(command,
205 stdout=subprocess.PIPE,
206 stderr=subprocess.STDOUT)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700207 for message in iter(s.stdout.readline, b''):
Aviv Keshet95251242013-10-10 07:43:41 -0700208 logging.info('quickmerge| %s', message.strip())
Aviv Keshetf0229422013-10-24 10:12:14 -0400209 return_code = s.wait()
210 if return_code:
Simran Basi14622bb2015-11-25 13:23:40 -0800211 raise test_runner_utils.TestThatRunError(
212 'autotest_quickmerge failed with error code %s.' %
213 return_code)
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700214
Fang Dengb3ee20b2013-09-17 10:34:13 -0700215 logging.info('Re-running test_that script in %s copy of autotest.',
216 autotest_path)
217 script_command = os.path.join(autotest_path, 'site_utils',
Simran Basi14622bb2015-11-25 13:23:40 -0800218 'test_that.py')
Aviv Keshet1a6ce6e2013-10-22 12:32:38 -0400219 if not os.path.exists(script_command):
Simran Basi14622bb2015-11-25 13:23:40 -0800220 raise test_runner_utils.TestThatRunError(
221 'Unable to bootstrap to autotest root, %s not found.' %
222 script_command)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700223 proc = None
224 def resend_sig(signum, stack_frame):
225 #pylint: disable-msg=C0111
226 if proc:
227 proc.send_signal(signum)
228 signal.signal(signal.SIGINT, resend_sig)
229 signal.signal(signal.SIGTERM, resend_sig)
Aviv Keshet712128f2013-06-11 14:41:08 -0700230
Aviv Keshete10e8d02013-09-09 17:04:58 -0700231 proc = subprocess.Popen([script_command] + argv)
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700232
Aviv Keshete10e8d02013-09-09 17:04:58 -0700233 return proc.wait()
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700234
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700235
Aviv Keshet6f74e192013-09-23 11:09:07 -0700236def _main_for_local_run(argv, arguments):
237 """
238 Effective entry point for local test_that runs.
239
240 @param argv: Script command line arguments.
241 @param arguments: Parsed command line arguments.
242 """
243 if not cros_build_lib.IsInsideChroot():
244 print >> sys.stderr, 'For local runs, script must be run inside chroot.'
Aviv Keshete10e8d02013-09-09 17:04:58 -0700245 return 1
246
Simran Basi14622bb2015-11-25 13:23:40 -0800247 results_directory = test_runner_utils.create_results_directory(
248 arguments.results_dir)
249 test_runner_utils.add_ssh_identity(results_directory,
250 arguments.ssh_private_key)
beeps4efdf032013-09-17 11:27:14 -0700251 arguments.results_dir = results_directory
252
253 # If the board has not been specified through --board, and is not set in the
254 # default_board file, determine the board by ssh-ing into the host. Also
255 # prepend it to argv so we can re-use it when we run test_that from the
256 # sysroot.
257 if arguments.board is None:
258 arguments.board = _get_board_from_host(arguments.remote)
Allen Li910c6042016-10-24 17:52:25 -0700259 argv = ['--board=%s' % (arguments.board,)] + argv
beeps4efdf032013-09-17 11:27:14 -0700260
Fang Dengb3ee20b2013-09-17 10:34:13 -0700261 if arguments.autotest_dir:
262 autotest_path = arguments.autotest_dir
263 arguments.no_quickmerge = True
264 else:
265 sysroot_path = os.path.join('/build', arguments.board, '')
Aviv Keshet6c028392013-07-22 12:57:32 -0700266
Fang Dengb3ee20b2013-09-17 10:34:13 -0700267 if not os.path.exists(sysroot_path):
268 print >> sys.stderr, ('%s does not exist. Have you run '
269 'setup_board?' % sysroot_path)
270 return 1
Aviv Keshete10e8d02013-09-09 17:04:58 -0700271
Aviv Keshet2252db32015-04-08 10:36:09 -0700272 path_ending = 'usr/local/build/autotest'
Aviv Keshet6c028392013-07-22 12:57:32 -0700273 autotest_path = os.path.join(sysroot_path, path_ending)
274
Fang Dengb3ee20b2013-09-17 10:34:13 -0700275 site_utils_path = os.path.join(autotest_path, 'site_utils')
276
277 if not os.path.exists(autotest_path):
Aviv Keshete10e8d02013-09-09 17:04:58 -0700278 print >> sys.stderr, ('%s does not exist. Have you run '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700279 'build_packages? Or if you are using '
Kevin Cheng47b68ee2016-06-06 11:36:49 -0700280 '--autotest_dir, make sure it points to '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700281 'a valid autotest directory.' % autotest_path)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700282 return 1
283
284 realpath = os.path.realpath(__file__)
Fang Deng8a89e9b2014-10-08 11:35:42 -0700285 site_utils_path = os.path.realpath(site_utils_path)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700286
287 # If we are not running the sysroot version of script, perform
288 # a quickmerge if necessary and then re-execute
289 # the sysroot version of script with the same arguments.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700290 if os.path.dirname(realpath) != site_utils_path:
Simran Basi14622bb2015-11-25 13:23:40 -0800291 return perform_bootstrap_into_autotest_root(
Aviv Keshet2252db32015-04-08 10:36:09 -0700292 arguments, autotest_path, argv)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700293 else:
Simran Basi14622bb2015-11-25 13:23:40 -0800294 return test_runner_utils.perform_run_from_autotest_root(
295 autotest_path, argv, arguments.tests, arguments.remote,
296 build=arguments.build, board=arguments.board,
297 args=arguments.args, ignore_deps=not arguments.enforce_deps,
298 results_directory=results_directory,
299 ssh_verbosity=arguments.ssh_verbosity,
300 ssh_options=arguments.ssh_options,
301 iterations=arguments.iterations,
302 fast_mode=arguments.fast_mode, debug=arguments.debug,
Simran Basi57740ca2016-02-19 11:20:22 -0800303 whitelist_chrome_crashes=arguments.whitelist_chrome_crashes,
304 pretend=arguments.pretend)
Aviv Keshetba4992a2013-07-02 14:09:23 -0700305
Aviv Keshet021c19f2013-02-22 13:19:43 -0800306
Aviv Keshet6f74e192013-09-23 11:09:07 -0700307def _main_for_lab_run(argv, arguments):
308 """
309 Effective entry point for lab test_that runs.
310
311 @param argv: Script command line arguments.
312 @param arguments: Parsed command line arguments.
313 """
Prathmesh Prabhu42a0bff2017-12-19 13:36:02 -0800314 autotest_path = os.path.realpath(os.path.join(
315 os.path.dirname(os.path.realpath(__file__)),
316 '..',
317 ))
Aviv Keshet6f74e192013-09-23 11:09:07 -0700318 command = [os.path.join(autotest_path, 'site_utils',
319 'run_suite.py'),
Allen Li910c6042016-10-24 17:52:25 -0700320 '--board=%s' % (arguments.board,),
321 '--build=%s' % (arguments.build,),
C Shapirof0dda1b2017-10-31 11:50:33 -0600322 '--model=%s' % (arguments.model,),
Allen Li910c6042016-10-24 17:52:25 -0700323 '--suite_name=%s' % 'test_that_wrapper',
324 '--pool=%s' % (arguments.pool,),
325 '--max_runtime_mins=%s' % str(arguments.max_runtime_mins),
Allen Li429fd802017-08-07 15:36:25 -0700326 '--suite_args=%s'
Allen Li3c0d6cb2017-08-21 17:05:57 -0700327 % repr({'tests': _suite_arg_tests(argv)})]
Allen Li02b46c52017-09-11 11:48:12 -0700328 # TODO(crbug.com/763207): This is to support calling old moblab RPC
329 # with ToT code. This does not need to be supported after M62.
330 if arguments.oldrpc:
331 command.append('--oldrpc')
Laurence Goodby079312e2015-08-05 12:43:04 -0700332 if arguments.web:
Allen Li910c6042016-10-24 17:52:25 -0700333 command.extend(['--web=%s' % (arguments.web,)])
Aviv Keshet6f74e192013-09-23 11:09:07 -0700334 logging.info('About to start lab suite with command %s.', command)
335 return subprocess.call(command)
336
337
Allen Li429fd802017-08-07 15:36:25 -0700338def _suite_arg_tests(argv):
339 """
340 Construct a list of tests to pass into suite_args.
341
342 This is passed in suite_args to run_suite for running a test in the
343 lab.
344
345 @param argv: Remote Script command line arguments.
346 """
347 arguments = parse_arguments(argv)
348 return arguments.tests
349
350
Aviv Keshet6f74e192013-09-23 11:09:07 -0700351def main(argv):
352 """
353 Entry point for test_that script.
354
355 @param argv: arguments list
356 """
Laurence Goodbycbb5ba02015-08-11 11:26:53 -0700357 arguments, remote_argv = _parse_arguments_internal(argv)
Aviv Keshet6f74e192013-09-23 11:09:07 -0700358 try:
359 validate_arguments(arguments)
360 except ValueError as err:
361 print >> sys.stderr, ('Invalid arguments. %s' % err.message)
362 return 1
363
364 if arguments.remote == ':lab:':
Laurence Goodby079312e2015-08-05 12:43:04 -0700365 return _main_for_lab_run(remote_argv, arguments)
Aviv Keshet6f74e192013-09-23 11:09:07 -0700366 else:
367 return _main_for_local_run(argv, arguments)
368
369
Aviv Keshet021c19f2013-02-22 13:19:43 -0800370if __name__ == '__main__':
Aviv Keshetd4a04302013-04-30 15:48:30 -0700371 sys.exit(main(sys.argv[1:]))