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, test_connection 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_runner import TestRunner 32from ermine_ctl import ErmineCtl 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', default_pave=False) 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 runner_args.pave) 120 else: 121 runner_args.target_id = stack.enter_context( 122 create_emulator_from_args(runner_args)) 123 124 test_connection(runner_args.target_id) 125 126 test_runner = _get_test_runner(runner_args, test_args) 127 package_deps = test_runner.package_deps 128 129 if not runner_args.repo: 130 # Create a directory that serves as a temporary repository. 131 runner_args.repo = stack.enter_context( 132 tempfile.TemporaryDirectory()) 133 134 publish_packages(package_deps.values(), runner_args.repo, 135 not runner_args.no_repo_init) 136 137 stack.enter_context(serve_repository(runner_args)) 138 139 # Start system logging, after all possible restarts of the ffx daemon 140 # so that logging will not be interrupted. 141 start_system_log(log_manager, False, package_deps.values(), 142 ('--since', 'now'), runner_args.target_id) 143 144 ermine = ErmineCtl(runner_args.target_id) 145 if ermine.exists: 146 ermine.take_to_shell() 147 148 resolve_packages(package_deps.keys(), runner_args.target_id) 149 return test_runner.run_test().returncode 150 151 152if __name__ == '__main__': 153 sys.exit(main()) 154