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