1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*6777b538SAndroid Build Coastguard Worker# 3*6777b538SAndroid Build Coastguard Worker# Copyright 2018 The Chromium Authors 4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Workerimport argparse 8*6777b538SAndroid Build Coastguard Workerimport collections 9*6777b538SAndroid Build Coastguard Workerimport json 10*6777b538SAndroid Build Coastguard Workerimport logging 11*6777b538SAndroid Build Coastguard Workerimport os 12*6777b538SAndroid Build Coastguard Workerimport re 13*6777b538SAndroid Build Coastguard Workerimport shutil 14*6777b538SAndroid Build Coastguard Workerimport signal 15*6777b538SAndroid Build Coastguard Workerimport socket 16*6777b538SAndroid Build Coastguard Workerimport sys 17*6777b538SAndroid Build Coastguard Workerimport tempfile 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker# The following non-std imports are fetched via vpython. See the list at 20*6777b538SAndroid Build Coastguard Worker# //.vpython3 21*6777b538SAndroid Build Coastguard Workerimport dateutil.parser # pylint: disable=import-error 22*6777b538SAndroid Build Coastguard Workerimport jsonlines # pylint: disable=import-error 23*6777b538SAndroid Build Coastguard Workerimport psutil # pylint: disable=import-error 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard WorkerCHROMIUM_SRC_PATH = os.path.abspath( 26*6777b538SAndroid Build Coastguard Worker os.path.join(os.path.dirname(__file__), '..', '..')) 27*6777b538SAndroid Build Coastguard Worker 28*6777b538SAndroid Build Coastguard Worker# Use the android test-runner's gtest results support library for generating 29*6777b538SAndroid Build Coastguard Worker# output json ourselves. 30*6777b538SAndroid Build Coastguard Workersys.path.insert(0, os.path.join(CHROMIUM_SRC_PATH, 'build', 'android')) 31*6777b538SAndroid Build Coastguard Workerfrom pylib.base import base_test_result # pylint: disable=import-error 32*6777b538SAndroid Build Coastguard Workerfrom pylib.results import json_results # pylint: disable=import-error 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Workersys.path.insert(0, os.path.join(CHROMIUM_SRC_PATH, 'build', 'util')) 35*6777b538SAndroid Build Coastguard Worker# TODO(crbug.com/1421441): Re-enable the 'no-name-in-module' check. 36*6777b538SAndroid Build Coastguard Workerfrom lib.results import result_sink # pylint: disable=import-error,no-name-in-module 37*6777b538SAndroid Build Coastguard Worker 38*6777b538SAndroid Build Coastguard Workerimport subprocess # pylint: disable=import-error,wrong-import-order 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard WorkerDEFAULT_CROS_CACHE = os.path.abspath( 41*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMIUM_SRC_PATH, 'build', 'cros_cache')) 42*6777b538SAndroid Build Coastguard WorkerCHROMITE_PATH = os.path.abspath( 43*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMIUM_SRC_PATH, 'third_party', 'chromite')) 44*6777b538SAndroid Build Coastguard WorkerCROS_RUN_TEST_PATH = os.path.abspath( 45*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMITE_PATH, 'bin', 'cros_run_test')) 46*6777b538SAndroid Build Coastguard Worker 47*6777b538SAndroid Build Coastguard WorkerLACROS_LAUNCHER_SCRIPT_PATH = os.path.abspath( 48*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMIUM_SRC_PATH, 'build', 'lacros', 49*6777b538SAndroid Build Coastguard Worker 'mojo_connection_lacros_launcher.py')) 50*6777b538SAndroid Build Coastguard Worker 51*6777b538SAndroid Build Coastguard Worker# This is a special hostname that resolves to a different DUT in the lab 52*6777b538SAndroid Build Coastguard Worker# depending on which lab machine you're on. 53*6777b538SAndroid Build Coastguard WorkerLAB_DUT_HOSTNAME = 'variable_chromeos_device_hostname' 54*6777b538SAndroid Build Coastguard Worker 55*6777b538SAndroid Build Coastguard WorkerSYSTEM_LOG_LOCATIONS = [ 56*6777b538SAndroid Build Coastguard Worker '/home/chronos/crash/', 57*6777b538SAndroid Build Coastguard Worker '/var/log/chrome/', 58*6777b538SAndroid Build Coastguard Worker '/var/log/messages', 59*6777b538SAndroid Build Coastguard Worker '/var/log/ui/', 60*6777b538SAndroid Build Coastguard Worker '/var/log/lacros/', 61*6777b538SAndroid Build Coastguard Worker] 62*6777b538SAndroid Build Coastguard Worker 63*6777b538SAndroid Build Coastguard WorkerTAST_DEBUG_DOC = 'https://bit.ly/2LgvIXz' 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Workerclass TestFormatError(Exception): 67*6777b538SAndroid Build Coastguard Worker pass 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker 70*6777b538SAndroid Build Coastguard Workerclass RemoteTest: 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker # This is a basic shell script that can be appended to in order to invoke the 73*6777b538SAndroid Build Coastguard Worker # test on the device. 74*6777b538SAndroid Build Coastguard Worker BASIC_SHELL_SCRIPT = [ 75*6777b538SAndroid Build Coastguard Worker '#!/bin/sh', 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker # /home and /tmp are mounted with "noexec" in the device, but some of our 78*6777b538SAndroid Build Coastguard Worker # tools and tests use those dirs as a workspace (eg: vpython downloads 79*6777b538SAndroid Build Coastguard Worker # python binaries to ~/.vpython-root and /tmp/vpython_bootstrap). 80*6777b538SAndroid Build Coastguard Worker # /usr/local/tmp doesn't have this restriction, so change the location of 81*6777b538SAndroid Build Coastguard Worker # the home and temp dirs for the duration of the test. 82*6777b538SAndroid Build Coastguard Worker 'export HOME=/usr/local/tmp', 83*6777b538SAndroid Build Coastguard Worker 'export TMPDIR=/usr/local/tmp', 84*6777b538SAndroid Build Coastguard Worker ] 85*6777b538SAndroid Build Coastguard Worker 86*6777b538SAndroid Build Coastguard Worker def __init__(self, args, unknown_args): 87*6777b538SAndroid Build Coastguard Worker self._additional_args = unknown_args 88*6777b538SAndroid Build Coastguard Worker self._path_to_outdir = args.path_to_outdir 89*6777b538SAndroid Build Coastguard Worker self._test_launcher_summary_output = args.test_launcher_summary_output 90*6777b538SAndroid Build Coastguard Worker self._logs_dir = args.logs_dir 91*6777b538SAndroid Build Coastguard Worker self._use_vm = args.use_vm 92*6777b538SAndroid Build Coastguard Worker self._rdb_client = result_sink.TryInitClient() 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker self._retries = 0 95*6777b538SAndroid Build Coastguard Worker self._timeout = None 96*6777b538SAndroid Build Coastguard Worker self._test_launcher_shard_index = args.test_launcher_shard_index 97*6777b538SAndroid Build Coastguard Worker self._test_launcher_total_shards = args.test_launcher_total_shards 98*6777b538SAndroid Build Coastguard Worker 99*6777b538SAndroid Build Coastguard Worker # The location on disk of a shell script that can be optionally used to 100*6777b538SAndroid Build Coastguard Worker # invoke the test on the device. If it's not set, we assume self._test_cmd 101*6777b538SAndroid Build Coastguard Worker # contains the test invocation. 102*6777b538SAndroid Build Coastguard Worker self._on_device_script = None 103*6777b538SAndroid Build Coastguard Worker 104*6777b538SAndroid Build Coastguard Worker self._test_cmd = [ 105*6777b538SAndroid Build Coastguard Worker CROS_RUN_TEST_PATH, 106*6777b538SAndroid Build Coastguard Worker '--board', 107*6777b538SAndroid Build Coastguard Worker args.board, 108*6777b538SAndroid Build Coastguard Worker '--cache-dir', 109*6777b538SAndroid Build Coastguard Worker args.cros_cache, 110*6777b538SAndroid Build Coastguard Worker ] 111*6777b538SAndroid Build Coastguard Worker if args.use_vm: 112*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 113*6777b538SAndroid Build Coastguard Worker '--start', 114*6777b538SAndroid Build Coastguard Worker # Don't persist any filesystem changes after the VM shutsdown. 115*6777b538SAndroid Build Coastguard Worker '--copy-on-write', 116*6777b538SAndroid Build Coastguard Worker ] 117*6777b538SAndroid Build Coastguard Worker else: 118*6777b538SAndroid Build Coastguard Worker if args.fetch_cros_hostname: 119*6777b538SAndroid Build Coastguard Worker self._test_cmd += ['--device', get_cros_hostname()] 120*6777b538SAndroid Build Coastguard Worker else: 121*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 122*6777b538SAndroid Build Coastguard Worker '--device', args.device if args.device else LAB_DUT_HOSTNAME 123*6777b538SAndroid Build Coastguard Worker ] 124*6777b538SAndroid Build Coastguard Worker 125*6777b538SAndroid Build Coastguard Worker if args.logs_dir: 126*6777b538SAndroid Build Coastguard Worker for log in SYSTEM_LOG_LOCATIONS: 127*6777b538SAndroid Build Coastguard Worker self._test_cmd += ['--results-src', log] 128*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 129*6777b538SAndroid Build Coastguard Worker '--results-dest-dir', 130*6777b538SAndroid Build Coastguard Worker os.path.join(args.logs_dir, 'system_logs') 131*6777b538SAndroid Build Coastguard Worker ] 132*6777b538SAndroid Build Coastguard Worker if args.flash: 133*6777b538SAndroid Build Coastguard Worker self._test_cmd += ['--flash'] 134*6777b538SAndroid Build Coastguard Worker if args.public_image: 135*6777b538SAndroid Build Coastguard Worker self._test_cmd += ['--public-image'] 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker self._test_env = setup_env() 138*6777b538SAndroid Build Coastguard Worker 139*6777b538SAndroid Build Coastguard Worker @property 140*6777b538SAndroid Build Coastguard Worker def suite_name(self): 141*6777b538SAndroid Build Coastguard Worker raise NotImplementedError('Child classes need to define suite name.') 142*6777b538SAndroid Build Coastguard Worker 143*6777b538SAndroid Build Coastguard Worker @property 144*6777b538SAndroid Build Coastguard Worker def test_cmd(self): 145*6777b538SAndroid Build Coastguard Worker return self._test_cmd 146*6777b538SAndroid Build Coastguard Worker 147*6777b538SAndroid Build Coastguard Worker def write_test_script_to_disk(self, script_contents): 148*6777b538SAndroid Build Coastguard Worker # Since we're using an on_device_script to invoke the test, we'll need to 149*6777b538SAndroid Build Coastguard Worker # set cwd. 150*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 151*6777b538SAndroid Build Coastguard Worker '--remote-cmd', 152*6777b538SAndroid Build Coastguard Worker '--cwd', 153*6777b538SAndroid Build Coastguard Worker os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH), 154*6777b538SAndroid Build Coastguard Worker ] 155*6777b538SAndroid Build Coastguard Worker logging.info('Running the following command on the device:') 156*6777b538SAndroid Build Coastguard Worker logging.info('\n%s', '\n'.join(script_contents)) 157*6777b538SAndroid Build Coastguard Worker fd, tmp_path = tempfile.mkstemp(suffix='.sh', dir=self._path_to_outdir) 158*6777b538SAndroid Build Coastguard Worker os.fchmod(fd, 0o755) 159*6777b538SAndroid Build Coastguard Worker with os.fdopen(fd, 'w') as f: 160*6777b538SAndroid Build Coastguard Worker f.write('\n'.join(script_contents) + '\n') 161*6777b538SAndroid Build Coastguard Worker return tmp_path 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker def run_test(self): 164*6777b538SAndroid Build Coastguard Worker # Traps SIGTERM and kills all child processes of cros_run_test when it's 165*6777b538SAndroid Build Coastguard Worker # caught. This will allow us to capture logs from the device if a test hangs 166*6777b538SAndroid Build Coastguard Worker # and gets timeout-killed by swarming. See also: 167*6777b538SAndroid Build Coastguard Worker # https://chromium.googlesource.com/infra/luci/luci-py/+/main/appengine/swarming/doc/Bot.md#graceful-termination_aka-the-sigterm-and-sigkill-dance 168*6777b538SAndroid Build Coastguard Worker test_proc = None 169*6777b538SAndroid Build Coastguard Worker 170*6777b538SAndroid Build Coastguard Worker def _kill_child_procs(trapped_signal, _): 171*6777b538SAndroid Build Coastguard Worker logging.warning('Received signal %d. Killing child processes of test.', 172*6777b538SAndroid Build Coastguard Worker trapped_signal) 173*6777b538SAndroid Build Coastguard Worker if not test_proc or not test_proc.pid: 174*6777b538SAndroid Build Coastguard Worker # This shouldn't happen? 175*6777b538SAndroid Build Coastguard Worker logging.error('Test process not running.') 176*6777b538SAndroid Build Coastguard Worker return 177*6777b538SAndroid Build Coastguard Worker for child in psutil.Process(test_proc.pid).children(): 178*6777b538SAndroid Build Coastguard Worker logging.warning('Killing process %s', child) 179*6777b538SAndroid Build Coastguard Worker child.kill() 180*6777b538SAndroid Build Coastguard Worker 181*6777b538SAndroid Build Coastguard Worker signal.signal(signal.SIGTERM, _kill_child_procs) 182*6777b538SAndroid Build Coastguard Worker 183*6777b538SAndroid Build Coastguard Worker for i in range(self._retries + 1): 184*6777b538SAndroid Build Coastguard Worker logging.info('########################################') 185*6777b538SAndroid Build Coastguard Worker logging.info('Test attempt #%d', i) 186*6777b538SAndroid Build Coastguard Worker logging.info('########################################') 187*6777b538SAndroid Build Coastguard Worker test_proc = subprocess.Popen( 188*6777b538SAndroid Build Coastguard Worker self._test_cmd, 189*6777b538SAndroid Build Coastguard Worker stdout=sys.stdout, 190*6777b538SAndroid Build Coastguard Worker stderr=sys.stderr, 191*6777b538SAndroid Build Coastguard Worker env=self._test_env) 192*6777b538SAndroid Build Coastguard Worker try: 193*6777b538SAndroid Build Coastguard Worker test_proc.wait(timeout=self._timeout) 194*6777b538SAndroid Build Coastguard Worker except subprocess.TimeoutExpired: # pylint: disable=no-member 195*6777b538SAndroid Build Coastguard Worker logging.error('Test timed out. Sending SIGTERM.') 196*6777b538SAndroid Build Coastguard Worker # SIGTERM the proc and wait 10s for it to close. 197*6777b538SAndroid Build Coastguard Worker test_proc.terminate() 198*6777b538SAndroid Build Coastguard Worker try: 199*6777b538SAndroid Build Coastguard Worker test_proc.wait(timeout=10) 200*6777b538SAndroid Build Coastguard Worker except subprocess.TimeoutExpired: # pylint: disable=no-member 201*6777b538SAndroid Build Coastguard Worker # If it hasn't closed in 10s, SIGKILL it. 202*6777b538SAndroid Build Coastguard Worker logging.error('Test did not exit in time. Sending SIGKILL.') 203*6777b538SAndroid Build Coastguard Worker test_proc.kill() 204*6777b538SAndroid Build Coastguard Worker test_proc.wait() 205*6777b538SAndroid Build Coastguard Worker logging.info('Test exitted with %d.', test_proc.returncode) 206*6777b538SAndroid Build Coastguard Worker if test_proc.returncode == 0: 207*6777b538SAndroid Build Coastguard Worker break 208*6777b538SAndroid Build Coastguard Worker 209*6777b538SAndroid Build Coastguard Worker self.post_run(test_proc.returncode) 210*6777b538SAndroid Build Coastguard Worker # Allow post_run to override test proc return code. (Useful when the host 211*6777b538SAndroid Build Coastguard Worker # side Tast bin returns 0 even for failed tests.) 212*6777b538SAndroid Build Coastguard Worker return test_proc.returncode 213*6777b538SAndroid Build Coastguard Worker 214*6777b538SAndroid Build Coastguard Worker def post_run(self, _): 215*6777b538SAndroid Build Coastguard Worker if self._on_device_script: 216*6777b538SAndroid Build Coastguard Worker os.remove(self._on_device_script) 217*6777b538SAndroid Build Coastguard Worker 218*6777b538SAndroid Build Coastguard Worker @staticmethod 219*6777b538SAndroid Build Coastguard Worker def get_artifacts(path): 220*6777b538SAndroid Build Coastguard Worker """Crawls a given directory for file artifacts to attach to a test. 221*6777b538SAndroid Build Coastguard Worker 222*6777b538SAndroid Build Coastguard Worker Args: 223*6777b538SAndroid Build Coastguard Worker path: Path to a directory to search for artifacts. 224*6777b538SAndroid Build Coastguard Worker Returns: 225*6777b538SAndroid Build Coastguard Worker A dict mapping name of the artifact to its absolute filepath. 226*6777b538SAndroid Build Coastguard Worker """ 227*6777b538SAndroid Build Coastguard Worker artifacts = {} 228*6777b538SAndroid Build Coastguard Worker for dirpath, _, filenames in os.walk(path): 229*6777b538SAndroid Build Coastguard Worker for f in filenames: 230*6777b538SAndroid Build Coastguard Worker artifact_path = os.path.join(dirpath, f) 231*6777b538SAndroid Build Coastguard Worker artifact_id = os.path.relpath(artifact_path, path) 232*6777b538SAndroid Build Coastguard Worker # Some artifacts will have non-Latin characters in the filename, eg: 233*6777b538SAndroid Build Coastguard Worker # 'ui_tree_Chinese Pinyin-你好.txt'. ResultDB's API rejects such 234*6777b538SAndroid Build Coastguard Worker # characters as an artifact ID, so force the file name down into ascii. 235*6777b538SAndroid Build Coastguard Worker # For more info, see: 236*6777b538SAndroid Build Coastguard Worker # https://source.chromium.org/chromium/infra/infra/+/main:go/src/go.chromium.org/luci/resultdb/proto/v1/artifact.proto;drc=3bff13b8037ca76ec19f9810033d914af7ec67cb;l=46 237*6777b538SAndroid Build Coastguard Worker artifact_id = artifact_id.encode('ascii', 'replace').decode() 238*6777b538SAndroid Build Coastguard Worker artifact_id = artifact_id.replace('\\', '?') 239*6777b538SAndroid Build Coastguard Worker artifacts[artifact_id] = { 240*6777b538SAndroid Build Coastguard Worker 'filePath': artifact_path, 241*6777b538SAndroid Build Coastguard Worker } 242*6777b538SAndroid Build Coastguard Worker return artifacts 243*6777b538SAndroid Build Coastguard Worker 244*6777b538SAndroid Build Coastguard Worker 245*6777b538SAndroid Build Coastguard Workerclass TastTest(RemoteTest): 246*6777b538SAndroid Build Coastguard Worker 247*6777b538SAndroid Build Coastguard Worker def __init__(self, args, unknown_args): 248*6777b538SAndroid Build Coastguard Worker super().__init__(args, unknown_args) 249*6777b538SAndroid Build Coastguard Worker 250*6777b538SAndroid Build Coastguard Worker self._suite_name = args.suite_name 251*6777b538SAndroid Build Coastguard Worker self._tast_vars = args.tast_vars 252*6777b538SAndroid Build Coastguard Worker self._tast_retries = args.tast_retries 253*6777b538SAndroid Build Coastguard Worker self._tests = args.tests 254*6777b538SAndroid Build Coastguard Worker # The CQ passes in '--gtest_filter' when specifying tests to skip. Store it 255*6777b538SAndroid Build Coastguard Worker # here and parse it later to integrate it into Tast executions. 256*6777b538SAndroid Build Coastguard Worker self._gtest_style_filter = args.gtest_filter 257*6777b538SAndroid Build Coastguard Worker self._attr_expr = args.attr_expr 258*6777b538SAndroid Build Coastguard Worker self._should_strip = args.strip_chrome 259*6777b538SAndroid Build Coastguard Worker self._deploy_lacros = args.deploy_lacros 260*6777b538SAndroid Build Coastguard Worker self._deploy_chrome = args.deploy_chrome 261*6777b538SAndroid Build Coastguard Worker 262*6777b538SAndroid Build Coastguard Worker if not self._logs_dir: 263*6777b538SAndroid Build Coastguard Worker # The host-side Tast bin returns 0 when tests fail, so we need to capture 264*6777b538SAndroid Build Coastguard Worker # and parse its json results to reliably determine if tests fail. 265*6777b538SAndroid Build Coastguard Worker raise TestFormatError( 266*6777b538SAndroid Build Coastguard Worker 'When using the host-side Tast bin, "--logs-dir" must be passed in ' 267*6777b538SAndroid Build Coastguard Worker 'order to parse its results.') 268*6777b538SAndroid Build Coastguard Worker 269*6777b538SAndroid Build Coastguard Worker # If the first test filter is negative, it should be safe to assume all of 270*6777b538SAndroid Build Coastguard Worker # them are, so just test the first filter. 271*6777b538SAndroid Build Coastguard Worker if self._gtest_style_filter and self._gtest_style_filter[0] == '-': 272*6777b538SAndroid Build Coastguard Worker raise TestFormatError('Negative test filters not supported for Tast.') 273*6777b538SAndroid Build Coastguard Worker 274*6777b538SAndroid Build Coastguard Worker @property 275*6777b538SAndroid Build Coastguard Worker def suite_name(self): 276*6777b538SAndroid Build Coastguard Worker return self._suite_name 277*6777b538SAndroid Build Coastguard Worker 278*6777b538SAndroid Build Coastguard Worker def build_test_command(self): 279*6777b538SAndroid Build Coastguard Worker unsupported_args = [ 280*6777b538SAndroid Build Coastguard Worker '--test-launcher-retry-limit', 281*6777b538SAndroid Build Coastguard Worker '--test-launcher-batch-limit', 282*6777b538SAndroid Build Coastguard Worker '--gtest_repeat', 283*6777b538SAndroid Build Coastguard Worker ] 284*6777b538SAndroid Build Coastguard Worker for unsupported_arg in unsupported_args: 285*6777b538SAndroid Build Coastguard Worker if any(arg.startswith(unsupported_arg) for arg in self._additional_args): 286*6777b538SAndroid Build Coastguard Worker logging.info( 287*6777b538SAndroid Build Coastguard Worker '%s not supported for Tast tests. The arg will be ignored.', 288*6777b538SAndroid Build Coastguard Worker unsupported_arg) 289*6777b538SAndroid Build Coastguard Worker self._additional_args = [ 290*6777b538SAndroid Build Coastguard Worker arg for arg in self._additional_args 291*6777b538SAndroid Build Coastguard Worker if not arg.startswith(unsupported_arg) 292*6777b538SAndroid Build Coastguard Worker ] 293*6777b538SAndroid Build Coastguard Worker 294*6777b538SAndroid Build Coastguard Worker # Lacros deployment mounts itself by default. 295*6777b538SAndroid Build Coastguard Worker if self._deploy_lacros: 296*6777b538SAndroid Build Coastguard Worker self._test_cmd.extend([ 297*6777b538SAndroid Build Coastguard Worker '--deploy-lacros', '--lacros-launcher-script', 298*6777b538SAndroid Build Coastguard Worker LACROS_LAUNCHER_SCRIPT_PATH 299*6777b538SAndroid Build Coastguard Worker ]) 300*6777b538SAndroid Build Coastguard Worker if self._deploy_chrome: 301*6777b538SAndroid Build Coastguard Worker self._test_cmd.extend(['--deploy', '--mount']) 302*6777b538SAndroid Build Coastguard Worker else: 303*6777b538SAndroid Build Coastguard Worker self._test_cmd.extend(['--deploy', '--mount']) 304*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 305*6777b538SAndroid Build Coastguard Worker '--build-dir', 306*6777b538SAndroid Build Coastguard Worker os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH) 307*6777b538SAndroid Build Coastguard Worker ] + self._additional_args 308*6777b538SAndroid Build Coastguard Worker 309*6777b538SAndroid Build Coastguard Worker # Capture tast's results in the logs dir as well. 310*6777b538SAndroid Build Coastguard Worker if self._logs_dir: 311*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 312*6777b538SAndroid Build Coastguard Worker '--results-dir', 313*6777b538SAndroid Build Coastguard Worker self._logs_dir, 314*6777b538SAndroid Build Coastguard Worker ] 315*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 316*6777b538SAndroid Build Coastguard Worker '--tast-total-shards=%d' % self._test_launcher_total_shards, 317*6777b538SAndroid Build Coastguard Worker '--tast-shard-index=%d' % self._test_launcher_shard_index, 318*6777b538SAndroid Build Coastguard Worker ] 319*6777b538SAndroid Build Coastguard Worker # If we're using a test filter, replace the contents of the Tast 320*6777b538SAndroid Build Coastguard Worker # conditional with a long list of "name:test" expressions, one for each 321*6777b538SAndroid Build Coastguard Worker # test in the filter. 322*6777b538SAndroid Build Coastguard Worker if self._gtest_style_filter: 323*6777b538SAndroid Build Coastguard Worker if self._attr_expr or self._tests: 324*6777b538SAndroid Build Coastguard Worker logging.warning( 325*6777b538SAndroid Build Coastguard Worker 'Presence of --gtest_filter will cause the specified Tast expr' 326*6777b538SAndroid Build Coastguard Worker ' or test list to be ignored.') 327*6777b538SAndroid Build Coastguard Worker names = [] 328*6777b538SAndroid Build Coastguard Worker for test in self._gtest_style_filter.split(':'): 329*6777b538SAndroid Build Coastguard Worker names.append('"name:%s"' % test) 330*6777b538SAndroid Build Coastguard Worker self._attr_expr = '(' + ' || '.join(names) + ')' 331*6777b538SAndroid Build Coastguard Worker 332*6777b538SAndroid Build Coastguard Worker if self._attr_expr: 333*6777b538SAndroid Build Coastguard Worker # Don't use shlex.quote() here. Something funky happens with the arg 334*6777b538SAndroid Build Coastguard Worker # as it gets passed down from cros_run_test to tast. (Tast picks up the 335*6777b538SAndroid Build Coastguard Worker # escaping single quotes and complains that the attribute expression 336*6777b538SAndroid Build Coastguard Worker # "must be within parentheses".) 337*6777b538SAndroid Build Coastguard Worker self._test_cmd.append('--tast=%s' % self._attr_expr) 338*6777b538SAndroid Build Coastguard Worker else: 339*6777b538SAndroid Build Coastguard Worker self._test_cmd.append('--tast') 340*6777b538SAndroid Build Coastguard Worker self._test_cmd.extend(self._tests) 341*6777b538SAndroid Build Coastguard Worker 342*6777b538SAndroid Build Coastguard Worker for v in self._tast_vars or []: 343*6777b538SAndroid Build Coastguard Worker self._test_cmd.extend(['--tast-var', v]) 344*6777b538SAndroid Build Coastguard Worker 345*6777b538SAndroid Build Coastguard Worker if self._tast_retries: 346*6777b538SAndroid Build Coastguard Worker self._test_cmd.append('--tast-retries=%d' % self._tast_retries) 347*6777b538SAndroid Build Coastguard Worker 348*6777b538SAndroid Build Coastguard Worker # Mounting ash-chrome gives it enough disk space to not need stripping, 349*6777b538SAndroid Build Coastguard Worker # but only for one not instrumented with code coverage. 350*6777b538SAndroid Build Coastguard Worker # Lacros uses --nostrip by default, so there is no need to specify. 351*6777b538SAndroid Build Coastguard Worker if not self._deploy_lacros and not self._should_strip: 352*6777b538SAndroid Build Coastguard Worker self._test_cmd.append('--nostrip') 353*6777b538SAndroid Build Coastguard Worker 354*6777b538SAndroid Build Coastguard Worker def post_run(self, return_code): 355*6777b538SAndroid Build Coastguard Worker tast_results_path = os.path.join(self._logs_dir, 'streamed_results.jsonl') 356*6777b538SAndroid Build Coastguard Worker if not os.path.exists(tast_results_path): 357*6777b538SAndroid Build Coastguard Worker logging.error( 358*6777b538SAndroid Build Coastguard Worker 'Tast results not found at %s. Falling back to generic result ' 359*6777b538SAndroid Build Coastguard Worker 'reporting.', tast_results_path) 360*6777b538SAndroid Build Coastguard Worker return super().post_run(return_code) 361*6777b538SAndroid Build Coastguard Worker 362*6777b538SAndroid Build Coastguard Worker # See the link below for the format of the results: 363*6777b538SAndroid Build Coastguard Worker # https://godoc.org/chromium.googlesource.com/chromiumos/platform/tast.git/src/chromiumos/cmd/tast/run#TestResult 364*6777b538SAndroid Build Coastguard Worker with jsonlines.open(tast_results_path) as reader: 365*6777b538SAndroid Build Coastguard Worker tast_results = collections.deque(reader) 366*6777b538SAndroid Build Coastguard Worker 367*6777b538SAndroid Build Coastguard Worker suite_results = base_test_result.TestRunResults() 368*6777b538SAndroid Build Coastguard Worker for test in tast_results: 369*6777b538SAndroid Build Coastguard Worker errors = test['errors'] 370*6777b538SAndroid Build Coastguard Worker start, end = test['start'], test['end'] 371*6777b538SAndroid Build Coastguard Worker # Use dateutil to parse the timestamps since datetime can't handle 372*6777b538SAndroid Build Coastguard Worker # nanosecond precision. 373*6777b538SAndroid Build Coastguard Worker duration = dateutil.parser.parse(end) - dateutil.parser.parse(start) 374*6777b538SAndroid Build Coastguard Worker # If the duration is negative, Tast has likely reported an incorrect 375*6777b538SAndroid Build Coastguard Worker # duration. See https://issuetracker.google.com/issues/187973541. Round 376*6777b538SAndroid Build Coastguard Worker # up to 0 in that case to avoid confusing RDB. 377*6777b538SAndroid Build Coastguard Worker duration_ms = max(duration.total_seconds() * 1000, 0) 378*6777b538SAndroid Build Coastguard Worker if bool(test['skipReason']): 379*6777b538SAndroid Build Coastguard Worker result = base_test_result.ResultType.SKIP 380*6777b538SAndroid Build Coastguard Worker elif errors: 381*6777b538SAndroid Build Coastguard Worker result = base_test_result.ResultType.FAIL 382*6777b538SAndroid Build Coastguard Worker else: 383*6777b538SAndroid Build Coastguard Worker result = base_test_result.ResultType.PASS 384*6777b538SAndroid Build Coastguard Worker primary_error_message = None 385*6777b538SAndroid Build Coastguard Worker error_log = '' 386*6777b538SAndroid Build Coastguard Worker if errors: 387*6777b538SAndroid Build Coastguard Worker # See the link below for the format of these errors: 388*6777b538SAndroid Build Coastguard Worker # https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/platform/tast/src/chromiumos/tast/cmd/tast/internal/run/resultsjson/resultsjson.go 389*6777b538SAndroid Build Coastguard Worker primary_error_message = errors[0]['reason'] 390*6777b538SAndroid Build Coastguard Worker for err in errors: 391*6777b538SAndroid Build Coastguard Worker error_log += err['stack'] + '\n' 392*6777b538SAndroid Build Coastguard Worker debug_link = ("If you're unsure why this test failed, consult the steps " 393*6777b538SAndroid Build Coastguard Worker 'outlined <a href="%s">here</a>.' % TAST_DEBUG_DOC) 394*6777b538SAndroid Build Coastguard Worker base_result = base_test_result.BaseTestResult( 395*6777b538SAndroid Build Coastguard Worker test['name'], result, duration=duration_ms, log=error_log) 396*6777b538SAndroid Build Coastguard Worker suite_results.AddResult(base_result) 397*6777b538SAndroid Build Coastguard Worker self._maybe_handle_perf_results(test['name']) 398*6777b538SAndroid Build Coastguard Worker 399*6777b538SAndroid Build Coastguard Worker if self._rdb_client: 400*6777b538SAndroid Build Coastguard Worker # Walk the contents of the test's "outDir" and atttach any file found 401*6777b538SAndroid Build Coastguard Worker # inside as an RDB 'artifact'. (This could include system logs, screen 402*6777b538SAndroid Build Coastguard Worker # shots, etc.) 403*6777b538SAndroid Build Coastguard Worker artifacts = self.get_artifacts(test['outDir']) 404*6777b538SAndroid Build Coastguard Worker html_artifact = debug_link 405*6777b538SAndroid Build Coastguard Worker if result == base_test_result.ResultType.SKIP: 406*6777b538SAndroid Build Coastguard Worker html_artifact = 'Test was skipped because: ' + test['skipReason'] 407*6777b538SAndroid Build Coastguard Worker self._rdb_client.Post( 408*6777b538SAndroid Build Coastguard Worker test['name'], 409*6777b538SAndroid Build Coastguard Worker result, 410*6777b538SAndroid Build Coastguard Worker duration_ms, 411*6777b538SAndroid Build Coastguard Worker error_log, 412*6777b538SAndroid Build Coastguard Worker None, 413*6777b538SAndroid Build Coastguard Worker artifacts=artifacts, 414*6777b538SAndroid Build Coastguard Worker failure_reason=primary_error_message, 415*6777b538SAndroid Build Coastguard Worker html_artifact=html_artifact) 416*6777b538SAndroid Build Coastguard Worker 417*6777b538SAndroid Build Coastguard Worker if self._rdb_client and self._logs_dir: 418*6777b538SAndroid Build Coastguard Worker # Attach artifacts from the device that don't apply to a single test. 419*6777b538SAndroid Build Coastguard Worker artifacts = self.get_artifacts( 420*6777b538SAndroid Build Coastguard Worker os.path.join(self._logs_dir, 'system_logs')) 421*6777b538SAndroid Build Coastguard Worker artifacts.update( 422*6777b538SAndroid Build Coastguard Worker self.get_artifacts(os.path.join(self._logs_dir, 'crashes'))) 423*6777b538SAndroid Build Coastguard Worker self._rdb_client.ReportInvocationLevelArtifacts(artifacts) 424*6777b538SAndroid Build Coastguard Worker 425*6777b538SAndroid Build Coastguard Worker if self._test_launcher_summary_output: 426*6777b538SAndroid Build Coastguard Worker with open(self._test_launcher_summary_output, 'w') as f: 427*6777b538SAndroid Build Coastguard Worker json.dump(json_results.GenerateResultsDict([suite_results]), f) 428*6777b538SAndroid Build Coastguard Worker 429*6777b538SAndroid Build Coastguard Worker if not suite_results.DidRunPass(): 430*6777b538SAndroid Build Coastguard Worker return 1 431*6777b538SAndroid Build Coastguard Worker if return_code: 432*6777b538SAndroid Build Coastguard Worker logging.warning( 433*6777b538SAndroid Build Coastguard Worker 'No failed tests found, but exit code of %d was returned from ' 434*6777b538SAndroid Build Coastguard Worker 'cros_run_test.', return_code) 435*6777b538SAndroid Build Coastguard Worker return return_code 436*6777b538SAndroid Build Coastguard Worker return 0 437*6777b538SAndroid Build Coastguard Worker 438*6777b538SAndroid Build Coastguard Worker def _maybe_handle_perf_results(self, test_name): 439*6777b538SAndroid Build Coastguard Worker """Prepares any perf results from |test_name| for process_perf_results. 440*6777b538SAndroid Build Coastguard Worker 441*6777b538SAndroid Build Coastguard Worker - process_perf_results looks for top level directories containing a 442*6777b538SAndroid Build Coastguard Worker perf_results.json file and a test_results.json file. The directory names 443*6777b538SAndroid Build Coastguard Worker are used as the benchmark names. 444*6777b538SAndroid Build Coastguard Worker - If a perf_results.json or results-chart.json file exists in the 445*6777b538SAndroid Build Coastguard Worker |test_name| results directory, a top level directory is created and the 446*6777b538SAndroid Build Coastguard Worker perf results file is copied to perf_results.json. 447*6777b538SAndroid Build Coastguard Worker - A trivial test_results.json file is also created to indicate that the test 448*6777b538SAndroid Build Coastguard Worker succeeded (this function would not be called otherwise). 449*6777b538SAndroid Build Coastguard Worker - When process_perf_results is run, it will find the expected files in the 450*6777b538SAndroid Build Coastguard Worker named directory and upload the benchmark results. 451*6777b538SAndroid Build Coastguard Worker """ 452*6777b538SAndroid Build Coastguard Worker 453*6777b538SAndroid Build Coastguard Worker perf_results = os.path.join(self._logs_dir, 'tests', test_name, 454*6777b538SAndroid Build Coastguard Worker 'perf_results.json') 455*6777b538SAndroid Build Coastguard Worker # TODO(stevenjb): Remove check for crosbolt results-chart.json file. 456*6777b538SAndroid Build Coastguard Worker if not os.path.exists(perf_results): 457*6777b538SAndroid Build Coastguard Worker perf_results = os.path.join(self._logs_dir, 'tests', test_name, 458*6777b538SAndroid Build Coastguard Worker 'results-chart.json') 459*6777b538SAndroid Build Coastguard Worker if os.path.exists(perf_results): 460*6777b538SAndroid Build Coastguard Worker benchmark_dir = os.path.join(self._logs_dir, test_name) 461*6777b538SAndroid Build Coastguard Worker if not os.path.isdir(benchmark_dir): 462*6777b538SAndroid Build Coastguard Worker os.makedirs(benchmark_dir) 463*6777b538SAndroid Build Coastguard Worker shutil.copyfile(perf_results, 464*6777b538SAndroid Build Coastguard Worker os.path.join(benchmark_dir, 'perf_results.json')) 465*6777b538SAndroid Build Coastguard Worker # process_perf_results.py expects a test_results.json file. 466*6777b538SAndroid Build Coastguard Worker test_results = {'valid': True, 'failures': []} 467*6777b538SAndroid Build Coastguard Worker with open(os.path.join(benchmark_dir, 'test_results.json'), 'w') as out: 468*6777b538SAndroid Build Coastguard Worker json.dump(test_results, out) 469*6777b538SAndroid Build Coastguard Worker 470*6777b538SAndroid Build Coastguard Worker 471*6777b538SAndroid Build Coastguard Workerclass GTestTest(RemoteTest): 472*6777b538SAndroid Build Coastguard Worker 473*6777b538SAndroid Build Coastguard Worker # The following list corresponds to paths that should not be copied over to 474*6777b538SAndroid Build Coastguard Worker # the device during tests. In other words, these files are only ever used on 475*6777b538SAndroid Build Coastguard Worker # the host. 476*6777b538SAndroid Build Coastguard Worker _FILE_IGNORELIST = [ 477*6777b538SAndroid Build Coastguard Worker re.compile(r'.*build/android.*'), 478*6777b538SAndroid Build Coastguard Worker re.compile(r'.*build/chromeos.*'), 479*6777b538SAndroid Build Coastguard Worker re.compile(r'.*build/cros_cache.*'), 480*6777b538SAndroid Build Coastguard Worker # The following matches anything under //testing/ that isn't under 481*6777b538SAndroid Build Coastguard Worker # //testing/buildbot/filters/. 482*6777b538SAndroid Build Coastguard Worker re.compile(r'.*testing/(?!buildbot/filters).*'), 483*6777b538SAndroid Build Coastguard Worker re.compile(r'.*third_party/chromite.*'), 484*6777b538SAndroid Build Coastguard Worker ] 485*6777b538SAndroid Build Coastguard Worker 486*6777b538SAndroid Build Coastguard Worker def __init__(self, args, unknown_args): 487*6777b538SAndroid Build Coastguard Worker super().__init__(args, unknown_args) 488*6777b538SAndroid Build Coastguard Worker 489*6777b538SAndroid Build Coastguard Worker self._test_cmd = ['vpython3'] + self._test_cmd 490*6777b538SAndroid Build Coastguard Worker if not args.clean: 491*6777b538SAndroid Build Coastguard Worker self._test_cmd += ['--no-clean'] 492*6777b538SAndroid Build Coastguard Worker 493*6777b538SAndroid Build Coastguard Worker self._test_exe = args.test_exe 494*6777b538SAndroid Build Coastguard Worker self._runtime_deps_path = args.runtime_deps_path 495*6777b538SAndroid Build Coastguard Worker self._vpython_dir = args.vpython_dir 496*6777b538SAndroid Build Coastguard Worker 497*6777b538SAndroid Build Coastguard Worker self._on_device_script = None 498*6777b538SAndroid Build Coastguard Worker self._env_vars = args.env_var 499*6777b538SAndroid Build Coastguard Worker self._stop_ui = args.stop_ui 500*6777b538SAndroid Build Coastguard Worker self._trace_dir = args.trace_dir 501*6777b538SAndroid Build Coastguard Worker self._run_test_sudo_helper = args.run_test_sudo_helper 502*6777b538SAndroid Build Coastguard Worker self._set_selinux_label = args.set_selinux_label 503*6777b538SAndroid Build Coastguard Worker 504*6777b538SAndroid Build Coastguard Worker @property 505*6777b538SAndroid Build Coastguard Worker def suite_name(self): 506*6777b538SAndroid Build Coastguard Worker return self._test_exe 507*6777b538SAndroid Build Coastguard Worker 508*6777b538SAndroid Build Coastguard Worker def build_test_command(self): 509*6777b538SAndroid Build Coastguard Worker # To keep things easy for us, ensure both types of output locations are 510*6777b538SAndroid Build Coastguard Worker # the same. 511*6777b538SAndroid Build Coastguard Worker if self._test_launcher_summary_output and self._logs_dir: 512*6777b538SAndroid Build Coastguard Worker json_out_dir = os.path.dirname(self._test_launcher_summary_output) or '.' 513*6777b538SAndroid Build Coastguard Worker if os.path.abspath(json_out_dir) != os.path.abspath(self._logs_dir): 514*6777b538SAndroid Build Coastguard Worker raise TestFormatError( 515*6777b538SAndroid Build Coastguard Worker '--test-launcher-summary-output and --logs-dir must point to ' 516*6777b538SAndroid Build Coastguard Worker 'the same directory.') 517*6777b538SAndroid Build Coastguard Worker 518*6777b538SAndroid Build Coastguard Worker if self._test_launcher_summary_output: 519*6777b538SAndroid Build Coastguard Worker result_dir, result_file = os.path.split( 520*6777b538SAndroid Build Coastguard Worker self._test_launcher_summary_output) 521*6777b538SAndroid Build Coastguard Worker # If args.test_launcher_summary_output is a file in cwd, result_dir will 522*6777b538SAndroid Build Coastguard Worker # be an empty string, so replace it with '.' when this is the case so 523*6777b538SAndroid Build Coastguard Worker # cros_run_test can correctly handle it. 524*6777b538SAndroid Build Coastguard Worker if not result_dir: 525*6777b538SAndroid Build Coastguard Worker result_dir = '.' 526*6777b538SAndroid Build Coastguard Worker device_result_file = '/tmp/%s' % result_file 527*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 528*6777b538SAndroid Build Coastguard Worker '--results-src', 529*6777b538SAndroid Build Coastguard Worker device_result_file, 530*6777b538SAndroid Build Coastguard Worker '--results-dest-dir', 531*6777b538SAndroid Build Coastguard Worker result_dir, 532*6777b538SAndroid Build Coastguard Worker ] 533*6777b538SAndroid Build Coastguard Worker 534*6777b538SAndroid Build Coastguard Worker if self._trace_dir and self._logs_dir: 535*6777b538SAndroid Build Coastguard Worker trace_path = os.path.dirname(self._trace_dir) or '.' 536*6777b538SAndroid Build Coastguard Worker if os.path.abspath(trace_path) != os.path.abspath(self._logs_dir): 537*6777b538SAndroid Build Coastguard Worker raise TestFormatError( 538*6777b538SAndroid Build Coastguard Worker '--trace-dir and --logs-dir must point to the same directory.') 539*6777b538SAndroid Build Coastguard Worker 540*6777b538SAndroid Build Coastguard Worker if self._trace_dir: 541*6777b538SAndroid Build Coastguard Worker trace_path, trace_dirname = os.path.split(self._trace_dir) 542*6777b538SAndroid Build Coastguard Worker device_trace_dir = '/tmp/%s' % trace_dirname 543*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 544*6777b538SAndroid Build Coastguard Worker '--results-src', 545*6777b538SAndroid Build Coastguard Worker device_trace_dir, 546*6777b538SAndroid Build Coastguard Worker '--results-dest-dir', 547*6777b538SAndroid Build Coastguard Worker trace_path, 548*6777b538SAndroid Build Coastguard Worker ] 549*6777b538SAndroid Build Coastguard Worker 550*6777b538SAndroid Build Coastguard Worker # Build the shell script that will be used on the device to invoke the test. 551*6777b538SAndroid Build Coastguard Worker # Stored here as a list of lines. 552*6777b538SAndroid Build Coastguard Worker device_test_script_contents = self.BASIC_SHELL_SCRIPT[:] 553*6777b538SAndroid Build Coastguard Worker for var_name, var_val in self._env_vars: 554*6777b538SAndroid Build Coastguard Worker device_test_script_contents += ['export %s=%s' % (var_name, var_val)] 555*6777b538SAndroid Build Coastguard Worker 556*6777b538SAndroid Build Coastguard Worker if self._vpython_dir: 557*6777b538SAndroid Build Coastguard Worker vpython_path = os.path.join(self._path_to_outdir, self._vpython_dir, 558*6777b538SAndroid Build Coastguard Worker 'vpython3') 559*6777b538SAndroid Build Coastguard Worker cpython_path = os.path.join(self._path_to_outdir, self._vpython_dir, 560*6777b538SAndroid Build Coastguard Worker 'bin', 'python3') 561*6777b538SAndroid Build Coastguard Worker if not os.path.exists(vpython_path) or not os.path.exists(cpython_path): 562*6777b538SAndroid Build Coastguard Worker raise TestFormatError( 563*6777b538SAndroid Build Coastguard Worker '--vpython-dir must point to a dir with both ' 564*6777b538SAndroid Build Coastguard Worker 'infra/3pp/tools/cpython3 and infra/tools/luci/vpython installed.') 565*6777b538SAndroid Build Coastguard Worker vpython_spec_path = os.path.relpath( 566*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMIUM_SRC_PATH, '.vpython3'), self._path_to_outdir) 567*6777b538SAndroid Build Coastguard Worker # Initialize the vpython cache. This can take 10-20s, and some tests 568*6777b538SAndroid Build Coastguard Worker # can't afford to wait that long on the first invocation. 569*6777b538SAndroid Build Coastguard Worker device_test_script_contents.extend([ 570*6777b538SAndroid Build Coastguard Worker 'export PATH=$PWD/%s:$PWD/%s/bin/:$PATH' % 571*6777b538SAndroid Build Coastguard Worker (self._vpython_dir, self._vpython_dir), 572*6777b538SAndroid Build Coastguard Worker 'vpython3 -vpython-spec %s -vpython-tool install' % 573*6777b538SAndroid Build Coastguard Worker (vpython_spec_path), 574*6777b538SAndroid Build Coastguard Worker ]) 575*6777b538SAndroid Build Coastguard Worker 576*6777b538SAndroid Build Coastguard Worker test_invocation = ('LD_LIBRARY_PATH=./ ./%s --test-launcher-shard-index=%d ' 577*6777b538SAndroid Build Coastguard Worker '--test-launcher-total-shards=%d' % 578*6777b538SAndroid Build Coastguard Worker (self._test_exe, self._test_launcher_shard_index, 579*6777b538SAndroid Build Coastguard Worker self._test_launcher_total_shards)) 580*6777b538SAndroid Build Coastguard Worker if self._test_launcher_summary_output: 581*6777b538SAndroid Build Coastguard Worker test_invocation += ' --test-launcher-summary-output=%s' % ( 582*6777b538SAndroid Build Coastguard Worker device_result_file) 583*6777b538SAndroid Build Coastguard Worker 584*6777b538SAndroid Build Coastguard Worker if self._trace_dir: 585*6777b538SAndroid Build Coastguard Worker device_test_script_contents.extend([ 586*6777b538SAndroid Build Coastguard Worker 'rm -rf %s' % device_trace_dir, 587*6777b538SAndroid Build Coastguard Worker 'sudo -E -u chronos -- /bin/bash -c "mkdir -p %s"' % device_trace_dir, 588*6777b538SAndroid Build Coastguard Worker ]) 589*6777b538SAndroid Build Coastguard Worker test_invocation += ' --trace-dir=%s' % device_trace_dir 590*6777b538SAndroid Build Coastguard Worker 591*6777b538SAndroid Build Coastguard Worker if self._run_test_sudo_helper: 592*6777b538SAndroid Build Coastguard Worker device_test_script_contents.extend([ 593*6777b538SAndroid Build Coastguard Worker 'TEST_SUDO_HELPER_PATH=$(mktemp)', 594*6777b538SAndroid Build Coastguard Worker './test_sudo_helper.py --socket-path=${TEST_SUDO_HELPER_PATH} &', 595*6777b538SAndroid Build Coastguard Worker 'TEST_SUDO_HELPER_PID=$!' 596*6777b538SAndroid Build Coastguard Worker ]) 597*6777b538SAndroid Build Coastguard Worker test_invocation += ( 598*6777b538SAndroid Build Coastguard Worker ' --test-sudo-helper-socket-path=${TEST_SUDO_HELPER_PATH}') 599*6777b538SAndroid Build Coastguard Worker 600*6777b538SAndroid Build Coastguard Worker # Append the selinux labels. The 'setfiles' command takes a file with each 601*6777b538SAndroid Build Coastguard Worker # line consisting of "<file-regex> <file-type> <new-label>", where '--' is 602*6777b538SAndroid Build Coastguard Worker # the type of a regular file. 603*6777b538SAndroid Build Coastguard Worker if self._set_selinux_label: 604*6777b538SAndroid Build Coastguard Worker for label_pair in self._set_selinux_label: 605*6777b538SAndroid Build Coastguard Worker filename, label = label_pair.split('=', 1) 606*6777b538SAndroid Build Coastguard Worker specfile = filename + '.specfile' 607*6777b538SAndroid Build Coastguard Worker device_test_script_contents.extend([ 608*6777b538SAndroid Build Coastguard Worker 'echo %s -- %s > %s' % (filename, label, specfile), 609*6777b538SAndroid Build Coastguard Worker 'setfiles -F %s %s' % (specfile, filename), 610*6777b538SAndroid Build Coastguard Worker ]) 611*6777b538SAndroid Build Coastguard Worker 612*6777b538SAndroid Build Coastguard Worker if self._additional_args: 613*6777b538SAndroid Build Coastguard Worker test_invocation += ' %s' % ' '.join(self._additional_args) 614*6777b538SAndroid Build Coastguard Worker 615*6777b538SAndroid Build Coastguard Worker if self._stop_ui: 616*6777b538SAndroid Build Coastguard Worker device_test_script_contents += [ 617*6777b538SAndroid Build Coastguard Worker 'stop ui', 618*6777b538SAndroid Build Coastguard Worker ] 619*6777b538SAndroid Build Coastguard Worker # Send a user activity ping to powerd to ensure the display is on. 620*6777b538SAndroid Build Coastguard Worker device_test_script_contents += [ 621*6777b538SAndroid Build Coastguard Worker 'dbus-send --system --type=method_call' 622*6777b538SAndroid Build Coastguard Worker ' --dest=org.chromium.PowerManager /org/chromium/PowerManager' 623*6777b538SAndroid Build Coastguard Worker ' org.chromium.PowerManager.HandleUserActivity int32:0' 624*6777b538SAndroid Build Coastguard Worker ] 625*6777b538SAndroid Build Coastguard Worker # The UI service on the device owns the chronos user session, so shutting 626*6777b538SAndroid Build Coastguard Worker # it down as chronos kills the entire execution of the test. So we'll have 627*6777b538SAndroid Build Coastguard Worker # to run as root up until the test invocation. 628*6777b538SAndroid Build Coastguard Worker test_invocation = ( 629*6777b538SAndroid Build Coastguard Worker 'sudo -E -u chronos -- /bin/bash -c "%s"' % test_invocation) 630*6777b538SAndroid Build Coastguard Worker # And we'll need to chown everything since cros_run_test's "--as-chronos" 631*6777b538SAndroid Build Coastguard Worker # option normally does that for us. 632*6777b538SAndroid Build Coastguard Worker device_test_script_contents.append('chown -R chronos: ../..') 633*6777b538SAndroid Build Coastguard Worker else: 634*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 635*6777b538SAndroid Build Coastguard Worker # Some tests fail as root, so run as the less privileged user 636*6777b538SAndroid Build Coastguard Worker # 'chronos'. 637*6777b538SAndroid Build Coastguard Worker '--as-chronos', 638*6777b538SAndroid Build Coastguard Worker ] 639*6777b538SAndroid Build Coastguard Worker 640*6777b538SAndroid Build Coastguard Worker device_test_script_contents.append(test_invocation) 641*6777b538SAndroid Build Coastguard Worker device_test_script_contents.append('TEST_RETURN_CODE=$?') 642*6777b538SAndroid Build Coastguard Worker 643*6777b538SAndroid Build Coastguard Worker # (Re)start ui after all tests are done. This is for developer convenienve. 644*6777b538SAndroid Build Coastguard Worker # Without this, the device would remain in a black screen which looks like 645*6777b538SAndroid Build Coastguard Worker # powered off. 646*6777b538SAndroid Build Coastguard Worker if self._stop_ui: 647*6777b538SAndroid Build Coastguard Worker device_test_script_contents += [ 648*6777b538SAndroid Build Coastguard Worker 'start ui', 649*6777b538SAndroid Build Coastguard Worker ] 650*6777b538SAndroid Build Coastguard Worker 651*6777b538SAndroid Build Coastguard Worker # Stop the crosier helper. 652*6777b538SAndroid Build Coastguard Worker if self._run_test_sudo_helper: 653*6777b538SAndroid Build Coastguard Worker device_test_script_contents.extend([ 654*6777b538SAndroid Build Coastguard Worker 'pkill -P $TEST_SUDO_HELPER_PID', 655*6777b538SAndroid Build Coastguard Worker 'kill $TEST_SUDO_HELPER_PID', 656*6777b538SAndroid Build Coastguard Worker 'unlink ${TEST_SUDO_HELPER_PATH}', 657*6777b538SAndroid Build Coastguard Worker ]) 658*6777b538SAndroid Build Coastguard Worker 659*6777b538SAndroid Build Coastguard Worker # This command should always be the last bash commandline so infra can 660*6777b538SAndroid Build Coastguard Worker # correctly get the error code from test invocations. 661*6777b538SAndroid Build Coastguard Worker device_test_script_contents.append('exit $TEST_RETURN_CODE') 662*6777b538SAndroid Build Coastguard Worker 663*6777b538SAndroid Build Coastguard Worker self._on_device_script = self.write_test_script_to_disk( 664*6777b538SAndroid Build Coastguard Worker device_test_script_contents) 665*6777b538SAndroid Build Coastguard Worker 666*6777b538SAndroid Build Coastguard Worker runtime_files = [os.path.relpath(self._on_device_script)] 667*6777b538SAndroid Build Coastguard Worker runtime_files += self._read_runtime_files() 668*6777b538SAndroid Build Coastguard Worker if self._vpython_dir: 669*6777b538SAndroid Build Coastguard Worker # --vpython-dir is relative to the out dir, but --files expects paths 670*6777b538SAndroid Build Coastguard Worker # relative to src dir, so fix the path up a bit. 671*6777b538SAndroid Build Coastguard Worker runtime_files.append( 672*6777b538SAndroid Build Coastguard Worker os.path.relpath( 673*6777b538SAndroid Build Coastguard Worker os.path.abspath( 674*6777b538SAndroid Build Coastguard Worker os.path.join(self._path_to_outdir, self._vpython_dir)), 675*6777b538SAndroid Build Coastguard Worker CHROMIUM_SRC_PATH)) 676*6777b538SAndroid Build Coastguard Worker 677*6777b538SAndroid Build Coastguard Worker for f in runtime_files: 678*6777b538SAndroid Build Coastguard Worker self._test_cmd.extend(['--files', f]) 679*6777b538SAndroid Build Coastguard Worker 680*6777b538SAndroid Build Coastguard Worker self._test_cmd += [ 681*6777b538SAndroid Build Coastguard Worker '--', 682*6777b538SAndroid Build Coastguard Worker './' + os.path.relpath(self._on_device_script, self._path_to_outdir) 683*6777b538SAndroid Build Coastguard Worker ] 684*6777b538SAndroid Build Coastguard Worker 685*6777b538SAndroid Build Coastguard Worker def _read_runtime_files(self): 686*6777b538SAndroid Build Coastguard Worker if not self._runtime_deps_path: 687*6777b538SAndroid Build Coastguard Worker return [] 688*6777b538SAndroid Build Coastguard Worker 689*6777b538SAndroid Build Coastguard Worker abs_runtime_deps_path = os.path.abspath( 690*6777b538SAndroid Build Coastguard Worker os.path.join(self._path_to_outdir, self._runtime_deps_path)) 691*6777b538SAndroid Build Coastguard Worker with open(abs_runtime_deps_path) as runtime_deps_file: 692*6777b538SAndroid Build Coastguard Worker files = [l.strip() for l in runtime_deps_file if l] 693*6777b538SAndroid Build Coastguard Worker rel_file_paths = [] 694*6777b538SAndroid Build Coastguard Worker for f in files: 695*6777b538SAndroid Build Coastguard Worker rel_file_path = os.path.relpath( 696*6777b538SAndroid Build Coastguard Worker os.path.abspath(os.path.join(self._path_to_outdir, f))) 697*6777b538SAndroid Build Coastguard Worker if not any(regex.match(rel_file_path) for regex in self._FILE_IGNORELIST): 698*6777b538SAndroid Build Coastguard Worker rel_file_paths.append(rel_file_path) 699*6777b538SAndroid Build Coastguard Worker return rel_file_paths 700*6777b538SAndroid Build Coastguard Worker 701*6777b538SAndroid Build Coastguard Worker def post_run(self, _): 702*6777b538SAndroid Build Coastguard Worker if self._on_device_script: 703*6777b538SAndroid Build Coastguard Worker os.remove(self._on_device_script) 704*6777b538SAndroid Build Coastguard Worker 705*6777b538SAndroid Build Coastguard Worker if self._test_launcher_summary_output and self._rdb_client: 706*6777b538SAndroid Build Coastguard Worker logging.error('Native ResultDB integration is not supported for GTests. ' 707*6777b538SAndroid Build Coastguard Worker 'Upload results via result_adapter instead. ' 708*6777b538SAndroid Build Coastguard Worker 'See crbug.com/1330441.') 709*6777b538SAndroid Build Coastguard Worker 710*6777b538SAndroid Build Coastguard Worker 711*6777b538SAndroid Build Coastguard Workerdef device_test(args, unknown_args): 712*6777b538SAndroid Build Coastguard Worker # cros_run_test has trouble with relative paths that go up directories, 713*6777b538SAndroid Build Coastguard Worker # so cd to src/, which should be the root of all data deps. 714*6777b538SAndroid Build Coastguard Worker os.chdir(CHROMIUM_SRC_PATH) 715*6777b538SAndroid Build Coastguard Worker 716*6777b538SAndroid Build Coastguard Worker # TODO: Remove the above when depot_tool's pylint is updated to include the 717*6777b538SAndroid Build Coastguard Worker # fix to https://github.com/PyCQA/pylint/issues/710. 718*6777b538SAndroid Build Coastguard Worker if args.test_type == 'tast': 719*6777b538SAndroid Build Coastguard Worker test = TastTest(args, unknown_args) 720*6777b538SAndroid Build Coastguard Worker else: 721*6777b538SAndroid Build Coastguard Worker test = GTestTest(args, unknown_args) 722*6777b538SAndroid Build Coastguard Worker 723*6777b538SAndroid Build Coastguard Worker test.build_test_command() 724*6777b538SAndroid Build Coastguard Worker logging.info('Running the following command on the device:') 725*6777b538SAndroid Build Coastguard Worker logging.info(' '.join(test.test_cmd)) 726*6777b538SAndroid Build Coastguard Worker 727*6777b538SAndroid Build Coastguard Worker return test.run_test() 728*6777b538SAndroid Build Coastguard Worker 729*6777b538SAndroid Build Coastguard Worker 730*6777b538SAndroid Build Coastguard Workerdef host_cmd(args, cmd_args): 731*6777b538SAndroid Build Coastguard Worker if not cmd_args: 732*6777b538SAndroid Build Coastguard Worker raise TestFormatError('Must specify command to run on the host.') 733*6777b538SAndroid Build Coastguard Worker if args.deploy_chrome and not args.path_to_outdir: 734*6777b538SAndroid Build Coastguard Worker raise TestFormatError( 735*6777b538SAndroid Build Coastguard Worker '--path-to-outdir must be specified if --deploy-chrome is passed.') 736*6777b538SAndroid Build Coastguard Worker 737*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd = [ 738*6777b538SAndroid Build Coastguard Worker CROS_RUN_TEST_PATH, 739*6777b538SAndroid Build Coastguard Worker '--board', 740*6777b538SAndroid Build Coastguard Worker args.board, 741*6777b538SAndroid Build Coastguard Worker '--cache-dir', 742*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMIUM_SRC_PATH, args.cros_cache), 743*6777b538SAndroid Build Coastguard Worker ] 744*6777b538SAndroid Build Coastguard Worker if args.use_vm: 745*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += [ 746*6777b538SAndroid Build Coastguard Worker '--start', 747*6777b538SAndroid Build Coastguard Worker # Don't persist any filesystem changes after the VM shutsdown. 748*6777b538SAndroid Build Coastguard Worker '--copy-on-write', 749*6777b538SAndroid Build Coastguard Worker ] 750*6777b538SAndroid Build Coastguard Worker else: 751*6777b538SAndroid Build Coastguard Worker if args.fetch_cros_hostname: 752*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += ['--device', get_cros_hostname()] 753*6777b538SAndroid Build Coastguard Worker else: 754*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += [ 755*6777b538SAndroid Build Coastguard Worker '--device', args.device if args.device else LAB_DUT_HOSTNAME 756*6777b538SAndroid Build Coastguard Worker ] 757*6777b538SAndroid Build Coastguard Worker if args.verbose: 758*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd.append('--debug') 759*6777b538SAndroid Build Coastguard Worker if args.flash: 760*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd.append('--flash') 761*6777b538SAndroid Build Coastguard Worker if args.public_image: 762*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += ['--public-image'] 763*6777b538SAndroid Build Coastguard Worker 764*6777b538SAndroid Build Coastguard Worker if args.logs_dir: 765*6777b538SAndroid Build Coastguard Worker for log in SYSTEM_LOG_LOCATIONS: 766*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += ['--results-src', log] 767*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += [ 768*6777b538SAndroid Build Coastguard Worker '--results-dest-dir', 769*6777b538SAndroid Build Coastguard Worker os.path.join(args.logs_dir, 'system_logs') 770*6777b538SAndroid Build Coastguard Worker ] 771*6777b538SAndroid Build Coastguard Worker 772*6777b538SAndroid Build Coastguard Worker test_env = setup_env() 773*6777b538SAndroid Build Coastguard Worker if args.deploy_chrome or args.deploy_lacros: 774*6777b538SAndroid Build Coastguard Worker if args.deploy_lacros: 775*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd.extend([ 776*6777b538SAndroid Build Coastguard Worker '--deploy-lacros', '--lacros-launcher-script', 777*6777b538SAndroid Build Coastguard Worker LACROS_LAUNCHER_SCRIPT_PATH 778*6777b538SAndroid Build Coastguard Worker ]) 779*6777b538SAndroid Build Coastguard Worker if args.deploy_chrome: 780*6777b538SAndroid Build Coastguard Worker # Mounting ash-chrome gives it enough disk space to not need stripping 781*6777b538SAndroid Build Coastguard Worker # most of the time. 782*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd.extend(['--deploy', '--mount']) 783*6777b538SAndroid Build Coastguard Worker else: 784*6777b538SAndroid Build Coastguard Worker # Mounting ash-chrome gives it enough disk space to not need stripping 785*6777b538SAndroid Build Coastguard Worker # most of the time. 786*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd.extend(['--deploy', '--mount']) 787*6777b538SAndroid Build Coastguard Worker 788*6777b538SAndroid Build Coastguard Worker if not args.strip_chrome: 789*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd.append('--nostrip') 790*6777b538SAndroid Build Coastguard Worker 791*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += [ 792*6777b538SAndroid Build Coastguard Worker '--build-dir', 793*6777b538SAndroid Build Coastguard Worker os.path.join(CHROMIUM_SRC_PATH, args.path_to_outdir) 794*6777b538SAndroid Build Coastguard Worker ] 795*6777b538SAndroid Build Coastguard Worker 796*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd += [ 797*6777b538SAndroid Build Coastguard Worker '--host-cmd', 798*6777b538SAndroid Build Coastguard Worker '--', 799*6777b538SAndroid Build Coastguard Worker ] + cmd_args 800*6777b538SAndroid Build Coastguard Worker 801*6777b538SAndroid Build Coastguard Worker logging.info('Running the following command:') 802*6777b538SAndroid Build Coastguard Worker logging.info(' '.join(cros_run_test_cmd)) 803*6777b538SAndroid Build Coastguard Worker 804*6777b538SAndroid Build Coastguard Worker return subprocess.call( 805*6777b538SAndroid Build Coastguard Worker cros_run_test_cmd, stdout=sys.stdout, stderr=sys.stderr, env=test_env) 806*6777b538SAndroid Build Coastguard Worker 807*6777b538SAndroid Build Coastguard Worker 808*6777b538SAndroid Build Coastguard Workerdef get_cros_hostname_from_bot_id(bot_id): 809*6777b538SAndroid Build Coastguard Worker """Parse hostname from a chromeos-swarming bot id.""" 810*6777b538SAndroid Build Coastguard Worker for prefix in ['cros-', 'crossk-']: 811*6777b538SAndroid Build Coastguard Worker if bot_id.startswith(prefix): 812*6777b538SAndroid Build Coastguard Worker return bot_id[len(prefix):] 813*6777b538SAndroid Build Coastguard Worker return bot_id 814*6777b538SAndroid Build Coastguard Worker 815*6777b538SAndroid Build Coastguard Worker 816*6777b538SAndroid Build Coastguard Workerdef get_cros_hostname(): 817*6777b538SAndroid Build Coastguard Worker """Fetch bot_id from env var and parse hostname.""" 818*6777b538SAndroid Build Coastguard Worker 819*6777b538SAndroid Build Coastguard Worker # In chromeos-swarming, we can extract hostname from bot ID, since 820*6777b538SAndroid Build Coastguard Worker # bot ID is formatted as "{prefix}{hostname}". 821*6777b538SAndroid Build Coastguard Worker bot_id = os.environ.get('SWARMING_BOT_ID') 822*6777b538SAndroid Build Coastguard Worker if bot_id: 823*6777b538SAndroid Build Coastguard Worker return get_cros_hostname_from_bot_id(bot_id) 824*6777b538SAndroid Build Coastguard Worker 825*6777b538SAndroid Build Coastguard Worker logging.warning( 826*6777b538SAndroid Build Coastguard Worker 'Attempted to read from SWARMING_BOT_ID env var and it was' 827*6777b538SAndroid Build Coastguard Worker ' not defined. Will set %s as device instead.', LAB_DUT_HOSTNAME) 828*6777b538SAndroid Build Coastguard Worker return LAB_DUT_HOSTNAME 829*6777b538SAndroid Build Coastguard Worker 830*6777b538SAndroid Build Coastguard Worker 831*6777b538SAndroid Build Coastguard Workerdef setup_env(): 832*6777b538SAndroid Build Coastguard Worker """Returns a copy of the current env with some needed vars added.""" 833*6777b538SAndroid Build Coastguard Worker env = os.environ.copy() 834*6777b538SAndroid Build Coastguard Worker # Some chromite scripts expect chromite/bin to be on PATH. 835*6777b538SAndroid Build Coastguard Worker env['PATH'] = env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin') 836*6777b538SAndroid Build Coastguard Worker # deploy_chrome needs a set of GN args used to build chrome to determine if 837*6777b538SAndroid Build Coastguard Worker # certain libraries need to be pushed to the device. It looks for the args via 838*6777b538SAndroid Build Coastguard Worker # an env var. To trigger the default deploying behavior, give it a dummy set 839*6777b538SAndroid Build Coastguard Worker # of args. 840*6777b538SAndroid Build Coastguard Worker # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd 841*6777b538SAndroid Build Coastguard Worker # line args. 842*6777b538SAndroid Build Coastguard Worker if not env.get('GN_ARGS'): 843*6777b538SAndroid Build Coastguard Worker env['GN_ARGS'] = 'enable_nacl = true' 844*6777b538SAndroid Build Coastguard Worker if not env.get('USE'): 845*6777b538SAndroid Build Coastguard Worker env['USE'] = 'highdpi' 846*6777b538SAndroid Build Coastguard Worker return env 847*6777b538SAndroid Build Coastguard Worker 848*6777b538SAndroid Build Coastguard Worker 849*6777b538SAndroid Build Coastguard Workerdef add_common_args(*parsers): 850*6777b538SAndroid Build Coastguard Worker for parser in parsers: 851*6777b538SAndroid Build Coastguard Worker parser.add_argument('--verbose', '-v', action='store_true') 852*6777b538SAndroid Build Coastguard Worker parser.add_argument( 853*6777b538SAndroid Build Coastguard Worker '--board', type=str, required=True, help='Type of CrOS device.') 854*6777b538SAndroid Build Coastguard Worker parser.add_argument( 855*6777b538SAndroid Build Coastguard Worker '--deploy-chrome', 856*6777b538SAndroid Build Coastguard Worker action='store_true', 857*6777b538SAndroid Build Coastguard Worker help='Will deploy a locally built ash-chrome binary to the device ' 858*6777b538SAndroid Build Coastguard Worker 'before running the host-cmd.') 859*6777b538SAndroid Build Coastguard Worker parser.add_argument( 860*6777b538SAndroid Build Coastguard Worker '--deploy-lacros', action='store_true', help='Deploy a lacros-chrome.') 861*6777b538SAndroid Build Coastguard Worker parser.add_argument( 862*6777b538SAndroid Build Coastguard Worker '--cros-cache', 863*6777b538SAndroid Build Coastguard Worker type=str, 864*6777b538SAndroid Build Coastguard Worker default=DEFAULT_CROS_CACHE, 865*6777b538SAndroid Build Coastguard Worker help='Path to cros cache.') 866*6777b538SAndroid Build Coastguard Worker parser.add_argument( 867*6777b538SAndroid Build Coastguard Worker '--path-to-outdir', 868*6777b538SAndroid Build Coastguard Worker type=str, 869*6777b538SAndroid Build Coastguard Worker required=True, 870*6777b538SAndroid Build Coastguard Worker help='Path to output directory, all of whose contents will be ' 871*6777b538SAndroid Build Coastguard Worker 'deployed to the device.') 872*6777b538SAndroid Build Coastguard Worker parser.add_argument( 873*6777b538SAndroid Build Coastguard Worker '--runtime-deps-path', 874*6777b538SAndroid Build Coastguard Worker type=str, 875*6777b538SAndroid Build Coastguard Worker help='Runtime data dependency file from GN.') 876*6777b538SAndroid Build Coastguard Worker parser.add_argument( 877*6777b538SAndroid Build Coastguard Worker '--vpython-dir', 878*6777b538SAndroid Build Coastguard Worker type=str, 879*6777b538SAndroid Build Coastguard Worker help='Location on host of a directory containing a vpython binary to ' 880*6777b538SAndroid Build Coastguard Worker 'deploy to the device before the test starts. The location of ' 881*6777b538SAndroid Build Coastguard Worker 'this dir will be added onto PATH in the device. WARNING: The ' 882*6777b538SAndroid Build Coastguard Worker 'arch of the device might not match the arch of the host, so ' 883*6777b538SAndroid Build Coastguard Worker 'avoid using "${platform}" when downloading vpython via CIPD.') 884*6777b538SAndroid Build Coastguard Worker parser.add_argument( 885*6777b538SAndroid Build Coastguard Worker '--logs-dir', 886*6777b538SAndroid Build Coastguard Worker type=str, 887*6777b538SAndroid Build Coastguard Worker dest='logs_dir', 888*6777b538SAndroid Build Coastguard Worker help='Will copy everything under /var/log/ from the device after the ' 889*6777b538SAndroid Build Coastguard Worker 'test into the specified dir.') 890*6777b538SAndroid Build Coastguard Worker # Shard args are parsed here since we might also specify them via env vars. 891*6777b538SAndroid Build Coastguard Worker parser.add_argument( 892*6777b538SAndroid Build Coastguard Worker '--test-launcher-shard-index', 893*6777b538SAndroid Build Coastguard Worker type=int, 894*6777b538SAndroid Build Coastguard Worker default=os.environ.get('GTEST_SHARD_INDEX', 0), 895*6777b538SAndroid Build Coastguard Worker help='Index of the external shard to run.') 896*6777b538SAndroid Build Coastguard Worker parser.add_argument( 897*6777b538SAndroid Build Coastguard Worker '--test-launcher-total-shards', 898*6777b538SAndroid Build Coastguard Worker type=int, 899*6777b538SAndroid Build Coastguard Worker default=os.environ.get('GTEST_TOTAL_SHARDS', 1), 900*6777b538SAndroid Build Coastguard Worker help='Total number of external shards.') 901*6777b538SAndroid Build Coastguard Worker parser.add_argument( 902*6777b538SAndroid Build Coastguard Worker '--flash', 903*6777b538SAndroid Build Coastguard Worker action='store_true', 904*6777b538SAndroid Build Coastguard Worker help='Will flash the device to the current SDK version before running ' 905*6777b538SAndroid Build Coastguard Worker 'the test.') 906*6777b538SAndroid Build Coastguard Worker parser.add_argument( 907*6777b538SAndroid Build Coastguard Worker '--no-flash', 908*6777b538SAndroid Build Coastguard Worker action='store_false', 909*6777b538SAndroid Build Coastguard Worker dest='flash', 910*6777b538SAndroid Build Coastguard Worker help='Will not flash the device before running the test.') 911*6777b538SAndroid Build Coastguard Worker parser.add_argument( 912*6777b538SAndroid Build Coastguard Worker '--public-image', 913*6777b538SAndroid Build Coastguard Worker action='store_true', 914*6777b538SAndroid Build Coastguard Worker help='Will flash a public "full" image to the device.') 915*6777b538SAndroid Build Coastguard Worker parser.add_argument( 916*6777b538SAndroid Build Coastguard Worker '--magic-vm-cache', 917*6777b538SAndroid Build Coastguard Worker help='Path to the magic CrOS VM cache dir. See the comment above ' 918*6777b538SAndroid Build Coastguard Worker '"magic_cros_vm_cache" in mixins.pyl for more info.') 919*6777b538SAndroid Build Coastguard Worker 920*6777b538SAndroid Build Coastguard Worker vm_or_device_group = parser.add_mutually_exclusive_group() 921*6777b538SAndroid Build Coastguard Worker vm_or_device_group.add_argument( 922*6777b538SAndroid Build Coastguard Worker '--use-vm', 923*6777b538SAndroid Build Coastguard Worker action='store_true', 924*6777b538SAndroid Build Coastguard Worker help='Will run the test in the VM instead of a device.') 925*6777b538SAndroid Build Coastguard Worker vm_or_device_group.add_argument( 926*6777b538SAndroid Build Coastguard Worker '--device', 927*6777b538SAndroid Build Coastguard Worker type=str, 928*6777b538SAndroid Build Coastguard Worker help='Hostname (or IP) of device to run the test on. This arg is not ' 929*6777b538SAndroid Build Coastguard Worker 'required if --use-vm is set.') 930*6777b538SAndroid Build Coastguard Worker vm_or_device_group.add_argument( 931*6777b538SAndroid Build Coastguard Worker '--fetch-cros-hostname', 932*6777b538SAndroid Build Coastguard Worker action='store_true', 933*6777b538SAndroid Build Coastguard Worker help='Will extract device hostname from the SWARMING_BOT_ID env var if ' 934*6777b538SAndroid Build Coastguard Worker 'running on ChromeOS Swarming.') 935*6777b538SAndroid Build Coastguard Worker 936*6777b538SAndroid Build Coastguard Workerdef main(): 937*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 938*6777b538SAndroid Build Coastguard Worker subparsers = parser.add_subparsers(dest='test_type') 939*6777b538SAndroid Build Coastguard Worker # Host-side test args. 940*6777b538SAndroid Build Coastguard Worker host_cmd_parser = subparsers.add_parser( 941*6777b538SAndroid Build Coastguard Worker 'host-cmd', 942*6777b538SAndroid Build Coastguard Worker help='Runs a host-side test. Pass the host-side command to run after ' 943*6777b538SAndroid Build Coastguard Worker '"--". If --use-vm is passed, hostname and port for the device ' 944*6777b538SAndroid Build Coastguard Worker 'will be 127.0.0.1:9222.') 945*6777b538SAndroid Build Coastguard Worker host_cmd_parser.set_defaults(func=host_cmd) 946*6777b538SAndroid Build Coastguard Worker host_cmd_parser.add_argument( 947*6777b538SAndroid Build Coastguard Worker '--strip-chrome', 948*6777b538SAndroid Build Coastguard Worker action='store_true', 949*6777b538SAndroid Build Coastguard Worker help='Strips symbols from ash-chrome or lacros-chrome before deploying ' 950*6777b538SAndroid Build Coastguard Worker ' to the device.') 951*6777b538SAndroid Build Coastguard Worker 952*6777b538SAndroid Build Coastguard Worker gtest_parser = subparsers.add_parser( 953*6777b538SAndroid Build Coastguard Worker 'gtest', help='Runs a device-side gtest.') 954*6777b538SAndroid Build Coastguard Worker gtest_parser.set_defaults(func=device_test) 955*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 956*6777b538SAndroid Build Coastguard Worker '--test-exe', 957*6777b538SAndroid Build Coastguard Worker type=str, 958*6777b538SAndroid Build Coastguard Worker required=True, 959*6777b538SAndroid Build Coastguard Worker help='Path to test executable to run inside the device.') 960*6777b538SAndroid Build Coastguard Worker 961*6777b538SAndroid Build Coastguard Worker # GTest args. Some are passed down to the test binary in the device. Others 962*6777b538SAndroid Build Coastguard Worker # are parsed here since they might need tweaking or special handling. 963*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 964*6777b538SAndroid Build Coastguard Worker '--test-launcher-summary-output', 965*6777b538SAndroid Build Coastguard Worker type=str, 966*6777b538SAndroid Build Coastguard Worker help='When set, will pass the same option down to the test and retrieve ' 967*6777b538SAndroid Build Coastguard Worker 'its result file at the specified location.') 968*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 969*6777b538SAndroid Build Coastguard Worker '--stop-ui', 970*6777b538SAndroid Build Coastguard Worker action='store_true', 971*6777b538SAndroid Build Coastguard Worker help='Will stop the UI service in the device before running the test. ' 972*6777b538SAndroid Build Coastguard Worker 'Also start the UI service after all tests are done.') 973*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 974*6777b538SAndroid Build Coastguard Worker '--trace-dir', 975*6777b538SAndroid Build Coastguard Worker type=str, 976*6777b538SAndroid Build Coastguard Worker help='When set, will pass down to the test to generate the trace and ' 977*6777b538SAndroid Build Coastguard Worker 'retrieve the trace files to the specified location.') 978*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 979*6777b538SAndroid Build Coastguard Worker '--env-var', 980*6777b538SAndroid Build Coastguard Worker nargs=2, 981*6777b538SAndroid Build Coastguard Worker action='append', 982*6777b538SAndroid Build Coastguard Worker default=[], 983*6777b538SAndroid Build Coastguard Worker help='Env var to set on the device for the duration of the test. ' 984*6777b538SAndroid Build Coastguard Worker 'Expected format is "--env-var SOME_VAR_NAME some_var_value". Specify ' 985*6777b538SAndroid Build Coastguard Worker 'multiple times for more than one var.') 986*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 987*6777b538SAndroid Build Coastguard Worker '--run-test-sudo-helper', 988*6777b538SAndroid Build Coastguard Worker action='store_true', 989*6777b538SAndroid Build Coastguard Worker help='When set, will run test_sudo_helper before the test and stop it ' 990*6777b538SAndroid Build Coastguard Worker 'after test finishes.') 991*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 992*6777b538SAndroid Build Coastguard Worker "--no-clean", 993*6777b538SAndroid Build Coastguard Worker action="store_false", 994*6777b538SAndroid Build Coastguard Worker dest="clean", 995*6777b538SAndroid Build Coastguard Worker default=True, 996*6777b538SAndroid Build Coastguard Worker help="Do not clean up the deployed files after running the test. " 997*6777b538SAndroid Build Coastguard Worker "Only supported for --remote-cmd tests") 998*6777b538SAndroid Build Coastguard Worker gtest_parser.add_argument( 999*6777b538SAndroid Build Coastguard Worker '--set-selinux-label', 1000*6777b538SAndroid Build Coastguard Worker action='append', 1001*6777b538SAndroid Build Coastguard Worker default=[], 1002*6777b538SAndroid Build Coastguard Worker help='Set the selinux label for a file before running. The format is:\n' 1003*6777b538SAndroid Build Coastguard Worker ' --set-selinux-label=<filename>=<label>\n' 1004*6777b538SAndroid Build Coastguard Worker 'So:\n' 1005*6777b538SAndroid Build Coastguard Worker ' --set-selinux-label=my_test=u:r:cros_foo_label:s0\n' 1006*6777b538SAndroid Build Coastguard Worker 'You can specify it more than one time to set multiple files tags.') 1007*6777b538SAndroid Build Coastguard Worker 1008*6777b538SAndroid Build Coastguard Worker # Tast test args. 1009*6777b538SAndroid Build Coastguard Worker # pylint: disable=line-too-long 1010*6777b538SAndroid Build Coastguard Worker tast_test_parser = subparsers.add_parser( 1011*6777b538SAndroid Build Coastguard Worker 'tast', 1012*6777b538SAndroid Build Coastguard Worker help='Runs a device-side set of Tast tests. For more details, see: ' 1013*6777b538SAndroid Build Coastguard Worker 'https://chromium.googlesource.com/chromiumos/platform/tast/+/main/docs/running_tests.md' 1014*6777b538SAndroid Build Coastguard Worker ) 1015*6777b538SAndroid Build Coastguard Worker tast_test_parser.set_defaults(func=device_test) 1016*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1017*6777b538SAndroid Build Coastguard Worker '--suite-name', 1018*6777b538SAndroid Build Coastguard Worker type=str, 1019*6777b538SAndroid Build Coastguard Worker required=True, 1020*6777b538SAndroid Build Coastguard Worker help='Name to apply to the set of Tast tests to run. This has no effect ' 1021*6777b538SAndroid Build Coastguard Worker 'on what is executed, but is used mainly for test results reporting ' 1022*6777b538SAndroid Build Coastguard Worker 'and tracking (eg: flakiness dashboard).') 1023*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1024*6777b538SAndroid Build Coastguard Worker '--test-launcher-summary-output', 1025*6777b538SAndroid Build Coastguard Worker type=str, 1026*6777b538SAndroid Build Coastguard Worker help='Generates a simple GTest-style JSON result file for the test run.') 1027*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1028*6777b538SAndroid Build Coastguard Worker '--attr-expr', 1029*6777b538SAndroid Build Coastguard Worker type=str, 1030*6777b538SAndroid Build Coastguard Worker help='A boolean expression whose matching tests will run ' 1031*6777b538SAndroid Build Coastguard Worker '(eg: ("dep:chrome")).') 1032*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1033*6777b538SAndroid Build Coastguard Worker '--strip-chrome', 1034*6777b538SAndroid Build Coastguard Worker action='store_true', 1035*6777b538SAndroid Build Coastguard Worker help='Strips symbols from ash-chrome before deploying to the device.') 1036*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1037*6777b538SAndroid Build Coastguard Worker '--tast-var', 1038*6777b538SAndroid Build Coastguard Worker action='append', 1039*6777b538SAndroid Build Coastguard Worker dest='tast_vars', 1040*6777b538SAndroid Build Coastguard Worker help='Runtime variables for Tast tests, and the format are expected to ' 1041*6777b538SAndroid Build Coastguard Worker 'be "key=value" pairs.') 1042*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1043*6777b538SAndroid Build Coastguard Worker '--tast-retries', 1044*6777b538SAndroid Build Coastguard Worker type=int, 1045*6777b538SAndroid Build Coastguard Worker dest='tast_retries', 1046*6777b538SAndroid Build Coastguard Worker help='Number of retries for failed Tast tests on the same DUT.') 1047*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1048*6777b538SAndroid Build Coastguard Worker '--test', 1049*6777b538SAndroid Build Coastguard Worker '-t', 1050*6777b538SAndroid Build Coastguard Worker action='append', 1051*6777b538SAndroid Build Coastguard Worker dest='tests', 1052*6777b538SAndroid Build Coastguard Worker help='A Tast test to run in the device (eg: "login.Chrome").') 1053*6777b538SAndroid Build Coastguard Worker tast_test_parser.add_argument( 1054*6777b538SAndroid Build Coastguard Worker '--gtest_filter', 1055*6777b538SAndroid Build Coastguard Worker type=str, 1056*6777b538SAndroid Build Coastguard Worker help="Similar to GTest's arg of the same name, this will filter out the " 1057*6777b538SAndroid Build Coastguard Worker "specified tests from the Tast run. However, due to the nature of Tast's " 1058*6777b538SAndroid Build Coastguard Worker 'cmd-line API, this will overwrite the value(s) of "--test" above.') 1059*6777b538SAndroid Build Coastguard Worker 1060*6777b538SAndroid Build Coastguard Worker add_common_args(gtest_parser, tast_test_parser, host_cmd_parser) 1061*6777b538SAndroid Build Coastguard Worker args, unknown_args = parser.parse_known_args() 1062*6777b538SAndroid Build Coastguard Worker # Re-add N-1 -v/--verbose flags to the args we'll pass to whatever we are 1063*6777b538SAndroid Build Coastguard Worker # running. The assumption is that only one verbosity incrase would be meant 1064*6777b538SAndroid Build Coastguard Worker # for this script since it's a boolean value instead of increasing verbosity 1065*6777b538SAndroid Build Coastguard Worker # with more instances. 1066*6777b538SAndroid Build Coastguard Worker verbose_flags = [a for a in sys.argv if a in ('-v', '--verbose')] 1067*6777b538SAndroid Build Coastguard Worker if verbose_flags: 1068*6777b538SAndroid Build Coastguard Worker unknown_args += verbose_flags[1:] 1069*6777b538SAndroid Build Coastguard Worker 1070*6777b538SAndroid Build Coastguard Worker logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARN) 1071*6777b538SAndroid Build Coastguard Worker 1072*6777b538SAndroid Build Coastguard Worker if not args.use_vm and not args.device and not args.fetch_cros_hostname: 1073*6777b538SAndroid Build Coastguard Worker logging.warning( 1074*6777b538SAndroid Build Coastguard Worker 'The test runner is now assuming running in the lab environment, if ' 1075*6777b538SAndroid Build Coastguard Worker 'this is unintentional, please re-invoke the test runner with the ' 1076*6777b538SAndroid Build Coastguard Worker '"--use-vm" arg if using a VM, otherwise use the "--device=<DUT>" arg ' 1077*6777b538SAndroid Build Coastguard Worker 'to specify a DUT.') 1078*6777b538SAndroid Build Coastguard Worker 1079*6777b538SAndroid Build Coastguard Worker # If we're not running on a VM, but haven't specified a hostname, assume 1080*6777b538SAndroid Build Coastguard Worker # we're on a lab bot and are trying to run a test on a lab DUT. See if the 1081*6777b538SAndroid Build Coastguard Worker # magic lab DUT hostname resolves to anything. (It will in the lab and will 1082*6777b538SAndroid Build Coastguard Worker # not on dev machines.) 1083*6777b538SAndroid Build Coastguard Worker try: 1084*6777b538SAndroid Build Coastguard Worker socket.getaddrinfo(LAB_DUT_HOSTNAME, None) 1085*6777b538SAndroid Build Coastguard Worker except socket.gaierror: 1086*6777b538SAndroid Build Coastguard Worker logging.error('The default lab DUT hostname of %s is unreachable.', 1087*6777b538SAndroid Build Coastguard Worker LAB_DUT_HOSTNAME) 1088*6777b538SAndroid Build Coastguard Worker return 1 1089*6777b538SAndroid Build Coastguard Worker 1090*6777b538SAndroid Build Coastguard Worker if args.flash and args.public_image: 1091*6777b538SAndroid Build Coastguard Worker # The flashing tools depend on being unauthenticated with GS when flashing 1092*6777b538SAndroid Build Coastguard Worker # public images, so make sure the env var GS uses to locate its creds is 1093*6777b538SAndroid Build Coastguard Worker # unset in that case. 1094*6777b538SAndroid Build Coastguard Worker os.environ.pop('BOTO_CONFIG', None) 1095*6777b538SAndroid Build Coastguard Worker 1096*6777b538SAndroid Build Coastguard Worker if args.magic_vm_cache: 1097*6777b538SAndroid Build Coastguard Worker full_vm_cache_path = os.path.join(CHROMIUM_SRC_PATH, args.magic_vm_cache) 1098*6777b538SAndroid Build Coastguard Worker if os.path.exists(full_vm_cache_path): 1099*6777b538SAndroid Build Coastguard Worker with open(os.path.join(full_vm_cache_path, 'swarming.txt'), 'w') as f: 1100*6777b538SAndroid Build Coastguard Worker f.write('non-empty file to make swarming persist this cache') 1101*6777b538SAndroid Build Coastguard Worker 1102*6777b538SAndroid Build Coastguard Worker return args.func(args, unknown_args) 1103*6777b538SAndroid Build Coastguard Worker 1104*6777b538SAndroid Build Coastguard Worker 1105*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 1106*6777b538SAndroid Build Coastguard Worker sys.exit(main()) 1107