xref: /aosp_15_r20/external/cronet/build/fuchsia/test/run_test.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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