1*9c5db199SXin Li#!/usr/bin/python3 2*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Lifrom __future__ import absolute_import 7*9c5db199SXin Lifrom __future__ import division 8*9c5db199SXin Lifrom __future__ import print_function 9*9c5db199SXin Li 10*9c5db199SXin Liimport argparse 11*9c5db199SXin Liimport json 12*9c5db199SXin Liimport os 13*9c5db199SXin Liimport signal 14*9c5db199SXin Liimport subprocess 15*9c5db199SXin Liimport sys 16*9c5db199SXin Li 17*9c5db199SXin Liimport logging 18*9c5db199SXin Li# Turn the logging level to INFO before importing other autotest 19*9c5db199SXin Li# code, to avoid having failed import logging messages confuse the 20*9c5db199SXin Li# test_that user. 21*9c5db199SXin Lilogging.basicConfig(level=logging.INFO) 22*9c5db199SXin Li 23*9c5db199SXin Liimport common 24*9c5db199SXin Lifrom autotest_lib.client.common_lib import error, logging_manager 25*9c5db199SXin Lifrom autotest_lib.server import server_logging_config 26*9c5db199SXin Lifrom autotest_lib.server.cros.dynamic_suite import constants 27*9c5db199SXin Lifrom autotest_lib.server.hosts import factory 28*9c5db199SXin Lifrom autotest_lib.site_utils import test_runner_utils 29*9c5db199SXin Li 30*9c5db199SXin Li 31*9c5db199SXin Li_QUICKMERGE_SCRIPTNAME = '/mnt/host/source/chromite/bin/autotest_quickmerge' 32*9c5db199SXin Li 33*9c5db199SXin Li 34*9c5db199SXin Lidef _get_info_from_host(remote, board=None, model=None, ssh_options=''): 35*9c5db199SXin Li """Get the info of the remote host if needed. 36*9c5db199SXin Li 37*9c5db199SXin Li @param remote: string representing the IP of the remote host. 38*9c5db199SXin Li @param board: board arg from CLI. 39*9c5db199SXin Li @param model: model arg from CLI. 40*9c5db199SXin Li 41*9c5db199SXin Li @return: board, model string representing the board, model 42*9c5db199SXin Li of the remote host. 43*9c5db199SXin Li """ 44*9c5db199SXin Li 45*9c5db199SXin Li if board and model: 46*9c5db199SXin Li return board, model 47*9c5db199SXin Li 48*9c5db199SXin Li host = factory.create_host(remote, ssh_options=ssh_options) 49*9c5db199SXin Li 50*9c5db199SXin Li if not board: 51*9c5db199SXin Li logging.info( 52*9c5db199SXin Li 'Board unspecified, attempting to determine board from host.') 53*9c5db199SXin Li try: 54*9c5db199SXin Li board = host.get_board().replace(constants.BOARD_PREFIX, '') 55*9c5db199SXin Li except error.AutoservRunError: 56*9c5db199SXin Li raise test_runner_utils.TestThatRunError( 57*9c5db199SXin Li 'Cannot determine board, please specify a --board option.') 58*9c5db199SXin Li logging.info('Detected host board: %s', board) 59*9c5db199SXin Li 60*9c5db199SXin Li if not model: 61*9c5db199SXin Li logging.info( 62*9c5db199SXin Li 'Model unspecified, attempting to determine model from host.') 63*9c5db199SXin Li try: 64*9c5db199SXin Li model = host.get_platform() 65*9c5db199SXin Li except error.AutoservRunError: 66*9c5db199SXin Li raise test_runner_utils.TestThatRunError( 67*9c5db199SXin Li 'Cannot determine model, please specify a --model option.') 68*9c5db199SXin Li logging.info('Detected host model: %s', model) 69*9c5db199SXin Li 70*9c5db199SXin Li return board, model 71*9c5db199SXin Li 72*9c5db199SXin Li 73*9c5db199SXin Lidef validate_arguments(arguments): 74*9c5db199SXin Li """ 75*9c5db199SXin Li Validates parsed arguments. 76*9c5db199SXin Li 77*9c5db199SXin Li @param arguments: arguments object, as parsed by ParseArguments 78*9c5db199SXin Li @raises: ValueError if arguments were invalid. 79*9c5db199SXin Li """ 80*9c5db199SXin Li if arguments.remote == ':lab:': 81*9c5db199SXin Li if arguments.args: 82*9c5db199SXin Li raise ValueError('--args flag not supported when running against ' 83*9c5db199SXin Li ':lab:') 84*9c5db199SXin Li if arguments.pretend: 85*9c5db199SXin Li raise ValueError('--pretend flag not supported when running ' 86*9c5db199SXin Li 'against :lab:') 87*9c5db199SXin Li if arguments.ssh_verbosity: 88*9c5db199SXin Li raise ValueError('--ssh_verbosity flag not supported when running ' 89*9c5db199SXin Li 'against :lab:') 90*9c5db199SXin Li if not arguments.board or arguments.build == test_runner_utils.NO_BUILD: 91*9c5db199SXin Li raise ValueError('--board and --build are both required when ' 92*9c5db199SXin Li 'running against :lab:') 93*9c5db199SXin Li else: 94*9c5db199SXin Li if arguments.web: 95*9c5db199SXin Li raise ValueError('--web flag not supported when running locally') 96*9c5db199SXin Li 97*9c5db199SXin Li try: 98*9c5db199SXin Li json.loads(arguments.host_attributes) 99*9c5db199SXin Li except TypeError: 100*9c5db199SXin Li raise ValueError("--host_attributes must be quoted dict, got: %s" % 101*9c5db199SXin Li arguments.host_attributes) 102*9c5db199SXin Li 103*9c5db199SXin Li 104*9c5db199SXin Lidef parse_arguments(argv): 105*9c5db199SXin Li """ 106*9c5db199SXin Li Parse command line arguments 107*9c5db199SXin Li 108*9c5db199SXin Li @param argv: argument list to parse 109*9c5db199SXin Li @returns: parsed arguments 110*9c5db199SXin Li @raises SystemExit if arguments are malformed, or required arguments 111*9c5db199SXin Li are not present. 112*9c5db199SXin Li """ 113*9c5db199SXin Li return _parse_arguments_internal(argv)[0] 114*9c5db199SXin Li 115*9c5db199SXin Li 116*9c5db199SXin Lidef _parse_arguments_internal(argv): 117*9c5db199SXin Li """ 118*9c5db199SXin Li Parse command line arguments 119*9c5db199SXin Li 120*9c5db199SXin Li @param argv: argument list to parse 121*9c5db199SXin Li @returns: tuple of parsed arguments and argv suitable for remote runs 122*9c5db199SXin Li @raises SystemExit if arguments are malformed, or required arguments 123*9c5db199SXin Li are not present. 124*9c5db199SXin Li """ 125*9c5db199SXin Li local_parser, remote_argv = parse_local_arguments(argv) 126*9c5db199SXin Li 127*9c5db199SXin Li parser = argparse.ArgumentParser(description='Run remote tests.', 128*9c5db199SXin Li parents=[local_parser]) 129*9c5db199SXin Li 130*9c5db199SXin Li parser.add_argument('remote', metavar='REMOTE', 131*9c5db199SXin Li help='hostname[:port] for remote device. Specify ' 132*9c5db199SXin Li ':lab: to run in test lab. When tests are run in ' 133*9c5db199SXin Li 'the lab, test_that will use the client autotest ' 134*9c5db199SXin Li 'package for the build specified with --build, ' 135*9c5db199SXin Li 'and the lab server code rather than local ' 136*9c5db199SXin Li 'changes.') 137*9c5db199SXin Li test_runner_utils.add_common_args(parser) 138*9c5db199SXin Li parser.add_argument('-b', '--board', metavar='BOARD', 139*9c5db199SXin Li action='store', 140*9c5db199SXin Li help='Board for which the test will run. ' 141*9c5db199SXin Li 'Default: %(default)s') 142*9c5db199SXin Li parser.add_argument('-m', 143*9c5db199SXin Li '--model', 144*9c5db199SXin Li metavar='MODEL', 145*9c5db199SXin Li help='Specific model the test will run against. ' 146*9c5db199SXin Li 'Matches the model:FAKE_MODEL label for the host.') 147*9c5db199SXin Li parser.add_argument('-i', '--build', metavar='BUILD', 148*9c5db199SXin Li default=test_runner_utils.NO_BUILD, 149*9c5db199SXin Li help='Build to test. Device will be reimaged if ' 150*9c5db199SXin Li 'necessary. Omit flag to skip reimage and test ' 151*9c5db199SXin Li 'against already installed DUT image. Examples: ' 152*9c5db199SXin Li 'link-paladin/R34-5222.0.0-rc2, ' 153*9c5db199SXin Li 'lumpy-release/R34-5205.0.0') 154*9c5db199SXin Li parser.add_argument('-p', '--pool', metavar='POOL', default='suites', 155*9c5db199SXin Li help='Pool to use when running tests in the lab. ' 156*9c5db199SXin Li 'Default is "suites"') 157*9c5db199SXin Li parser.add_argument('--autotest_dir', metavar='AUTOTEST_DIR', 158*9c5db199SXin Li help='Use AUTOTEST_DIR instead of normal board sysroot ' 159*9c5db199SXin Li 'copy of autotest, and skip the quickmerge step.') 160*9c5db199SXin Li parser.add_argument('--no-quickmerge', action='store_true', default=False, 161*9c5db199SXin Li dest='no_quickmerge', 162*9c5db199SXin Li help='Skip the quickmerge step and use the sysroot ' 163*9c5db199SXin Li 'as it currently is. May result in un-merged ' 164*9c5db199SXin Li 'source tree changes not being reflected in the ' 165*9c5db199SXin Li 'run. If using --autotest_dir, this flag is ' 166*9c5db199SXin Li 'automatically applied.') 167*9c5db199SXin Li parser.add_argument('--allow-chrome-crashes', 168*9c5db199SXin Li action='store_true', 169*9c5db199SXin Li default=False, 170*9c5db199SXin Li dest='allow_chrome_crashes', 171*9c5db199SXin Li help='Ignore chrome crashes when producing test ' 172*9c5db199SXin Li 'report. This flag gets passed along to the ' 173*9c5db199SXin Li 'report generation tool.') 174*9c5db199SXin Li parser.add_argument('--ssh_private_key', action='store', 175*9c5db199SXin Li default=test_runner_utils.TEST_KEY_PATH, 176*9c5db199SXin Li help='Path to the private ssh key.') 177*9c5db199SXin Li parser.add_argument( 178*9c5db199SXin Li '--companion_hosts', 179*9c5db199SXin Li action='store', 180*9c5db199SXin Li default=None, 181*9c5db199SXin Li help='Companion duts for the test, quoted space seperated strings') 182*9c5db199SXin Li parser.add_argument('--dut_servers', 183*9c5db199SXin Li action='store', 184*9c5db199SXin Li default=None, 185*9c5db199SXin Li help='DUT servers for the test.') 186*9c5db199SXin Li parser.add_argument('--minus', 187*9c5db199SXin Li dest='minus', 188*9c5db199SXin Li nargs='*', 189*9c5db199SXin Li help='List of tests to not use.', 190*9c5db199SXin Li default=['']) 191*9c5db199SXin Li parser.add_argument('--py_version', 192*9c5db199SXin Li dest='py_version', 193*9c5db199SXin Li help='Python version to use, passed ' 194*9c5db199SXin Li 'to Autotest modules, defaults to 2.', 195*9c5db199SXin Li default=None) 196*9c5db199SXin Li parser.add_argument('--CFT', 197*9c5db199SXin Li action='store_true', 198*9c5db199SXin Li default=False, 199*9c5db199SXin Li dest='CFT', 200*9c5db199SXin Li help="If running in, or mocking, the CFT env.") 201*9c5db199SXin Li parser.add_argument('--host_attributes', 202*9c5db199SXin Li action='store', 203*9c5db199SXin Li default='{}', 204*9c5db199SXin Li help='host_attributes') 205*9c5db199SXin Li parser.add_argument('--host_labels', 206*9c5db199SXin Li action='store', 207*9c5db199SXin Li default="", 208*9c5db199SXin Li help='host_labels, quoted space seperated strings') 209*9c5db199SXin Li parser.add_argument('--label', 210*9c5db199SXin Li action='store', 211*9c5db199SXin Li default="", 212*9c5db199SXin Li help='label for test name') 213*9c5db199SXin Li return parser.parse_args(argv), remote_argv 214*9c5db199SXin Li 215*9c5db199SXin Li 216*9c5db199SXin Lidef parse_local_arguments(argv): 217*9c5db199SXin Li """ 218*9c5db199SXin Li Strips out arguments that are not to be passed through to runs. 219*9c5db199SXin Li 220*9c5db199SXin Li Add any arguments that should not be passed to remote test_that runs here. 221*9c5db199SXin Li 222*9c5db199SXin Li @param argv: argument list to parse. 223*9c5db199SXin Li @returns: tuple of local argument parser and remaining argv. 224*9c5db199SXin Li """ 225*9c5db199SXin Li parser = argparse.ArgumentParser(add_help=False) 226*9c5db199SXin Li parser.add_argument('-w', '--web', dest='web', default=None, 227*9c5db199SXin Li help='Address of a webserver to receive test requests.') 228*9c5db199SXin Li parser.add_argument('-x', '--max_runtime_mins', type=int, 229*9c5db199SXin Li dest='max_runtime_mins', default=20, 230*9c5db199SXin Li help='Default time allowed for the tests to complete.') 231*9c5db199SXin Li parser.add_argument('--no-retries', '--no-retry', 232*9c5db199SXin Li dest='retry', action='store_false', default=True, 233*9c5db199SXin Li help='For local runs only, ignore any retries ' 234*9c5db199SXin Li 'specified in the control files.') 235*9c5db199SXin Li _, remaining_argv = parser.parse_known_args(argv) 236*9c5db199SXin Li return parser, remaining_argv 237*9c5db199SXin Li 238*9c5db199SXin Li 239*9c5db199SXin Lidef perform_bootstrap_into_autotest_root(arguments, autotest_path, argv): 240*9c5db199SXin Li """ 241*9c5db199SXin Li Perfoms a bootstrap to run test_that from the |autotest_path|. 242*9c5db199SXin Li 243*9c5db199SXin Li This function is to be called from test_that's main() script, when 244*9c5db199SXin Li test_that is executed from the source tree location. It runs 245*9c5db199SXin Li autotest_quickmerge to update the sysroot unless arguments.no_quickmerge 246*9c5db199SXin Li is set. It then executes and waits on the version of test_that.py 247*9c5db199SXin Li in |autotest_path|. 248*9c5db199SXin Li 249*9c5db199SXin Li @param arguments: A parsed arguments object, as returned from 250*9c5db199SXin Li test_that.parse_arguments(...). 251*9c5db199SXin Li @param autotest_path: Full absolute path to the autotest root directory. 252*9c5db199SXin Li @param argv: The arguments list, as passed to main(...) 253*9c5db199SXin Li 254*9c5db199SXin Li @returns: The return code of the test_that script that was executed in 255*9c5db199SXin Li |autotest_path|. 256*9c5db199SXin Li """ 257*9c5db199SXin Li logging_manager.configure_logging( 258*9c5db199SXin Li server_logging_config.ServerLoggingConfig(), 259*9c5db199SXin Li use_console=True, 260*9c5db199SXin Li verbose=arguments.debug) 261*9c5db199SXin Li if arguments.no_quickmerge: 262*9c5db199SXin Li logging.info('Skipping quickmerge step.') 263*9c5db199SXin Li else: 264*9c5db199SXin Li logging.info('Running autotest_quickmerge step.') 265*9c5db199SXin Li command = [_QUICKMERGE_SCRIPTNAME, '--board='+arguments.board] 266*9c5db199SXin Li s = subprocess.Popen(command, 267*9c5db199SXin Li stdout=subprocess.PIPE, 268*9c5db199SXin Li stderr=subprocess.STDOUT) 269*9c5db199SXin Li for message in iter(s.stdout.readline, b''): 270*9c5db199SXin Li logging.info('quickmerge| %s', message.strip()) 271*9c5db199SXin Li return_code = s.wait() 272*9c5db199SXin Li if return_code: 273*9c5db199SXin Li raise test_runner_utils.TestThatRunError( 274*9c5db199SXin Li 'autotest_quickmerge failed with error code %s.' % 275*9c5db199SXin Li return_code) 276*9c5db199SXin Li 277*9c5db199SXin Li logging.info('Re-running test_that script in %s copy of autotest.', 278*9c5db199SXin Li autotest_path) 279*9c5db199SXin Li script_command = os.path.join(autotest_path, 'site_utils', 280*9c5db199SXin Li 'test_that.py') 281*9c5db199SXin Li if not os.path.exists(script_command): 282*9c5db199SXin Li raise test_runner_utils.TestThatRunError( 283*9c5db199SXin Li 'Unable to bootstrap to autotest root, %s not found.' % 284*9c5db199SXin Li script_command) 285*9c5db199SXin Li proc = None 286*9c5db199SXin Li def resend_sig(signum, stack_frame): 287*9c5db199SXin Li #pylint: disable-msg=C0111 288*9c5db199SXin Li if proc: 289*9c5db199SXin Li proc.send_signal(signum) 290*9c5db199SXin Li signal.signal(signal.SIGINT, resend_sig) 291*9c5db199SXin Li signal.signal(signal.SIGTERM, resend_sig) 292*9c5db199SXin Li 293*9c5db199SXin Li proc = subprocess.Popen([script_command] + argv) 294*9c5db199SXin Li 295*9c5db199SXin Li return proc.wait() 296*9c5db199SXin Li 297*9c5db199SXin Li 298*9c5db199SXin Lidef _main_for_local_run(argv, arguments): 299*9c5db199SXin Li """ 300*9c5db199SXin Li Effective entry point for local test_that runs. 301*9c5db199SXin Li 302*9c5db199SXin Li @param argv: Script command line arguments. 303*9c5db199SXin Li @param arguments: Parsed command line arguments. 304*9c5db199SXin Li """ 305*9c5db199SXin Li results_directory = test_runner_utils.create_results_directory( 306*9c5db199SXin Li arguments.results_dir, arguments.board) 307*9c5db199SXin Li test_runner_utils.add_ssh_identity(results_directory, 308*9c5db199SXin Li arguments.ssh_private_key) 309*9c5db199SXin Li arguments.results_dir = results_directory 310*9c5db199SXin Li 311*9c5db199SXin Li # If the board and/or model is not specified through --board and/or 312*9c5db199SXin Li # --model, and is not set in the default_board file, determine the board by 313*9c5db199SXin Li # ssh-ing into the host. Also prepend it to argv so we can re-use it when we 314*9c5db199SXin Li # run test_that from the sysroot. 315*9c5db199SXin Li arguments.board, arguments.model = _get_info_from_host( 316*9c5db199SXin Li arguments.remote, 317*9c5db199SXin Li arguments.board, 318*9c5db199SXin Li arguments.model, 319*9c5db199SXin Li ssh_options=arguments.ssh_options) 320*9c5db199SXin Li argv = ['--board=%s' % (arguments.board, )] + argv 321*9c5db199SXin Li argv = ['--model=%s' % (arguments.model, )] + argv 322*9c5db199SXin Li 323*9c5db199SXin Li if arguments.autotest_dir: 324*9c5db199SXin Li autotest_path = arguments.autotest_dir 325*9c5db199SXin Li arguments.no_quickmerge = True 326*9c5db199SXin Li else: 327*9c5db199SXin Li sysroot_path = os.path.join('/build', arguments.board, '') 328*9c5db199SXin Li 329*9c5db199SXin Li if not os.path.exists(sysroot_path): 330*9c5db199SXin Li print(('%s does not exist. Have you run ' 331*9c5db199SXin Li 'setup_board?' % sysroot_path), file=sys.stderr) 332*9c5db199SXin Li return 1 333*9c5db199SXin Li 334*9c5db199SXin Li path_ending = 'usr/local/build/autotest' 335*9c5db199SXin Li autotest_path = os.path.join(sysroot_path, path_ending) 336*9c5db199SXin Li 337*9c5db199SXin Li site_utils_path = os.path.join(autotest_path, 'site_utils') 338*9c5db199SXin Li 339*9c5db199SXin Li if not os.path.exists(autotest_path): 340*9c5db199SXin Li print(('%s does not exist. Have you run ' 341*9c5db199SXin Li 'build_packages? Or if you are using ' 342*9c5db199SXin Li '--autotest_dir, make sure it points to ' 343*9c5db199SXin Li 'a valid autotest directory.' % autotest_path), file=sys.stderr) 344*9c5db199SXin Li return 1 345*9c5db199SXin Li 346*9c5db199SXin Li realpath = os.path.realpath(__file__) 347*9c5db199SXin Li site_utils_path = os.path.realpath(site_utils_path) 348*9c5db199SXin Li 349*9c5db199SXin Li # If we are not running the sysroot version of script, perform 350*9c5db199SXin Li # a quickmerge if necessary and then re-execute 351*9c5db199SXin Li # the sysroot version of script with the same arguments. 352*9c5db199SXin Li if os.path.dirname(realpath) != site_utils_path: 353*9c5db199SXin Li return perform_bootstrap_into_autotest_root( 354*9c5db199SXin Li arguments, autotest_path, argv) 355*9c5db199SXin Li else: 356*9c5db199SXin Li return test_runner_utils.perform_run_from_autotest_root( 357*9c5db199SXin Li autotest_path, 358*9c5db199SXin Li argv, 359*9c5db199SXin Li arguments.tests, 360*9c5db199SXin Li arguments.remote, 361*9c5db199SXin Li build=arguments.build, 362*9c5db199SXin Li board=arguments.board, 363*9c5db199SXin Li model=arguments.model, 364*9c5db199SXin Li args=arguments.args, 365*9c5db199SXin Li ignore_deps=not arguments.enforce_deps, 366*9c5db199SXin Li results_directory=results_directory, 367*9c5db199SXin Li ssh_verbosity=arguments.ssh_verbosity, 368*9c5db199SXin Li ssh_options=arguments.ssh_options, 369*9c5db199SXin Li iterations=arguments.iterations, 370*9c5db199SXin Li fast_mode=arguments.fast_mode, 371*9c5db199SXin Li debug=arguments.debug, 372*9c5db199SXin Li allow_chrome_crashes=arguments.allow_chrome_crashes, 373*9c5db199SXin Li pretend=arguments.pretend, 374*9c5db199SXin Li job_retry=arguments.retry, 375*9c5db199SXin Li companion_hosts=arguments.companion_hosts, 376*9c5db199SXin Li minus=arguments.minus, 377*9c5db199SXin Li dut_servers=arguments.dut_servers, 378*9c5db199SXin Li is_cft=arguments.CFT, 379*9c5db199SXin Li host_attributes=json.loads(arguments.host_attributes), 380*9c5db199SXin Li host_labels=arguments.host_labels, 381*9c5db199SXin Li label=arguments.label) 382*9c5db199SXin Li 383*9c5db199SXin Li 384*9c5db199SXin Lidef _main_for_lab_run(argv, arguments): 385*9c5db199SXin Li """ 386*9c5db199SXin Li Effective entry point for lab test_that runs. 387*9c5db199SXin Li 388*9c5db199SXin Li @param argv: Script command line arguments. 389*9c5db199SXin Li @param arguments: Parsed command line arguments. 390*9c5db199SXin Li """ 391*9c5db199SXin Li autotest_path = os.path.realpath(os.path.join( 392*9c5db199SXin Li os.path.dirname(os.path.realpath(__file__)), 393*9c5db199SXin Li '..', 394*9c5db199SXin Li )) 395*9c5db199SXin Li command = [os.path.join(autotest_path, 'site_utils', 396*9c5db199SXin Li 'run_suite.py'), 397*9c5db199SXin Li '--board=%s' % (arguments.board,), 398*9c5db199SXin Li '--build=%s' % (arguments.build,), 399*9c5db199SXin Li '--model=%s' % (arguments.model,), 400*9c5db199SXin Li '--suite_name=%s' % 'test_that_wrapper', 401*9c5db199SXin Li '--pool=%s' % (arguments.pool,), 402*9c5db199SXin Li '--max_runtime_mins=%s' % str(arguments.max_runtime_mins), 403*9c5db199SXin Li '--suite_args=%s' 404*9c5db199SXin Li % repr({'tests': _suite_arg_tests(argv)})] 405*9c5db199SXin Li if arguments.web: 406*9c5db199SXin Li command.extend(['--web=%s' % (arguments.web,)]) 407*9c5db199SXin Li logging.info('About to start lab suite with command %s.', command) 408*9c5db199SXin Li return subprocess.call(command) 409*9c5db199SXin Li 410*9c5db199SXin Li 411*9c5db199SXin Lidef _suite_arg_tests(argv): 412*9c5db199SXin Li """ 413*9c5db199SXin Li Construct a list of tests to pass into suite_args. 414*9c5db199SXin Li 415*9c5db199SXin Li This is passed in suite_args to run_suite for running a test in the 416*9c5db199SXin Li lab. 417*9c5db199SXin Li 418*9c5db199SXin Li @param argv: Remote Script command line arguments. 419*9c5db199SXin Li """ 420*9c5db199SXin Li arguments = parse_arguments(argv) 421*9c5db199SXin Li return arguments.tests 422*9c5db199SXin Li 423*9c5db199SXin Li 424*9c5db199SXin Lidef main(argv): 425*9c5db199SXin Li """ 426*9c5db199SXin Li Entry point for test_that script. 427*9c5db199SXin Li 428*9c5db199SXin Li @param argv: arguments list 429*9c5db199SXin Li """ 430*9c5db199SXin Li arguments, remote_argv = _parse_arguments_internal(argv) 431*9c5db199SXin Li try: 432*9c5db199SXin Li validate_arguments(arguments) 433*9c5db199SXin Li except ValueError as err: 434*9c5db199SXin Li print(('Invalid arguments. %s' % str(err)), file=sys.stderr) 435*9c5db199SXin Li return 1 436*9c5db199SXin Li 437*9c5db199SXin Li if arguments.remote == ':lab:': 438*9c5db199SXin Li return _main_for_lab_run(remote_argv, arguments) 439*9c5db199SXin Li else: 440*9c5db199SXin Li return _main_for_local_run(argv, arguments) 441*9c5db199SXin Li 442*9c5db199SXin Li 443*9c5db199SXin Liif __name__ == '__main__': 444*9c5db199SXin Li sys.exit(main(sys.argv[1:])) 445