blob: 55834f4e9e72adbf06f3ee9f7ad28904acd2e606 [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
Aviv Keshet20b20c72014-04-02 11:54:28 -070071def fetch_local_suite(autotest_path, suite_predicate, afe, remote,
Fang Dengb1da8302013-09-24 13:57:54 -070072 build=_NO_BUILD, board=_NO_BOARD,
73 results_directory=None, no_experimental=False,
74 ignore_deps=True):
Aviv Keshet20b20c72014-04-02 11:54:28 -070075 """Create a suite from the given suite predicate.
Fang Dengb1da8302013-09-24 13:57:54 -070076
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 Keshet20b20c72014-04-02 11:54:28 -070097 @returns: A suite.Suite object.
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 Keshetf6e40242014-10-02 16:34:08 -0700108 raise ValueError('Found no tests. Check your suite name, test name, '
109 'or test matching wildcard.')
Fang Dengb1da8302013-09-24 13:57:54 -0700110
111 if not ignore_deps:
112 # Log tests whose dependencies can't be satisfied.
113 labels = [label.name for label in
114 afe.get_labels(host__hostname=remote)]
115 for test in my_suite.tests:
116 if test.experimental and no_experimental:
117 continue
118 unsatisfiable_deps = set(test.dependencies).difference(labels)
119 if unsatisfiable_deps:
Ilja H. Friedel04be2bd2014-05-07 21:29:59 -0700120 logging.warning('%s will be skipped, unsatisfiable '
Fang Dengb1da8302013-09-24 13:57:54 -0700121 'test dependencies: %s', test.name,
122 unsatisfiable_deps)
Aviv Keshet20b20c72014-04-02 11:54:28 -0700123 return my_suite
Aviv Keshet021c19f2013-02-22 13:19:43 -0800124
Fang Deng9a841232013-09-17 16:29:14 -0700125def _run_autoserv(command, pretend=False):
126 """Run autoserv command.
127
128 Run the autoserv command and wait on it. Log the stdout.
129 Ensure that SIGINT signals are passed along to autoserv.
130
131 @param command: the autoserv command to run.
132 @returns: exit code of the command.
133
134 """
135 if not pretend:
136 logging.debug('Running autoserv command: %s', command)
137 global _autoserv_proc
138 _autoserv_proc = subprocess.Popen(command,
139 stdout=subprocess.PIPE,
140 stderr=subprocess.STDOUT)
141 # This incantation forces unbuffered reading from stdout,
142 # so that autoserv output can be displayed to the user
143 # immediately.
144 for message in iter(_autoserv_proc.stdout.readline, b''):
145 logging.info('autoserv| %s', message.strip())
146
147 _autoserv_proc.wait()
148 returncode = _autoserv_proc.returncode
149 _autoserv_proc = None
150 else:
151 logging.info('Pretend mode. Would run autoserv command: %s',
152 command)
153 returncode = 0
154 return returncode
155
156
157def run_provisioning_job(provision_label, host, autotest_path,
158 results_directory, fast_mode,
159 ssh_verbosity=0, ssh_options=None,
160 pretend=False, autoserv_verbose=False):
161 """Shell out to autoserv to run provisioning job.
162
163 @param provision_label: Label to provision the machine to.
164 @param host: Hostname of DUT.
165 @param autotest_path: Absolute path of autotest directory.
166 @param results_directory: Absolute path of directory to store results in.
167 (results will be stored in subdirectory of this).
168 @param fast_mode: bool to use fast mode (disables slow autotest features).
169 @param ssh_verbosity: SSH verbosity level, passed along to autoserv_utils
170 @param ssh_options: Additional ssh options to be passed to autoserv_utils
171 @param pretend: If True, will print out autoserv commands rather than
172 running them.
173 @param autoserv_verbose: If true, pass the --verbose flag to autoserv.
174
175 @returns: Absolute path of directory where results were stored.
176
177 """
178 # TODO(fdeng): When running against a local DUT, autoserv
179 # is still hitting the AFE in the lab.
180 # provision_AutoUpdate checks the current build of DUT by
181 # retrieving build info from AFE. crosbug.com/295178
182 results_directory = os.path.join(results_directory, 'results-provision')
183 provision_arg = '='.join(['--provision', provision_label])
184 command = autoserv_utils.autoserv_run_job_command(
185 os.path.join(autotest_path, 'server'),
186 machines=host, job=None, verbose=autoserv_verbose,
187 results_directory=results_directory,
188 fast_mode=fast_mode, ssh_verbosity=ssh_verbosity,
189 ssh_options=ssh_options, extra_args=[provision_arg],
190 no_console_prefix=True)
191 if _run_autoserv(command, pretend) != 0:
192 raise TestThatProvisioningError('Command returns non-zero code: %s ' %
193 command)
194 return results_directory
195
196
Fang Dengb3ee20b2013-09-17 10:34:13 -0700197def run_job(job, host, autotest_path, results_directory, fast_mode,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700198 id_digits=1, ssh_verbosity=0, ssh_options=None,
199 args=None, pretend=False,
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700200 autoserv_verbose=False):
Aviv Keshetd4a04302013-04-30 15:48:30 -0700201 """
202 Shell out to autoserv to run an individual test job.
203
204 @param job: A Job object containing the control file contents and other
205 relevent metadata for this test.
206 @param host: Hostname of DUT to run test against.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700207 @param autotest_path: Absolute path of autotest directory.
Aviv Keshetc8824402013-06-29 20:37:30 -0700208 @param results_directory: Absolute path of directory to store results in.
209 (results will be stored in subdirectory of this).
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700210 @param fast_mode: bool to use fast mode (disables slow autotest features).
Aviv Keshet5e33c172013-07-16 05:00:49 -0700211 @param id_digits: The minimum number of digits that job ids should be
212 0-padded to when formatting as a string for results
213 directory.
Aviv Keshetc14951a2013-08-12 18:17:35 -0700214 @param ssh_verbosity: SSH verbosity level, passed along to autoserv_utils
Aviv Keshet6a704f72013-09-04 14:57:43 -0700215 @param ssh_options: Additional ssh options to be passed to autoserv_utils
Aviv Keshet30322f92013-07-18 13:21:52 -0700216 @param args: String that should be passed as args parameter to autoserv,
217 and then ultimitely to test itself.
Aviv Keshetc5e46092013-07-19 10:15:40 -0700218 @param pretend: If True, will print out autoserv commands rather than
219 running them.
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700220 @param autoserv_verbose: If true, pass the --verbose flag to autoserv.
Aviv Keshetc8824402013-06-29 20:37:30 -0700221 @returns: Absolute path of directory where results were stored.
Aviv Keshetd4a04302013-04-30 15:48:30 -0700222 """
223 with tempfile.NamedTemporaryFile() as temp_file:
224 temp_file.write(job.control_file)
225 temp_file.flush()
Aviv Keshetad7e34e2013-08-19 18:09:27 -0700226 name_tail = job.name.split('/')[-1]
Aviv Keshetc8824402013-06-29 20:37:30 -0700227 results_directory = os.path.join(results_directory,
Aviv Keshetad7e34e2013-08-19 18:09:27 -0700228 'results-%0*d-%s' % (id_digits, job.id,
229 name_tail))
Fang Deng2db96762013-10-03 16:45:31 -0700230 # Drop experimental keyval in the keval file in the job result folder.
231 os.makedirs(results_directory)
232 utils.write_keyval(results_directory,
233 {constants.JOB_EXPERIMENTAL_KEY: job.keyvals[
234 constants.JOB_EXPERIMENTAL_KEY]})
Aviv Keshet30322f92013-07-18 13:21:52 -0700235 extra_args = [temp_file.name]
236 if args:
237 extra_args.extend(['--args', args])
Aviv Keshetc8824402013-06-29 20:37:30 -0700238
Aviv Keshetd4a04302013-04-30 15:48:30 -0700239 command = autoserv_utils.autoserv_run_job_command(
Fang Dengb3ee20b2013-09-17 10:34:13 -0700240 os.path.join(autotest_path, 'server'),
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700241 machines=host, job=job, verbose=autoserv_verbose,
Aviv Keshetc8824402013-06-29 20:37:30 -0700242 results_directory=results_directory,
Aviv Keshetc14951a2013-08-12 18:17:35 -0700243 fast_mode=fast_mode, ssh_verbosity=ssh_verbosity,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700244 ssh_options=ssh_options,
Aviv Keshete43bccf2013-08-14 14:11:59 -0700245 extra_args=extra_args,
246 no_console_prefix=True)
Aviv Keshetc5e46092013-07-19 10:15:40 -0700247
Fang Deng9a841232013-09-17 16:29:14 -0700248 _run_autoserv(command, pretend)
249 return results_directory
Aviv Keshetd4a04302013-04-30 15:48:30 -0700250
251
252def setup_local_afe():
253 """
254 Setup a local afe database and return a direct_afe object to access it.
255
256 @returns: A autotest_lib.frontend.afe.direct_afe instance.
257 """
258 # This import statement is delayed until now rather than running at
259 # module load time, because it kicks off a local sqlite :memory: backed
260 # database, and we don't need that unless we are doing a local run.
261 from autotest_lib.frontend import setup_django_lite_environment
262 from autotest_lib.frontend.afe import direct_afe
263 return direct_afe.directAFE()
264
265
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700266def get_predicate_for_test_arg(test):
267 """
268 Gets a suite predicte function for a given command-line argument.
269
270 @param test: String. An individual TEST command line argument, e.g.
271 'login_CryptohomeMounted' or 'suite:smoke'
272 @returns: A (predicate, string) tuple with the necessary suite
273 predicate, and a description string of the suite that
274 this predicate will produce.
275 """
Fang Dengb1da8302013-09-24 13:57:54 -0700276 suitematch = re.match(_SUITE_REGEX, test)
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700277 name_pattern_match = re.match(r'e:(.*)', test)
278 file_pattern_match = re.match(r'f:(.*)', test)
279 if suitematch:
280 suitename = suitematch.group(1)
281 return (suite.Suite.name_in_tag_predicate(suitename),
282 'suite named %s' % suitename)
283 if name_pattern_match:
284 pattern = '^%s$' % name_pattern_match.group(1)
285 return (suite.Suite.test_name_matches_pattern_predicate(pattern),
286 'suite to match name pattern %s' % pattern)
287 if file_pattern_match:
288 pattern = '^%s$' % file_pattern_match.group(1)
289 return (suite.Suite.test_file_matches_pattern_predicate(pattern),
290 'suite to match file name pattern %s' % pattern)
291 return (suite.Suite.test_name_equals_predicate(test),
292 'job named %s' % test)
293
294
beeps4efdf032013-09-17 11:27:14 -0700295def _add_ssh_identity(temp_directory):
296 """Add an ssh identity to the agent.
297
298 @param temp_directory: A directory to copy the testing_rsa into.
299 """
300 # Add the testing key to the current ssh agent.
301 if os.environ.has_key('SSH_AGENT_PID'):
302 # Copy the testing key to the temp directory and make it NOT
303 # world-readable. Otherwise, ssh-add complains.
304 shutil.copy(_TEST_KEY_PATH, temp_directory)
305 key_copy_path = os.path.join(temp_directory, _TEST_KEY_FILENAME)
306 os.chmod(key_copy_path, stat.S_IRUSR | stat.S_IWUSR)
307 p = subprocess.Popen(['ssh-add', key_copy_path],
308 stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
309 p_out, _ = p.communicate()
310 for line in p_out.splitlines():
Fang Dengb1da8302013-09-24 13:57:54 -0700311 logging.info(line)
beeps4efdf032013-09-17 11:27:14 -0700312 else:
Fang Dengb1da8302013-09-24 13:57:54 -0700313 logging.warning('There appears to be no running ssh-agent. Attempting '
314 'to continue without running ssh-add, but ssh commands '
315 'may fail.')
beeps4efdf032013-09-17 11:27:14 -0700316
317
318def _get_board_from_host(remote):
319 """Get the board of the remote host.
320
321 @param remote: string representing the IP of the remote host.
322
323 @return: A string representing the board of the remote host.
324 """
325 logging.info('Board unspecified, attempting to determine board from host.')
326 host = factory.create_host(remote)
327 try:
328 board = host.get_board().replace(constants.BOARD_PREFIX, '')
329 except error.AutoservRunError:
330 raise TestThatRunError('Cannot determine board, please specify '
331 'a --board option.')
332 logging.info('Detected host board: %s', board)
333 return board
334
335
Fang Dengb1da8302013-09-24 13:57:54 -0700336def _auto_detect_labels(afe, remote):
337 """Automatically detect host labels and add them to the host in afe.
338
339 Note that the label of board will not be auto-detected.
340 This method assumes the host |remote| has already been added to afe.
341
342 @param afe: A direct_afe object used to interact with local afe database.
343 @param remote: The hostname of the remote device.
344
345 """
346 cros_host = factory.create_host(remote)
347 labels_to_create = [label for label in cros_host.get_labels()
348 if not label.startswith(constants.BOARD_PREFIX)]
349 labels_to_add_to_afe_host = []
350 for label in labels_to_create:
351 new_label = afe.create_label(label)
352 labels_to_add_to_afe_host.append(new_label.name)
353 hosts = afe.get_hosts(hostname=remote)
354 if not hosts:
355 raise TestThatRunError('Unexpected error: %s has not '
356 'been added to afe.' % remote)
357 afe_host = hosts[0]
358 afe_host.add_labels(labels_to_add_to_afe_host)
359
360
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700361def perform_local_run(afe, autotest_path, tests, remote, fast_mode,
Aviv Keshetc5e46092013-07-19 10:15:40 -0700362 build=_NO_BUILD, board=_NO_BOARD, args=None,
Aviv Keshet15782de2013-07-31 11:40:41 -0700363 pretend=False, no_experimental=False,
Fang Denga6d597a2013-10-10 13:58:42 -0700364 ignore_deps=True,
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700365 results_directory=None, ssh_verbosity=0,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700366 ssh_options=None,
Christopher Wiley2ce92d52014-03-14 11:07:49 -0700367 autoserv_verbose=False,
368 iterations=1):
Fang Dengb1da8302013-09-24 13:57:54 -0700369 """Perform local run of tests.
370
371 This method enforces satisfaction of test dependencies for tests that are
372 run as a part of a suite.
373
Aviv Keshetd4a04302013-04-30 15:48:30 -0700374 @param afe: A direct_afe object used to interact with local afe database.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700375 @param autotest_path: Absolute path of autotest installed in sysroot or
376 custom autotest path set by --autotest_dir.
Aviv Keshetd4a04302013-04-30 15:48:30 -0700377 @param tests: List of strings naming tests and suites to run. Suite strings
378 should be formed like "suite:smoke".
379 @param remote: Remote hostname.
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700380 @param fast_mode: bool to use fast mode (disables slow autotest features).
Aviv Keshetd4a04302013-04-30 15:48:30 -0700381 @param build: String specifying build for local run.
Aviv Keshet10711962013-06-24 12:20:33 -0700382 @param board: String specifyinb board for local run.
Aviv Keshet30322f92013-07-18 13:21:52 -0700383 @param args: String that should be passed as args parameter to autoserv,
384 and then ultimitely to test itself.
Aviv Keshetc5e46092013-07-19 10:15:40 -0700385 @param pretend: If True, will print out autoserv commands rather than
386 running them.
Aviv Keshete9170d92013-07-19 11:20:45 -0700387 @param no_experimental: Skip experimental tests when scheduling a suite.
Fang Denga6d597a2013-10-10 13:58:42 -0700388 @param ignore_deps: If True, test dependencies will be ignored.
Aviv Keshet15782de2013-07-31 11:40:41 -0700389 @param results_directory: Directory to store results in. Defaults to None,
390 in which case results will be stored in a new
391 subdirectory of /tmp
Aviv Keshetc14951a2013-08-12 18:17:35 -0700392 @param ssh_verbosity: SSH verbosity level, passed through to
393 autoserv_utils.
Aviv Keshet6a704f72013-09-04 14:57:43 -0700394 @param ssh_options: Additional ssh options to be passed to autoserv_utils
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700395 @param autoserv_verbose: If true, pass the --verbose flag to autoserv.
Christopher Wiley2ce92d52014-03-14 11:07:49 -0700396 @param iterations: int number of times to schedule tests.
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
Aviv Keshet20b20c72014-04-02 11:54:28 -0700422 # Create suites that will be scheduled.
423 suites_and_descriptions = []
424 for test in tests:
425 (predicate, description) = get_predicate_for_test_arg(test)
426 logging.info('Fetching suite for %s...', description)
427 suite = fetch_local_suite(autotest_path, predicate, afe,
428 remote=remote,
429 build=build, board=board,
430 results_directory=results_directory,
431 no_experimental=no_experimental,
432 ignore_deps=ignore_deps)
433 suites_and_descriptions.append((suite, description))
434
435 # Schedule the suites, looping over iterations if necessary.
Christopher Wiley2ce92d52014-03-14 11:07:49 -0700436 for iteration in range(iterations):
437 if iteration > 0:
438 logging.info('Repeating scheduling for iteration %d:', iteration)
Aviv Keshet20b20c72014-04-02 11:54:28 -0700439
440 for suite, description in suites_and_descriptions:
441 logging.info('Scheduling suite for %s...', description)
442 ntests = suite.schedule(
443 lambda log_entry, log_in_subdir=False: None,
444 add_experimental=not no_experimental)
Christopher Wiley2ce92d52014-03-14 11:07:49 -0700445 logging.info('... scheduled %s job(s).', ntests)
Aviv Keshetd4a04302013-04-30 15:48:30 -0700446
Aviv Keshet5e33c172013-07-16 05:00:49 -0700447 if not afe.get_jobs():
448 logging.info('No jobs scheduled. End of local run.')
Fang Dengb1da8302013-09-24 13:57:54 -0700449 return
Aviv Keshet5e33c172013-07-16 05:00:49 -0700450
451 last_job_id = afe.get_jobs()[-1].id
Fang Dengb3ee20b2013-09-17 10:34:13 -0700452 job_id_digits = len(str(last_job_id))
Aviv Keshetd4a04302013-04-30 15:48:30 -0700453 for job in afe.get_jobs():
Aviv Keshet5e33c172013-07-16 05:00:49 -0700454 run_job(job, remote, autotest_path, results_directory, fast_mode,
Aviv Keshet6a704f72013-09-04 14:57:43 -0700455 job_id_digits, ssh_verbosity, ssh_options, args, pretend,
456 autoserv_verbose)
Aviv Keshetd4a04302013-04-30 15:48:30 -0700457
Aviv Keshetd4a04302013-04-30 15:48:30 -0700458
459def validate_arguments(arguments):
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700460 """
461 Validates parsed arguments.
462
463 @param arguments: arguments object, as parsed by ParseArguments
464 @raises: ValueError if arguments were invalid.
465 """
Aviv Keshetd4a04302013-04-30 15:48:30 -0700466 if arguments.remote == ':lab:':
Aviv Keshet30322f92013-07-18 13:21:52 -0700467 if arguments.args:
468 raise ValueError('--args flag not supported when running against '
469 ':lab:')
Aviv Keshetc5e46092013-07-19 10:15:40 -0700470 if arguments.pretend:
471 raise ValueError('--pretend flag not supported when running '
472 'against :lab:')
Aviv Keshetc14951a2013-08-12 18:17:35 -0700473 if arguments.ssh_verbosity:
474 raise ValueError('--ssh_verbosity flag not supported when running '
475 'against :lab:')
476
Aviv Keshetd4a04302013-04-30 15:48:30 -0700477
478def parse_arguments(argv):
Aviv Keshet021c19f2013-02-22 13:19:43 -0800479 """
480 Parse command line arguments
481
482 @param argv: argument list to parse
483 @returns: parsed arguments.
Aviv Keshet7cd12312013-07-25 10:25:55 -0700484 @raises SystemExit if arguments are malformed, or required arguments
485 are not present.
Aviv Keshet021c19f2013-02-22 13:19:43 -0800486 """
487 parser = argparse.ArgumentParser(description='Run remote tests.')
488
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700489 parser.add_argument('remote', metavar='REMOTE',
Aviv Keshet021c19f2013-02-22 13:19:43 -0800490 help='hostname[:port] for remote device. Specify '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700491 ':lab: to run in test lab, or :vm:PORT_NUMBER to '
492 'run in vm.')
Aviv Keshet021c19f2013-02-22 13:19:43 -0800493 parser.add_argument('tests', nargs='+', metavar='TEST',
494 help='Run given test(s). Use suite:SUITE to specify '
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700495 'test suite. Use e:[NAME_PATTERN] to specify a '
496 'NAME-matching regular expression. Use '
497 'f:[FILE_PATTERN] to specify a filename matching '
498 'regular expression. Specified regular '
Jorge Lucangeli Obesf81917c2014-04-17 16:28:39 -0700499 'expressions will be implicitly wrapped in '
Aviv Kesheta6adc7a2013-08-30 11:13:38 -0700500 '^ and $.')
Prathmesh Prabhu63f00aa2013-07-26 13:33:06 -0700501 default_board = cros_build_lib.GetDefaultBoard()
502 parser.add_argument('-b', '--board', metavar='BOARD', default=default_board,
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700503 action='store',
Prathmesh Prabhu63f00aa2013-07-26 13:33:06 -0700504 help='Board for which the test will run. Default: %s' %
505 (default_board or 'Not configured'))
Fang Deng9a841232013-09-17 16:29:14 -0700506 parser.add_argument('-i', '--build', metavar='BUILD', default=_NO_BUILD,
Aviv Keshet021c19f2013-02-22 13:19:43 -0800507 help='Build to test. Device will be reimaged if '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700508 'necessary. Omit flag to skip reimage and test '
Aviv Keshet21137742014-01-10 14:52:38 -0800509 'against already installed DUT image. Examples: '
510 'link-paladin/R34-5222.0.0-rc2, '
511 'lumpy-release/R34-5205.0.0')
Christopher Wileyf6b5aae2013-07-09 10:14:02 -0700512 parser.add_argument('--fast', action='store_true', dest='fast_mode',
513 default=False,
514 help='Enable fast mode. This will cause test_that to '
515 'skip time consuming steps like sysinfo and '
516 'collecting crash information.')
Aviv Keshetd4a04302013-04-30 15:48:30 -0700517 parser.add_argument('--args', metavar='ARGS',
beepsf860bd12014-01-23 18:06:06 -0800518 help='Whitespace separated argument string to pass '
519 'through to test. Only supported for runs '
520 'against a local DUT.')
Fang Dengb3ee20b2013-09-17 10:34:13 -0700521 parser.add_argument('--autotest_dir', metavar='AUTOTEST_DIR',
522 help='Use AUTOTEST_DIR instead of normal board sysroot '
523 'copy of autotest, and skip the quickmerge step.')
beeps4efdf032013-09-17 11:27:14 -0700524 parser.add_argument('--results_dir', metavar='RESULTS_DIR', default=None,
Aviv Keshet15782de2013-07-31 11:40:41 -0700525 help='Instead of storing results in a new subdirectory'
Aviv Keshete43bccf2013-08-14 14:11:59 -0700526 ' of /tmp , store results in RESULTS_DIR. If '
Dan Shi49db6aa2013-09-13 12:09:39 -0700527 'RESULTS_DIR already exists, it will be deleted.')
Aviv Keshetc5e46092013-07-19 10:15:40 -0700528 parser.add_argument('--pretend', action='store_true', default=False,
529 help='Print autoserv commands that would be run, '
530 'rather than running them.')
Aviv Keshet8ea71df2013-07-19 10:49:36 -0700531 parser.add_argument('--no-quickmerge', action='store_true', default=False,
532 dest='no_quickmerge',
533 help='Skip the quickmerge step and use the sysroot '
534 'as it currently is. May result in un-merged '
Jorge Lucangeli Obesad7309b2014-02-12 09:57:37 -0800535 'source tree changes not being reflected in the '
536 'run. If using --autotest_dir, this flag is '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700537 'automatically applied.')
Aviv Keshete9170d92013-07-19 11:20:45 -0700538 parser.add_argument('--no-experimental', action='store_true',
539 default=False, dest='no_experimental',
540 help='When scheduling a suite, skip any tests marked '
541 'as experimental. Applies only to tests scheduled'
542 ' via suite:[SUITE].')
Aviv Keshetfd775912013-08-06 11:37:16 -0700543 parser.add_argument('--whitelist-chrome-crashes', action='store_true',
544 default=False, dest='whitelist_chrome_crashes',
545 help='Ignore chrome crashes when producing test '
Aviv Keshete43bccf2013-08-14 14:11:59 -0700546 'report. This flag gets passed along to the '
547 'report generation tool.')
Fang Denga6d597a2013-10-10 13:58:42 -0700548 parser.add_argument('--enforce-deps', action='store_true',
549 default=False, dest='enforce_deps',
550 help='Skip tests whose DEPENDENCIES can not '
551 'be satisfied.')
Aviv Keshetc14951a2013-08-12 18:17:35 -0700552 parser.add_argument('--ssh_verbosity', action='store', type=int,
553 choices=[0, 1, 2, 3], default=0,
554 help='Verbosity level for ssh, between 0 and 3 '
555 'inclusive.')
Aviv Keshet6a704f72013-09-04 14:57:43 -0700556 parser.add_argument('--ssh_options', action='store', default=None,
557 help='A string giving additional options to be '
558 'added to ssh commands.')
Aviv Keshete43bccf2013-08-14 14:11:59 -0700559 parser.add_argument('--debug', action='store_true',
560 help='Include DEBUG level messages in stdout. Note: '
561 'these messages will be included in output log '
Aviv Keshet2ebbd352013-08-27 17:04:43 -0700562 'file regardless. In addition, turn on autoserv '
563 'verbosity.')
Christopher Wiley2ce92d52014-03-14 11:07:49 -0700564 parser.add_argument('--iterations', action='store', type=int, default=1,
565 help='Number of times to run the tests specified.')
Aviv Keshet021c19f2013-02-22 13:19:43 -0800566 return parser.parse_args(argv)
567
568
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700569def sigint_handler(signum, stack_frame):
570 #pylint: disable-msg=C0111
571 """Handle SIGINT or SIGTERM to a local test_that run.
572
573 This handler sends a SIGINT to the running autoserv process,
574 if one is running, giving it up to 5 seconds to clean up and exit. After
575 the timeout elapses, autoserv is killed. In either case, after autoserv
576 exits then this process exits with status 1.
577 """
578 # If multiple signals arrive before handler is unset, ignore duplicates
579 if not _sigint_handler_lock.acquire(False):
580 return
581 try:
582 # Ignore future signals by unsetting handler.
583 signal.signal(signal.SIGINT, signal.SIG_IGN)
584 signal.signal(signal.SIGTERM, signal.SIG_IGN)
585
586 logging.warning('Received SIGINT or SIGTERM. Cleaning up and exiting.')
587 if _autoserv_proc:
588 logging.warning('Sending SIGINT to autoserv process. Waiting up '
589 'to %s seconds for cleanup.',
590 _AUTOSERV_SIGINT_TIMEOUT_SECONDS)
591 _autoserv_proc.send_signal(signal.SIGINT)
592 timed_out, _ = retry.timeout(_autoserv_proc.wait,
593 timeout_sec=_AUTOSERV_SIGINT_TIMEOUT_SECONDS)
594 if timed_out:
595 _autoserv_proc.kill()
596 logging.warning('Timed out waiting for autoserv to handle '
597 'SIGINT. Killed autoserv.')
598 finally:
599 _sigint_handler_lock.release() # this is not really necessary?
600 sys.exit(1)
601
602
beeps4efdf032013-09-17 11:27:14 -0700603def _create_results_directory(results_directory=None):
604 """Create a results directory.
605
606 If no directory is specified this method will create and return a
607 temp directory to hold results. If a directory name is specified this
608 method will create a directory at the given path, provided it doesn't
609 already exist.
610
611 @param results_directory: The path to the results_directory to create.
612
613 @return results_directory: A path to the results_directory, ready for use.
614 """
615 if results_directory is None:
616 # Create a results_directory as subdir of /tmp
617 results_directory = tempfile.mkdtemp(prefix='test_that_results_')
618 else:
619 # Delete results_directory if it already exists.
620 try:
621 shutil.rmtree(results_directory)
622 except OSError as e:
623 if e.errno != errno.ENOENT:
624 raise
625
626 # Create results_directory if it does not exist
627 try:
628 os.makedirs(results_directory)
629 except OSError as e:
630 if e.errno != errno.EEXIST:
631 raise
632 return results_directory
633
634
Aviv Keshet6c028392013-07-22 12:57:32 -0700635def _perform_bootstrap_into_autotest_root(arguments, autotest_path, argv,
636 legacy_path=False):
Aviv Keshet021c19f2013-02-22 13:19:43 -0800637 """
Fang Dengb3ee20b2013-09-17 10:34:13 -0700638 Perfoms a bootstrap to run test_that from the |autotest_path|.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700639
640 This function is to be called from test_that's main() script, when
641 test_that is executed from the source tree location. It runs
Fang Dengb3ee20b2013-09-17 10:34:13 -0700642 autotest_quickmerge to update the sysroot unless arguments.no_quickmerge
643 is set. It then executes and waits on the version of test_that.py
644 in |autotest_path|.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700645
646 @param arguments: A parsed arguments object, as returned from
647 parse_arguments(...).
Fang Dengb3ee20b2013-09-17 10:34:13 -0700648 @param autotest_path: Full absolute path to the autotest root directory.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700649 @param argv: The arguments list, as passed to main(...)
Aviv Keshet6c028392013-07-22 12:57:32 -0700650 @param legacy_path: Flag for backwards compatibility with builds
651 that have autotest in old usr/local/autotest location
Aviv Keshete10e8d02013-09-09 17:04:58 -0700652
Fang Dengb3ee20b2013-09-17 10:34:13 -0700653 @returns: The return code of the test_that script that was executed in
654 |autotest_path|.
Aviv Keshet021c19f2013-02-22 13:19:43 -0800655 """
Aviv Keshete10e8d02013-09-09 17:04:58 -0700656 logging_manager.configure_logging(
657 server_logging_config.ServerLoggingConfig(),
658 use_console=True,
659 verbose=arguments.debug)
660 if arguments.no_quickmerge:
Fang Dengb3ee20b2013-09-17 10:34:13 -0700661 logging.info('Skipping quickmerge step.')
Aviv Keshete10e8d02013-09-09 17:04:58 -0700662 else:
663 logging.info('Running autotest_quickmerge step.')
Aviv Keshet6c028392013-07-22 12:57:32 -0700664 command = [_QUICKMERGE_SCRIPTNAME, '--board='+arguments.board]
665 if legacy_path:
666 command.append('--legacy_path')
667 s = subprocess.Popen(command,
668 stdout=subprocess.PIPE,
669 stderr=subprocess.STDOUT)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700670 for message in iter(s.stdout.readline, b''):
Aviv Keshet95251242013-10-10 07:43:41 -0700671 logging.info('quickmerge| %s', message.strip())
Aviv Keshetf0229422013-10-24 10:12:14 -0400672 return_code = s.wait()
673 if return_code:
674 raise TestThatRunError('autotest_quickmerge failed with error code'
675 ' %s.' % return_code)
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700676
Fang Dengb3ee20b2013-09-17 10:34:13 -0700677 logging.info('Re-running test_that script in %s copy of autotest.',
678 autotest_path)
679 script_command = os.path.join(autotest_path, 'site_utils',
Aviv Keshete10e8d02013-09-09 17:04:58 -0700680 os.path.basename(__file__))
Aviv Keshet1a6ce6e2013-10-22 12:32:38 -0400681 if not os.path.exists(script_command):
682 raise TestThatRunError('Unable to bootstrap to autotest root, '
683 '%s not found.' % script_command)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700684 proc = None
685 def resend_sig(signum, stack_frame):
686 #pylint: disable-msg=C0111
687 if proc:
688 proc.send_signal(signum)
689 signal.signal(signal.SIGINT, resend_sig)
690 signal.signal(signal.SIGTERM, resend_sig)
Aviv Keshet712128f2013-06-11 14:41:08 -0700691
Aviv Keshete10e8d02013-09-09 17:04:58 -0700692 proc = subprocess.Popen([script_command] + argv)
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700693
Aviv Keshete10e8d02013-09-09 17:04:58 -0700694 return proc.wait()
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700695
Aviv Keshet0e5d5252013-04-26 16:01:36 -0700696
Fang Dengb3ee20b2013-09-17 10:34:13 -0700697def _perform_run_from_autotest_root(arguments, autotest_path, argv):
Aviv Keshete10e8d02013-09-09 17:04:58 -0700698 """
Fang Dengb3ee20b2013-09-17 10:34:13 -0700699 Perform a test_that run, from the |autotest_path|.
Aviv Keshet2dc98932013-06-17 15:22:10 -0700700
Aviv Keshete10e8d02013-09-09 17:04:58 -0700701 This function is to be called from test_that's main() script, when
Fang Dengb3ee20b2013-09-17 10:34:13 -0700702 test_that is executed from the |autotest_path|. It handles all stages
703 of a test_that run that come after the bootstrap into |autotest_path|.
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700704
Aviv Keshete10e8d02013-09-09 17:04:58 -0700705 @param arguments: A parsed arguments object, as returned from
706 parse_arguments(...).
Fang Dengb3ee20b2013-09-17 10:34:13 -0700707 @param autotest_path: Full absolute path to the autotest root directory.
Aviv Keshete10e8d02013-09-09 17:04:58 -0700708 @param argv: The arguments list, as passed to main(...)
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700709
Aviv Keshete10e8d02013-09-09 17:04:58 -0700710 @returns: A return code that test_that should exit with.
711 """
Aviv Keshete43bccf2013-08-14 14:11:59 -0700712 results_directory = arguments.results_dir
beeps4efdf032013-09-17 11:27:14 -0700713 if results_directory is None or not os.path.exists(results_directory):
714 raise ValueError('Expected valid results directory, got %s' %
715 results_directory)
Aviv Keshete43bccf2013-08-14 14:11:59 -0700716
717 logging_manager.configure_logging(
718 server_logging_config.ServerLoggingConfig(),
719 results_dir=results_directory,
720 use_console=True,
721 verbose=arguments.debug,
722 debug_log_name='test_that')
723 logging.info('Began logging to %s', results_directory)
724
Aviv Keshetbebd6212013-09-04 17:36:23 -0700725 logging.debug('test_that command line was: %s', argv)
726
Aviv Keshet1d991ea2013-06-12 17:24:23 -0700727 signal.signal(signal.SIGINT, sigint_handler)
728 signal.signal(signal.SIGTERM, sigint_handler)
729
Aviv Keshet6f74e192013-09-23 11:09:07 -0700730 afe = setup_local_afe()
731 perform_local_run(afe, autotest_path, arguments.tests,
732 arguments.remote, arguments.fast_mode,
Fang Dengb1da8302013-09-24 13:57:54 -0700733 arguments.build, arguments.board,
Aviv Keshet6f74e192013-09-23 11:09:07 -0700734 args=arguments.args,
735 pretend=arguments.pretend,
736 no_experimental=arguments.no_experimental,
Fang Denga6d597a2013-10-10 13:58:42 -0700737 ignore_deps=not arguments.enforce_deps,
Aviv Keshet6f74e192013-09-23 11:09:07 -0700738 results_directory=results_directory,
739 ssh_verbosity=arguments.ssh_verbosity,
740 ssh_options=arguments.ssh_options,
Christopher Wiley2ce92d52014-03-14 11:07:49 -0700741 autoserv_verbose=arguments.debug,
742 iterations=arguments.iterations)
Aviv Keshet6f74e192013-09-23 11:09:07 -0700743 if arguments.pretend:
744 logging.info('Finished pretend run. Exiting.')
745 return 0
Aviv Keshetc5e46092013-07-19 10:15:40 -0700746
Aviv Keshet6f74e192013-09-23 11:09:07 -0700747 test_report_command = [_TEST_REPORT_SCRIPTNAME]
Fang Denga2227272013-10-03 11:26:43 -0700748 # Experimental test results do not influence the exit code.
749 test_report_command.append('--ignore_experimental_tests')
Aviv Keshet6f74e192013-09-23 11:09:07 -0700750 if arguments.whitelist_chrome_crashes:
751 test_report_command.append('--whitelist_chrome_crashes')
752 test_report_command.append(results_directory)
753 final_result = subprocess.call(test_report_command)
754 with open(os.path.join(results_directory, 'test_report.log'),
755 'w') as report_log:
756 subprocess.call(test_report_command, stdout=report_log)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700757 try:
Aviv Keshet6f74e192013-09-23 11:09:07 -0700758 os.unlink(_LATEST_RESULTS_DIRECTORY)
759 except OSError:
760 pass
Josh Triplett63033412014-06-27 10:02:08 -0700761 link_target = os.path.relpath(results_directory,
762 os.path.dirname(_LATEST_RESULTS_DIRECTORY))
763 os.symlink(link_target, _LATEST_RESULTS_DIRECTORY)
Josh Triplett8e555332014-06-27 10:06:01 -0700764 logging.info('Finished running tests. Results can be found in %s or %s',
765 results_directory, _LATEST_RESULTS_DIRECTORY)
Aviv Keshet6f74e192013-09-23 11:09:07 -0700766 return final_result
767
768
769def _main_for_local_run(argv, arguments):
770 """
771 Effective entry point for local test_that runs.
772
773 @param argv: Script command line arguments.
774 @param arguments: Parsed command line arguments.
775 """
776 if not cros_build_lib.IsInsideChroot():
777 print >> sys.stderr, 'For local runs, script must be run inside chroot.'
Aviv Keshete10e8d02013-09-09 17:04:58 -0700778 return 1
779
beeps4efdf032013-09-17 11:27:14 -0700780 results_directory = _create_results_directory(arguments.results_dir)
781 _add_ssh_identity(results_directory)
782 arguments.results_dir = results_directory
Aviv Keshet6c028392013-07-22 12:57:32 -0700783 legacy_path = False
beeps4efdf032013-09-17 11:27:14 -0700784
785 # If the board has not been specified through --board, and is not set in the
786 # default_board file, determine the board by ssh-ing into the host. Also
787 # prepend it to argv so we can re-use it when we run test_that from the
788 # sysroot.
789 if arguments.board is None:
790 arguments.board = _get_board_from_host(arguments.remote)
791 argv = ['--board', arguments.board] + argv
792
Fang Dengb3ee20b2013-09-17 10:34:13 -0700793 if arguments.autotest_dir:
794 autotest_path = arguments.autotest_dir
795 arguments.no_quickmerge = True
796 else:
797 sysroot_path = os.path.join('/build', arguments.board, '')
Aviv Keshet6c028392013-07-22 12:57:32 -0700798
Fang Dengb3ee20b2013-09-17 10:34:13 -0700799 if not os.path.exists(sysroot_path):
800 print >> sys.stderr, ('%s does not exist. Have you run '
801 'setup_board?' % sysroot_path)
802 return 1
Aviv Keshete10e8d02013-09-09 17:04:58 -0700803
Aviv Keshet6c028392013-07-22 12:57:32 -0700804 # For backwards compatibility with builds that pre-date
805 # https://chromium-review.googlesource.com/#/c/62880/
806 # This code can eventually be removed once those builds no longer need
807 # test_that support.
Aviv Keshet3f6c99a2013-10-31 15:01:56 -0700808 new_path = 'usr/local/build/autotest'
809 old_path = 'usr/local/autotest'
810 legacy_path = (os.path.exists(os.path.join(sysroot_path, old_path))
811 and not
812 os.path.exists(os.path.join(sysroot_path, new_path)))
Aviv Keshet6c028392013-07-22 12:57:32 -0700813 if legacy_path:
Aviv Keshet3f6c99a2013-10-31 15:01:56 -0700814 path_ending = old_path
Aviv Keshet6c028392013-07-22 12:57:32 -0700815 else:
Aviv Keshet3f6c99a2013-10-31 15:01:56 -0700816 path_ending = new_path
Aviv Keshet6c028392013-07-22 12:57:32 -0700817 autotest_path = os.path.join(sysroot_path, path_ending)
818
Fang Dengb3ee20b2013-09-17 10:34:13 -0700819 site_utils_path = os.path.join(autotest_path, 'site_utils')
820
821 if not os.path.exists(autotest_path):
Aviv Keshete10e8d02013-09-09 17:04:58 -0700822 print >> sys.stderr, ('%s does not exist. Have you run '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700823 'build_packages? Or if you are using '
Jorge Lucangeli Obes89dc43d2014-05-29 14:44:04 -0700824 '--autotest-dir, make sure it points to '
Fang Dengb3ee20b2013-09-17 10:34:13 -0700825 'a valid autotest directory.' % autotest_path)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700826 return 1
827
828 realpath = os.path.realpath(__file__)
829
830 # If we are not running the sysroot version of script, perform
831 # a quickmerge if necessary and then re-execute
832 # the sysroot version of script with the same arguments.
Fang Dengb3ee20b2013-09-17 10:34:13 -0700833 if os.path.dirname(realpath) != site_utils_path:
834 return _perform_bootstrap_into_autotest_root(
Aviv Keshet6c028392013-07-22 12:57:32 -0700835 arguments, autotest_path, argv, legacy_path)
Aviv Keshete10e8d02013-09-09 17:04:58 -0700836 else:
Fang Dengb3ee20b2013-09-17 10:34:13 -0700837 return _perform_run_from_autotest_root(
838 arguments, autotest_path, argv)
Aviv Keshetba4992a2013-07-02 14:09:23 -0700839
Aviv Keshet021c19f2013-02-22 13:19:43 -0800840
Aviv Keshet6f74e192013-09-23 11:09:07 -0700841def _main_for_lab_run(argv, arguments):
842 """
843 Effective entry point for lab test_that runs.
844
845 @param argv: Script command line arguments.
846 @param arguments: Parsed command line arguments.
847 """
848 autotest_path = os.path.realpath(os.path.join(os.path.dirname(__file__),
849 '..'))
850 flattened_argv = ' '.join([pipes.quote(item) for item in argv])
851 command = [os.path.join(autotest_path, 'site_utils',
852 'run_suite.py'),
853 '--board', arguments.board,
854 '--build', arguments.build,
855 '--suite_name', 'test_that_wrapper',
856 '--pool', 'try-bot',
857 '--suite_args', flattened_argv]
858 logging.info('About to start lab suite with command %s.', command)
859 return subprocess.call(command)
860
861
862def main(argv):
863 """
864 Entry point for test_that script.
865
866 @param argv: arguments list
867 """
868 arguments = parse_arguments(argv)
869 try:
870 validate_arguments(arguments)
871 except ValueError as err:
872 print >> sys.stderr, ('Invalid arguments. %s' % err.message)
873 return 1
874
875 if arguments.remote == ':lab:':
876 return _main_for_lab_run(argv, arguments)
877 else:
878 return _main_for_local_run(argv, arguments)
879
880
Aviv Keshet021c19f2013-02-22 13:19:43 -0800881if __name__ == '__main__':
Aviv Keshetd4a04302013-04-30 15:48:30 -0700882 sys.exit(main(sys.argv[1:]))