1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2022 The Chromium Authors 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker"""Implements commands for running tests E2E on a Fuchsia device.""" 6*8975f5c5SAndroid Build Coastguard Worker 7*8975f5c5SAndroid Build Coastguard Workerimport argparse 8*8975f5c5SAndroid Build Coastguard Workerimport logging 9*8975f5c5SAndroid Build Coastguard Workerimport os 10*8975f5c5SAndroid Build Coastguard Workerimport sys 11*8975f5c5SAndroid Build Coastguard Workerimport tempfile 12*8975f5c5SAndroid Build Coastguard Worker 13*8975f5c5SAndroid Build Coastguard Workerfrom contextlib import ExitStack 14*8975f5c5SAndroid Build Coastguard Workerfrom typing import List 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard Workerimport monitors 17*8975f5c5SAndroid Build Coastguard Worker 18*8975f5c5SAndroid Build Coastguard Workerfrom common import has_ffx_isolate_dir, is_daemon_running, \ 19*8975f5c5SAndroid Build Coastguard Worker register_common_args, register_device_args, \ 20*8975f5c5SAndroid Build Coastguard Worker register_log_args, resolve_packages 21*8975f5c5SAndroid Build Coastguard Workerfrom compatible_utils import running_unattended 22*8975f5c5SAndroid Build Coastguard Workerfrom ffx_integration import ScopedFfxConfig 23*8975f5c5SAndroid Build Coastguard Workerfrom flash_device import register_update_args, update 24*8975f5c5SAndroid Build Coastguard Workerfrom isolate_daemon import IsolateDaemon 25*8975f5c5SAndroid Build Coastguard Workerfrom log_manager import LogManager, start_system_log 26*8975f5c5SAndroid Build Coastguard Workerfrom publish_package import publish_packages, register_package_args 27*8975f5c5SAndroid Build Coastguard Workerfrom run_blink_test import BlinkTestRunner 28*8975f5c5SAndroid Build Coastguard Workerfrom run_executable_test import create_executable_test_runner, \ 29*8975f5c5SAndroid Build Coastguard Worker register_executable_test_args 30*8975f5c5SAndroid Build Coastguard Workerfrom run_telemetry_test import TelemetryTestRunner 31*8975f5c5SAndroid Build Coastguard Workerfrom run_webpage_test import WebpageTestRunner 32*8975f5c5SAndroid Build Coastguard Workerfrom serve_repo import register_serve_args, serve_repository 33*8975f5c5SAndroid Build Coastguard Workerfrom start_emulator import create_emulator_from_args, register_emulator_args 34*8975f5c5SAndroid Build Coastguard Workerfrom test_connection import test_connection, test_device_connection 35*8975f5c5SAndroid Build Coastguard Workerfrom test_runner import TestRunner 36*8975f5c5SAndroid Build Coastguard Worker 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Workerdef _get_test_runner(runner_args: argparse.Namespace, 39*8975f5c5SAndroid Build Coastguard Worker test_args: List[str]) -> TestRunner: 40*8975f5c5SAndroid Build Coastguard Worker """Initialize a suitable TestRunner class.""" 41*8975f5c5SAndroid Build Coastguard Worker 42*8975f5c5SAndroid Build Coastguard Worker if not runner_args.out_dir: 43*8975f5c5SAndroid Build Coastguard Worker raise ValueError('--out-dir must be specified.') 44*8975f5c5SAndroid Build Coastguard Worker 45*8975f5c5SAndroid Build Coastguard Worker if runner_args.test_type == 'blink': 46*8975f5c5SAndroid Build Coastguard Worker return BlinkTestRunner(runner_args.out_dir, test_args, 47*8975f5c5SAndroid Build Coastguard Worker runner_args.target_id) 48*8975f5c5SAndroid Build Coastguard Worker if runner_args.test_type in ['gpu', 'perf']: 49*8975f5c5SAndroid Build Coastguard Worker return TelemetryTestRunner(runner_args.test_type, runner_args.out_dir, 50*8975f5c5SAndroid Build Coastguard Worker test_args, runner_args.target_id) 51*8975f5c5SAndroid Build Coastguard Worker if runner_args.test_type == 'webpage': 52*8975f5c5SAndroid Build Coastguard Worker return WebpageTestRunner(runner_args.out_dir, test_args, 53*8975f5c5SAndroid Build Coastguard Worker runner_args.target_id, runner_args.logs_dir) 54*8975f5c5SAndroid Build Coastguard Worker return create_executable_test_runner(runner_args, test_args) 55*8975f5c5SAndroid Build Coastguard Worker 56*8975f5c5SAndroid Build Coastguard Worker 57*8975f5c5SAndroid Build Coastguard Worker# pylint: disable=too-many-statements 58*8975f5c5SAndroid Build Coastguard Workerdef main(): 59*8975f5c5SAndroid Build Coastguard Worker """E2E method for installing packages and running a test.""" 60*8975f5c5SAndroid Build Coastguard Worker # Always add time stamps to the logs. 61*8975f5c5SAndroid Build Coastguard Worker logging.basicConfig(format='%(levelname)s %(asctime)s %(message)s') 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 64*8975f5c5SAndroid Build Coastguard Worker parser.add_argument( 65*8975f5c5SAndroid Build Coastguard Worker 'test_type', 66*8975f5c5SAndroid Build Coastguard Worker help='The type of test to run. Options include \'blink\', \'gpu\', ' 67*8975f5c5SAndroid Build Coastguard Worker 'or in the case of executable tests, the test name.') 68*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--device', 69*8975f5c5SAndroid Build Coastguard Worker '-d', 70*8975f5c5SAndroid Build Coastguard Worker action='store_true', 71*8975f5c5SAndroid Build Coastguard Worker default=False, 72*8975f5c5SAndroid Build Coastguard Worker help='Use an existing device.') 73*8975f5c5SAndroid Build Coastguard Worker parser.add_argument('--extra-path', 74*8975f5c5SAndroid Build Coastguard Worker action='append', 75*8975f5c5SAndroid Build Coastguard Worker help='Extra paths to append to the PATH environment') 76*8975f5c5SAndroid Build Coastguard Worker 77*8975f5c5SAndroid Build Coastguard Worker # Register arguments 78*8975f5c5SAndroid Build Coastguard Worker register_common_args(parser) 79*8975f5c5SAndroid Build Coastguard Worker register_device_args(parser) 80*8975f5c5SAndroid Build Coastguard Worker register_emulator_args(parser) 81*8975f5c5SAndroid Build Coastguard Worker register_executable_test_args(parser) 82*8975f5c5SAndroid Build Coastguard Worker register_update_args(parser, default_os_check='ignore') 83*8975f5c5SAndroid Build Coastguard Worker register_log_args(parser) 84*8975f5c5SAndroid Build Coastguard Worker register_package_args(parser, allow_temp_repo=True) 85*8975f5c5SAndroid Build Coastguard Worker register_serve_args(parser) 86*8975f5c5SAndroid Build Coastguard Worker 87*8975f5c5SAndroid Build Coastguard Worker # Treat unrecognized arguments as test specific arguments. 88*8975f5c5SAndroid Build Coastguard Worker runner_args, test_args = parser.parse_known_args() 89*8975f5c5SAndroid Build Coastguard Worker 90*8975f5c5SAndroid Build Coastguard Worker if runner_args.target_id: 91*8975f5c5SAndroid Build Coastguard Worker runner_args.device = True 92*8975f5c5SAndroid Build Coastguard Worker 93*8975f5c5SAndroid Build Coastguard Worker with ExitStack() as stack: 94*8975f5c5SAndroid Build Coastguard Worker if runner_args.logs_dir: 95*8975f5c5SAndroid Build Coastguard Worker # TODO(crbug.com/343242386): Find a way to upload metric output when 96*8975f5c5SAndroid Build Coastguard Worker # logs_dir is not defined. 97*8975f5c5SAndroid Build Coastguard Worker stack.push(lambda *_: monitors.dump( 98*8975f5c5SAndroid Build Coastguard Worker os.path.join(runner_args.logs_dir, 'invocations'))) 99*8975f5c5SAndroid Build Coastguard Worker if runner_args.extra_path: 100*8975f5c5SAndroid Build Coastguard Worker os.environ['PATH'] += os.pathsep + os.pathsep.join( 101*8975f5c5SAndroid Build Coastguard Worker runner_args.extra_path) 102*8975f5c5SAndroid Build Coastguard Worker if running_unattended(): 103*8975f5c5SAndroid Build Coastguard Worker # Only restart the daemon if 1) daemon will be run in a new isolate 104*8975f5c5SAndroid Build Coastguard Worker # dir, or 2) if there isn't a daemon running in the predefined 105*8975f5c5SAndroid Build Coastguard Worker # isolate dir. 106*8975f5c5SAndroid Build Coastguard Worker if not has_ffx_isolate_dir() or not is_daemon_running(): 107*8975f5c5SAndroid Build Coastguard Worker stack.enter_context(IsolateDaemon(runner_args.logs_dir)) 108*8975f5c5SAndroid Build Coastguard Worker 109*8975f5c5SAndroid Build Coastguard Worker if runner_args.everlasting: 110*8975f5c5SAndroid Build Coastguard Worker # Setting the emu.instance_dir to match the named cache, so 111*8975f5c5SAndroid Build Coastguard Worker # we can keep these files across multiple runs. 112*8975f5c5SAndroid Build Coastguard Worker # The configuration attaches to the daemon isolate-dir, so it 113*8975f5c5SAndroid Build Coastguard Worker # needs to go after the IsolateDaemon. 114*8975f5c5SAndroid Build Coastguard Worker # There isn't a point of enabling the feature on devbox, it 115*8975f5c5SAndroid Build Coastguard Worker # won't use isolate-dir and the emu.instance_dir always goes to 116*8975f5c5SAndroid Build Coastguard Worker # the HOME directory. 117*8975f5c5SAndroid Build Coastguard Worker stack.enter_context( 118*8975f5c5SAndroid Build Coastguard Worker ScopedFfxConfig( 119*8975f5c5SAndroid Build Coastguard Worker 'emu.instance_dir', 120*8975f5c5SAndroid Build Coastguard Worker os.path.join(os.environ['HOME'], 121*8975f5c5SAndroid Build Coastguard Worker '.fuchsia_emulator/'))) 122*8975f5c5SAndroid Build Coastguard Worker elif runner_args.logs_dir: 123*8975f5c5SAndroid Build Coastguard Worker # Never restart daemon if not in the unattended mode. 124*8975f5c5SAndroid Build Coastguard Worker logging.warning('You are using a --logs-dir, ensure the ffx ' 125*8975f5c5SAndroid Build Coastguard Worker 'daemon is started with the logs.dir config ' 126*8975f5c5SAndroid Build Coastguard Worker 'updated. We won\'t restart the daemon randomly' 127*8975f5c5SAndroid Build Coastguard Worker ' anymore.') 128*8975f5c5SAndroid Build Coastguard Worker log_manager = LogManager(runner_args.logs_dir) 129*8975f5c5SAndroid Build Coastguard Worker stack.enter_context(log_manager) 130*8975f5c5SAndroid Build Coastguard Worker 131*8975f5c5SAndroid Build Coastguard Worker if runner_args.device: 132*8975f5c5SAndroid Build Coastguard Worker update(runner_args.system_image_dir, runner_args.os_check, 133*8975f5c5SAndroid Build Coastguard Worker runner_args.target_id, runner_args.serial_num) 134*8975f5c5SAndroid Build Coastguard Worker # Try to reboot the device if necessary since the ffx may ignore the 135*8975f5c5SAndroid Build Coastguard Worker # device state after the flash. See 136*8975f5c5SAndroid Build Coastguard Worker # https://cs.opensource.google/fuchsia/fuchsia/+/main:src/developer/ffx/lib/fastboot/src/common/fastboot.rs;drc=cfba0bdd4f8857adb6409f8ae9e35af52c0da93e;l=454 137*8975f5c5SAndroid Build Coastguard Worker test_device_connection(runner_args.target_id) 138*8975f5c5SAndroid Build Coastguard Worker else: 139*8975f5c5SAndroid Build Coastguard Worker runner_args.target_id = stack.enter_context( 140*8975f5c5SAndroid Build Coastguard Worker create_emulator_from_args(runner_args)) 141*8975f5c5SAndroid Build Coastguard Worker test_connection(runner_args.target_id) 142*8975f5c5SAndroid Build Coastguard Worker 143*8975f5c5SAndroid Build Coastguard Worker test_runner = _get_test_runner(runner_args, test_args) 144*8975f5c5SAndroid Build Coastguard Worker package_deps = test_runner.package_deps 145*8975f5c5SAndroid Build Coastguard Worker 146*8975f5c5SAndroid Build Coastguard Worker # Start system logging, after all possible restarts of the ffx daemon 147*8975f5c5SAndroid Build Coastguard Worker # so that logging will not be interrupted. 148*8975f5c5SAndroid Build Coastguard Worker start_system_log(log_manager, False, package_deps.values(), 149*8975f5c5SAndroid Build Coastguard Worker ('--since', 'now'), runner_args.target_id) 150*8975f5c5SAndroid Build Coastguard Worker 151*8975f5c5SAndroid Build Coastguard Worker if package_deps: 152*8975f5c5SAndroid Build Coastguard Worker if not runner_args.repo: 153*8975f5c5SAndroid Build Coastguard Worker # Create a directory that serves as a temporary repository. 154*8975f5c5SAndroid Build Coastguard Worker runner_args.repo = stack.enter_context( 155*8975f5c5SAndroid Build Coastguard Worker tempfile.TemporaryDirectory()) 156*8975f5c5SAndroid Build Coastguard Worker publish_packages(package_deps.values(), runner_args.repo, 157*8975f5c5SAndroid Build Coastguard Worker not runner_args.no_repo_init) 158*8975f5c5SAndroid Build Coastguard Worker stack.enter_context(serve_repository(runner_args)) 159*8975f5c5SAndroid Build Coastguard Worker resolve_packages(package_deps.keys(), runner_args.target_id) 160*8975f5c5SAndroid Build Coastguard Worker 161*8975f5c5SAndroid Build Coastguard Worker return test_runner.run_test().returncode 162*8975f5c5SAndroid Build Coastguard Worker 163*8975f5c5SAndroid Build Coastguard Worker 164*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 165*8975f5c5SAndroid Build Coastguard Worker sys.exit(main()) 166