blob: 7230cbb256783649f4c9c6e79af38a6804caba93 [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 Keshet15782de2013-07-31 11:40:41 -07007import errno
Aviv Keshet0e5d5252013-04-26 16:01:36 -07008import os
Aviv Keshet7cd12312013-07-25 10:25:55 -07009import pipes
Aviv Keshetd4a04302013-04-30 15:48:30 -070010import re
Aviv Keshet1de5bc62013-08-19 14:19:26 -070011import shutil
Aviv Keshet1d991ea2013-06-12 17:24:23 -070012import signal
Aviv Keshet1de5bc62013-08-19 14:19:26 -070013import stat
Aviv Keshet0e5d5252013-04-26 16:01:36 -070014import subprocess
Aviv Keshet021c19f2013-02-22 13:19:43 -080015import sys
Aviv Keshetd4a04302013-04-30 15:48:30 -070016import tempfile
Aviv Keshet1d991ea2013-06-12 17:24:23 -070017import threading
Aviv Keshet021c19f2013-02-22 13:19:43 -080018
Aviv Keshete43bccf2013-08-14 14:11:59 -070019import logging
20# Turn the logging level to INFO before importing other autotest
21# code, to avoid having failed import logging messages confuse the
22# test_that user.
23logging.basicConfig(level=logging.INFO)
24
Aviv Keshet021c19f2013-02-22 13:19:43 -080025import common
Aviv Keshet1d991ea2013-06-12 17:24:23 -070026from autotest_lib.client.common_lib.cros import dev_server, retry
beeps4efdf032013-09-17 11:27:14 -070027from autotest_lib.client.common_lib import error, logging_manager
28from autotest_lib.server.cros.dynamic_suite import suite, constants
Aviv Keshetf2b69102013-08-28 10:34:49 -070029from autotest_lib.server.cros import provision
beeps4efdf032013-09-17 11:27:14 -070030from autotest_lib.server.hosts import factory
Aviv Keshetd4a04302013-04-30 15:48:30 -070031from autotest_lib.server import autoserv_utils
Aviv Keshete43bccf2013-08-14 14:11:59 -070032from autotest_lib.server import server_logging_config
Fang Deng2db96762013-10-03 16:45:31 -070033from autotest_lib.server import utils
Aviv Keshete43bccf2013-08-14 14:11:59 -070034
Aviv Keshetd4a04302013-04-30 15:48:30 -070035
Aviv Keshet0e5d5252013-04-26 16:01:36 -070036try:
37 from chromite.lib import cros_build_lib
38except ImportError:
39 print 'Unable to import chromite.'
40 print 'This script must be either:'
41 print ' - Be run in the chroot.'
42 print ' - (not yet supported) be run after running '
43 print ' ../utils/build_externals.py'
Aviv Keshet021c19f2013-02-22 13:19:43 -080044
Aviv Keshet1d991ea2013-06-12 17:24:23 -070045_autoserv_proc = None
46_sigint_handler_lock = threading.Lock()
47
48_AUTOSERV_SIGINT_TIMEOUT_SECONDS = 5
Alex Millera0913072013-06-12 10:01:51 -070049_NO_BOARD = 'ad_hoc_board'
Aviv Keshet10711962013-06-24 12:20:33 -070050_NO_BUILD = 'ad_hoc_build'
Fang Dengb1da8302013-09-24 13:57:54 -070051_SUITE_REGEX = r'suite:(.*)'
Aviv Keshet1d991ea2013-06-12 17:24:23 -070052
Aviv Keshet2dc98932013-06-17 15:22:10 -070053_QUICKMERGE_SCRIPTNAME = '/mnt/host/source/chromite/bin/autotest_quickmerge'
Aviv Keshet1de5bc62013-08-19 14:19:26 -070054_TEST_KEY_FILENAME = 'testing_rsa'
55_TEST_KEY_PATH = ('/mnt/host/source/src/scripts/mod_for_test_scripts/'
56 'ssh_keys/%s' % _TEST_KEY_FILENAME)
Aviv Keshet2dc98932013-06-17 15:22:10 -070057
Aviv Keshetba4992a2013-07-02 14:09:23 -070058_TEST_REPORT_SCRIPTNAME = '/usr/bin/generate_test_report'
59
Aviv Keshetc9e74622013-07-18 10:11:11 -070060_LATEST_RESULTS_DIRECTORY = '/tmp/test_that_latest'
61
Aviv Keshetd4a04302013-04-30 15:48:30 -070062
beeps4efdf032013-09-17 11:27:14 -070063class TestThatRunError(Exception):
64 """Raised if test_that encounters something unexpected while running."""
65
66
Fang Deng9a841232013-09-17 16:29:14 -070067class TestThatProvisioningError(Exception):
68 """Raised when it fails to provision the DUT to the requested build."""
69
70
Fang Dengb1da8302013-09-24 13:57:54 -070071def schedule_local_suite(autotest_path, suite_predicate, afe, remote,
72 build=_NO_BUILD, board=_NO_BOARD,
73 results_directory=None, no_experimental=False,
74 ignore_deps=True):
75 """Schedule a suite against a mock afe object, for a local suite run.
76
77 Satisfaction of dependencies is enforced by Suite.schedule() if
78 ignore_deps is False. Note that this method assumes only one host,
79 i.e. |remote|, was added to afe. Suite.schedule() will not
80 schedule a job if none of the hosts in the afe (in our case,
81 just one host |remote|) has a label that matches a requested
82 test dependency.
83
Fang Dengb3ee20b2013-09-17 10:34:13 -070084 @param autotest_path: Absolute path to autotest (in sysroot or
85 custom autotest directory set by --autotest_dir).
Aviv Kesheta6adc7a2013-08-30 11:13:38 -070086 @param suite_predicate: callable that takes ControlData objects, and
87 returns True on those that should be in suite
Aviv Keshetd4a04302013-04-30 15:48:30 -070088 @param afe: afe object to schedule against (typically a directAFE)
Fang Dengb1da8302013-09-24 13:57:54 -070089 @param remote: String representing the IP of the remote host.
Aviv Keshetd4a04302013-04-30 15:48:30 -070090 @param build: Build to schedule suite for.
Aviv Keshet10711962013-06-24 12:20:33 -070091 @param board: Board to schedule suite for.
Aviv Keshetba4992a2013-07-02 14:09:23 -070092 @param results_directory: Absolute path of directory to store results in.
93 (results will be stored in subdirectory of this).
Aviv Keshete9170d92013-07-19 11:20:45 -070094 @param no_experimental: Skip experimental tests when scheduling a suite.
Fang Dengb1da8302013-09-24 13:57:54 -070095 @param ignore_deps: If True, test dependencies will be ignored.
96
Aviv Keshet69ebb6c2013-06-11 13:58:44 -070097 @returns: The number of tests scheduled.
Fang Dengb1da8302013-09-24 13:57:54 -070098
Aviv Keshetd4a04302013-04-30 15:48:30 -070099 """
100 fs_getter = suite.Suite.create_fs_getter(autotest_path)
101 devserver = dev_server.ImageServer('')
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700102 my_suite = suite.Suite.create_from_predicates([suite_predicate],
Fang Dengb1da8302013-09-24 13:57:54 -0700103 build, constants.BOARD_PREFIX + board,
104 devserver, fs_getter, afe=afe,
105 ignore_deps=ignore_deps,
beeps89f1e062013-09-18 12:00:17 -0700106 results_dir=results_directory, forgiving_parser=False)
Aviv Keshetd4a04302013-04-30 15:48:30 -0700107 if len(my_suite.tests) == 0:
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700108 raise ValueError('Suite contained no tests.')
Fang Dengb1da8302013-09-24 13:57:54 -0700109
110 if not ignore_deps:
111 # Log tests whose dependencies can't be satisfied.
112 labels = [label.name for label in
113 afe.get_labels(host__hostname=remote)]
114 for test in my_suite.tests:
115 if test.experimental and no_experimental:
116 continue
117 unsatisfiable_deps = set(test.dependencies).difference(labels)
118 if unsatisfiable_deps:
119 logging.warn('%s will be skipped, unsatisfiable '
120 'test dependencies: %s', test.name,
121 unsatisfiable_deps)
Aviv Keshete9170d92013-07-19 11:20:45 -0700122 # Schedule tests, discard record calls.
123 return my_suite.schedule(lambda x: None,
124 add_experimental=not no_experimental)
Aviv Keshet021c19f2013-02-22 13:19:43 -0800125
126
Fang Deng9a841232013-09-17 16:29:14 -0700127def _run_autoserv(command, pretend=False):
128 """Run autoserv command.
129
130 Run the autoserv command and wait on it. Log the stdout.
131 Ensure that SIGINT signals are passed along to autoserv.
132
133 @param command: the autoserv command to run.
134 @returns: exit code of the command.
135
136 """
137 if not pretend:
138 logging.debug('Running autoserv command: %s', command)
139 global _autoserv_proc
140 _autoserv_proc = subprocess.Popen(command,
141 stdout=subprocess.PIPE,
142 stderr=subprocess.STDOUT)
143 # This incantation forces unbuffered reading from stdout,
144 # so that autoserv output can be displayed to the user
145 # immediately.
146 for message in iter(_autoserv_proc.stdout.readline, b''):
147 logging.info('autoserv| %s', message.strip())
148
149 _autoserv_proc.wait()
150 returncode = _autoserv_proc.returncode
151 _autoserv_proc = None
152 else:
153 logging.info('Pretend mode. Would run autoserv command: %s',
154 command)
155 returncode = 0
156 return returncode
157
158
159def run_provisioning_job(provision_label, host, autotest_path,
160 results_directory, fast_mode,
161 ssh_verbosity=0, ssh_options=None,
162 pretend=False, autoserv_verbose=False):
163 """Shell out to autoserv to run provisioning job.
164
165 @param provision_label: Label to provision the machine to.
166 @param host: Hostname of DUT.
167 @param autotest_path: Absolute path of autotest directory.
168 @param results_directory: Absolute path of directory to store results in.
169 (results will be stored in subdirectory of this).
170 @param fast_mode: bool to use fast mode (disables slow autotest features).
171 @param ssh_verbosity: SSH verbosity level, passed along to autoserv_utils
172 @param ssh_options: Additional ssh options to be passed to autoserv_utils
173 @param pretend: If True, will print out autoserv commands rather than
174 running them.
175 @param autoserv_verbose: If true, pass the --verbose flag to autoserv.
176
177 @returns: Absolute path of directory where results were stored.
178
179 """
180 # TODO(fdeng): When running against a local DUT, autoserv
181 # is still hitting the AFE in the lab.
182 # provision_AutoUpdate checks the current build of DUT by
183 # retrieving build info from AFE. crosbug.com/295178
184 results_directory = os.path.join(results_directory, 'results-provision')
185 provision_arg = '='.join(['--provision', provision_label])
186 command = autoserv_utils.autoserv_run_job_command(
187 os.path.join(autotest_path, 'server'),
188 machines=host, job=None, verbose=autoserv_verbose,
189 results_directory=results_directory,
190 fast_mode=fast_mode, ssh_verbosity=ssh_verbosity,
191 ssh_options=ssh_options, extra_args=[provision_arg],
192 no_console_prefix=True)
193 if _run_autoserv(command, pretend) != 0:
194 raise TestThatProvisioningError('Command returns non-zero code: %s ' %
195 command)
196 return results_directory
197
198
Fang Dengb3ee20b2013-09-17 10:34:13 -0700199def run_job(job, host, autotest_path, results_directory, fast_mode,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700200 id_digits=1, ssh_verbosity=0, ssh_options=None,
201 args=None, pretend=False,
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700202 autoserv_verbose=False):
Aviv Keshetd4a04302013-04-30 15:48:30 -0700203 """
204 Shell out to autoserv to run an individual test job.
205
206 @param job: A Job object containing the control file contents and other
207 relevent metadata for this test.
208 @param host: Hostname of DUT to run test against.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700209 @param autotest_path: Absolute path of autotest directory.
Aviv Keshetc8824402013-06-29 20:37:30 -0700210 @param results_directory: Absolute path of directory to store results in.
211 (results will be stored in subdirectory of this).
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700212 @param fast_mode: bool to use fast mode (disables slow autotest features).
Aviv Keshet5e33c172013-07-16 05:00:49 -0700213 @param id_digits: The minimum number of digits that job ids should be
214 0-padded to when formatting as a string for results
215 directory.
Aviv Keshetc14951a2013-08-12 18:17:35 -0700216 @param ssh_verbosity: SSH verbosity level, passed along to autoserv_utils
Aviv Keshet6a704f72013-09-04 14:57:43 -0700217 @param ssh_options: Additional ssh options to be passed to autoserv_utils
Aviv Keshet30322f92013-07-18 13:21:52 -0700218 @param args: String that should be passed as args parameter to autoserv,
219 and then ultimitely to test itself.
Aviv Keshetc5e46092013-07-19 10:15:40 -0700220 @param pretend: If True, will print out autoserv commands rather than
221 running them.
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700222 @param autoserv_verbose: If true, pass the --verbose flag to autoserv.
Aviv Keshetc8824402013-06-29 20:37:30 -0700223 @returns: Absolute path of directory where results were stored.
Aviv Keshetd4a04302013-04-30 15:48:30 -0700224 """
225 with tempfile.NamedTemporaryFile() as temp_file:
226 temp_file.write(job.control_file)
227 temp_file.flush()
Aviv Keshetad7e34e2013-08-19 18:09:27 -0700228 name_tail = job.name.split('/')[-1]
Aviv Keshetc8824402013-06-29 20:37:30 -0700229 results_directory = os.path.join(results_directory,
Aviv Keshetad7e34e2013-08-19 18:09:27 -0700230 'results-%0*d-%s' % (id_digits, job.id,
231 name_tail))
Fang Deng2db96762013-10-03 16:45:31 -0700232 # Drop experimental keyval in the keval file in the job result folder.
233 os.makedirs(results_directory)
234 utils.write_keyval(results_directory,
235 {constants.JOB_EXPERIMENTAL_KEY: job.keyvals[
236 constants.JOB_EXPERIMENTAL_KEY]})
Aviv Keshet30322f92013-07-18 13:21:52 -0700237 extra_args = [temp_file.name]
238 if args:
239 extra_args.extend(['--args', args])
Aviv Keshetc8824402013-06-29 20:37:30 -0700240
Aviv Keshetd4a04302013-04-30 15:48:30 -0700241 command = autoserv_utils.autoserv_run_job_command(
Fang Dengb3ee20b2013-09-17 10:34:13 -0700242 os.path.join(autotest_path, 'server'),
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700243 machines=host, job=job, verbose=autoserv_verbose,
Aviv Keshetc8824402013-06-29 20:37:30 -0700244 results_directory=results_directory,
Aviv Keshetc14951a2013-08-12 18:17:35 -0700245 fast_mode=fast_mode, ssh_verbosity=ssh_verbosity,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700246 ssh_options=ssh_options,
Aviv Keshete43bccf2013-08-14 14:11:59 -0700247 extra_args=extra_args,
248 no_console_prefix=True)
Aviv Keshetc5e46092013-07-19 10:15:40 -0700249
Fang Deng9a841232013-09-17 16:29:14 -0700250 _run_autoserv(command, pretend)
251 return results_directory
Aviv Keshetd4a04302013-04-30 15:48:30 -0700252
253
254def setup_local_afe():
255 """
256 Setup a local afe database and return a direct_afe object to access it.
257
258 @returns: A autotest_lib.frontend.afe.direct_afe instance.
259 """
260 # This import statement is delayed until now rather than running at
261 # module load time, because it kicks off a local sqlite :memory: backed
262 # database, and we don't need that unless we are doing a local run.
263 from autotest_lib.frontend import setup_django_lite_environment
264 from autotest_lib.frontend.afe import direct_afe
265 return direct_afe.directAFE()
266
267
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700268def get_predicate_for_test_arg(test):
269 """
270 Gets a suite predicte function for a given command-line argument.
271
272 @param test: String. An individual TEST command line argument, e.g.
273 'login_CryptohomeMounted' or 'suite:smoke'
274 @returns: A (predicate, string) tuple with the necessary suite
275 predicate, and a description string of the suite that
276 this predicate will produce.
277 """
Fang Dengb1da8302013-09-24 13:57:54 -0700278 suitematch = re.match(_SUITE_REGEX, test)
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700279 name_pattern_match = re.match(r'e:(.*)', test)
280 file_pattern_match = re.match(r'f:(.*)', test)
281 if suitematch:
282 suitename = suitematch.group(1)
283 return (suite.Suite.name_in_tag_predicate(suitename),
284 'suite named %s' % suitename)
285 if name_pattern_match:
286 pattern = '^%s$' % name_pattern_match.group(1)
287 return (suite.Suite.test_name_matches_pattern_predicate(pattern),
288 'suite to match name pattern %s' % pattern)
289 if file_pattern_match:
290 pattern = '^%s$' % file_pattern_match.group(1)
291 return (suite.Suite.test_file_matches_pattern_predicate(pattern),
292 'suite to match file name pattern %s' % pattern)
293 return (suite.Suite.test_name_equals_predicate(test),
294 'job named %s' % test)
295
296
beeps4efdf032013-09-17 11:27:14 -0700297def _add_ssh_identity(temp_directory):
298 """Add an ssh identity to the agent.
299
300 @param temp_directory: A directory to copy the testing_rsa into.
301 """
302 # Add the testing key to the current ssh agent.
303 if os.environ.has_key('SSH_AGENT_PID'):
304 # Copy the testing key to the temp directory and make it NOT
305 # world-readable. Otherwise, ssh-add complains.
306 shutil.copy(_TEST_KEY_PATH, temp_directory)
307 key_copy_path = os.path.join(temp_directory, _TEST_KEY_FILENAME)
308 os.chmod(key_copy_path, stat.S_IRUSR | stat.S_IWUSR)
309 p = subprocess.Popen(['ssh-add', key_copy_path],
310 stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
311 p_out, _ = p.communicate()
312 for line in p_out.splitlines():
Fang Dengb1da8302013-09-24 13:57:54 -0700313 logging.info(line)
beeps4efdf032013-09-17 11:27:14 -0700314 else:
Fang Dengb1da8302013-09-24 13:57:54 -0700315 logging.warning('There appears to be no running ssh-agent. Attempting '
316 'to continue without running ssh-add, but ssh commands '
317 'may fail.')
beeps4efdf032013-09-17 11:27:14 -0700318
319
320def _get_board_from_host(remote):
321 """Get the board of the remote host.
322
323 @param remote: string representing the IP of the remote host.
324
325 @return: A string representing the board of the remote host.
326 """
327 logging.info('Board unspecified, attempting to determine board from host.')
328 host = factory.create_host(remote)
329 try:
330 board = host.get_board().replace(constants.BOARD_PREFIX, '')
331 except error.AutoservRunError:
332 raise TestThatRunError('Cannot determine board, please specify '
333 'a --board option.')
334 logging.info('Detected host board: %s', board)
335 return board
336
337
Fang Dengb1da8302013-09-24 13:57:54 -0700338def _auto_detect_labels(afe, remote):
339 """Automatically detect host labels and add them to the host in afe.
340
341 Note that the label of board will not be auto-detected.
342 This method assumes the host |remote| has already been added to afe.
343
344 @param afe: A direct_afe object used to interact with local afe database.
345 @param remote: The hostname of the remote device.
346
347 """
348 cros_host = factory.create_host(remote)
349 labels_to_create = [label for label in cros_host.get_labels()
350 if not label.startswith(constants.BOARD_PREFIX)]
351 labels_to_add_to_afe_host = []
352 for label in labels_to_create:
353 new_label = afe.create_label(label)
354 labels_to_add_to_afe_host.append(new_label.name)
355 hosts = afe.get_hosts(hostname=remote)
356 if not hosts:
357 raise TestThatRunError('Unexpected error: %s has not '
358 'been added to afe.' % remote)
359 afe_host = hosts[0]
360 afe_host.add_labels(labels_to_add_to_afe_host)
361
362
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700363def perform_local_run(afe, autotest_path, tests, remote, fast_mode,
Aviv Keshetc5e46092013-07-19 10:15:40 -0700364 build=_NO_BUILD, board=_NO_BOARD, args=None,
Aviv Keshet15782de2013-07-31 11:40:41 -0700365 pretend=False, no_experimental=False,
Fang Denga6d597a2013-10-10 13:58:42 -0700366 ignore_deps=True,
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700367 results_directory=None, ssh_verbosity=0,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700368 ssh_options=None,
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700369 autoserv_verbose=False):
Fang Dengb1da8302013-09-24 13:57:54 -0700370 """Perform local run of tests.
371
372 This method enforces satisfaction of test dependencies for tests that are
373 run as a part of a suite.
374
Aviv Keshetd4a04302013-04-30 15:48:30 -0700375 @param afe: A direct_afe object used to interact with local afe database.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700376 @param autotest_path: Absolute path of autotest installed in sysroot or
377 custom autotest path set by --autotest_dir.
Aviv Keshetd4a04302013-04-30 15:48:30 -0700378 @param tests: List of strings naming tests and suites to run. Suite strings
379 should be formed like "suite:smoke".
380 @param remote: Remote hostname.
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700381 @param fast_mode: bool to use fast mode (disables slow autotest features).
Aviv Keshetd4a04302013-04-30 15:48:30 -0700382 @param build: String specifying build for local run.
Aviv Keshet10711962013-06-24 12:20:33 -0700383 @param board: String specifyinb board for local run.
Aviv Keshet30322f92013-07-18 13:21:52 -0700384 @param args: String that should be passed as args parameter to autoserv,
385 and then ultimitely to test itself.
Aviv Keshetc5e46092013-07-19 10:15:40 -0700386 @param pretend: If True, will print out autoserv commands rather than
387 running them.
Aviv Keshete9170d92013-07-19 11:20:45 -0700388 @param no_experimental: Skip experimental tests when scheduling a suite.
Fang Denga6d597a2013-10-10 13:58:42 -0700389 @param ignore_deps: If True, test dependencies will be ignored.
Aviv Keshet15782de2013-07-31 11:40:41 -0700390 @param results_directory: Directory to store results in. Defaults to None,
391 in which case results will be stored in a new
392 subdirectory of /tmp
Aviv Keshetc14951a2013-08-12 18:17:35 -0700393 @param ssh_verbosity: SSH verbosity level, passed through to
394 autoserv_utils.
Aviv Keshet6a704f72013-09-04 14:57:43 -0700395 @param ssh_options: Additional ssh options to be passed to autoserv_utils
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700396 @param autoserv_verbose: If true, pass the --verbose flag to autoserv.
Aviv Keshetd4a04302013-04-30 15:48:30 -0700397 """
Fang Dengb1da8302013-09-24 13:57:54 -0700398
399 # Create host in afe, add board and build labels.
Fang Deng9a841232013-09-17 16:29:14 -0700400 cros_version_label = provision.cros_version_to_label(build)
401 build_label = afe.create_label(cros_version_label)
Fang Dengb1da8302013-09-24 13:57:54 -0700402 board_label = afe.create_label(constants.BOARD_PREFIX + board)
Aviv Keshetf2b69102013-08-28 10:34:49 -0700403 new_host = afe.create_host(remote)
404 new_host.add_labels([build_label.name, board_label.name])
Fang Denga6d597a2013-10-10 13:58:42 -0700405 if not ignore_deps:
406 logging.info('Auto-detecting labels for %s', remote)
407 _auto_detect_labels(afe, remote)
Fang Deng9a841232013-09-17 16:29:14 -0700408 # Provision the host to |build|.
409 if build != _NO_BUILD:
410 logging.info('Provisioning %s...', cros_version_label)
411 try:
412 run_provisioning_job(cros_version_label, remote, autotest_path,
413 results_directory, fast_mode,
414 ssh_verbosity, ssh_options,
415 pretend, autoserv_verbose)
416 except TestThatProvisioningError as e:
417 logging.error('Provisioning %s to %s failed, tests are aborted, '
418 'failure reason: %s',
419 remote, cros_version_label, e)
420 return
Aviv Keshetd4a04302013-04-30 15:48:30 -0700421
422 # Schedule tests / suites in local afe
423 for test in tests:
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700424 (predicate, description) = get_predicate_for_test_arg(test)
425 logging.info('Scheduling %s...', description)
426 ntests = schedule_local_suite(autotest_path, predicate, afe,
Fang Dengb1da8302013-09-24 13:57:54 -0700427 remote=remote,
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700428 build=build, board=board,
429 results_directory=results_directory,
Fang Dengb1da8302013-09-24 13:57:54 -0700430 no_experimental=no_experimental,
431 ignore_deps=ignore_deps)
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700432 logging.info('... scheduled %s job(s).', ntests)
Aviv Keshetd4a04302013-04-30 15:48:30 -0700433
Aviv Keshet5e33c172013-07-16 05:00:49 -0700434 if not afe.get_jobs():
435 logging.info('No jobs scheduled. End of local run.')
Fang Dengb1da8302013-09-24 13:57:54 -0700436 return
Aviv Keshet5e33c172013-07-16 05:00:49 -0700437
438 last_job_id = afe.get_jobs()[-1].id
Fang Dengb3ee20b2013-09-17 10:34:13 -0700439 job_id_digits = len(str(last_job_id))
Aviv Keshetd4a04302013-04-30 15:48:30 -0700440 for job in afe.get_jobs():
Aviv Keshet5e33c172013-07-16 05:00:49 -0700441 run_job(job, remote, autotest_path, results_directory, fast_mode,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700442 job_id_digits, ssh_verbosity, ssh_options, args, pretend,
443 autoserv_verbose)
Aviv Keshetd4a04302013-04-30 15:48:30 -0700444
Aviv Keshetd4a04302013-04-30 15:48:30 -0700445
446def validate_arguments(arguments):
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700447 """
448 Validates parsed arguments.
449
450 @param arguments: arguments object, as parsed by ParseArguments
451 @raises: ValueError if arguments were invalid.
452 """
Aviv Keshetd4a04302013-04-30 15:48:30 -0700453 if arguments.remote == ':lab:':
Aviv Keshet30322f92013-07-18 13:21:52 -0700454 if arguments.args:
455 raise ValueError('--args flag not supported when running against '
456 ':lab:')
Aviv Keshetc5e46092013-07-19 10:15:40 -0700457 if arguments.pretend:
458 raise ValueError('--pretend flag not supported when running '
459 'against :lab:')
Aviv Keshetc14951a2013-08-12 18:17:35 -0700460 if arguments.ssh_verbosity:
461 raise ValueError('--ssh_verbosity flag not supported when running '
462 'against :lab:')
463
Aviv Keshetd4a04302013-04-30 15:48:30 -0700464
465def parse_arguments(argv):
Aviv Keshet021c19f2013-02-22 13:19:43 -0800466 """
467 Parse command line arguments
468
469 @param argv: argument list to parse
470 @returns: parsed arguments.
Aviv Keshet7cd12312013-07-25 10:25:55 -0700471 @raises SystemExit if arguments are malformed, or required arguments
472 are not present.
Aviv Keshet021c19f2013-02-22 13:19:43 -0800473 """
474 parser = argparse.ArgumentParser(description='Run remote tests.')
475
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700476 parser.add_argument('remote', metavar='REMOTE',
Aviv Keshet021c19f2013-02-22 13:19:43 -0800477 help='hostname[:port] for remote device. Specify '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700478 ':lab: to run in test lab, or :vm:PORT_NUMBER to '
479 'run in vm.')
Aviv Keshet021c19f2013-02-22 13:19:43 -0800480 parser.add_argument('tests', nargs='+', metavar='TEST',
481 help='Run given test(s). Use suite:SUITE to specify '
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700482 'test suite. Use e:[NAME_PATTERN] to specify a '
483 'NAME-matching regular expression. Use '
484 'f:[FILE_PATTERN] to specify a filename matching '
485 'regular expression. Specified regular '
486 'expressiosn will be implicitly wrapped in '
487 '^ and $.')
Prathmesh Prabhu63f00aa2013-07-26 13:33:06 -0700488 default_board = cros_build_lib.GetDefaultBoard()
489 parser.add_argument('-b', '--board', metavar='BOARD', default=default_board,
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700490 action='store',
Prathmesh Prabhu63f00aa2013-07-26 13:33:06 -0700491 help='Board for which the test will run. Default: %s' %
492 (default_board or 'Not configured'))
Fang Deng9a841232013-09-17 16:29:14 -0700493 parser.add_argument('-i', '--build', metavar='BUILD', default=_NO_BUILD,
Aviv Keshet021c19f2013-02-22 13:19:43 -0800494 help='Build to test. Device will be reimaged if '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700495 'necessary. Omit flag to skip reimage and test '
Aviv Keshet21137742014-01-10 14:52:38 -0800496 'against already installed DUT image. Examples: '
497 'link-paladin/R34-5222.0.0-rc2, '
498 'lumpy-release/R34-5205.0.0')
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700499 parser.add_argument('--fast', action='store_true', dest='fast_mode',
500 default=False,
501 help='Enable fast mode. This will cause test_that to '
502 'skip time consuming steps like sysinfo and '
503 'collecting crash information.')
Aviv Keshetd4a04302013-04-30 15:48:30 -0700504 parser.add_argument('--args', metavar='ARGS',
Aviv Keshet30322f92013-07-18 13:21:52 -0700505 help='Argument string to pass through to test. Only '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700506 'supported for runs against a local DUT.')
Fang Dengb3ee20b2013-09-17 10:34:13 -0700507 parser.add_argument('--autotest_dir', metavar='AUTOTEST_DIR',
508 help='Use AUTOTEST_DIR instead of normal board sysroot '
509 'copy of autotest, and skip the quickmerge step.')
beeps4efdf032013-09-17 11:27:14 -0700510 parser.add_argument('--results_dir', metavar='RESULTS_DIR', default=None,
Aviv Keshet15782de2013-07-31 11:40:41 -0700511 help='Instead of storing results in a new subdirectory'
Aviv Keshete43bccf2013-08-14 14:11:59 -0700512 ' of /tmp , store results in RESULTS_DIR. If '
Dan Shi49db6aa2013-09-13 12:09:39 -0700513 'RESULTS_DIR already exists, it will be deleted.')
Aviv Keshetc5e46092013-07-19 10:15:40 -0700514 parser.add_argument('--pretend', action='store_true', default=False,
515 help='Print autoserv commands that would be run, '
516 'rather than running them.')
Aviv Keshet8ea71df2013-07-19 10:49:36 -0700517 parser.add_argument('--no-quickmerge', action='store_true', default=False,
518 dest='no_quickmerge',
519 help='Skip the quickmerge step and use the sysroot '
520 'as it currently is. May result in un-merged '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700521 'source tree changes not being reflected in run.'
522 'If using --autotest_dir, this flag is '
523 'automatically applied.')
Aviv Keshete9170d92013-07-19 11:20:45 -0700524 parser.add_argument('--no-experimental', action='store_true',
525 default=False, dest='no_experimental',
526 help='When scheduling a suite, skip any tests marked '
527 'as experimental. Applies only to tests scheduled'
528 ' via suite:[SUITE].')
Aviv Keshetfd775912013-08-06 11:37:16 -0700529 parser.add_argument('--whitelist-chrome-crashes', action='store_true',
530 default=False, dest='whitelist_chrome_crashes',
531 help='Ignore chrome crashes when producing test '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700532 'report. This flag gets passed along to the '
533 'report generation tool.')
Fang Denga6d597a2013-10-10 13:58:42 -0700534 parser.add_argument('--enforce-deps', action='store_true',
535 default=False, dest='enforce_deps',
536 help='Skip tests whose DEPENDENCIES can not '
537 'be satisfied.')
Aviv Keshetc14951a2013-08-12 18:17:35 -0700538 parser.add_argument('--ssh_verbosity', action='store', type=int,
539 choices=[0, 1, 2, 3], default=0,
540 help='Verbosity level for ssh, between 0 and 3 '
541 'inclusive.')
Aviv Keshet6a704f72013-09-04 14:57:43 -0700542 parser.add_argument('--ssh_options', action='store', default=None,
543 help='A string giving additional options to be '
544 'added to ssh commands.')
Aviv Keshete43bccf2013-08-14 14:11:59 -0700545 parser.add_argument('--debug', action='store_true',
546 help='Include DEBUG level messages in stdout. Note: '
547 'these messages will be included in output log '
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700548 'file regardless. In addition, turn on autoserv '
549 'verbosity.')
Aviv Keshet021c19f2013-02-22 13:19:43 -0800550 return parser.parse_args(argv)
551
552
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700553def sigint_handler(signum, stack_frame):
554 #pylint: disable-msg=C0111
555 """Handle SIGINT or SIGTERM to a local test_that run.
556
557 This handler sends a SIGINT to the running autoserv process,
558 if one is running, giving it up to 5 seconds to clean up and exit. After
559 the timeout elapses, autoserv is killed. In either case, after autoserv
560 exits then this process exits with status 1.
561 """
562 # If multiple signals arrive before handler is unset, ignore duplicates
563 if not _sigint_handler_lock.acquire(False):
564 return
565 try:
566 # Ignore future signals by unsetting handler.
567 signal.signal(signal.SIGINT, signal.SIG_IGN)
568 signal.signal(signal.SIGTERM, signal.SIG_IGN)
569
570 logging.warning('Received SIGINT or SIGTERM. Cleaning up and exiting.')
571 if _autoserv_proc:
572 logging.warning('Sending SIGINT to autoserv process. Waiting up '
573 'to %s seconds for cleanup.',
574 _AUTOSERV_SIGINT_TIMEOUT_SECONDS)
575 _autoserv_proc.send_signal(signal.SIGINT)
576 timed_out, _ = retry.timeout(_autoserv_proc.wait,
577 timeout_sec=_AUTOSERV_SIGINT_TIMEOUT_SECONDS)
578 if timed_out:
579 _autoserv_proc.kill()
580 logging.warning('Timed out waiting for autoserv to handle '
581 'SIGINT. Killed autoserv.')
582 finally:
583 _sigint_handler_lock.release() # this is not really necessary?
584 sys.exit(1)
585
586
beeps4efdf032013-09-17 11:27:14 -0700587def _create_results_directory(results_directory=None):
588 """Create a results directory.
589
590 If no directory is specified this method will create and return a
591 temp directory to hold results. If a directory name is specified this
592 method will create a directory at the given path, provided it doesn't
593 already exist.
594
595 @param results_directory: The path to the results_directory to create.
596
597 @return results_directory: A path to the results_directory, ready for use.
598 """
599 if results_directory is None:
600 # Create a results_directory as subdir of /tmp
601 results_directory = tempfile.mkdtemp(prefix='test_that_results_')
602 else:
603 # Delete results_directory if it already exists.
604 try:
605 shutil.rmtree(results_directory)
606 except OSError as e:
607 if e.errno != errno.ENOENT:
608 raise
609
610 # Create results_directory if it does not exist
611 try:
612 os.makedirs(results_directory)
613 except OSError as e:
614 if e.errno != errno.EEXIST:
615 raise
616 return results_directory
617
618
Aviv Keshet6c028392013-07-22 12:57:32 -0700619def _perform_bootstrap_into_autotest_root(arguments, autotest_path, argv,
620 legacy_path=False):
Aviv Keshet021c19f2013-02-22 13:19:43 -0800621 """
Fang Dengb3ee20b2013-09-17 10:34:13 -0700622 Perfoms a bootstrap to run test_that from the |autotest_path|.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700623
624 This function is to be called from test_that's main() script, when
625 test_that is executed from the source tree location. It runs
Fang Dengb3ee20b2013-09-17 10:34:13 -0700626 autotest_quickmerge to update the sysroot unless arguments.no_quickmerge
627 is set. It then executes and waits on the version of test_that.py
628 in |autotest_path|.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700629
630 @param arguments: A parsed arguments object, as returned from
631 parse_arguments(...).
Fang Dengb3ee20b2013-09-17 10:34:13 -0700632 @param autotest_path: Full absolute path to the autotest root directory.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700633 @param argv: The arguments list, as passed to main(...)
Aviv Keshet6c028392013-07-22 12:57:32 -0700634 @param legacy_path: Flag for backwards compatibility with builds
635 that have autotest in old usr/local/autotest location
Aviv Keshete10e8d02013-09-09 17:04:58 -0700636
Fang Dengb3ee20b2013-09-17 10:34:13 -0700637 @returns: The return code of the test_that script that was executed in
638 |autotest_path|.
Aviv Keshet021c19f2013-02-22 13:19:43 -0800639 """
Aviv Keshete10e8d02013-09-09 17:04:58 -0700640 logging_manager.configure_logging(
641 server_logging_config.ServerLoggingConfig(),
642 use_console=True,
643 verbose=arguments.debug)
644 if arguments.no_quickmerge:
Fang Dengb3ee20b2013-09-17 10:34:13 -0700645 logging.info('Skipping quickmerge step.')
Aviv Keshete10e8d02013-09-09 17:04:58 -0700646 else:
647 logging.info('Running autotest_quickmerge step.')
Aviv Keshet6c028392013-07-22 12:57:32 -0700648 command = [_QUICKMERGE_SCRIPTNAME, '--board='+arguments.board]
649 if legacy_path:
650 command.append('--legacy_path')
651 s = subprocess.Popen(command,
652 stdout=subprocess.PIPE,
653 stderr=subprocess.STDOUT)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700654 for message in iter(s.stdout.readline, b''):
Aviv Keshet95251242013-10-10 07:43:41 -0700655 logging.info('quickmerge| %s', message.strip())
Aviv Keshetf0229422013-10-24 10:12:14 -0400656 return_code = s.wait()
657 if return_code:
658 raise TestThatRunError('autotest_quickmerge failed with error code'
659 ' %s.' % return_code)
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700660
Fang Dengb3ee20b2013-09-17 10:34:13 -0700661 logging.info('Re-running test_that script in %s copy of autotest.',
662 autotest_path)
663 script_command = os.path.join(autotest_path, 'site_utils',
Aviv Keshete10e8d02013-09-09 17:04:58 -0700664 os.path.basename(__file__))
Aviv Keshet1a6ce6e2013-10-22 12:32:38 -0400665 if not os.path.exists(script_command):
666 raise TestThatRunError('Unable to bootstrap to autotest root, '
667 '%s not found.' % script_command)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700668 proc = None
669 def resend_sig(signum, stack_frame):
670 #pylint: disable-msg=C0111
671 if proc:
672 proc.send_signal(signum)
673 signal.signal(signal.SIGINT, resend_sig)
674 signal.signal(signal.SIGTERM, resend_sig)
Aviv Keshet712128f2013-06-11 14:41:08 -0700675
Aviv Keshete10e8d02013-09-09 17:04:58 -0700676 proc = subprocess.Popen([script_command] + argv)
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700677
Aviv Keshete10e8d02013-09-09 17:04:58 -0700678 return proc.wait()
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700679
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700680
Fang Dengb3ee20b2013-09-17 10:34:13 -0700681def _perform_run_from_autotest_root(arguments, autotest_path, argv):
Aviv Keshete10e8d02013-09-09 17:04:58 -0700682 """
Fang Dengb3ee20b2013-09-17 10:34:13 -0700683 Perform a test_that run, from the |autotest_path|.
Aviv Keshet2dc98932013-06-17 15:22:10 -0700684
Aviv Keshete10e8d02013-09-09 17:04:58 -0700685 This function is to be called from test_that's main() script, when
Fang Dengb3ee20b2013-09-17 10:34:13 -0700686 test_that is executed from the |autotest_path|. It handles all stages
687 of a test_that run that come after the bootstrap into |autotest_path|.
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700688
Aviv Keshete10e8d02013-09-09 17:04:58 -0700689 @param arguments: A parsed arguments object, as returned from
690 parse_arguments(...).
Fang Dengb3ee20b2013-09-17 10:34:13 -0700691 @param autotest_path: Full absolute path to the autotest root directory.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700692 @param argv: The arguments list, as passed to main(...)
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700693
Aviv Keshete10e8d02013-09-09 17:04:58 -0700694 @returns: A return code that test_that should exit with.
695 """
Aviv Keshete43bccf2013-08-14 14:11:59 -0700696 results_directory = arguments.results_dir
beeps4efdf032013-09-17 11:27:14 -0700697 if results_directory is None or not os.path.exists(results_directory):
698 raise ValueError('Expected valid results directory, got %s' %
699 results_directory)
Aviv Keshete43bccf2013-08-14 14:11:59 -0700700
701 logging_manager.configure_logging(
702 server_logging_config.ServerLoggingConfig(),
703 results_dir=results_directory,
704 use_console=True,
705 verbose=arguments.debug,
706 debug_log_name='test_that')
707 logging.info('Began logging to %s', results_directory)
708
Aviv Keshetbebd6212013-09-04 17:36:23 -0700709 logging.debug('test_that command line was: %s', argv)
710
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700711 signal.signal(signal.SIGINT, sigint_handler)
712 signal.signal(signal.SIGTERM, sigint_handler)
713
Aviv Keshet6f74e192013-09-23 11:09:07 -0700714 afe = setup_local_afe()
715 perform_local_run(afe, autotest_path, arguments.tests,
716 arguments.remote, arguments.fast_mode,
Fang Dengb1da8302013-09-24 13:57:54 -0700717 arguments.build, arguments.board,
Aviv Keshet6f74e192013-09-23 11:09:07 -0700718 args=arguments.args,
719 pretend=arguments.pretend,
720 no_experimental=arguments.no_experimental,
Fang Denga6d597a2013-10-10 13:58:42 -0700721 ignore_deps=not arguments.enforce_deps,
Aviv Keshet6f74e192013-09-23 11:09:07 -0700722 results_directory=results_directory,
723 ssh_verbosity=arguments.ssh_verbosity,
724 ssh_options=arguments.ssh_options,
725 autoserv_verbose=arguments.debug)
726 if arguments.pretend:
727 logging.info('Finished pretend run. Exiting.')
728 return 0
Aviv Keshetc5e46092013-07-19 10:15:40 -0700729
Aviv Keshet6f74e192013-09-23 11:09:07 -0700730 test_report_command = [_TEST_REPORT_SCRIPTNAME]
Fang Denga2227272013-10-03 11:26:43 -0700731 # Experimental test results do not influence the exit code.
732 test_report_command.append('--ignore_experimental_tests')
Aviv Keshet6f74e192013-09-23 11:09:07 -0700733 if arguments.whitelist_chrome_crashes:
734 test_report_command.append('--whitelist_chrome_crashes')
735 test_report_command.append(results_directory)
736 final_result = subprocess.call(test_report_command)
737 with open(os.path.join(results_directory, 'test_report.log'),
738 'w') as report_log:
739 subprocess.call(test_report_command, stdout=report_log)
740 logging.info('Finished running tests. Results can be found in %s',
741 results_directory)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700742 try:
Aviv Keshet6f74e192013-09-23 11:09:07 -0700743 os.unlink(_LATEST_RESULTS_DIRECTORY)
744 except OSError:
745 pass
746 os.symlink(results_directory, _LATEST_RESULTS_DIRECTORY)
747 return final_result
748
749
750def _main_for_local_run(argv, arguments):
751 """
752 Effective entry point for local test_that runs.
753
754 @param argv: Script command line arguments.
755 @param arguments: Parsed command line arguments.
756 """
757 if not cros_build_lib.IsInsideChroot():
758 print >> sys.stderr, 'For local runs, script must be run inside chroot.'
Aviv Keshete10e8d02013-09-09 17:04:58 -0700759 return 1
760
beeps4efdf032013-09-17 11:27:14 -0700761 results_directory = _create_results_directory(arguments.results_dir)
762 _add_ssh_identity(results_directory)
763 arguments.results_dir = results_directory
Aviv Keshet6c028392013-07-22 12:57:32 -0700764 legacy_path = False
beeps4efdf032013-09-17 11:27:14 -0700765
766 # If the board has not been specified through --board, and is not set in the
767 # default_board file, determine the board by ssh-ing into the host. Also
768 # prepend it to argv so we can re-use it when we run test_that from the
769 # sysroot.
770 if arguments.board is None:
771 arguments.board = _get_board_from_host(arguments.remote)
772 argv = ['--board', arguments.board] + argv
773
Fang Dengb3ee20b2013-09-17 10:34:13 -0700774 if arguments.autotest_dir:
775 autotest_path = arguments.autotest_dir
776 arguments.no_quickmerge = True
777 else:
778 sysroot_path = os.path.join('/build', arguments.board, '')
Aviv Keshet6c028392013-07-22 12:57:32 -0700779
Fang Dengb3ee20b2013-09-17 10:34:13 -0700780 if not os.path.exists(sysroot_path):
781 print >> sys.stderr, ('%s does not exist. Have you run '
782 'setup_board?' % sysroot_path)
783 return 1
Aviv Keshete10e8d02013-09-09 17:04:58 -0700784
Aviv Keshet6c028392013-07-22 12:57:32 -0700785 # For backwards compatibility with builds that pre-date
786 # https://chromium-review.googlesource.com/#/c/62880/
787 # This code can eventually be removed once those builds no longer need
788 # test_that support.
Aviv Keshet3f6c99a2013-10-31 15:01:56 -0700789 new_path = 'usr/local/build/autotest'
790 old_path = 'usr/local/autotest'
791 legacy_path = (os.path.exists(os.path.join(sysroot_path, old_path))
792 and not
793 os.path.exists(os.path.join(sysroot_path, new_path)))
Aviv Keshet6c028392013-07-22 12:57:32 -0700794 if legacy_path:
Aviv Keshet3f6c99a2013-10-31 15:01:56 -0700795 path_ending = old_path
Aviv Keshet6c028392013-07-22 12:57:32 -0700796 else:
Aviv Keshet3f6c99a2013-10-31 15:01:56 -0700797 path_ending = new_path
Aviv Keshet6c028392013-07-22 12:57:32 -0700798 autotest_path = os.path.join(sysroot_path, path_ending)
799
Fang Dengb3ee20b2013-09-17 10:34:13 -0700800 site_utils_path = os.path.join(autotest_path, 'site_utils')
801
802 if not os.path.exists(autotest_path):
Aviv Keshete10e8d02013-09-09 17:04:58 -0700803 print >> sys.stderr, ('%s does not exist. Have you run '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700804 'build_packages? Or if you are using '
805 '--autotest-dir, make sure it points to'
806 'a valid autotest directory.' % autotest_path)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700807 return 1
808
809 realpath = os.path.realpath(__file__)
810
811 # If we are not running the sysroot version of script, perform
812 # a quickmerge if necessary and then re-execute
813 # the sysroot version of script with the same arguments.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700814 if os.path.dirname(realpath) != site_utils_path:
815 return _perform_bootstrap_into_autotest_root(
Aviv Keshet6c028392013-07-22 12:57:32 -0700816 arguments, autotest_path, argv, legacy_path)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700817 else:
Fang Dengb3ee20b2013-09-17 10:34:13 -0700818 return _perform_run_from_autotest_root(
819 arguments, autotest_path, argv)
Aviv Keshetba4992a2013-07-02 14:09:23 -0700820
Aviv Keshet021c19f2013-02-22 13:19:43 -0800821
Aviv Keshet6f74e192013-09-23 11:09:07 -0700822def _main_for_lab_run(argv, arguments):
823 """
824 Effective entry point for lab test_that runs.
825
826 @param argv: Script command line arguments.
827 @param arguments: Parsed command line arguments.
828 """
829 autotest_path = os.path.realpath(os.path.join(os.path.dirname(__file__),
830 '..'))
831 flattened_argv = ' '.join([pipes.quote(item) for item in argv])
832 command = [os.path.join(autotest_path, 'site_utils',
833 'run_suite.py'),
834 '--board', arguments.board,
835 '--build', arguments.build,
836 '--suite_name', 'test_that_wrapper',
837 '--pool', 'try-bot',
838 '--suite_args', flattened_argv]
839 logging.info('About to start lab suite with command %s.', command)
840 return subprocess.call(command)
841
842
843def main(argv):
844 """
845 Entry point for test_that script.
846
847 @param argv: arguments list
848 """
849 arguments = parse_arguments(argv)
850 try:
851 validate_arguments(arguments)
852 except ValueError as err:
853 print >> sys.stderr, ('Invalid arguments. %s' % err.message)
854 return 1
855
856 if arguments.remote == ':lab:':
857 return _main_for_lab_run(argv, arguments)
858 else:
859 return _main_for_local_run(argv, arguments)
860
861
Aviv Keshet021c19f2013-02-22 13:19:43 -0800862if __name__ == '__main__':
Aviv Keshetd4a04302013-04-30 15:48:30 -0700863 sys.exit(main(sys.argv[1:]))