xref: /aosp_15_r20/tools/asuite/atest/atest_main.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1*c2e18aaaSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*c2e18aaaSAndroid Build Coastguard Worker#
3*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2017, The Android Open Source Project
4*c2e18aaaSAndroid Build Coastguard Worker#
5*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*c2e18aaaSAndroid Build Coastguard Worker#
9*c2e18aaaSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*c2e18aaaSAndroid Build Coastguard Worker#
11*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License.
16*c2e18aaaSAndroid Build Coastguard Worker
17*c2e18aaaSAndroid Build Coastguard Worker"""Command line utility for running Android tests through TradeFederation.
18*c2e18aaaSAndroid Build Coastguard Worker
19*c2e18aaaSAndroid Build Coastguard Workeratest helps automate the flow of building test modules across the Android
20*c2e18aaaSAndroid Build Coastguard Workercode base and executing the tests via the TradeFederation test harness.
21*c2e18aaaSAndroid Build Coastguard Worker
22*c2e18aaaSAndroid Build Coastguard Workeratest is designed to support any test types that can be ran by TradeFederation.
23*c2e18aaaSAndroid Build Coastguard Worker"""
24*c2e18aaaSAndroid Build Coastguard Worker
25*c2e18aaaSAndroid Build Coastguard Worker# pylint: disable=too-many-lines
26*c2e18aaaSAndroid Build Coastguard Worker
27*c2e18aaaSAndroid Build Coastguard Workerfrom __future__ import annotations
28*c2e18aaaSAndroid Build Coastguard Workerfrom __future__ import print_function
29*c2e18aaaSAndroid Build Coastguard Worker
30*c2e18aaaSAndroid Build Coastguard Workerimport abc
31*c2e18aaaSAndroid Build Coastguard Workerimport argparse
32*c2e18aaaSAndroid Build Coastguard Workerimport collections
33*c2e18aaaSAndroid Build Coastguard Workerimport dataclasses
34*c2e18aaaSAndroid Build Coastguard Workerimport functools
35*c2e18aaaSAndroid Build Coastguard Workerimport itertools
36*c2e18aaaSAndroid Build Coastguard Workerimport logging
37*c2e18aaaSAndroid Build Coastguard Workerimport os
38*c2e18aaaSAndroid Build Coastguard Workerimport platform
39*c2e18aaaSAndroid Build Coastguard Workerimport subprocess
40*c2e18aaaSAndroid Build Coastguard Workerimport sys
41*c2e18aaaSAndroid Build Coastguard Workerimport tempfile
42*c2e18aaaSAndroid Build Coastguard Workerimport threading
43*c2e18aaaSAndroid Build Coastguard Workerimport time
44*c2e18aaaSAndroid Build Coastguard Workerfrom typing import Any, Dict, List, Set
45*c2e18aaaSAndroid Build Coastguard Worker
46*c2e18aaaSAndroid Build Coastguard Workerfrom atest import arg_parser
47*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_configs
48*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_execution_info
49*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_utils
50*c2e18aaaSAndroid Build Coastguard Workerfrom atest import banner
51*c2e18aaaSAndroid Build Coastguard Workerfrom atest import bazel_mode
52*c2e18aaaSAndroid Build Coastguard Workerfrom atest import bug_detector
53*c2e18aaaSAndroid Build Coastguard Workerfrom atest import cli_translator
54*c2e18aaaSAndroid Build Coastguard Workerfrom atest import constants
55*c2e18aaaSAndroid Build Coastguard Workerfrom atest import device_update
56*c2e18aaaSAndroid Build Coastguard Workerfrom atest import module_info
57*c2e18aaaSAndroid Build Coastguard Workerfrom atest import result_reporter
58*c2e18aaaSAndroid Build Coastguard Workerfrom atest import test_runner_handler
59*c2e18aaaSAndroid Build Coastguard Workerfrom atest.atest_enum import DetectType
60*c2e18aaaSAndroid Build Coastguard Workerfrom atest.atest_enum import ExitCode
61*c2e18aaaSAndroid Build Coastguard Workerfrom atest.coverage import coverage
62*c2e18aaaSAndroid Build Coastguard Workerfrom atest.metrics import metrics
63*c2e18aaaSAndroid Build Coastguard Workerfrom atest.metrics import metrics_base
64*c2e18aaaSAndroid Build Coastguard Workerfrom atest.metrics import metrics_utils
65*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_finders import test_finder_utils
66*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_finders import test_info
67*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_finders.test_info import TestInfo
68*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_runner_invocation import TestRunnerInvocation
69*c2e18aaaSAndroid Build Coastguard Workerfrom atest.tools import indexing
70*c2e18aaaSAndroid Build Coastguard Workerfrom atest.tools import start_avd as avd
71*c2e18aaaSAndroid Build Coastguard Worker
72*c2e18aaaSAndroid Build Coastguard WorkerEXPECTED_VARS = frozenset([
73*c2e18aaaSAndroid Build Coastguard Worker    constants.ANDROID_BUILD_TOP,
74*c2e18aaaSAndroid Build Coastguard Worker    'ANDROID_TARGET_OUT_TESTCASES',
75*c2e18aaaSAndroid Build Coastguard Worker    constants.ANDROID_OUT,
76*c2e18aaaSAndroid Build Coastguard Worker])
77*c2e18aaaSAndroid Build Coastguard WorkerTEST_RUN_DIR_PREFIX = '%Y%m%d_%H%M%S'
78*c2e18aaaSAndroid Build Coastguard WorkerCUSTOM_ARG_FLAG = '--'
79*c2e18aaaSAndroid Build Coastguard WorkerOPTION_NOT_FOR_TEST_MAPPING = (
80*c2e18aaaSAndroid Build Coastguard Worker    'Option "{}" does not work for running tests in TEST_MAPPING files'
81*c2e18aaaSAndroid Build Coastguard Worker)
82*c2e18aaaSAndroid Build Coastguard Worker
83*c2e18aaaSAndroid Build Coastguard WorkerDEVICE_TESTS = 'tests that require device'
84*c2e18aaaSAndroid Build Coastguard WorkerHOST_TESTS = 'tests that do NOT require device'
85*c2e18aaaSAndroid Build Coastguard WorkerRESULT_HEADER_FMT = '\nResults from %(test_type)s:'
86*c2e18aaaSAndroid Build Coastguard WorkerRUN_HEADER_FMT = '\nRunning %(test_count)d %(test_type)s.'
87*c2e18aaaSAndroid Build Coastguard WorkerTEST_COUNT = 'test_count'
88*c2e18aaaSAndroid Build Coastguard WorkerTEST_TYPE = 'test_type'
89*c2e18aaaSAndroid Build Coastguard WorkerEND_OF_OPTION = '--'
90*c2e18aaaSAndroid Build Coastguard WorkerHAS_IGNORED_ARGS = False
91*c2e18aaaSAndroid Build Coastguard Worker# Conditions that atest should exit without sending result to metrics.
92*c2e18aaaSAndroid Build Coastguard WorkerEXIT_CODES_BEFORE_TEST = [
93*c2e18aaaSAndroid Build Coastguard Worker    ExitCode.ENV_NOT_SETUP,
94*c2e18aaaSAndroid Build Coastguard Worker    ExitCode.TEST_NOT_FOUND,
95*c2e18aaaSAndroid Build Coastguard Worker    ExitCode.OUTSIDE_ROOT,
96*c2e18aaaSAndroid Build Coastguard Worker    ExitCode.AVD_CREATE_FAILURE,
97*c2e18aaaSAndroid Build Coastguard Worker    ExitCode.AVD_INVALID_ARGS,
98*c2e18aaaSAndroid Build Coastguard Worker]
99*c2e18aaaSAndroid Build Coastguard Worker
100*c2e18aaaSAndroid Build Coastguard Worker# Stdout print prefix for results directory. May be used in integration tests.
101*c2e18aaaSAndroid Build Coastguard Worker_RESULTS_DIR_PRINT_PREFIX = 'Atest results and logs directory: '
102*c2e18aaaSAndroid Build Coastguard Worker# Log prefix for dry-run run command. May be used in integration tests.
103*c2e18aaaSAndroid Build Coastguard Worker_DRY_RUN_COMMAND_LOG_PREFIX = 'Internal run command from dry-run: '
104*c2e18aaaSAndroid Build Coastguard Worker
105*c2e18aaaSAndroid Build Coastguard Worker
106*c2e18aaaSAndroid Build Coastguard Worker@dataclasses.dataclass
107*c2e18aaaSAndroid Build Coastguard Workerclass Steps:
108*c2e18aaaSAndroid Build Coastguard Worker  """A dataclass that stores enabled steps."""
109*c2e18aaaSAndroid Build Coastguard Worker
110*c2e18aaaSAndroid Build Coastguard Worker  build: bool
111*c2e18aaaSAndroid Build Coastguard Worker  install: bool
112*c2e18aaaSAndroid Build Coastguard Worker  test: bool
113*c2e18aaaSAndroid Build Coastguard Worker
114*c2e18aaaSAndroid Build Coastguard Worker
115*c2e18aaaSAndroid Build Coastguard Workerdef parse_steps(args: arg_parser.AtestArgParser) -> Steps:
116*c2e18aaaSAndroid Build Coastguard Worker  """Return Steps object.
117*c2e18aaaSAndroid Build Coastguard Worker
118*c2e18aaaSAndroid Build Coastguard Worker  Args:
119*c2e18aaaSAndroid Build Coastguard Worker      args: an AtestArgParser object.
120*c2e18aaaSAndroid Build Coastguard Worker
121*c2e18aaaSAndroid Build Coastguard Worker  Returns:
122*c2e18aaaSAndroid Build Coastguard Worker      Step object that stores the boolean of build, install and test.
123*c2e18aaaSAndroid Build Coastguard Worker  """
124*c2e18aaaSAndroid Build Coastguard Worker  # Implicitly running 'build', 'install' and 'test' when args.steps is None.
125*c2e18aaaSAndroid Build Coastguard Worker  if not args.steps:
126*c2e18aaaSAndroid Build Coastguard Worker    return Steps(True, True, True)
127*c2e18aaaSAndroid Build Coastguard Worker  build = constants.BUILD_STEP in args.steps
128*c2e18aaaSAndroid Build Coastguard Worker  test = constants.TEST_STEP in args.steps
129*c2e18aaaSAndroid Build Coastguard Worker  install = constants.INSTALL_STEP in args.steps
130*c2e18aaaSAndroid Build Coastguard Worker  if install and not test:
131*c2e18aaaSAndroid Build Coastguard Worker    atest_utils.print_and_log_warning(
132*c2e18aaaSAndroid Build Coastguard Worker        'Installing without test step is currently not '
133*c2e18aaaSAndroid Build Coastguard Worker        'supported; Atest will proceed testing!'
134*c2e18aaaSAndroid Build Coastguard Worker    )
135*c2e18aaaSAndroid Build Coastguard Worker    test = True
136*c2e18aaaSAndroid Build Coastguard Worker  return Steps(build, install, test)
137*c2e18aaaSAndroid Build Coastguard Worker
138*c2e18aaaSAndroid Build Coastguard Worker
139*c2e18aaaSAndroid Build Coastguard Workerdef _get_args_from_config():
140*c2e18aaaSAndroid Build Coastguard Worker  """Get customized atest arguments in the config file.
141*c2e18aaaSAndroid Build Coastguard Worker
142*c2e18aaaSAndroid Build Coastguard Worker  If the config has not existed yet, atest will initialize an example
143*c2e18aaaSAndroid Build Coastguard Worker  config file for it without any effective options.
144*c2e18aaaSAndroid Build Coastguard Worker
145*c2e18aaaSAndroid Build Coastguard Worker  Returns:
146*c2e18aaaSAndroid Build Coastguard Worker      A list read from the config file.
147*c2e18aaaSAndroid Build Coastguard Worker  """
148*c2e18aaaSAndroid Build Coastguard Worker  _config = atest_utils.get_config_folder().joinpath('config')
149*c2e18aaaSAndroid Build Coastguard Worker  if not _config.parent.is_dir():
150*c2e18aaaSAndroid Build Coastguard Worker    _config.parent.mkdir(parents=True)
151*c2e18aaaSAndroid Build Coastguard Worker  args = []
152*c2e18aaaSAndroid Build Coastguard Worker  if not _config.is_file():
153*c2e18aaaSAndroid Build Coastguard Worker    with open(_config, 'w+', encoding='utf8') as cache:
154*c2e18aaaSAndroid Build Coastguard Worker      cache.write(constants.ATEST_EXAMPLE_ARGS)
155*c2e18aaaSAndroid Build Coastguard Worker    return args
156*c2e18aaaSAndroid Build Coastguard Worker  warning = 'Line {} contains {} and will be ignored.'
157*c2e18aaaSAndroid Build Coastguard Worker  print(
158*c2e18aaaSAndroid Build Coastguard Worker      '\n{} {}'.format(
159*c2e18aaaSAndroid Build Coastguard Worker          atest_utils.mark_cyan('Reading config:'),
160*c2e18aaaSAndroid Build Coastguard Worker          _config,
161*c2e18aaaSAndroid Build Coastguard Worker      )
162*c2e18aaaSAndroid Build Coastguard Worker  )
163*c2e18aaaSAndroid Build Coastguard Worker  # pylint: disable=global-statement:
164*c2e18aaaSAndroid Build Coastguard Worker  global HAS_IGNORED_ARGS
165*c2e18aaaSAndroid Build Coastguard Worker  with open(_config, 'r', encoding='utf8') as cache:
166*c2e18aaaSAndroid Build Coastguard Worker    for entry in cache.readlines():
167*c2e18aaaSAndroid Build Coastguard Worker      # Strip comments.
168*c2e18aaaSAndroid Build Coastguard Worker      arg_in_line = entry.partition('#')[0].strip()
169*c2e18aaaSAndroid Build Coastguard Worker      # Strip test name/path.
170*c2e18aaaSAndroid Build Coastguard Worker      if arg_in_line.startswith('-'):
171*c2e18aaaSAndroid Build Coastguard Worker        # Process argument that contains whitespaces.
172*c2e18aaaSAndroid Build Coastguard Worker        # e.g. ["--serial foo"] -> ["--serial", "foo"]
173*c2e18aaaSAndroid Build Coastguard Worker        if len(arg_in_line.split()) > 1:
174*c2e18aaaSAndroid Build Coastguard Worker          # remove "--" to avoid messing up atest/tradefed commands.
175*c2e18aaaSAndroid Build Coastguard Worker          if END_OF_OPTION in arg_in_line.split():
176*c2e18aaaSAndroid Build Coastguard Worker            HAS_IGNORED_ARGS = True
177*c2e18aaaSAndroid Build Coastguard Worker            print(
178*c2e18aaaSAndroid Build Coastguard Worker                warning.format(
179*c2e18aaaSAndroid Build Coastguard Worker                    atest_utils.mark_yellow(arg_in_line), END_OF_OPTION
180*c2e18aaaSAndroid Build Coastguard Worker                )
181*c2e18aaaSAndroid Build Coastguard Worker            )
182*c2e18aaaSAndroid Build Coastguard Worker          args.extend(arg_in_line.split())
183*c2e18aaaSAndroid Build Coastguard Worker        else:
184*c2e18aaaSAndroid Build Coastguard Worker          if END_OF_OPTION == arg_in_line:
185*c2e18aaaSAndroid Build Coastguard Worker            HAS_IGNORED_ARGS = True
186*c2e18aaaSAndroid Build Coastguard Worker            print(
187*c2e18aaaSAndroid Build Coastguard Worker                warning.format(
188*c2e18aaaSAndroid Build Coastguard Worker                    atest_utils.mark_yellow(arg_in_line), END_OF_OPTION
189*c2e18aaaSAndroid Build Coastguard Worker                )
190*c2e18aaaSAndroid Build Coastguard Worker            )
191*c2e18aaaSAndroid Build Coastguard Worker          args.append(arg_in_line)
192*c2e18aaaSAndroid Build Coastguard Worker  return args
193*c2e18aaaSAndroid Build Coastguard Worker
194*c2e18aaaSAndroid Build Coastguard Worker
195*c2e18aaaSAndroid Build Coastguard Workerdef _parse_args(argv: List[str]) -> argparse.Namespace:
196*c2e18aaaSAndroid Build Coastguard Worker  """Parse command line arguments.
197*c2e18aaaSAndroid Build Coastguard Worker
198*c2e18aaaSAndroid Build Coastguard Worker  Args:
199*c2e18aaaSAndroid Build Coastguard Worker      argv: A list of arguments.
200*c2e18aaaSAndroid Build Coastguard Worker
201*c2e18aaaSAndroid Build Coastguard Worker  Returns:
202*c2e18aaaSAndroid Build Coastguard Worker      A Namespace holding parsed args
203*c2e18aaaSAndroid Build Coastguard Worker  """
204*c2e18aaaSAndroid Build Coastguard Worker  # Store everything after '--' in custom_args.
205*c2e18aaaSAndroid Build Coastguard Worker  pruned_argv = argv
206*c2e18aaaSAndroid Build Coastguard Worker  custom_args_index = None
207*c2e18aaaSAndroid Build Coastguard Worker  if CUSTOM_ARG_FLAG in argv:
208*c2e18aaaSAndroid Build Coastguard Worker    custom_args_index = argv.index(CUSTOM_ARG_FLAG)
209*c2e18aaaSAndroid Build Coastguard Worker    pruned_argv = argv[:custom_args_index]
210*c2e18aaaSAndroid Build Coastguard Worker  args = arg_parser.create_atest_arg_parser().parse_args(pruned_argv)
211*c2e18aaaSAndroid Build Coastguard Worker  args.custom_args = []
212*c2e18aaaSAndroid Build Coastguard Worker  if custom_args_index is not None:
213*c2e18aaaSAndroid Build Coastguard Worker    for arg in argv[custom_args_index + 1 :]:
214*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('Quoting regex argument %s', arg)
215*c2e18aaaSAndroid Build Coastguard Worker      args.custom_args.append(atest_utils.quote(arg))
216*c2e18aaaSAndroid Build Coastguard Worker
217*c2e18aaaSAndroid Build Coastguard Worker  return args
218*c2e18aaaSAndroid Build Coastguard Worker
219*c2e18aaaSAndroid Build Coastguard Worker
220*c2e18aaaSAndroid Build Coastguard Workerdef _configure_logging(verbose: bool, results_dir: str):
221*c2e18aaaSAndroid Build Coastguard Worker  """Configure the logger.
222*c2e18aaaSAndroid Build Coastguard Worker
223*c2e18aaaSAndroid Build Coastguard Worker  Args:
224*c2e18aaaSAndroid Build Coastguard Worker      verbose: If true display DEBUG level logs on console.
225*c2e18aaaSAndroid Build Coastguard Worker      results_dir: A directory which stores the ATest execution information.
226*c2e18aaaSAndroid Build Coastguard Worker  """
227*c2e18aaaSAndroid Build Coastguard Worker  log_fmat = '%(asctime)s %(filename)s:%(lineno)s:%(levelname)s: %(message)s'
228*c2e18aaaSAndroid Build Coastguard Worker  date_fmt = '%Y-%m-%d %H:%M:%S'
229*c2e18aaaSAndroid Build Coastguard Worker  log_path = os.path.join(results_dir, 'atest.log')
230*c2e18aaaSAndroid Build Coastguard Worker
231*c2e18aaaSAndroid Build Coastguard Worker  logger = logging.getLogger('')
232*c2e18aaaSAndroid Build Coastguard Worker  # Clear the handlers to prevent logging.basicConfig from being called twice.
233*c2e18aaaSAndroid Build Coastguard Worker  logger.handlers = []
234*c2e18aaaSAndroid Build Coastguard Worker
235*c2e18aaaSAndroid Build Coastguard Worker  logging.basicConfig(
236*c2e18aaaSAndroid Build Coastguard Worker      filename=log_path, level=logging.DEBUG, format=log_fmat, datefmt=date_fmt
237*c2e18aaaSAndroid Build Coastguard Worker  )
238*c2e18aaaSAndroid Build Coastguard Worker
239*c2e18aaaSAndroid Build Coastguard Worker  class _StreamToLogger:
240*c2e18aaaSAndroid Build Coastguard Worker    """A file like class to that redirect writes to a printer and logger."""
241*c2e18aaaSAndroid Build Coastguard Worker
242*c2e18aaaSAndroid Build Coastguard Worker    def __init__(self, logger, log_level, printer):
243*c2e18aaaSAndroid Build Coastguard Worker      self._logger = logger
244*c2e18aaaSAndroid Build Coastguard Worker      self._log_level = log_level
245*c2e18aaaSAndroid Build Coastguard Worker      self._printer = printer
246*c2e18aaaSAndroid Build Coastguard Worker      self._buffers = []
247*c2e18aaaSAndroid Build Coastguard Worker
248*c2e18aaaSAndroid Build Coastguard Worker    def write(self, buf: str) -> None:
249*c2e18aaaSAndroid Build Coastguard Worker      self._printer.write(buf)
250*c2e18aaaSAndroid Build Coastguard Worker
251*c2e18aaaSAndroid Build Coastguard Worker      if len(buf) == 1 and buf[0] == '\n' and self._buffers:
252*c2e18aaaSAndroid Build Coastguard Worker        self._logger.log(self._log_level, ''.join(self._buffers))
253*c2e18aaaSAndroid Build Coastguard Worker        self._buffers.clear()
254*c2e18aaaSAndroid Build Coastguard Worker      else:
255*c2e18aaaSAndroid Build Coastguard Worker        self._buffers.append(buf)
256*c2e18aaaSAndroid Build Coastguard Worker
257*c2e18aaaSAndroid Build Coastguard Worker    def flush(self) -> None:
258*c2e18aaaSAndroid Build Coastguard Worker      self._printer.flush()
259*c2e18aaaSAndroid Build Coastguard Worker
260*c2e18aaaSAndroid Build Coastguard Worker  stdout_log_level = 25
261*c2e18aaaSAndroid Build Coastguard Worker  stderr_log_level = 45
262*c2e18aaaSAndroid Build Coastguard Worker  logging.addLevelName(stdout_log_level, 'STDOUT')
263*c2e18aaaSAndroid Build Coastguard Worker  logging.addLevelName(stderr_log_level, 'STDERR')
264*c2e18aaaSAndroid Build Coastguard Worker  sys.stdout = _StreamToLogger(logger, stdout_log_level, sys.stdout)
265*c2e18aaaSAndroid Build Coastguard Worker  sys.stderr = _StreamToLogger(logger, stderr_log_level, sys.stderr)
266*c2e18aaaSAndroid Build Coastguard Worker
267*c2e18aaaSAndroid Build Coastguard Worker
268*c2e18aaaSAndroid Build Coastguard Workerdef _missing_environment_variables():
269*c2e18aaaSAndroid Build Coastguard Worker  """Verify the local environment has been set up to run atest.
270*c2e18aaaSAndroid Build Coastguard Worker
271*c2e18aaaSAndroid Build Coastguard Worker  Returns:
272*c2e18aaaSAndroid Build Coastguard Worker      List of strings of any missing environment variables.
273*c2e18aaaSAndroid Build Coastguard Worker  """
274*c2e18aaaSAndroid Build Coastguard Worker  missing = list(
275*c2e18aaaSAndroid Build Coastguard Worker      filter(None, [x for x in EXPECTED_VARS if not os.environ.get(x)])
276*c2e18aaaSAndroid Build Coastguard Worker  )
277*c2e18aaaSAndroid Build Coastguard Worker  if missing:
278*c2e18aaaSAndroid Build Coastguard Worker    atest_utils.print_and_log_error(
279*c2e18aaaSAndroid Build Coastguard Worker        "Local environment doesn't appear to have been "
280*c2e18aaaSAndroid Build Coastguard Worker        'initialized. Did you remember to run lunch? Expected '
281*c2e18aaaSAndroid Build Coastguard Worker        'Environment Variables: %s.',
282*c2e18aaaSAndroid Build Coastguard Worker        missing,
283*c2e18aaaSAndroid Build Coastguard Worker    )
284*c2e18aaaSAndroid Build Coastguard Worker  return missing
285*c2e18aaaSAndroid Build Coastguard Worker
286*c2e18aaaSAndroid Build Coastguard Worker
287*c2e18aaaSAndroid Build Coastguard Workerdef make_test_run_dir() -> str:
288*c2e18aaaSAndroid Build Coastguard Worker  """Make the test run dir in ATEST_RESULT_ROOT.
289*c2e18aaaSAndroid Build Coastguard Worker
290*c2e18aaaSAndroid Build Coastguard Worker  Returns:
291*c2e18aaaSAndroid Build Coastguard Worker      A string of the dir path.
292*c2e18aaaSAndroid Build Coastguard Worker  """
293*c2e18aaaSAndroid Build Coastguard Worker  if not os.path.exists(constants.ATEST_RESULT_ROOT):
294*c2e18aaaSAndroid Build Coastguard Worker    os.makedirs(constants.ATEST_RESULT_ROOT)
295*c2e18aaaSAndroid Build Coastguard Worker  ctime = time.strftime(TEST_RUN_DIR_PREFIX, time.localtime())
296*c2e18aaaSAndroid Build Coastguard Worker  test_result_dir = tempfile.mkdtemp(
297*c2e18aaaSAndroid Build Coastguard Worker      prefix='%s_' % ctime, dir=constants.ATEST_RESULT_ROOT
298*c2e18aaaSAndroid Build Coastguard Worker  )
299*c2e18aaaSAndroid Build Coastguard Worker  print(_RESULTS_DIR_PRINT_PREFIX + test_result_dir)
300*c2e18aaaSAndroid Build Coastguard Worker  return test_result_dir
301*c2e18aaaSAndroid Build Coastguard Worker
302*c2e18aaaSAndroid Build Coastguard Worker
303*c2e18aaaSAndroid Build Coastguard Workerdef get_extra_args(args):
304*c2e18aaaSAndroid Build Coastguard Worker  """Get extra args for test runners.
305*c2e18aaaSAndroid Build Coastguard Worker
306*c2e18aaaSAndroid Build Coastguard Worker  Args:
307*c2e18aaaSAndroid Build Coastguard Worker      args: arg parsed object.
308*c2e18aaaSAndroid Build Coastguard Worker
309*c2e18aaaSAndroid Build Coastguard Worker  Returns:
310*c2e18aaaSAndroid Build Coastguard Worker      Dict of extra args for test runners to utilize.
311*c2e18aaaSAndroid Build Coastguard Worker  """
312*c2e18aaaSAndroid Build Coastguard Worker  extra_args = {}
313*c2e18aaaSAndroid Build Coastguard Worker  if args.wait_for_debugger:
314*c2e18aaaSAndroid Build Coastguard Worker    extra_args[constants.WAIT_FOR_DEBUGGER] = None
315*c2e18aaaSAndroid Build Coastguard Worker  if not parse_steps(args).install:
316*c2e18aaaSAndroid Build Coastguard Worker    extra_args[constants.DISABLE_INSTALL] = None
317*c2e18aaaSAndroid Build Coastguard Worker  # The key and its value of the dict can be called via:
318*c2e18aaaSAndroid Build Coastguard Worker  # if args.aaaa:
319*c2e18aaaSAndroid Build Coastguard Worker  #     extra_args[constants.AAAA] = args.aaaa
320*c2e18aaaSAndroid Build Coastguard Worker  arg_maps = {
321*c2e18aaaSAndroid Build Coastguard Worker      'all_abi': constants.ALL_ABI,
322*c2e18aaaSAndroid Build Coastguard Worker      'annotation_filter': constants.ANNOTATION_FILTER,
323*c2e18aaaSAndroid Build Coastguard Worker      'bazel_arg': constants.BAZEL_ARG,
324*c2e18aaaSAndroid Build Coastguard Worker      'collect_tests_only': constants.COLLECT_TESTS_ONLY,
325*c2e18aaaSAndroid Build Coastguard Worker      'experimental_coverage': constants.COVERAGE,
326*c2e18aaaSAndroid Build Coastguard Worker      'custom_args': constants.CUSTOM_ARGS,
327*c2e18aaaSAndroid Build Coastguard Worker      'device_only': constants.DEVICE_ONLY,
328*c2e18aaaSAndroid Build Coastguard Worker      'disable_teardown': constants.DISABLE_TEARDOWN,
329*c2e18aaaSAndroid Build Coastguard Worker      'disable_upload_result': constants.DISABLE_UPLOAD_RESULT,
330*c2e18aaaSAndroid Build Coastguard Worker      'dry_run': constants.DRY_RUN,
331*c2e18aaaSAndroid Build Coastguard Worker      'host': constants.HOST,
332*c2e18aaaSAndroid Build Coastguard Worker      'instant': constants.INSTANT,
333*c2e18aaaSAndroid Build Coastguard Worker      'iterations': constants.ITERATIONS,
334*c2e18aaaSAndroid Build Coastguard Worker      'request_upload_result': constants.REQUEST_UPLOAD_RESULT,
335*c2e18aaaSAndroid Build Coastguard Worker      'bazel_mode_features': constants.BAZEL_MODE_FEATURES,
336*c2e18aaaSAndroid Build Coastguard Worker      'rerun_until_failure': constants.RERUN_UNTIL_FAILURE,
337*c2e18aaaSAndroid Build Coastguard Worker      'retry_any_failure': constants.RETRY_ANY_FAILURE,
338*c2e18aaaSAndroid Build Coastguard Worker      'serial': constants.SERIAL,
339*c2e18aaaSAndroid Build Coastguard Worker      'sharding': constants.SHARDING,
340*c2e18aaaSAndroid Build Coastguard Worker      'test_filter': constants.TEST_FILTER,
341*c2e18aaaSAndroid Build Coastguard Worker      'test_timeout': constants.TEST_TIMEOUT,
342*c2e18aaaSAndroid Build Coastguard Worker      'tf_debug': constants.TF_DEBUG,
343*c2e18aaaSAndroid Build Coastguard Worker      'tf_template': constants.TF_TEMPLATE,
344*c2e18aaaSAndroid Build Coastguard Worker      'user_type': constants.USER_TYPE,
345*c2e18aaaSAndroid Build Coastguard Worker      'verbose': constants.VERBOSE,
346*c2e18aaaSAndroid Build Coastguard Worker      'use_tf_min_base_template': constants.USE_TF_MIN_BASE_TEMPLATE,
347*c2e18aaaSAndroid Build Coastguard Worker  }
348*c2e18aaaSAndroid Build Coastguard Worker  not_match = [k for k in arg_maps if k not in vars(args)]
349*c2e18aaaSAndroid Build Coastguard Worker  if not_match:
350*c2e18aaaSAndroid Build Coastguard Worker    raise AttributeError(
351*c2e18aaaSAndroid Build Coastguard Worker        '%s object has no attribute %s' % (type(args).__name__, not_match)
352*c2e18aaaSAndroid Build Coastguard Worker    )
353*c2e18aaaSAndroid Build Coastguard Worker  extra_args.update({
354*c2e18aaaSAndroid Build Coastguard Worker      arg_maps.get(k): v for k, v in vars(args).items() if arg_maps.get(k) and v
355*c2e18aaaSAndroid Build Coastguard Worker  })
356*c2e18aaaSAndroid Build Coastguard Worker  return extra_args
357*c2e18aaaSAndroid Build Coastguard Worker
358*c2e18aaaSAndroid Build Coastguard Worker
359*c2e18aaaSAndroid Build Coastguard Workerdef _validate_exec_mode(args, test_infos: list[TestInfo], host_tests=None):
360*c2e18aaaSAndroid Build Coastguard Worker  """Validate all test execution modes are not in conflict.
361*c2e18aaaSAndroid Build Coastguard Worker
362*c2e18aaaSAndroid Build Coastguard Worker  Exit the program with INVALID_EXEC_MODE code if the desired is a host-side
363*c2e18aaaSAndroid Build Coastguard Worker  test but the given is a device-side test.
364*c2e18aaaSAndroid Build Coastguard Worker
365*c2e18aaaSAndroid Build Coastguard Worker  If the given is a host-side test and not specified `args.host`, forcibly
366*c2e18aaaSAndroid Build Coastguard Worker  set `args.host` to True.
367*c2e18aaaSAndroid Build Coastguard Worker
368*c2e18aaaSAndroid Build Coastguard Worker  Args:
369*c2e18aaaSAndroid Build Coastguard Worker      args: parsed args object.
370*c2e18aaaSAndroid Build Coastguard Worker      test_infos: a list of TestInfo objects.
371*c2e18aaaSAndroid Build Coastguard Worker      host_tests: True if all tests should be deviceless, False if all tests
372*c2e18aaaSAndroid Build Coastguard Worker        should be device tests. Default is set to None, which means tests can be
373*c2e18aaaSAndroid Build Coastguard Worker        either deviceless or device tests.
374*c2e18aaaSAndroid Build Coastguard Worker  """
375*c2e18aaaSAndroid Build Coastguard Worker  all_device_modes = {x.get_supported_exec_mode() for x in test_infos}
376*c2e18aaaSAndroid Build Coastguard Worker  err_msg = None
377*c2e18aaaSAndroid Build Coastguard Worker  # In the case of '$atest <device-only> --host', exit.
378*c2e18aaaSAndroid Build Coastguard Worker  if (host_tests or args.host) and constants.DEVICE_TEST in all_device_modes:
379*c2e18aaaSAndroid Build Coastguard Worker    device_only_tests = [
380*c2e18aaaSAndroid Build Coastguard Worker        x.test_name
381*c2e18aaaSAndroid Build Coastguard Worker        for x in test_infos
382*c2e18aaaSAndroid Build Coastguard Worker        if x.get_supported_exec_mode() == constants.DEVICE_TEST
383*c2e18aaaSAndroid Build Coastguard Worker    ]
384*c2e18aaaSAndroid Build Coastguard Worker    err_msg = (
385*c2e18aaaSAndroid Build Coastguard Worker        'Specified --host, but the following tests are device-only:\n  '
386*c2e18aaaSAndroid Build Coastguard Worker        + '\n  '.join(sorted(device_only_tests))
387*c2e18aaaSAndroid Build Coastguard Worker        + '\nPlease remove the  option when running device-only tests.'
388*c2e18aaaSAndroid Build Coastguard Worker    )
389*c2e18aaaSAndroid Build Coastguard Worker  # In the case of '$atest <host-only> <device-only> --host' or
390*c2e18aaaSAndroid Build Coastguard Worker  # '$atest <host-only> <device-only>', exit.
391*c2e18aaaSAndroid Build Coastguard Worker  if (
392*c2e18aaaSAndroid Build Coastguard Worker      constants.DEVICELESS_TEST in all_device_modes
393*c2e18aaaSAndroid Build Coastguard Worker      and constants.DEVICE_TEST in all_device_modes
394*c2e18aaaSAndroid Build Coastguard Worker  ):
395*c2e18aaaSAndroid Build Coastguard Worker    err_msg = 'There are host-only and device-only tests in command.'
396*c2e18aaaSAndroid Build Coastguard Worker  if host_tests is False and constants.DEVICELESS_TEST in all_device_modes:
397*c2e18aaaSAndroid Build Coastguard Worker    err_msg = 'There are host-only tests in command.'
398*c2e18aaaSAndroid Build Coastguard Worker  if err_msg:
399*c2e18aaaSAndroid Build Coastguard Worker    atest_utils.print_and_log_error(err_msg)
400*c2e18aaaSAndroid Build Coastguard Worker    metrics_utils.send_exit_event(ExitCode.INVALID_EXEC_MODE, logs=err_msg)
401*c2e18aaaSAndroid Build Coastguard Worker    sys.exit(ExitCode.INVALID_EXEC_MODE)
402*c2e18aaaSAndroid Build Coastguard Worker  # The 'adb' may not be available for the first repo sync or a clean build;
403*c2e18aaaSAndroid Build Coastguard Worker  # run `adb devices` in the build step again.
404*c2e18aaaSAndroid Build Coastguard Worker  if atest_utils.has_command('adb'):
405*c2e18aaaSAndroid Build Coastguard Worker    _validate_adb_devices(args, test_infos)
406*c2e18aaaSAndroid Build Coastguard Worker  # In the case of '$atest <host-only>', we add --host to run on host-side.
407*c2e18aaaSAndroid Build Coastguard Worker  # The option should only be overridden if `host_tests` is not set.
408*c2e18aaaSAndroid Build Coastguard Worker  if not args.host and host_tests is None:
409*c2e18aaaSAndroid Build Coastguard Worker    logging.debug('Appending "--host" for a deviceless test...')
410*c2e18aaaSAndroid Build Coastguard Worker    args.host = bool(constants.DEVICELESS_TEST in all_device_modes)
411*c2e18aaaSAndroid Build Coastguard Worker
412*c2e18aaaSAndroid Build Coastguard Worker
413*c2e18aaaSAndroid Build Coastguard Workerdef _validate_adb_devices(args, test_infos):
414*c2e18aaaSAndroid Build Coastguard Worker  """Validate the availability of connected devices via adb command.
415*c2e18aaaSAndroid Build Coastguard Worker
416*c2e18aaaSAndroid Build Coastguard Worker  Exit the program with error code if have device-only and host-only.
417*c2e18aaaSAndroid Build Coastguard Worker
418*c2e18aaaSAndroid Build Coastguard Worker  Args:
419*c2e18aaaSAndroid Build Coastguard Worker      args: parsed args object.
420*c2e18aaaSAndroid Build Coastguard Worker      test_infos: TestInfo object.
421*c2e18aaaSAndroid Build Coastguard Worker  """
422*c2e18aaaSAndroid Build Coastguard Worker  # No need to check device availability if the user does not acquire to test.
423*c2e18aaaSAndroid Build Coastguard Worker  if not parse_steps(args).test:
424*c2e18aaaSAndroid Build Coastguard Worker    return
425*c2e18aaaSAndroid Build Coastguard Worker  if args.no_checking_device:
426*c2e18aaaSAndroid Build Coastguard Worker    return
427*c2e18aaaSAndroid Build Coastguard Worker  # No need to check local device availability if the device test is running
428*c2e18aaaSAndroid Build Coastguard Worker  # remotely.
429*c2e18aaaSAndroid Build Coastguard Worker  if args.bazel_mode_features and (
430*c2e18aaaSAndroid Build Coastguard Worker      bazel_mode.Features.EXPERIMENTAL_REMOTE_AVD in args.bazel_mode_features
431*c2e18aaaSAndroid Build Coastguard Worker  ):
432*c2e18aaaSAndroid Build Coastguard Worker    return
433*c2e18aaaSAndroid Build Coastguard Worker  all_device_modes = {x.get_supported_exec_mode() for x in test_infos}
434*c2e18aaaSAndroid Build Coastguard Worker  device_tests = [
435*c2e18aaaSAndroid Build Coastguard Worker      x.test_name
436*c2e18aaaSAndroid Build Coastguard Worker      for x in test_infos
437*c2e18aaaSAndroid Build Coastguard Worker      if x.get_supported_exec_mode() != constants.DEVICELESS_TEST
438*c2e18aaaSAndroid Build Coastguard Worker  ]
439*c2e18aaaSAndroid Build Coastguard Worker  # Only block testing if it is a device test.
440*c2e18aaaSAndroid Build Coastguard Worker  if constants.DEVICE_TEST in all_device_modes:
441*c2e18aaaSAndroid Build Coastguard Worker    if (
442*c2e18aaaSAndroid Build Coastguard Worker        not any((args.host, args.start_avd, args.acloud_create))
443*c2e18aaaSAndroid Build Coastguard Worker        and not atest_utils.get_adb_devices()
444*c2e18aaaSAndroid Build Coastguard Worker    ):
445*c2e18aaaSAndroid Build Coastguard Worker      err_msg = (
446*c2e18aaaSAndroid Build Coastguard Worker          f'Stop running test(s): {", ".join(device_tests)} require a device.'
447*c2e18aaaSAndroid Build Coastguard Worker      )
448*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(err_msg, constants.RED)
449*c2e18aaaSAndroid Build Coastguard Worker      logging.debug(atest_utils.mark_red(constants.REQUIRE_DEVICES_MSG))
450*c2e18aaaSAndroid Build Coastguard Worker      metrics_utils.send_exit_event(ExitCode.DEVICE_NOT_FOUND, logs=err_msg)
451*c2e18aaaSAndroid Build Coastguard Worker      sys.exit(ExitCode.DEVICE_NOT_FOUND)
452*c2e18aaaSAndroid Build Coastguard Worker
453*c2e18aaaSAndroid Build Coastguard Worker
454*c2e18aaaSAndroid Build Coastguard Workerdef _validate_tm_tests_exec_mode(
455*c2e18aaaSAndroid Build Coastguard Worker    args: argparse.Namespace,
456*c2e18aaaSAndroid Build Coastguard Worker    device_test_infos: List[test_info.TestInfo],
457*c2e18aaaSAndroid Build Coastguard Worker    host_test_infos: List[test_info.TestInfo],
458*c2e18aaaSAndroid Build Coastguard Worker):
459*c2e18aaaSAndroid Build Coastguard Worker  """Validate all test execution modes are not in conflict.
460*c2e18aaaSAndroid Build Coastguard Worker
461*c2e18aaaSAndroid Build Coastguard Worker  Validate the tests' platform variant setting. For device tests, exit the
462*c2e18aaaSAndroid Build Coastguard Worker  program if any test is found for host-only. For host tests, exit the
463*c2e18aaaSAndroid Build Coastguard Worker  program if any test is found for device-only.
464*c2e18aaaSAndroid Build Coastguard Worker
465*c2e18aaaSAndroid Build Coastguard Worker  Args:
466*c2e18aaaSAndroid Build Coastguard Worker      args: parsed args object.
467*c2e18aaaSAndroid Build Coastguard Worker      device_test_infos: TestInfo instances for device tests.
468*c2e18aaaSAndroid Build Coastguard Worker      host_test_infos: TestInfo instances for host tests.
469*c2e18aaaSAndroid Build Coastguard Worker  """
470*c2e18aaaSAndroid Build Coastguard Worker
471*c2e18aaaSAndroid Build Coastguard Worker  # No need to verify device tests if atest command is set to only run host
472*c2e18aaaSAndroid Build Coastguard Worker  # tests.
473*c2e18aaaSAndroid Build Coastguard Worker  if device_test_infos and not args.host:
474*c2e18aaaSAndroid Build Coastguard Worker    _validate_exec_mode(args, device_test_infos, host_tests=False)
475*c2e18aaaSAndroid Build Coastguard Worker  if host_test_infos:
476*c2e18aaaSAndroid Build Coastguard Worker    _validate_exec_mode(args, host_test_infos, host_tests=True)
477*c2e18aaaSAndroid Build Coastguard Worker
478*c2e18aaaSAndroid Build Coastguard Worker
479*c2e18aaaSAndroid Build Coastguard Workerdef _has_valid_test_mapping_args(args):
480*c2e18aaaSAndroid Build Coastguard Worker  """Validate test mapping args.
481*c2e18aaaSAndroid Build Coastguard Worker
482*c2e18aaaSAndroid Build Coastguard Worker  Not all args work when running tests in TEST_MAPPING files. Validate the
483*c2e18aaaSAndroid Build Coastguard Worker  args before running the tests.
484*c2e18aaaSAndroid Build Coastguard Worker
485*c2e18aaaSAndroid Build Coastguard Worker  Args:
486*c2e18aaaSAndroid Build Coastguard Worker      args: parsed args object.
487*c2e18aaaSAndroid Build Coastguard Worker
488*c2e18aaaSAndroid Build Coastguard Worker  Returns:
489*c2e18aaaSAndroid Build Coastguard Worker      True if args are valid
490*c2e18aaaSAndroid Build Coastguard Worker  """
491*c2e18aaaSAndroid Build Coastguard Worker  is_test_mapping = atest_utils.is_test_mapping(args)
492*c2e18aaaSAndroid Build Coastguard Worker  if is_test_mapping:
493*c2e18aaaSAndroid Build Coastguard Worker    metrics.LocalDetectEvent(detect_type=DetectType.IS_TEST_MAPPING, result=1)
494*c2e18aaaSAndroid Build Coastguard Worker  else:
495*c2e18aaaSAndroid Build Coastguard Worker    metrics.LocalDetectEvent(detect_type=DetectType.IS_TEST_MAPPING, result=0)
496*c2e18aaaSAndroid Build Coastguard Worker  if not is_test_mapping:
497*c2e18aaaSAndroid Build Coastguard Worker    return True
498*c2e18aaaSAndroid Build Coastguard Worker  options_to_validate = [
499*c2e18aaaSAndroid Build Coastguard Worker      (args.annotation_filter, '--annotation-filter'),
500*c2e18aaaSAndroid Build Coastguard Worker  ]
501*c2e18aaaSAndroid Build Coastguard Worker  for arg_value, arg in options_to_validate:
502*c2e18aaaSAndroid Build Coastguard Worker    if arg_value:
503*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.print_and_log_error(
504*c2e18aaaSAndroid Build Coastguard Worker          atest_utils.mark_red(OPTION_NOT_FOR_TEST_MAPPING.format(arg))
505*c2e18aaaSAndroid Build Coastguard Worker      )
506*c2e18aaaSAndroid Build Coastguard Worker      return False
507*c2e18aaaSAndroid Build Coastguard Worker  return True
508*c2e18aaaSAndroid Build Coastguard Worker
509*c2e18aaaSAndroid Build Coastguard Worker
510*c2e18aaaSAndroid Build Coastguard Workerdef _print_deprecation_warning(arg_to_deprecate: str):
511*c2e18aaaSAndroid Build Coastguard Worker  """For features that are up for deprecation in the near future, print a message
512*c2e18aaaSAndroid Build Coastguard Worker
513*c2e18aaaSAndroid Build Coastguard Worker  to alert the user about the upcoming deprecation.
514*c2e18aaaSAndroid Build Coastguard Worker
515*c2e18aaaSAndroid Build Coastguard Worker  Args:
516*c2e18aaaSAndroid Build Coastguard Worker      arg_to_deprecate: the arg with which the to-be-deprecated feature is
517*c2e18aaaSAndroid Build Coastguard Worker        called.
518*c2e18aaaSAndroid Build Coastguard Worker  """
519*c2e18aaaSAndroid Build Coastguard Worker  args_to_deprecation_info = {
520*c2e18aaaSAndroid Build Coastguard Worker      # arg_to_deprecate : (deprecation timeframe, additional info for users)
521*c2e18aaaSAndroid Build Coastguard Worker      '--info': ('is deprecated.', '\nUse CodeSearch or `gomod` instead.')
522*c2e18aaaSAndroid Build Coastguard Worker  }
523*c2e18aaaSAndroid Build Coastguard Worker
524*c2e18aaaSAndroid Build Coastguard Worker  warning_message = (
525*c2e18aaaSAndroid Build Coastguard Worker      f'\nWARNING: The `{arg_to_deprecate}` feature '
526*c2e18aaaSAndroid Build Coastguard Worker      + ' '.join(args_to_deprecation_info[arg_to_deprecate])
527*c2e18aaaSAndroid Build Coastguard Worker      + '\nPlease file a bug or feature request to the Atest team if you have'
528*c2e18aaaSAndroid Build Coastguard Worker      ' any concerns.'
529*c2e18aaaSAndroid Build Coastguard Worker  )
530*c2e18aaaSAndroid Build Coastguard Worker  atest_utils.colorful_print(warning_message, constants.RED)
531*c2e18aaaSAndroid Build Coastguard Worker
532*c2e18aaaSAndroid Build Coastguard Worker
533*c2e18aaaSAndroid Build Coastguard Workerdef is_from_test_mapping(test_infos):
534*c2e18aaaSAndroid Build Coastguard Worker  """Check that the test_infos came from TEST_MAPPING files.
535*c2e18aaaSAndroid Build Coastguard Worker
536*c2e18aaaSAndroid Build Coastguard Worker  Args:
537*c2e18aaaSAndroid Build Coastguard Worker      test_infos: A set of TestInfos.
538*c2e18aaaSAndroid Build Coastguard Worker
539*c2e18aaaSAndroid Build Coastguard Worker  Returns:
540*c2e18aaaSAndroid Build Coastguard Worker      True if the test infos are from TEST_MAPPING files.
541*c2e18aaaSAndroid Build Coastguard Worker  """
542*c2e18aaaSAndroid Build Coastguard Worker  return list(test_infos)[0].from_test_mapping
543*c2e18aaaSAndroid Build Coastguard Worker
544*c2e18aaaSAndroid Build Coastguard Worker
545*c2e18aaaSAndroid Build Coastguard Workerdef _split_test_mapping_tests(test_infos):
546*c2e18aaaSAndroid Build Coastguard Worker  """Split Test Mapping tests into 2 groups: device tests and host tests.
547*c2e18aaaSAndroid Build Coastguard Worker
548*c2e18aaaSAndroid Build Coastguard Worker  Args:
549*c2e18aaaSAndroid Build Coastguard Worker      test_infos: A set of TestInfos.
550*c2e18aaaSAndroid Build Coastguard Worker
551*c2e18aaaSAndroid Build Coastguard Worker  Returns:
552*c2e18aaaSAndroid Build Coastguard Worker      A tuple of (device_test_infos, host_test_infos), where
553*c2e18aaaSAndroid Build Coastguard Worker      device_test_infos: A set of TestInfos for tests that require device.
554*c2e18aaaSAndroid Build Coastguard Worker      host_test_infos: A set of TestInfos for tests that do NOT require
555*c2e18aaaSAndroid Build Coastguard Worker          device.
556*c2e18aaaSAndroid Build Coastguard Worker  """
557*c2e18aaaSAndroid Build Coastguard Worker  assert is_from_test_mapping(test_infos)
558*c2e18aaaSAndroid Build Coastguard Worker  host_test_infos = {info for info in test_infos if info.host}
559*c2e18aaaSAndroid Build Coastguard Worker  device_test_infos = {info for info in test_infos if not info.host}
560*c2e18aaaSAndroid Build Coastguard Worker  return device_test_infos, host_test_infos
561*c2e18aaaSAndroid Build Coastguard Worker
562*c2e18aaaSAndroid Build Coastguard Worker
563*c2e18aaaSAndroid Build Coastguard Workerdef _exclude_modules_in_targets(build_targets):
564*c2e18aaaSAndroid Build Coastguard Worker  """Method that excludes MODULES-IN-* targets.
565*c2e18aaaSAndroid Build Coastguard Worker
566*c2e18aaaSAndroid Build Coastguard Worker  Args:
567*c2e18aaaSAndroid Build Coastguard Worker      build_targets: A set of build targets.
568*c2e18aaaSAndroid Build Coastguard Worker
569*c2e18aaaSAndroid Build Coastguard Worker  Returns:
570*c2e18aaaSAndroid Build Coastguard Worker      A set of build targets that excludes MODULES-IN-*.
571*c2e18aaaSAndroid Build Coastguard Worker  """
572*c2e18aaaSAndroid Build Coastguard Worker  shrank_build_targets = build_targets.copy()
573*c2e18aaaSAndroid Build Coastguard Worker  logging.debug(
574*c2e18aaaSAndroid Build Coastguard Worker      'Will exclude all "%s*" from the build targets.', constants.MODULES_IN
575*c2e18aaaSAndroid Build Coastguard Worker  )
576*c2e18aaaSAndroid Build Coastguard Worker  for target in build_targets:
577*c2e18aaaSAndroid Build Coastguard Worker    if target.startswith(constants.MODULES_IN):
578*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('Ignore %s.', target)
579*c2e18aaaSAndroid Build Coastguard Worker      shrank_build_targets.remove(target)
580*c2e18aaaSAndroid Build Coastguard Worker  return shrank_build_targets
581*c2e18aaaSAndroid Build Coastguard Worker
582*c2e18aaaSAndroid Build Coastguard Worker
583*c2e18aaaSAndroid Build Coastguard Workerdef get_device_count_config(test_infos, mod_info):
584*c2e18aaaSAndroid Build Coastguard Worker  """Get the amount of desired devices from the test config.
585*c2e18aaaSAndroid Build Coastguard Worker
586*c2e18aaaSAndroid Build Coastguard Worker  Args:
587*c2e18aaaSAndroid Build Coastguard Worker      test_infos: A set of TestInfo instances.
588*c2e18aaaSAndroid Build Coastguard Worker      mod_info: ModuleInfo object.
589*c2e18aaaSAndroid Build Coastguard Worker
590*c2e18aaaSAndroid Build Coastguard Worker  Returns: the count of devices in test config. If there are more than one
591*c2e18aaaSAndroid Build Coastguard Worker           configs, return the maximum.
592*c2e18aaaSAndroid Build Coastguard Worker  """
593*c2e18aaaSAndroid Build Coastguard Worker  max_count = 0
594*c2e18aaaSAndroid Build Coastguard Worker  for tinfo in test_infos:
595*c2e18aaaSAndroid Build Coastguard Worker    test_config, _ = test_finder_utils.get_test_config_and_srcs(tinfo, mod_info)
596*c2e18aaaSAndroid Build Coastguard Worker    if test_config:
597*c2e18aaaSAndroid Build Coastguard Worker      devices = atest_utils.get_config_device(test_config)
598*c2e18aaaSAndroid Build Coastguard Worker      if devices:
599*c2e18aaaSAndroid Build Coastguard Worker        max_count = max(len(devices), max_count)
600*c2e18aaaSAndroid Build Coastguard Worker  return max_count
601*c2e18aaaSAndroid Build Coastguard Worker
602*c2e18aaaSAndroid Build Coastguard Worker
603*c2e18aaaSAndroid Build Coastguard Workerdef has_set_sufficient_devices(
604*c2e18aaaSAndroid Build Coastguard Worker    required_amount: int, serial: List[str] = None
605*c2e18aaaSAndroid Build Coastguard Worker) -> bool:
606*c2e18aaaSAndroid Build Coastguard Worker  """Detect whether sufficient device serial is set for test."""
607*c2e18aaaSAndroid Build Coastguard Worker  given_amount = len(serial) if serial else 0
608*c2e18aaaSAndroid Build Coastguard Worker  # Only check when both given_amount and required_amount are non zero.
609*c2e18aaaSAndroid Build Coastguard Worker  if all((given_amount, required_amount)):
610*c2e18aaaSAndroid Build Coastguard Worker    # Base on TF rules, given_amount can be greater than or equal to
611*c2e18aaaSAndroid Build Coastguard Worker    # required_amount.
612*c2e18aaaSAndroid Build Coastguard Worker    if required_amount > given_amount:
613*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
614*c2e18aaaSAndroid Build Coastguard Worker          f'The test requires {required_amount} devices, '
615*c2e18aaaSAndroid Build Coastguard Worker          f'but {given_amount} were given.',
616*c2e18aaaSAndroid Build Coastguard Worker          constants.RED,
617*c2e18aaaSAndroid Build Coastguard Worker      )
618*c2e18aaaSAndroid Build Coastguard Worker      return False
619*c2e18aaaSAndroid Build Coastguard Worker  return True
620*c2e18aaaSAndroid Build Coastguard Worker
621*c2e18aaaSAndroid Build Coastguard Worker
622*c2e18aaaSAndroid Build Coastguard Workerdef setup_metrics_tool_name(no_metrics: bool = False):
623*c2e18aaaSAndroid Build Coastguard Worker  """Setup tool_name and sub_tool_name for MetricsBase."""
624*c2e18aaaSAndroid Build Coastguard Worker  if (
625*c2e18aaaSAndroid Build Coastguard Worker      not no_metrics
626*c2e18aaaSAndroid Build Coastguard Worker      and metrics_base.MetricsBase.user_type == metrics_base.INTERNAL_USER
627*c2e18aaaSAndroid Build Coastguard Worker  ):
628*c2e18aaaSAndroid Build Coastguard Worker    metrics_utils.print_data_collection_notice()
629*c2e18aaaSAndroid Build Coastguard Worker
630*c2e18aaaSAndroid Build Coastguard Worker    USER_FROM_TOOL = os.getenv(constants.USER_FROM_TOOL)
631*c2e18aaaSAndroid Build Coastguard Worker    metrics_base.MetricsBase.tool_name = (
632*c2e18aaaSAndroid Build Coastguard Worker        USER_FROM_TOOL if USER_FROM_TOOL else constants.TOOL_NAME
633*c2e18aaaSAndroid Build Coastguard Worker    )
634*c2e18aaaSAndroid Build Coastguard Worker
635*c2e18aaaSAndroid Build Coastguard Worker    USER_FROM_SUB_TOOL = os.getenv(constants.USER_FROM_SUB_TOOL)
636*c2e18aaaSAndroid Build Coastguard Worker    metrics_base.MetricsBase.sub_tool_name = (
637*c2e18aaaSAndroid Build Coastguard Worker        USER_FROM_SUB_TOOL if USER_FROM_SUB_TOOL else constants.SUB_TOOL_NAME
638*c2e18aaaSAndroid Build Coastguard Worker    )
639*c2e18aaaSAndroid Build Coastguard Worker
640*c2e18aaaSAndroid Build Coastguard Worker
641*c2e18aaaSAndroid Build Coastguard Workerclass _AtestMain:
642*c2e18aaaSAndroid Build Coastguard Worker  """Entry point of atest script."""
643*c2e18aaaSAndroid Build Coastguard Worker
644*c2e18aaaSAndroid Build Coastguard Worker  def __init__(
645*c2e18aaaSAndroid Build Coastguard Worker      self,
646*c2e18aaaSAndroid Build Coastguard Worker      argv: list[str],
647*c2e18aaaSAndroid Build Coastguard Worker  ):
648*c2e18aaaSAndroid Build Coastguard Worker    """Initializes the _AtestMain object.
649*c2e18aaaSAndroid Build Coastguard Worker
650*c2e18aaaSAndroid Build Coastguard Worker    Args:
651*c2e18aaaSAndroid Build Coastguard Worker        argv: A list of command line arguments.
652*c2e18aaaSAndroid Build Coastguard Worker    """
653*c2e18aaaSAndroid Build Coastguard Worker    self._argv: list[str] = argv
654*c2e18aaaSAndroid Build Coastguard Worker
655*c2e18aaaSAndroid Build Coastguard Worker    self._banner_printer: banner.BannerPrinter = None
656*c2e18aaaSAndroid Build Coastguard Worker    self._steps: Steps = None
657*c2e18aaaSAndroid Build Coastguard Worker    self._results_dir: str = None
658*c2e18aaaSAndroid Build Coastguard Worker    self._mod_info: module_info.ModuleInfo = None
659*c2e18aaaSAndroid Build Coastguard Worker    self._test_infos: list[test_info.TestInfo] = None
660*c2e18aaaSAndroid Build Coastguard Worker    self._test_execution_plan: _TestExecutionPlan = None
661*c2e18aaaSAndroid Build Coastguard Worker
662*c2e18aaaSAndroid Build Coastguard Worker    self._acloud_proc: subprocess.Popen = None
663*c2e18aaaSAndroid Build Coastguard Worker    self._acloud_report_file: str = None
664*c2e18aaaSAndroid Build Coastguard Worker    self._test_info_loading_duration: float = 0
665*c2e18aaaSAndroid Build Coastguard Worker    self._build_duration: float = 0
666*c2e18aaaSAndroid Build Coastguard Worker    self._module_info_rebuild_required: bool = False
667*c2e18aaaSAndroid Build Coastguard Worker    self._is_out_clean_before_module_info_build: bool = False
668*c2e18aaaSAndroid Build Coastguard Worker    self._invocation_begin_time: float = None
669*c2e18aaaSAndroid Build Coastguard Worker
670*c2e18aaaSAndroid Build Coastguard Worker  def run(self):
671*c2e18aaaSAndroid Build Coastguard Worker    self._results_dir = make_test_run_dir()
672*c2e18aaaSAndroid Build Coastguard Worker
673*c2e18aaaSAndroid Build Coastguard Worker    if END_OF_OPTION in self._argv:
674*c2e18aaaSAndroid Build Coastguard Worker      end_position = self._argv.index(END_OF_OPTION)
675*c2e18aaaSAndroid Build Coastguard Worker      final_args = [
676*c2e18aaaSAndroid Build Coastguard Worker          *self._argv[1:end_position],
677*c2e18aaaSAndroid Build Coastguard Worker          *_get_args_from_config(),
678*c2e18aaaSAndroid Build Coastguard Worker          *self._argv[end_position:],
679*c2e18aaaSAndroid Build Coastguard Worker      ]
680*c2e18aaaSAndroid Build Coastguard Worker    else:
681*c2e18aaaSAndroid Build Coastguard Worker      final_args = [*self._argv[1:], *_get_args_from_config()]
682*c2e18aaaSAndroid Build Coastguard Worker    if final_args != self._argv[1:]:
683*c2e18aaaSAndroid Build Coastguard Worker      print(
684*c2e18aaaSAndroid Build Coastguard Worker          'The actual cmd will be: \n\t{}\n'.format(
685*c2e18aaaSAndroid Build Coastguard Worker              atest_utils.mark_cyan('atest ' + ' '.join(final_args))
686*c2e18aaaSAndroid Build Coastguard Worker          )
687*c2e18aaaSAndroid Build Coastguard Worker      )
688*c2e18aaaSAndroid Build Coastguard Worker      metrics.LocalDetectEvent(detect_type=DetectType.ATEST_CONFIG, result=1)
689*c2e18aaaSAndroid Build Coastguard Worker      if HAS_IGNORED_ARGS:
690*c2e18aaaSAndroid Build Coastguard Worker        atest_utils.colorful_print(
691*c2e18aaaSAndroid Build Coastguard Worker            'Please correct the config and try again.', constants.YELLOW
692*c2e18aaaSAndroid Build Coastguard Worker        )
693*c2e18aaaSAndroid Build Coastguard Worker        sys.exit(ExitCode.EXIT_BEFORE_MAIN)
694*c2e18aaaSAndroid Build Coastguard Worker    else:
695*c2e18aaaSAndroid Build Coastguard Worker      metrics.LocalDetectEvent(detect_type=DetectType.ATEST_CONFIG, result=0)
696*c2e18aaaSAndroid Build Coastguard Worker
697*c2e18aaaSAndroid Build Coastguard Worker    self._args = _parse_args(final_args)
698*c2e18aaaSAndroid Build Coastguard Worker    atest_configs.GLOBAL_ARGS = self._args
699*c2e18aaaSAndroid Build Coastguard Worker    _configure_logging(self._args.verbose, self._results_dir)
700*c2e18aaaSAndroid Build Coastguard Worker
701*c2e18aaaSAndroid Build Coastguard Worker    logging.debug(
702*c2e18aaaSAndroid Build Coastguard Worker        'Start of atest run. sys.argv: %s, final_args: %s',
703*c2e18aaaSAndroid Build Coastguard Worker        self._argv,
704*c2e18aaaSAndroid Build Coastguard Worker        final_args,
705*c2e18aaaSAndroid Build Coastguard Worker    )
706*c2e18aaaSAndroid Build Coastguard Worker
707*c2e18aaaSAndroid Build Coastguard Worker    self._steps = parse_steps(self._args)
708*c2e18aaaSAndroid Build Coastguard Worker
709*c2e18aaaSAndroid Build Coastguard Worker    self._banner_printer = banner.BannerPrinter.create()
710*c2e18aaaSAndroid Build Coastguard Worker
711*c2e18aaaSAndroid Build Coastguard Worker    with atest_execution_info.AtestExecutionInfo(
712*c2e18aaaSAndroid Build Coastguard Worker        final_args, self._results_dir, atest_configs.GLOBAL_ARGS
713*c2e18aaaSAndroid Build Coastguard Worker    ):
714*c2e18aaaSAndroid Build Coastguard Worker      setup_metrics_tool_name(atest_configs.GLOBAL_ARGS.no_metrics)
715*c2e18aaaSAndroid Build Coastguard Worker
716*c2e18aaaSAndroid Build Coastguard Worker      logging.debug(
717*c2e18aaaSAndroid Build Coastguard Worker          'Creating atest script with argv: %s\n  results_dir: %s\n  args: %s\n'
718*c2e18aaaSAndroid Build Coastguard Worker          '  run id: %s',
719*c2e18aaaSAndroid Build Coastguard Worker          self._argv,
720*c2e18aaaSAndroid Build Coastguard Worker          self._results_dir,
721*c2e18aaaSAndroid Build Coastguard Worker          self._args,
722*c2e18aaaSAndroid Build Coastguard Worker          metrics.get_run_id(),
723*c2e18aaaSAndroid Build Coastguard Worker      )
724*c2e18aaaSAndroid Build Coastguard Worker      exit_code = self._run_all_steps()
725*c2e18aaaSAndroid Build Coastguard Worker      detector = bug_detector.BugDetector(final_args, exit_code)
726*c2e18aaaSAndroid Build Coastguard Worker      if exit_code not in EXIT_CODES_BEFORE_TEST:
727*c2e18aaaSAndroid Build Coastguard Worker        metrics.LocalDetectEvent(
728*c2e18aaaSAndroid Build Coastguard Worker            detect_type=DetectType.BUG_DETECTED, result=detector.caught_result
729*c2e18aaaSAndroid Build Coastguard Worker        )
730*c2e18aaaSAndroid Build Coastguard Worker
731*c2e18aaaSAndroid Build Coastguard Worker    self._banner_printer.print()
732*c2e18aaaSAndroid Build Coastguard Worker
733*c2e18aaaSAndroid Build Coastguard Worker    sys.exit(exit_code)
734*c2e18aaaSAndroid Build Coastguard Worker
735*c2e18aaaSAndroid Build Coastguard Worker  def _check_no_action_argument(self) -> int:
736*c2e18aaaSAndroid Build Coastguard Worker    """Method for non-action arguments such as --version, --history, --latest_result, etc.
737*c2e18aaaSAndroid Build Coastguard Worker
738*c2e18aaaSAndroid Build Coastguard Worker    Returns:
739*c2e18aaaSAndroid Build Coastguard Worker        Exit code if no action. None otherwise.
740*c2e18aaaSAndroid Build Coastguard Worker    """
741*c2e18aaaSAndroid Build Coastguard Worker    if self._args.version:
742*c2e18aaaSAndroid Build Coastguard Worker      print(atest_utils.get_atest_version())
743*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.SUCCESS
744*c2e18aaaSAndroid Build Coastguard Worker    if self._args.history:
745*c2e18aaaSAndroid Build Coastguard Worker      atest_execution_info.print_test_result(
746*c2e18aaaSAndroid Build Coastguard Worker          constants.ATEST_RESULT_ROOT, self._args.history
747*c2e18aaaSAndroid Build Coastguard Worker      )
748*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.SUCCESS
749*c2e18aaaSAndroid Build Coastguard Worker    if self._args.latest_result:
750*c2e18aaaSAndroid Build Coastguard Worker      atest_execution_info.print_test_result_by_path(
751*c2e18aaaSAndroid Build Coastguard Worker          constants.LATEST_RESULT_FILE
752*c2e18aaaSAndroid Build Coastguard Worker      )
753*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.SUCCESS
754*c2e18aaaSAndroid Build Coastguard Worker    return None
755*c2e18aaaSAndroid Build Coastguard Worker
756*c2e18aaaSAndroid Build Coastguard Worker  def _check_envs_and_args(self) -> int:
757*c2e18aaaSAndroid Build Coastguard Worker    """Validate environment variables and args.
758*c2e18aaaSAndroid Build Coastguard Worker
759*c2e18aaaSAndroid Build Coastguard Worker    Returns:
760*c2e18aaaSAndroid Build Coastguard Worker        Exit code if any setup or arg is invalid. None otherwise.
761*c2e18aaaSAndroid Build Coastguard Worker    """
762*c2e18aaaSAndroid Build Coastguard Worker    if (
763*c2e18aaaSAndroid Build Coastguard Worker        not os.getenv(constants.ANDROID_BUILD_TOP, ' ') in os.getcwd()
764*c2e18aaaSAndroid Build Coastguard Worker    ):  # Not under android root.
765*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
766*c2e18aaaSAndroid Build Coastguard Worker          '\nAtest must always work under ${}!'.format(
767*c2e18aaaSAndroid Build Coastguard Worker              constants.ANDROID_BUILD_TOP
768*c2e18aaaSAndroid Build Coastguard Worker          ),
769*c2e18aaaSAndroid Build Coastguard Worker          constants.RED,
770*c2e18aaaSAndroid Build Coastguard Worker      )
771*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.OUTSIDE_ROOT
772*c2e18aaaSAndroid Build Coastguard Worker    if _missing_environment_variables():
773*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.ENV_NOT_SETUP
774*c2e18aaaSAndroid Build Coastguard Worker    if not _has_valid_test_mapping_args(self._args):
775*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.INVALID_TM_ARGS
776*c2e18aaaSAndroid Build Coastguard Worker
777*c2e18aaaSAndroid Build Coastguard Worker    # Checks whether ANDROID_SERIAL environment variable is set to an empty string.
778*c2e18aaaSAndroid Build Coastguard Worker    if 'ANDROID_SERIAL' in os.environ and not os.environ['ANDROID_SERIAL']:
779*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.print_and_log_warning(
780*c2e18aaaSAndroid Build Coastguard Worker          'Empty device serial detected in the ANDROID_SERIAL environment'
781*c2e18aaaSAndroid Build Coastguard Worker          ' variable. This may causes unexpected behavior in TradeFed. If not'
782*c2e18aaaSAndroid Build Coastguard Worker          ' targeting a specific device, consider unset the ANDROID_SERIAL'
783*c2e18aaaSAndroid Build Coastguard Worker          ' environment variable. See b/330365573 for details.'
784*c2e18aaaSAndroid Build Coastguard Worker      )
785*c2e18aaaSAndroid Build Coastguard Worker
786*c2e18aaaSAndroid Build Coastguard Worker    # Checks whether any empty serial strings exist in the argument array.
787*c2e18aaaSAndroid Build Coastguard Worker    if self._args.serial and not all(self._args.serial):
788*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.print_and_log_warning(
789*c2e18aaaSAndroid Build Coastguard Worker          'Empty device serial specified via command-line argument. This may'
790*c2e18aaaSAndroid Build Coastguard Worker          ' cause unexpected behavior in TradeFed. If not targeting a specific'
791*c2e18aaaSAndroid Build Coastguard Worker          ' device, consider remove the serial argument. See b/330365573 for'
792*c2e18aaaSAndroid Build Coastguard Worker          ' details.'
793*c2e18aaaSAndroid Build Coastguard Worker      )
794*c2e18aaaSAndroid Build Coastguard Worker
795*c2e18aaaSAndroid Build Coastguard Worker    return None
796*c2e18aaaSAndroid Build Coastguard Worker
797*c2e18aaaSAndroid Build Coastguard Worker  def _update_build_env(self):
798*c2e18aaaSAndroid Build Coastguard Worker    """Updates build environment variables."""
799*c2e18aaaSAndroid Build Coastguard Worker    # Sets coverage environment variables.
800*c2e18aaaSAndroid Build Coastguard Worker    if self._args.experimental_coverage:
801*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.update_build_env(coverage.build_env_vars())
802*c2e18aaaSAndroid Build Coastguard Worker
803*c2e18aaaSAndroid Build Coastguard Worker    # Update environment variable dict accordingly to args.build_output
804*c2e18aaaSAndroid Build Coastguard Worker    atest_utils.update_build_env({
805*c2e18aaaSAndroid Build Coastguard Worker        'ANDROID_QUIET_BUILD': 'true',
806*c2e18aaaSAndroid Build Coastguard Worker        'BUILD_OUTPUT_MODE': self._args.build_output.value,
807*c2e18aaaSAndroid Build Coastguard Worker    })
808*c2e18aaaSAndroid Build Coastguard Worker
809*c2e18aaaSAndroid Build Coastguard Worker  def _start_acloud_if_requested(self) -> None:
810*c2e18aaaSAndroid Build Coastguard Worker    if not self._args.acloud_create and not self._args.start_avd:
811*c2e18aaaSAndroid Build Coastguard Worker      return
812*c2e18aaaSAndroid Build Coastguard Worker    if not parse_steps(self._args).test:
813*c2e18aaaSAndroid Build Coastguard Worker      print('acloud/avd is requested but ignored because no test is requested.')
814*c2e18aaaSAndroid Build Coastguard Worker      return
815*c2e18aaaSAndroid Build Coastguard Worker    print('Creating acloud/avd...')
816*c2e18aaaSAndroid Build Coastguard Worker    self._acloud_proc, self._acloud_report_file = avd.acloud_create_validator(
817*c2e18aaaSAndroid Build Coastguard Worker        self._results_dir, self._args
818*c2e18aaaSAndroid Build Coastguard Worker    )
819*c2e18aaaSAndroid Build Coastguard Worker
820*c2e18aaaSAndroid Build Coastguard Worker  def _check_acloud_status(self) -> int:
821*c2e18aaaSAndroid Build Coastguard Worker    """Checks acloud status if acloud is requested.
822*c2e18aaaSAndroid Build Coastguard Worker
823*c2e18aaaSAndroid Build Coastguard Worker    Returns:
824*c2e18aaaSAndroid Build Coastguard Worker        acloud status code. None if no acloud requested.
825*c2e18aaaSAndroid Build Coastguard Worker    """
826*c2e18aaaSAndroid Build Coastguard Worker    if self._acloud_proc:
827*c2e18aaaSAndroid Build Coastguard Worker      self._acloud_proc.join()
828*c2e18aaaSAndroid Build Coastguard Worker      status = avd.probe_acloud_status(
829*c2e18aaaSAndroid Build Coastguard Worker          self._acloud_report_file,
830*c2e18aaaSAndroid Build Coastguard Worker          self._test_info_loading_duration + self._build_duration,
831*c2e18aaaSAndroid Build Coastguard Worker      )
832*c2e18aaaSAndroid Build Coastguard Worker      return status
833*c2e18aaaSAndroid Build Coastguard Worker    return None
834*c2e18aaaSAndroid Build Coastguard Worker
835*c2e18aaaSAndroid Build Coastguard Worker  def _start_indexing_if_required(self) -> threading.Thread:
836*c2e18aaaSAndroid Build Coastguard Worker    """Starts indexing if required.
837*c2e18aaaSAndroid Build Coastguard Worker
838*c2e18aaaSAndroid Build Coastguard Worker    Returns:
839*c2e18aaaSAndroid Build Coastguard Worker        A thread that runs indexing. None if no indexing is required.
840*c2e18aaaSAndroid Build Coastguard Worker    """
841*c2e18aaaSAndroid Build Coastguard Worker    if not self._steps.build:
842*c2e18aaaSAndroid Build Coastguard Worker      logging.debug("Skip indexing because there's no build required.")
843*c2e18aaaSAndroid Build Coastguard Worker      return None
844*c2e18aaaSAndroid Build Coastguard Worker
845*c2e18aaaSAndroid Build Coastguard Worker    if indexing.Indices().has_all_indices():
846*c2e18aaaSAndroid Build Coastguard Worker      no_indexing_args = (
847*c2e18aaaSAndroid Build Coastguard Worker          self._args.dry_run,
848*c2e18aaaSAndroid Build Coastguard Worker          self._args.list_modules,
849*c2e18aaaSAndroid Build Coastguard Worker      )
850*c2e18aaaSAndroid Build Coastguard Worker      if any(no_indexing_args):
851*c2e18aaaSAndroid Build Coastguard Worker        logging.debug(
852*c2e18aaaSAndroid Build Coastguard Worker            'Skip indexing for no_indexing_args=%s.', no_indexing_args
853*c2e18aaaSAndroid Build Coastguard Worker        )
854*c2e18aaaSAndroid Build Coastguard Worker        return None
855*c2e18aaaSAndroid Build Coastguard Worker    else:
856*c2e18aaaSAndroid Build Coastguard Worker      logging.debug(
857*c2e18aaaSAndroid Build Coastguard Worker          'Indexing targets is required because some index files do not exist.'
858*c2e18aaaSAndroid Build Coastguard Worker      )
859*c2e18aaaSAndroid Build Coastguard Worker
860*c2e18aaaSAndroid Build Coastguard Worker    logging.debug('Starting to index targets in a background thread.')
861*c2e18aaaSAndroid Build Coastguard Worker    return atest_utils.start_threading(
862*c2e18aaaSAndroid Build Coastguard Worker        indexing.index_targets,
863*c2e18aaaSAndroid Build Coastguard Worker        daemon=True,
864*c2e18aaaSAndroid Build Coastguard Worker    )
865*c2e18aaaSAndroid Build Coastguard Worker
866*c2e18aaaSAndroid Build Coastguard Worker  @functools.cache
867*c2e18aaaSAndroid Build Coastguard Worker  def _get_device_update_method(self) -> device_update.AdeviceUpdateMethod:
868*c2e18aaaSAndroid Build Coastguard Worker    """Creates a device update method."""
869*c2e18aaaSAndroid Build Coastguard Worker    return device_update.AdeviceUpdateMethod(
870*c2e18aaaSAndroid Build Coastguard Worker        targets=set(self._args.update_modules or [])
871*c2e18aaaSAndroid Build Coastguard Worker    )
872*c2e18aaaSAndroid Build Coastguard Worker
873*c2e18aaaSAndroid Build Coastguard Worker  def _get_device_update_dependencies(self) -> set[str]:
874*c2e18aaaSAndroid Build Coastguard Worker    """Gets device update dependencies.
875*c2e18aaaSAndroid Build Coastguard Worker
876*c2e18aaaSAndroid Build Coastguard Worker    Returns:
877*c2e18aaaSAndroid Build Coastguard Worker        A set of dependencies for the device update method.
878*c2e18aaaSAndroid Build Coastguard Worker    """
879*c2e18aaaSAndroid Build Coastguard Worker    if not self._args.update_device:
880*c2e18aaaSAndroid Build Coastguard Worker      return set()
881*c2e18aaaSAndroid Build Coastguard Worker
882*c2e18aaaSAndroid Build Coastguard Worker    if (
883*c2e18aaaSAndroid Build Coastguard Worker        self._test_execution_plan
884*c2e18aaaSAndroid Build Coastguard Worker        and not self._test_execution_plan.requires_device_update()
885*c2e18aaaSAndroid Build Coastguard Worker    ):
886*c2e18aaaSAndroid Build Coastguard Worker      return set()
887*c2e18aaaSAndroid Build Coastguard Worker
888*c2e18aaaSAndroid Build Coastguard Worker    return self._get_device_update_method().dependencies()
889*c2e18aaaSAndroid Build Coastguard Worker
890*c2e18aaaSAndroid Build Coastguard Worker  def _need_rebuild_module_info(self) -> bool:
891*c2e18aaaSAndroid Build Coastguard Worker    """Method that tells whether we need to rebuild module-info.json or not.
892*c2e18aaaSAndroid Build Coastguard Worker
893*c2e18aaaSAndroid Build Coastguard Worker    Returns:
894*c2e18aaaSAndroid Build Coastguard Worker        True for forcely/smartly rebuild, otherwise False without rebuilding.
895*c2e18aaaSAndroid Build Coastguard Worker    """
896*c2e18aaaSAndroid Build Coastguard Worker    # +-----------------+
897*c2e18aaaSAndroid Build Coastguard Worker    # | Explicitly pass |  yes
898*c2e18aaaSAndroid Build Coastguard Worker    # |    '--test'     +-------> False (won't rebuild)
899*c2e18aaaSAndroid Build Coastguard Worker    # +--------+--------+
900*c2e18aaaSAndroid Build Coastguard Worker    #          | no
901*c2e18aaaSAndroid Build Coastguard Worker    #          V
902*c2e18aaaSAndroid Build Coastguard Worker    # +-------------------------+
903*c2e18aaaSAndroid Build Coastguard Worker    # | Explicitly pass         |  yes
904*c2e18aaaSAndroid Build Coastguard Worker    # | '--rebuild-module-info' +-------> True (forcely rebuild)
905*c2e18aaaSAndroid Build Coastguard Worker    # +--------+----------------+
906*c2e18aaaSAndroid Build Coastguard Worker    #          | no
907*c2e18aaaSAndroid Build Coastguard Worker    #          V
908*c2e18aaaSAndroid Build Coastguard Worker    # +-------------------+
909*c2e18aaaSAndroid Build Coastguard Worker    # |    Build files    |  no
910*c2e18aaaSAndroid Build Coastguard Worker    # | integrity is good +-------> True (smartly rebuild)
911*c2e18aaaSAndroid Build Coastguard Worker    # +--------+----------+
912*c2e18aaaSAndroid Build Coastguard Worker    #          | yes
913*c2e18aaaSAndroid Build Coastguard Worker    #          V
914*c2e18aaaSAndroid Build Coastguard Worker    #        False (won't rebuild)
915*c2e18aaaSAndroid Build Coastguard Worker    if not self._steps.build:
916*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('"--test" mode detected, will not rebuild module-info.')
917*c2e18aaaSAndroid Build Coastguard Worker      return False
918*c2e18aaaSAndroid Build Coastguard Worker    if self._args.rebuild_module_info:
919*c2e18aaaSAndroid Build Coastguard Worker      return True
920*c2e18aaaSAndroid Build Coastguard Worker    logging.debug('Examinating the consistency of build files...')
921*c2e18aaaSAndroid Build Coastguard Worker    if not atest_utils.build_files_integrity_is_ok():
922*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('Found build files were changed.')
923*c2e18aaaSAndroid Build Coastguard Worker      return True
924*c2e18aaaSAndroid Build Coastguard Worker    return False
925*c2e18aaaSAndroid Build Coastguard Worker
926*c2e18aaaSAndroid Build Coastguard Worker  def _load_module_info(self):
927*c2e18aaaSAndroid Build Coastguard Worker    self._is_out_clean_before_module_info_build = not os.path.exists(
928*c2e18aaaSAndroid Build Coastguard Worker        os.environ.get(constants.ANDROID_PRODUCT_OUT, '')
929*c2e18aaaSAndroid Build Coastguard Worker    )
930*c2e18aaaSAndroid Build Coastguard Worker    self._module_info_rebuild_required = self._need_rebuild_module_info()
931*c2e18aaaSAndroid Build Coastguard Worker    logging.debug(
932*c2e18aaaSAndroid Build Coastguard Worker        'need_rebuild_module_info returned %s',
933*c2e18aaaSAndroid Build Coastguard Worker        self._module_info_rebuild_required,
934*c2e18aaaSAndroid Build Coastguard Worker    )
935*c2e18aaaSAndroid Build Coastguard Worker
936*c2e18aaaSAndroid Build Coastguard Worker    self._mod_info = module_info.load(
937*c2e18aaaSAndroid Build Coastguard Worker        force_build=self._module_info_rebuild_required,
938*c2e18aaaSAndroid Build Coastguard Worker        sqlite_module_cache=self._args.sqlite_module_cache,
939*c2e18aaaSAndroid Build Coastguard Worker    )
940*c2e18aaaSAndroid Build Coastguard Worker    logging.debug('Obtained module info object: %s', self._mod_info)
941*c2e18aaaSAndroid Build Coastguard Worker
942*c2e18aaaSAndroid Build Coastguard Worker  def _load_test_info_and_execution_plan(self) -> int | None:
943*c2e18aaaSAndroid Build Coastguard Worker    """Loads test info and execution plan.
944*c2e18aaaSAndroid Build Coastguard Worker
945*c2e18aaaSAndroid Build Coastguard Worker    Returns:
946*c2e18aaaSAndroid Build Coastguard Worker        Exit code if anything went wrong. None otherwise.
947*c2e18aaaSAndroid Build Coastguard Worker    """
948*c2e18aaaSAndroid Build Coastguard Worker    indexing_thread = self._start_indexing_if_required()
949*c2e18aaaSAndroid Build Coastguard Worker
950*c2e18aaaSAndroid Build Coastguard Worker    self._load_module_info()
951*c2e18aaaSAndroid Build Coastguard Worker
952*c2e18aaaSAndroid Build Coastguard Worker    translator = cli_translator.CLITranslator(
953*c2e18aaaSAndroid Build Coastguard Worker        mod_info=self._mod_info,
954*c2e18aaaSAndroid Build Coastguard Worker        print_cache_msg=not self._args.clear_cache,
955*c2e18aaaSAndroid Build Coastguard Worker        bazel_mode_enabled=self._args.bazel_mode,
956*c2e18aaaSAndroid Build Coastguard Worker        host=self._args.host,
957*c2e18aaaSAndroid Build Coastguard Worker        bazel_mode_features=self._args.bazel_mode_features,
958*c2e18aaaSAndroid Build Coastguard Worker        indexing_thread=indexing_thread,
959*c2e18aaaSAndroid Build Coastguard Worker    )
960*c2e18aaaSAndroid Build Coastguard Worker
961*c2e18aaaSAndroid Build Coastguard Worker    find_start = time.time()
962*c2e18aaaSAndroid Build Coastguard Worker    self._test_infos = translator.translate(self._args)
963*c2e18aaaSAndroid Build Coastguard Worker
964*c2e18aaaSAndroid Build Coastguard Worker    _AtestMain._inject_default_arguments_based_on_test_infos(
965*c2e18aaaSAndroid Build Coastguard Worker        self._test_infos, self._args
966*c2e18aaaSAndroid Build Coastguard Worker    )
967*c2e18aaaSAndroid Build Coastguard Worker
968*c2e18aaaSAndroid Build Coastguard Worker    # Only check for sufficient devices if not dry run.
969*c2e18aaaSAndroid Build Coastguard Worker    self._args.device_count_config = get_device_count_config(
970*c2e18aaaSAndroid Build Coastguard Worker        self._test_infos, self._mod_info
971*c2e18aaaSAndroid Build Coastguard Worker    )
972*c2e18aaaSAndroid Build Coastguard Worker    if not self._args.dry_run and not has_set_sufficient_devices(
973*c2e18aaaSAndroid Build Coastguard Worker        self._args.device_count_config, self._args.serial
974*c2e18aaaSAndroid Build Coastguard Worker    ):
975*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.INSUFFICIENT_DEVICES
976*c2e18aaaSAndroid Build Coastguard Worker
977*c2e18aaaSAndroid Build Coastguard Worker    self._test_info_loading_duration = time.time() - find_start
978*c2e18aaaSAndroid Build Coastguard Worker    if not self._test_infos:
979*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.TEST_NOT_FOUND
980*c2e18aaaSAndroid Build Coastguard Worker
981*c2e18aaaSAndroid Build Coastguard Worker    self._test_execution_plan = _TestExecutionPlan.create(
982*c2e18aaaSAndroid Build Coastguard Worker        args=self._args,
983*c2e18aaaSAndroid Build Coastguard Worker        test_infos=self._test_infos,
984*c2e18aaaSAndroid Build Coastguard Worker        results_dir=self._results_dir,
985*c2e18aaaSAndroid Build Coastguard Worker        mod_info=self._mod_info,
986*c2e18aaaSAndroid Build Coastguard Worker    )
987*c2e18aaaSAndroid Build Coastguard Worker
988*c2e18aaaSAndroid Build Coastguard Worker    return None
989*c2e18aaaSAndroid Build Coastguard Worker
990*c2e18aaaSAndroid Build Coastguard Worker  @staticmethod
991*c2e18aaaSAndroid Build Coastguard Worker  def _inject_default_arguments_based_on_test_infos(
992*c2e18aaaSAndroid Build Coastguard Worker      test_infos: list[test_info.TestInfo], args: argparse.Namespace
993*c2e18aaaSAndroid Build Coastguard Worker  ) -> None:
994*c2e18aaaSAndroid Build Coastguard Worker    if any(
995*c2e18aaaSAndroid Build Coastguard Worker        'performance-tests' in info.compatibility_suites for info in test_infos
996*c2e18aaaSAndroid Build Coastguard Worker    ):
997*c2e18aaaSAndroid Build Coastguard Worker      if not args.disable_upload_result:
998*c2e18aaaSAndroid Build Coastguard Worker        args.request_upload_result = True
999*c2e18aaaSAndroid Build Coastguard Worker
1000*c2e18aaaSAndroid Build Coastguard Worker  def _handle_list_modules(self) -> int:
1001*c2e18aaaSAndroid Build Coastguard Worker    """Print the testable modules for a given suite.
1002*c2e18aaaSAndroid Build Coastguard Worker
1003*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1004*c2e18aaaSAndroid Build Coastguard Worker        Exit code.
1005*c2e18aaaSAndroid Build Coastguard Worker    """
1006*c2e18aaaSAndroid Build Coastguard Worker    self._load_module_info()
1007*c2e18aaaSAndroid Build Coastguard Worker
1008*c2e18aaaSAndroid Build Coastguard Worker    testable_modules = self._mod_info.get_testable_modules(
1009*c2e18aaaSAndroid Build Coastguard Worker        self._args.list_modules
1010*c2e18aaaSAndroid Build Coastguard Worker    )
1011*c2e18aaaSAndroid Build Coastguard Worker    print(
1012*c2e18aaaSAndroid Build Coastguard Worker        '\n%s'
1013*c2e18aaaSAndroid Build Coastguard Worker        % atest_utils.mark_cyan(
1014*c2e18aaaSAndroid Build Coastguard Worker            '%s Testable %s modules'
1015*c2e18aaaSAndroid Build Coastguard Worker            % (len(testable_modules), self._args.list_modules)
1016*c2e18aaaSAndroid Build Coastguard Worker        )
1017*c2e18aaaSAndroid Build Coastguard Worker    )
1018*c2e18aaaSAndroid Build Coastguard Worker    print(atest_utils.delimiter('-'))
1019*c2e18aaaSAndroid Build Coastguard Worker    for module in sorted(testable_modules):
1020*c2e18aaaSAndroid Build Coastguard Worker      print('\t%s' % module)
1021*c2e18aaaSAndroid Build Coastguard Worker
1022*c2e18aaaSAndroid Build Coastguard Worker    return ExitCode.SUCCESS
1023*c2e18aaaSAndroid Build Coastguard Worker
1024*c2e18aaaSAndroid Build Coastguard Worker  def _handle_dry_run(self) -> int:
1025*c2e18aaaSAndroid Build Coastguard Worker    """Only print the commands of the target tests rather than running them.
1026*c2e18aaaSAndroid Build Coastguard Worker
1027*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1028*c2e18aaaSAndroid Build Coastguard Worker        Exit code.
1029*c2e18aaaSAndroid Build Coastguard Worker    """
1030*c2e18aaaSAndroid Build Coastguard Worker    error_code = self._load_test_info_and_execution_plan()
1031*c2e18aaaSAndroid Build Coastguard Worker    if error_code is not None:
1032*c2e18aaaSAndroid Build Coastguard Worker      return error_code
1033*c2e18aaaSAndroid Build Coastguard Worker
1034*c2e18aaaSAndroid Build Coastguard Worker    print(
1035*c2e18aaaSAndroid Build Coastguard Worker        'Would build the following targets: %s'
1036*c2e18aaaSAndroid Build Coastguard Worker        % (atest_utils.mark_green('%s' % self._get_build_targets()))
1037*c2e18aaaSAndroid Build Coastguard Worker    )
1038*c2e18aaaSAndroid Build Coastguard Worker
1039*c2e18aaaSAndroid Build Coastguard Worker    all_run_cmds = []
1040*c2e18aaaSAndroid Build Coastguard Worker    for test_runner, tests in test_runner_handler.group_tests_by_test_runners(
1041*c2e18aaaSAndroid Build Coastguard Worker        self._test_infos
1042*c2e18aaaSAndroid Build Coastguard Worker    ):
1043*c2e18aaaSAndroid Build Coastguard Worker      runner = test_runner(
1044*c2e18aaaSAndroid Build Coastguard Worker          self._results_dir,
1045*c2e18aaaSAndroid Build Coastguard Worker          mod_info=self._mod_info,
1046*c2e18aaaSAndroid Build Coastguard Worker          extra_args=self._test_execution_plan.extra_args,
1047*c2e18aaaSAndroid Build Coastguard Worker      )
1048*c2e18aaaSAndroid Build Coastguard Worker      run_cmds = runner.generate_run_commands(
1049*c2e18aaaSAndroid Build Coastguard Worker          tests, self._test_execution_plan.extra_args
1050*c2e18aaaSAndroid Build Coastguard Worker      )
1051*c2e18aaaSAndroid Build Coastguard Worker      for run_cmd in run_cmds:
1052*c2e18aaaSAndroid Build Coastguard Worker        all_run_cmds.append(run_cmd)
1053*c2e18aaaSAndroid Build Coastguard Worker        logging.debug(_DRY_RUN_COMMAND_LOG_PREFIX + run_cmd)
1054*c2e18aaaSAndroid Build Coastguard Worker        print(
1055*c2e18aaaSAndroid Build Coastguard Worker            'Would run test via command: %s' % (atest_utils.mark_green(run_cmd))
1056*c2e18aaaSAndroid Build Coastguard Worker        )
1057*c2e18aaaSAndroid Build Coastguard Worker
1058*c2e18aaaSAndroid Build Coastguard Worker    return ExitCode.SUCCESS
1059*c2e18aaaSAndroid Build Coastguard Worker
1060*c2e18aaaSAndroid Build Coastguard Worker  def _update_device_if_requested(self) -> None:
1061*c2e18aaaSAndroid Build Coastguard Worker    """Runs the device update step."""
1062*c2e18aaaSAndroid Build Coastguard Worker    if not self._args.update_device:
1063*c2e18aaaSAndroid Build Coastguard Worker      if self._test_execution_plan.requires_device_update():
1064*c2e18aaaSAndroid Build Coastguard Worker        self._banner_printer.register(
1065*c2e18aaaSAndroid Build Coastguard Worker            'Tips: If your test requires device update, consider '
1066*c2e18aaaSAndroid Build Coastguard Worker            'http://go/atest-single-command to simplify your workflow!'
1067*c2e18aaaSAndroid Build Coastguard Worker        )
1068*c2e18aaaSAndroid Build Coastguard Worker      return
1069*c2e18aaaSAndroid Build Coastguard Worker    if not self._steps.test:
1070*c2e18aaaSAndroid Build Coastguard Worker      print(
1071*c2e18aaaSAndroid Build Coastguard Worker          'Device update requested but skipped due to running in build only'
1072*c2e18aaaSAndroid Build Coastguard Worker          ' mode.'
1073*c2e18aaaSAndroid Build Coastguard Worker      )
1074*c2e18aaaSAndroid Build Coastguard Worker      return
1075*c2e18aaaSAndroid Build Coastguard Worker
1076*c2e18aaaSAndroid Build Coastguard Worker    if not self._test_execution_plan.requires_device_update():
1077*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
1078*c2e18aaaSAndroid Build Coastguard Worker          '\nWarning: Device update ignored because it is not required by '
1079*c2e18aaaSAndroid Build Coastguard Worker          'tests in this invocation.',
1080*c2e18aaaSAndroid Build Coastguard Worker          constants.YELLOW,
1081*c2e18aaaSAndroid Build Coastguard Worker      )
1082*c2e18aaaSAndroid Build Coastguard Worker      return
1083*c2e18aaaSAndroid Build Coastguard Worker
1084*c2e18aaaSAndroid Build Coastguard Worker    device_update_start = time.time()
1085*c2e18aaaSAndroid Build Coastguard Worker    self._get_device_update_method().update(
1086*c2e18aaaSAndroid Build Coastguard Worker        self._test_execution_plan.extra_args.get(constants.SERIAL, [])
1087*c2e18aaaSAndroid Build Coastguard Worker    )
1088*c2e18aaaSAndroid Build Coastguard Worker    device_update_duration = time.time() - device_update_start
1089*c2e18aaaSAndroid Build Coastguard Worker    logging.debug('Updating device took %ss', device_update_duration)
1090*c2e18aaaSAndroid Build Coastguard Worker    metrics.LocalDetectEvent(
1091*c2e18aaaSAndroid Build Coastguard Worker        detect_type=DetectType.DEVICE_UPDATE_MS,
1092*c2e18aaaSAndroid Build Coastguard Worker        result=int(round(device_update_duration * 1000)),
1093*c2e18aaaSAndroid Build Coastguard Worker    )
1094*c2e18aaaSAndroid Build Coastguard Worker
1095*c2e18aaaSAndroid Build Coastguard Worker  def _get_build_targets(self) -> set[str]:
1096*c2e18aaaSAndroid Build Coastguard Worker    """Gets the build targets."""
1097*c2e18aaaSAndroid Build Coastguard Worker    build_targets = self._test_execution_plan.required_build_targets()
1098*c2e18aaaSAndroid Build Coastguard Worker
1099*c2e18aaaSAndroid Build Coastguard Worker    # Remove MODULE-IN-* from build targets by default.
1100*c2e18aaaSAndroid Build Coastguard Worker    if not self._args.use_modules_in:
1101*c2e18aaaSAndroid Build Coastguard Worker      build_targets = _exclude_modules_in_targets(build_targets)
1102*c2e18aaaSAndroid Build Coastguard Worker
1103*c2e18aaaSAndroid Build Coastguard Worker    if not build_targets:
1104*c2e18aaaSAndroid Build Coastguard Worker      return None
1105*c2e18aaaSAndroid Build Coastguard Worker
1106*c2e18aaaSAndroid Build Coastguard Worker    if self._args.experimental_coverage:
1107*c2e18aaaSAndroid Build Coastguard Worker      build_targets.update(coverage.build_modules())
1108*c2e18aaaSAndroid Build Coastguard Worker
1109*c2e18aaaSAndroid Build Coastguard Worker    # Add module-info.json target to the list of build targets to keep the
1110*c2e18aaaSAndroid Build Coastguard Worker    # file up to date.
1111*c2e18aaaSAndroid Build Coastguard Worker    build_targets.add(module_info.get_module_info_target())
1112*c2e18aaaSAndroid Build Coastguard Worker
1113*c2e18aaaSAndroid Build Coastguard Worker    build_targets |= self._get_device_update_dependencies()
1114*c2e18aaaSAndroid Build Coastguard Worker    return build_targets
1115*c2e18aaaSAndroid Build Coastguard Worker
1116*c2e18aaaSAndroid Build Coastguard Worker  def _run_build_step(self) -> int:
1117*c2e18aaaSAndroid Build Coastguard Worker    """Runs the build step.
1118*c2e18aaaSAndroid Build Coastguard Worker
1119*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1120*c2e18aaaSAndroid Build Coastguard Worker        Exit code if failed. None otherwise.
1121*c2e18aaaSAndroid Build Coastguard Worker    """
1122*c2e18aaaSAndroid Build Coastguard Worker    build_targets = self._get_build_targets()
1123*c2e18aaaSAndroid Build Coastguard Worker
1124*c2e18aaaSAndroid Build Coastguard Worker    # Add the -jx as a build target if user specify it.
1125*c2e18aaaSAndroid Build Coastguard Worker    if self._args.build_j:
1126*c2e18aaaSAndroid Build Coastguard Worker      build_targets.add(f'-j{self._args.build_j}')
1127*c2e18aaaSAndroid Build Coastguard Worker
1128*c2e18aaaSAndroid Build Coastguard Worker    build_start = time.time()
1129*c2e18aaaSAndroid Build Coastguard Worker    success = atest_utils.build(build_targets)
1130*c2e18aaaSAndroid Build Coastguard Worker    self._build_duration = time.time() - build_start
1131*c2e18aaaSAndroid Build Coastguard Worker    metrics.BuildFinishEvent(
1132*c2e18aaaSAndroid Build Coastguard Worker        duration=metrics_utils.convert_duration(self._build_duration),
1133*c2e18aaaSAndroid Build Coastguard Worker        success=success,
1134*c2e18aaaSAndroid Build Coastguard Worker        targets=build_targets,
1135*c2e18aaaSAndroid Build Coastguard Worker    )
1136*c2e18aaaSAndroid Build Coastguard Worker    metrics.LocalDetectEvent(
1137*c2e18aaaSAndroid Build Coastguard Worker        detect_type=DetectType.BUILD_TIME_PER_TARGET,
1138*c2e18aaaSAndroid Build Coastguard Worker        result=int(round(self._build_duration / len(build_targets))),
1139*c2e18aaaSAndroid Build Coastguard Worker    )
1140*c2e18aaaSAndroid Build Coastguard Worker    rebuild_module_info = DetectType.NOT_REBUILD_MODULE_INFO
1141*c2e18aaaSAndroid Build Coastguard Worker    if self._is_out_clean_before_module_info_build:
1142*c2e18aaaSAndroid Build Coastguard Worker      rebuild_module_info = DetectType.CLEAN_BUILD
1143*c2e18aaaSAndroid Build Coastguard Worker    elif self._args.rebuild_module_info:
1144*c2e18aaaSAndroid Build Coastguard Worker      rebuild_module_info = DetectType.REBUILD_MODULE_INFO
1145*c2e18aaaSAndroid Build Coastguard Worker    elif self._module_info_rebuild_required:
1146*c2e18aaaSAndroid Build Coastguard Worker      rebuild_module_info = DetectType.SMART_REBUILD_MODULE_INFO
1147*c2e18aaaSAndroid Build Coastguard Worker    metrics.LocalDetectEvent(
1148*c2e18aaaSAndroid Build Coastguard Worker        detect_type=rebuild_module_info, result=int(round(self._build_duration))
1149*c2e18aaaSAndroid Build Coastguard Worker    )
1150*c2e18aaaSAndroid Build Coastguard Worker    if not success:
1151*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.BUILD_FAILURE
1152*c2e18aaaSAndroid Build Coastguard Worker
1153*c2e18aaaSAndroid Build Coastguard Worker  def _run_test_step(self) -> int:
1154*c2e18aaaSAndroid Build Coastguard Worker    """Runs the test step.
1155*c2e18aaaSAndroid Build Coastguard Worker
1156*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1157*c2e18aaaSAndroid Build Coastguard Worker        Exit code.
1158*c2e18aaaSAndroid Build Coastguard Worker    """
1159*c2e18aaaSAndroid Build Coastguard Worker    # Stop calling Tradefed if the tests require a device.
1160*c2e18aaaSAndroid Build Coastguard Worker    _validate_adb_devices(self._args, self._test_infos)
1161*c2e18aaaSAndroid Build Coastguard Worker
1162*c2e18aaaSAndroid Build Coastguard Worker    test_start = time.time()
1163*c2e18aaaSAndroid Build Coastguard Worker    # Only send duration to metrics when no --build.
1164*c2e18aaaSAndroid Build Coastguard Worker    if not self._steps.build:
1165*c2e18aaaSAndroid Build Coastguard Worker      _init_and_find = time.time() - self._invocation_begin_time
1166*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('Initiation and finding tests took %ss', _init_and_find)
1167*c2e18aaaSAndroid Build Coastguard Worker      metrics.LocalDetectEvent(
1168*c2e18aaaSAndroid Build Coastguard Worker          detect_type=DetectType.INIT_AND_FIND_MS,
1169*c2e18aaaSAndroid Build Coastguard Worker          result=int(round(_init_and_find * 1000)),
1170*c2e18aaaSAndroid Build Coastguard Worker      )
1171*c2e18aaaSAndroid Build Coastguard Worker
1172*c2e18aaaSAndroid Build Coastguard Worker    tests_exit_code = self._test_execution_plan.execute()
1173*c2e18aaaSAndroid Build Coastguard Worker
1174*c2e18aaaSAndroid Build Coastguard Worker    if self._args.experimental_coverage:
1175*c2e18aaaSAndroid Build Coastguard Worker      coverage.generate_coverage_report(
1176*c2e18aaaSAndroid Build Coastguard Worker          self._results_dir,
1177*c2e18aaaSAndroid Build Coastguard Worker          self._test_infos,
1178*c2e18aaaSAndroid Build Coastguard Worker          self._mod_info,
1179*c2e18aaaSAndroid Build Coastguard Worker          self._test_execution_plan.extra_args.get(constants.HOST, False),
1180*c2e18aaaSAndroid Build Coastguard Worker          self._args.code_under_test,
1181*c2e18aaaSAndroid Build Coastguard Worker      )
1182*c2e18aaaSAndroid Build Coastguard Worker
1183*c2e18aaaSAndroid Build Coastguard Worker    metrics.RunTestsFinishEvent(
1184*c2e18aaaSAndroid Build Coastguard Worker        duration=metrics_utils.convert_duration(time.time() - test_start)
1185*c2e18aaaSAndroid Build Coastguard Worker    )
1186*c2e18aaaSAndroid Build Coastguard Worker    preparation_time = atest_execution_info.preparation_time(test_start)
1187*c2e18aaaSAndroid Build Coastguard Worker    if preparation_time:
1188*c2e18aaaSAndroid Build Coastguard Worker      # Send the preparation time only if it's set.
1189*c2e18aaaSAndroid Build Coastguard Worker      metrics.RunnerFinishEvent(
1190*c2e18aaaSAndroid Build Coastguard Worker          duration=metrics_utils.convert_duration(preparation_time),
1191*c2e18aaaSAndroid Build Coastguard Worker          success=True,
1192*c2e18aaaSAndroid Build Coastguard Worker          runner_name=constants.TF_PREPARATION,
1193*c2e18aaaSAndroid Build Coastguard Worker          test=[],
1194*c2e18aaaSAndroid Build Coastguard Worker      )
1195*c2e18aaaSAndroid Build Coastguard Worker
1196*c2e18aaaSAndroid Build Coastguard Worker    return tests_exit_code
1197*c2e18aaaSAndroid Build Coastguard Worker
1198*c2e18aaaSAndroid Build Coastguard Worker  def _send_start_event(self) -> None:
1199*c2e18aaaSAndroid Build Coastguard Worker    metrics_utils.send_start_event(
1200*c2e18aaaSAndroid Build Coastguard Worker        command_line=' '.join(self._argv),
1201*c2e18aaaSAndroid Build Coastguard Worker        test_references=self._args.tests,
1202*c2e18aaaSAndroid Build Coastguard Worker        cwd=os.getcwd(),
1203*c2e18aaaSAndroid Build Coastguard Worker        operating_system=(
1204*c2e18aaaSAndroid Build Coastguard Worker            f'{platform.platform()}:{platform.python_version()}/'
1205*c2e18aaaSAndroid Build Coastguard Worker            f'{atest_utils.get_manifest_branch(True)}:'
1206*c2e18aaaSAndroid Build Coastguard Worker            f'{atest_utils.get_atest_version()}'
1207*c2e18aaaSAndroid Build Coastguard Worker        ),
1208*c2e18aaaSAndroid Build Coastguard Worker        source_root=os.environ.get('ANDROID_BUILD_TOP', ''),
1209*c2e18aaaSAndroid Build Coastguard Worker        hostname=platform.node(),
1210*c2e18aaaSAndroid Build Coastguard Worker    )
1211*c2e18aaaSAndroid Build Coastguard Worker
1212*c2e18aaaSAndroid Build Coastguard Worker  def _disable_bazel_mode_if_unsupported(self) -> None:
1213*c2e18aaaSAndroid Build Coastguard Worker    if (
1214*c2e18aaaSAndroid Build Coastguard Worker        atest_utils.is_test_mapping(self._args)
1215*c2e18aaaSAndroid Build Coastguard Worker        or self._args.experimental_coverage
1216*c2e18aaaSAndroid Build Coastguard Worker    ):
1217*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('Running test mapping or coverage, disabling bazel mode.')
1218*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
1219*c2e18aaaSAndroid Build Coastguard Worker          'Not running using bazel-mode.', constants.YELLOW
1220*c2e18aaaSAndroid Build Coastguard Worker      )
1221*c2e18aaaSAndroid Build Coastguard Worker      self._args.bazel_mode = False
1222*c2e18aaaSAndroid Build Coastguard Worker
1223*c2e18aaaSAndroid Build Coastguard Worker  def _run_all_steps(self) -> int:
1224*c2e18aaaSAndroid Build Coastguard Worker    """Executes the atest script.
1225*c2e18aaaSAndroid Build Coastguard Worker
1226*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1227*c2e18aaaSAndroid Build Coastguard Worker        Exit code.
1228*c2e18aaaSAndroid Build Coastguard Worker    """
1229*c2e18aaaSAndroid Build Coastguard Worker    self._invocation_begin_time = time.time()
1230*c2e18aaaSAndroid Build Coastguard Worker
1231*c2e18aaaSAndroid Build Coastguard Worker    self._update_build_env()
1232*c2e18aaaSAndroid Build Coastguard Worker
1233*c2e18aaaSAndroid Build Coastguard Worker    invalid_arg_exit_code = self._check_envs_and_args()
1234*c2e18aaaSAndroid Build Coastguard Worker    if invalid_arg_exit_code is not None:
1235*c2e18aaaSAndroid Build Coastguard Worker      sys.exit(invalid_arg_exit_code)
1236*c2e18aaaSAndroid Build Coastguard Worker
1237*c2e18aaaSAndroid Build Coastguard Worker    self._send_start_event()
1238*c2e18aaaSAndroid Build Coastguard Worker
1239*c2e18aaaSAndroid Build Coastguard Worker    no_action_exit_code = self._check_no_action_argument()
1240*c2e18aaaSAndroid Build Coastguard Worker    if no_action_exit_code is not None:
1241*c2e18aaaSAndroid Build Coastguard Worker      sys.exit(no_action_exit_code)
1242*c2e18aaaSAndroid Build Coastguard Worker
1243*c2e18aaaSAndroid Build Coastguard Worker    if self._args.list_modules:
1244*c2e18aaaSAndroid Build Coastguard Worker      return self._handle_list_modules()
1245*c2e18aaaSAndroid Build Coastguard Worker
1246*c2e18aaaSAndroid Build Coastguard Worker    self._disable_bazel_mode_if_unsupported()
1247*c2e18aaaSAndroid Build Coastguard Worker
1248*c2e18aaaSAndroid Build Coastguard Worker    if self._args.dry_run:
1249*c2e18aaaSAndroid Build Coastguard Worker      return self._handle_dry_run()
1250*c2e18aaaSAndroid Build Coastguard Worker
1251*c2e18aaaSAndroid Build Coastguard Worker    self._start_acloud_if_requested()
1252*c2e18aaaSAndroid Build Coastguard Worker
1253*c2e18aaaSAndroid Build Coastguard Worker    error_code = self._load_test_info_and_execution_plan()
1254*c2e18aaaSAndroid Build Coastguard Worker    if error_code is not None:
1255*c2e18aaaSAndroid Build Coastguard Worker      return error_code
1256*c2e18aaaSAndroid Build Coastguard Worker
1257*c2e18aaaSAndroid Build Coastguard Worker    if self._steps.build:
1258*c2e18aaaSAndroid Build Coastguard Worker      error_code = self._run_build_step()
1259*c2e18aaaSAndroid Build Coastguard Worker      if error_code is not None:
1260*c2e18aaaSAndroid Build Coastguard Worker        return error_code
1261*c2e18aaaSAndroid Build Coastguard Worker
1262*c2e18aaaSAndroid Build Coastguard Worker    acloud_status = self._check_acloud_status()
1263*c2e18aaaSAndroid Build Coastguard Worker    if acloud_status:
1264*c2e18aaaSAndroid Build Coastguard Worker      return acloud_status
1265*c2e18aaaSAndroid Build Coastguard Worker
1266*c2e18aaaSAndroid Build Coastguard Worker    self._update_device_if_requested()
1267*c2e18aaaSAndroid Build Coastguard Worker
1268*c2e18aaaSAndroid Build Coastguard Worker    if self._steps.test and self._run_test_step() != ExitCode.SUCCESS:
1269*c2e18aaaSAndroid Build Coastguard Worker      return ExitCode.TEST_FAILURE
1270*c2e18aaaSAndroid Build Coastguard Worker
1271*c2e18aaaSAndroid Build Coastguard Worker    return ExitCode.SUCCESS
1272*c2e18aaaSAndroid Build Coastguard Worker
1273*c2e18aaaSAndroid Build Coastguard Worker
1274*c2e18aaaSAndroid Build Coastguard Workerclass _TestExecutionPlan(abc.ABC):
1275*c2e18aaaSAndroid Build Coastguard Worker  """Represents how an Atest invocation's tests will execute."""
1276*c2e18aaaSAndroid Build Coastguard Worker
1277*c2e18aaaSAndroid Build Coastguard Worker  @staticmethod
1278*c2e18aaaSAndroid Build Coastguard Worker  def create(
1279*c2e18aaaSAndroid Build Coastguard Worker      args: argparse.Namespace,
1280*c2e18aaaSAndroid Build Coastguard Worker      test_infos: List[test_info.TestInfo],
1281*c2e18aaaSAndroid Build Coastguard Worker      results_dir: str,
1282*c2e18aaaSAndroid Build Coastguard Worker      mod_info: module_info.ModuleInfo,
1283*c2e18aaaSAndroid Build Coastguard Worker  ) -> _TestExecutionPlan:
1284*c2e18aaaSAndroid Build Coastguard Worker    """Creates a plan to execute the tests.
1285*c2e18aaaSAndroid Build Coastguard Worker
1286*c2e18aaaSAndroid Build Coastguard Worker    Args:
1287*c2e18aaaSAndroid Build Coastguard Worker        args: An argparse.Namespace instance holding parsed args.
1288*c2e18aaaSAndroid Build Coastguard Worker        test_infos: A list of instances of TestInfo.
1289*c2e18aaaSAndroid Build Coastguard Worker        results_dir: A directory which stores the ATest execution information.
1290*c2e18aaaSAndroid Build Coastguard Worker        mod_info: An instance of ModuleInfo.
1291*c2e18aaaSAndroid Build Coastguard Worker
1292*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1293*c2e18aaaSAndroid Build Coastguard Worker        An instance of _TestExecutionPlan.
1294*c2e18aaaSAndroid Build Coastguard Worker    """
1295*c2e18aaaSAndroid Build Coastguard Worker
1296*c2e18aaaSAndroid Build Coastguard Worker    if is_from_test_mapping(test_infos):
1297*c2e18aaaSAndroid Build Coastguard Worker      return _TestMappingExecutionPlan.create(
1298*c2e18aaaSAndroid Build Coastguard Worker          args=args,
1299*c2e18aaaSAndroid Build Coastguard Worker          test_infos=test_infos,
1300*c2e18aaaSAndroid Build Coastguard Worker          results_dir=results_dir,
1301*c2e18aaaSAndroid Build Coastguard Worker          mod_info=mod_info,
1302*c2e18aaaSAndroid Build Coastguard Worker      )
1303*c2e18aaaSAndroid Build Coastguard Worker
1304*c2e18aaaSAndroid Build Coastguard Worker    return _TestModuleExecutionPlan.create(
1305*c2e18aaaSAndroid Build Coastguard Worker        args=args,
1306*c2e18aaaSAndroid Build Coastguard Worker        test_infos=test_infos,
1307*c2e18aaaSAndroid Build Coastguard Worker        results_dir=results_dir,
1308*c2e18aaaSAndroid Build Coastguard Worker        mod_info=mod_info,
1309*c2e18aaaSAndroid Build Coastguard Worker    )
1310*c2e18aaaSAndroid Build Coastguard Worker
1311*c2e18aaaSAndroid Build Coastguard Worker  def __init__(
1312*c2e18aaaSAndroid Build Coastguard Worker      self,
1313*c2e18aaaSAndroid Build Coastguard Worker      args: argparse.Namespace,
1314*c2e18aaaSAndroid Build Coastguard Worker      extra_args: Dict[str, Any],
1315*c2e18aaaSAndroid Build Coastguard Worker      test_infos: List[test_info.TestInfo],
1316*c2e18aaaSAndroid Build Coastguard Worker  ):
1317*c2e18aaaSAndroid Build Coastguard Worker    self._args = args
1318*c2e18aaaSAndroid Build Coastguard Worker    self._extra_args = extra_args
1319*c2e18aaaSAndroid Build Coastguard Worker    self._test_infos = test_infos
1320*c2e18aaaSAndroid Build Coastguard Worker
1321*c2e18aaaSAndroid Build Coastguard Worker  @property
1322*c2e18aaaSAndroid Build Coastguard Worker  def extra_args(self) -> Dict[str, Any]:
1323*c2e18aaaSAndroid Build Coastguard Worker    return self._extra_args
1324*c2e18aaaSAndroid Build Coastguard Worker
1325*c2e18aaaSAndroid Build Coastguard Worker  @abc.abstractmethod
1326*c2e18aaaSAndroid Build Coastguard Worker  def execute(self) -> ExitCode:
1327*c2e18aaaSAndroid Build Coastguard Worker    """Executes all test runner invocations in this plan."""
1328*c2e18aaaSAndroid Build Coastguard Worker
1329*c2e18aaaSAndroid Build Coastguard Worker  @abc.abstractmethod
1330*c2e18aaaSAndroid Build Coastguard Worker  def required_build_targets(self) -> Set[str]:
1331*c2e18aaaSAndroid Build Coastguard Worker    """Returns the list of build targets required by this plan."""
1332*c2e18aaaSAndroid Build Coastguard Worker
1333*c2e18aaaSAndroid Build Coastguard Worker  @abc.abstractmethod
1334*c2e18aaaSAndroid Build Coastguard Worker  def requires_device_update(self) -> bool:
1335*c2e18aaaSAndroid Build Coastguard Worker    """Checks whether this plan requires device update."""
1336*c2e18aaaSAndroid Build Coastguard Worker
1337*c2e18aaaSAndroid Build Coastguard Worker
1338*c2e18aaaSAndroid Build Coastguard Workerclass _TestMappingExecutionPlan(_TestExecutionPlan):
1339*c2e18aaaSAndroid Build Coastguard Worker  """A plan to execute Test Mapping tests."""
1340*c2e18aaaSAndroid Build Coastguard Worker
1341*c2e18aaaSAndroid Build Coastguard Worker  def __init__(
1342*c2e18aaaSAndroid Build Coastguard Worker      self,
1343*c2e18aaaSAndroid Build Coastguard Worker      args: argparse.Namespace,
1344*c2e18aaaSAndroid Build Coastguard Worker      extra_args: Dict[str, Any],
1345*c2e18aaaSAndroid Build Coastguard Worker      test_infos: List[test_info.TestInfo],
1346*c2e18aaaSAndroid Build Coastguard Worker      test_type_to_invocations: Dict[str, List[TestRunnerInvocation]],
1347*c2e18aaaSAndroid Build Coastguard Worker  ):
1348*c2e18aaaSAndroid Build Coastguard Worker    super().__init__(args, extra_args, test_infos)
1349*c2e18aaaSAndroid Build Coastguard Worker    self._test_type_to_invocations = test_type_to_invocations
1350*c2e18aaaSAndroid Build Coastguard Worker
1351*c2e18aaaSAndroid Build Coastguard Worker  @staticmethod
1352*c2e18aaaSAndroid Build Coastguard Worker  def create(
1353*c2e18aaaSAndroid Build Coastguard Worker      args: argparse.Namespace,
1354*c2e18aaaSAndroid Build Coastguard Worker      test_infos: List[test_info.TestInfo],
1355*c2e18aaaSAndroid Build Coastguard Worker      results_dir: str,
1356*c2e18aaaSAndroid Build Coastguard Worker      mod_info: module_info.ModuleInfo,
1357*c2e18aaaSAndroid Build Coastguard Worker  ) -> _TestMappingExecutionPlan:
1358*c2e18aaaSAndroid Build Coastguard Worker    """Creates an instance of _TestMappingExecutionPlan.
1359*c2e18aaaSAndroid Build Coastguard Worker
1360*c2e18aaaSAndroid Build Coastguard Worker    Args:
1361*c2e18aaaSAndroid Build Coastguard Worker        args: An argparse.Namespace instance holding parsed args.
1362*c2e18aaaSAndroid Build Coastguard Worker        test_infos: A list of instances of TestInfo.
1363*c2e18aaaSAndroid Build Coastguard Worker        results_dir: A directory which stores the ATest execution information.
1364*c2e18aaaSAndroid Build Coastguard Worker        mod_info: An instance of ModuleInfo.
1365*c2e18aaaSAndroid Build Coastguard Worker
1366*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1367*c2e18aaaSAndroid Build Coastguard Worker        An instance of _TestMappingExecutionPlan.
1368*c2e18aaaSAndroid Build Coastguard Worker    """
1369*c2e18aaaSAndroid Build Coastguard Worker
1370*c2e18aaaSAndroid Build Coastguard Worker    device_test_infos, host_test_infos = _split_test_mapping_tests(test_infos)
1371*c2e18aaaSAndroid Build Coastguard Worker    _validate_tm_tests_exec_mode(args, device_test_infos, host_test_infos)
1372*c2e18aaaSAndroid Build Coastguard Worker    extra_args = get_extra_args(args)
1373*c2e18aaaSAndroid Build Coastguard Worker
1374*c2e18aaaSAndroid Build Coastguard Worker    # TODO: change to another approach that put constants.CUSTOM_ARGS in the
1375*c2e18aaaSAndroid Build Coastguard Worker    # end of command to make sure that customized args can override default
1376*c2e18aaaSAndroid Build Coastguard Worker    # options.
1377*c2e18aaaSAndroid Build Coastguard Worker    # For TEST_MAPPING, set timeout to 600000ms.
1378*c2e18aaaSAndroid Build Coastguard Worker    custom_timeout = False
1379*c2e18aaaSAndroid Build Coastguard Worker    for custom_args in args.custom_args:
1380*c2e18aaaSAndroid Build Coastguard Worker      if '-timeout' in custom_args:
1381*c2e18aaaSAndroid Build Coastguard Worker        custom_timeout = True
1382*c2e18aaaSAndroid Build Coastguard Worker
1383*c2e18aaaSAndroid Build Coastguard Worker    if args.test_timeout is None and not custom_timeout:
1384*c2e18aaaSAndroid Build Coastguard Worker      extra_args.update({constants.TEST_TIMEOUT: 600000})
1385*c2e18aaaSAndroid Build Coastguard Worker      logging.debug(
1386*c2e18aaaSAndroid Build Coastguard Worker          'Set test timeout to %sms to align it in TEST_MAPPING.',
1387*c2e18aaaSAndroid Build Coastguard Worker          extra_args.get(constants.TEST_TIMEOUT),
1388*c2e18aaaSAndroid Build Coastguard Worker      )
1389*c2e18aaaSAndroid Build Coastguard Worker
1390*c2e18aaaSAndroid Build Coastguard Worker    def create_invocations(runner_extra_args, runner_test_infos):
1391*c2e18aaaSAndroid Build Coastguard Worker      return test_runner_handler.create_test_runner_invocations(
1392*c2e18aaaSAndroid Build Coastguard Worker          test_infos=runner_test_infos,
1393*c2e18aaaSAndroid Build Coastguard Worker          results_dir=results_dir,
1394*c2e18aaaSAndroid Build Coastguard Worker          mod_info=mod_info,
1395*c2e18aaaSAndroid Build Coastguard Worker          extra_args=runner_extra_args,
1396*c2e18aaaSAndroid Build Coastguard Worker          minimal_build=args.minimal_build,
1397*c2e18aaaSAndroid Build Coastguard Worker      )
1398*c2e18aaaSAndroid Build Coastguard Worker
1399*c2e18aaaSAndroid Build Coastguard Worker    test_type_to_invocations = collections.OrderedDict()
1400*c2e18aaaSAndroid Build Coastguard Worker    if extra_args.get(constants.DEVICE_ONLY):
1401*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
1402*c2e18aaaSAndroid Build Coastguard Worker          'Option `--device-only` specified. Skip running deviceless tests.',
1403*c2e18aaaSAndroid Build Coastguard Worker          constants.MAGENTA,
1404*c2e18aaaSAndroid Build Coastguard Worker      )
1405*c2e18aaaSAndroid Build Coastguard Worker    else:
1406*c2e18aaaSAndroid Build Coastguard Worker      # `host` option needs to be set to True to run host side tests.
1407*c2e18aaaSAndroid Build Coastguard Worker      host_extra_args = extra_args.copy()
1408*c2e18aaaSAndroid Build Coastguard Worker      host_extra_args[constants.HOST] = True
1409*c2e18aaaSAndroid Build Coastguard Worker      test_type_to_invocations.setdefault(HOST_TESTS, []).extend(
1410*c2e18aaaSAndroid Build Coastguard Worker          create_invocations(host_extra_args, host_test_infos)
1411*c2e18aaaSAndroid Build Coastguard Worker      )
1412*c2e18aaaSAndroid Build Coastguard Worker
1413*c2e18aaaSAndroid Build Coastguard Worker    if extra_args.get(constants.HOST):
1414*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
1415*c2e18aaaSAndroid Build Coastguard Worker          'Option `--host` specified. Skip running device tests.',
1416*c2e18aaaSAndroid Build Coastguard Worker          constants.MAGENTA,
1417*c2e18aaaSAndroid Build Coastguard Worker      )
1418*c2e18aaaSAndroid Build Coastguard Worker    else:
1419*c2e18aaaSAndroid Build Coastguard Worker      test_type_to_invocations.setdefault(DEVICE_TESTS, []).extend(
1420*c2e18aaaSAndroid Build Coastguard Worker          create_invocations(extra_args, device_test_infos)
1421*c2e18aaaSAndroid Build Coastguard Worker      )
1422*c2e18aaaSAndroid Build Coastguard Worker
1423*c2e18aaaSAndroid Build Coastguard Worker    return _TestMappingExecutionPlan(
1424*c2e18aaaSAndroid Build Coastguard Worker        args=args,
1425*c2e18aaaSAndroid Build Coastguard Worker        extra_args=extra_args,
1426*c2e18aaaSAndroid Build Coastguard Worker        test_infos=test_infos,
1427*c2e18aaaSAndroid Build Coastguard Worker        test_type_to_invocations=test_type_to_invocations,
1428*c2e18aaaSAndroid Build Coastguard Worker    )
1429*c2e18aaaSAndroid Build Coastguard Worker
1430*c2e18aaaSAndroid Build Coastguard Worker  def requires_device_update(self) -> bool:
1431*c2e18aaaSAndroid Build Coastguard Worker    return any(
1432*c2e18aaaSAndroid Build Coastguard Worker        inv.requires_device_update()
1433*c2e18aaaSAndroid Build Coastguard Worker        for inv in itertools.chain.from_iterable(
1434*c2e18aaaSAndroid Build Coastguard Worker            self._test_type_to_invocations.values()
1435*c2e18aaaSAndroid Build Coastguard Worker        )
1436*c2e18aaaSAndroid Build Coastguard Worker    )
1437*c2e18aaaSAndroid Build Coastguard Worker
1438*c2e18aaaSAndroid Build Coastguard Worker  def required_build_targets(self) -> Set[str]:
1439*c2e18aaaSAndroid Build Coastguard Worker    build_targets = set()
1440*c2e18aaaSAndroid Build Coastguard Worker    for invocation in itertools.chain.from_iterable(
1441*c2e18aaaSAndroid Build Coastguard Worker        self._test_type_to_invocations.values()
1442*c2e18aaaSAndroid Build Coastguard Worker    ):
1443*c2e18aaaSAndroid Build Coastguard Worker      build_targets |= invocation.get_test_runner_reqs()
1444*c2e18aaaSAndroid Build Coastguard Worker
1445*c2e18aaaSAndroid Build Coastguard Worker    return build_targets
1446*c2e18aaaSAndroid Build Coastguard Worker
1447*c2e18aaaSAndroid Build Coastguard Worker  def execute(self) -> ExitCode:
1448*c2e18aaaSAndroid Build Coastguard Worker    """Run all tests in TEST_MAPPING files.
1449*c2e18aaaSAndroid Build Coastguard Worker
1450*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1451*c2e18aaaSAndroid Build Coastguard Worker        Exit code.
1452*c2e18aaaSAndroid Build Coastguard Worker    """
1453*c2e18aaaSAndroid Build Coastguard Worker
1454*c2e18aaaSAndroid Build Coastguard Worker    test_results = []
1455*c2e18aaaSAndroid Build Coastguard Worker    for test_type, invocations in self._test_type_to_invocations.items():
1456*c2e18aaaSAndroid Build Coastguard Worker      tests = list(
1457*c2e18aaaSAndroid Build Coastguard Worker          itertools.chain.from_iterable(i.test_infos for i in invocations)
1458*c2e18aaaSAndroid Build Coastguard Worker      )
1459*c2e18aaaSAndroid Build Coastguard Worker      if not tests:
1460*c2e18aaaSAndroid Build Coastguard Worker        continue
1461*c2e18aaaSAndroid Build Coastguard Worker      header = RUN_HEADER_FMT % {TEST_COUNT: len(tests), TEST_TYPE: test_type}
1462*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(header, constants.MAGENTA)
1463*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('\n'.join([str(info) for info in tests]))
1464*c2e18aaaSAndroid Build Coastguard Worker
1465*c2e18aaaSAndroid Build Coastguard Worker      reporter = result_reporter.ResultReporter(
1466*c2e18aaaSAndroid Build Coastguard Worker          collect_only=self._extra_args.get(constants.COLLECT_TESTS_ONLY),
1467*c2e18aaaSAndroid Build Coastguard Worker          wait_for_debugger=atest_configs.GLOBAL_ARGS.wait_for_debugger,
1468*c2e18aaaSAndroid Build Coastguard Worker          args=self._args,
1469*c2e18aaaSAndroid Build Coastguard Worker          test_infos=self._test_infos,
1470*c2e18aaaSAndroid Build Coastguard Worker      )
1471*c2e18aaaSAndroid Build Coastguard Worker      reporter.print_starting_text()
1472*c2e18aaaSAndroid Build Coastguard Worker
1473*c2e18aaaSAndroid Build Coastguard Worker      tests_exit_code = ExitCode.SUCCESS
1474*c2e18aaaSAndroid Build Coastguard Worker      for invocation in invocations:
1475*c2e18aaaSAndroid Build Coastguard Worker        tests_exit_code |= invocation.run_all_tests(reporter)
1476*c2e18aaaSAndroid Build Coastguard Worker
1477*c2e18aaaSAndroid Build Coastguard Worker      atest_execution_info.AtestExecutionInfo.result_reporters.append(reporter)
1478*c2e18aaaSAndroid Build Coastguard Worker      test_results.append((tests_exit_code, reporter, test_type))
1479*c2e18aaaSAndroid Build Coastguard Worker
1480*c2e18aaaSAndroid Build Coastguard Worker    all_tests_exit_code = ExitCode.SUCCESS
1481*c2e18aaaSAndroid Build Coastguard Worker    failed_tests = []
1482*c2e18aaaSAndroid Build Coastguard Worker    for tests_exit_code, reporter, test_type in test_results:
1483*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
1484*c2e18aaaSAndroid Build Coastguard Worker          RESULT_HEADER_FMT % {TEST_TYPE: test_type}, constants.MAGENTA
1485*c2e18aaaSAndroid Build Coastguard Worker      )
1486*c2e18aaaSAndroid Build Coastguard Worker      result = tests_exit_code | reporter.print_summary()
1487*c2e18aaaSAndroid Build Coastguard Worker      if result:
1488*c2e18aaaSAndroid Build Coastguard Worker        failed_tests.append(test_type)
1489*c2e18aaaSAndroid Build Coastguard Worker      all_tests_exit_code |= result
1490*c2e18aaaSAndroid Build Coastguard Worker
1491*c2e18aaaSAndroid Build Coastguard Worker    # List failed tests at the end as a reminder.
1492*c2e18aaaSAndroid Build Coastguard Worker    if failed_tests:
1493*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print(
1494*c2e18aaaSAndroid Build Coastguard Worker          atest_utils.delimiter('=', 30, prenl=1), constants.YELLOW
1495*c2e18aaaSAndroid Build Coastguard Worker      )
1496*c2e18aaaSAndroid Build Coastguard Worker      atest_utils.colorful_print('\nFollowing tests failed:', constants.MAGENTA)
1497*c2e18aaaSAndroid Build Coastguard Worker      for failure in failed_tests:
1498*c2e18aaaSAndroid Build Coastguard Worker        atest_utils.colorful_print(failure, constants.RED)
1499*c2e18aaaSAndroid Build Coastguard Worker
1500*c2e18aaaSAndroid Build Coastguard Worker    return all_tests_exit_code
1501*c2e18aaaSAndroid Build Coastguard Worker
1502*c2e18aaaSAndroid Build Coastguard Worker
1503*c2e18aaaSAndroid Build Coastguard Workerclass _TestModuleExecutionPlan(_TestExecutionPlan):
1504*c2e18aaaSAndroid Build Coastguard Worker  """A plan to execute the test modules explicitly passed on the command-line."""
1505*c2e18aaaSAndroid Build Coastguard Worker
1506*c2e18aaaSAndroid Build Coastguard Worker  def __init__(
1507*c2e18aaaSAndroid Build Coastguard Worker      self,
1508*c2e18aaaSAndroid Build Coastguard Worker      args: argparse.Namespace,
1509*c2e18aaaSAndroid Build Coastguard Worker      extra_args: Dict[str, Any],
1510*c2e18aaaSAndroid Build Coastguard Worker      test_infos: List[test_info.TestInfo],
1511*c2e18aaaSAndroid Build Coastguard Worker      test_runner_invocations: List[TestRunnerInvocation],
1512*c2e18aaaSAndroid Build Coastguard Worker  ):
1513*c2e18aaaSAndroid Build Coastguard Worker    super().__init__(args, extra_args, test_infos)
1514*c2e18aaaSAndroid Build Coastguard Worker    self._test_runner_invocations = test_runner_invocations
1515*c2e18aaaSAndroid Build Coastguard Worker
1516*c2e18aaaSAndroid Build Coastguard Worker  @staticmethod
1517*c2e18aaaSAndroid Build Coastguard Worker  def create(
1518*c2e18aaaSAndroid Build Coastguard Worker      args: argparse.Namespace,
1519*c2e18aaaSAndroid Build Coastguard Worker      test_infos: List[test_info.TestInfo],
1520*c2e18aaaSAndroid Build Coastguard Worker      results_dir: str,
1521*c2e18aaaSAndroid Build Coastguard Worker      mod_info: module_info.ModuleInfo,
1522*c2e18aaaSAndroid Build Coastguard Worker  ) -> _TestModuleExecutionPlan:
1523*c2e18aaaSAndroid Build Coastguard Worker    """Creates an instance of _TestModuleExecutionPlan.
1524*c2e18aaaSAndroid Build Coastguard Worker
1525*c2e18aaaSAndroid Build Coastguard Worker    Args:
1526*c2e18aaaSAndroid Build Coastguard Worker        args: An argparse.Namespace instance holding parsed args.
1527*c2e18aaaSAndroid Build Coastguard Worker        test_infos: A list of instances of TestInfo.
1528*c2e18aaaSAndroid Build Coastguard Worker        results_dir: A directory which stores the ATest execution information.
1529*c2e18aaaSAndroid Build Coastguard Worker        mod_info: An instance of ModuleInfo.
1530*c2e18aaaSAndroid Build Coastguard Worker        dry_run: A boolean of whether this invocation is a dry run.
1531*c2e18aaaSAndroid Build Coastguard Worker
1532*c2e18aaaSAndroid Build Coastguard Worker    Returns:
1533*c2e18aaaSAndroid Build Coastguard Worker        An instance of _TestModuleExecutionPlan.
1534*c2e18aaaSAndroid Build Coastguard Worker    """
1535*c2e18aaaSAndroid Build Coastguard Worker
1536*c2e18aaaSAndroid Build Coastguard Worker    if not args.dry_run:
1537*c2e18aaaSAndroid Build Coastguard Worker      _validate_exec_mode(args, test_infos)
1538*c2e18aaaSAndroid Build Coastguard Worker
1539*c2e18aaaSAndroid Build Coastguard Worker    # _validate_exec_mode appends --host automatically when pure
1540*c2e18aaaSAndroid Build Coastguard Worker    # host-side tests, so re-parsing extra_args is a must.
1541*c2e18aaaSAndroid Build Coastguard Worker    extra_args = get_extra_args(args)
1542*c2e18aaaSAndroid Build Coastguard Worker
1543*c2e18aaaSAndroid Build Coastguard Worker    invocations = test_runner_handler.create_test_runner_invocations(
1544*c2e18aaaSAndroid Build Coastguard Worker        test_infos=test_infos,
1545*c2e18aaaSAndroid Build Coastguard Worker        results_dir=results_dir,
1546*c2e18aaaSAndroid Build Coastguard Worker        mod_info=mod_info,
1547*c2e18aaaSAndroid Build Coastguard Worker        extra_args=extra_args,
1548*c2e18aaaSAndroid Build Coastguard Worker        minimal_build=args.minimal_build,
1549*c2e18aaaSAndroid Build Coastguard Worker    )
1550*c2e18aaaSAndroid Build Coastguard Worker
1551*c2e18aaaSAndroid Build Coastguard Worker    return _TestModuleExecutionPlan(
1552*c2e18aaaSAndroid Build Coastguard Worker        args=args,
1553*c2e18aaaSAndroid Build Coastguard Worker        extra_args=extra_args,
1554*c2e18aaaSAndroid Build Coastguard Worker        test_infos=test_infos,
1555*c2e18aaaSAndroid Build Coastguard Worker        test_runner_invocations=invocations,
1556*c2e18aaaSAndroid Build Coastguard Worker    )
1557*c2e18aaaSAndroid Build Coastguard Worker
1558*c2e18aaaSAndroid Build Coastguard Worker  def requires_device_update(self) -> bool:
1559*c2e18aaaSAndroid Build Coastguard Worker    return any(
1560*c2e18aaaSAndroid Build Coastguard Worker        inv.requires_device_update() for inv in self._test_runner_invocations
1561*c2e18aaaSAndroid Build Coastguard Worker    )
1562*c2e18aaaSAndroid Build Coastguard Worker
1563*c2e18aaaSAndroid Build Coastguard Worker  def required_build_targets(self) -> Set[str]:
1564*c2e18aaaSAndroid Build Coastguard Worker    build_targets = set()
1565*c2e18aaaSAndroid Build Coastguard Worker    for test_runner_invocation in self._test_runner_invocations:
1566*c2e18aaaSAndroid Build Coastguard Worker      build_targets |= test_runner_invocation.get_test_runner_reqs()
1567*c2e18aaaSAndroid Build Coastguard Worker
1568*c2e18aaaSAndroid Build Coastguard Worker    return build_targets
1569*c2e18aaaSAndroid Build Coastguard Worker
1570*c2e18aaaSAndroid Build Coastguard Worker  def execute(self) -> ExitCode:
1571*c2e18aaaSAndroid Build Coastguard Worker
1572*c2e18aaaSAndroid Build Coastguard Worker    reporter = result_reporter.ResultReporter(
1573*c2e18aaaSAndroid Build Coastguard Worker        collect_only=self.extra_args.get(constants.COLLECT_TESTS_ONLY),
1574*c2e18aaaSAndroid Build Coastguard Worker        wait_for_debugger=atest_configs.GLOBAL_ARGS.wait_for_debugger,
1575*c2e18aaaSAndroid Build Coastguard Worker        args=self._args,
1576*c2e18aaaSAndroid Build Coastguard Worker        test_infos=self._test_infos,
1577*c2e18aaaSAndroid Build Coastguard Worker    )
1578*c2e18aaaSAndroid Build Coastguard Worker    reporter.print_starting_text()
1579*c2e18aaaSAndroid Build Coastguard Worker
1580*c2e18aaaSAndroid Build Coastguard Worker    exit_code = ExitCode.SUCCESS
1581*c2e18aaaSAndroid Build Coastguard Worker    for invocation in self._test_runner_invocations:
1582*c2e18aaaSAndroid Build Coastguard Worker      exit_code |= invocation.run_all_tests(reporter)
1583*c2e18aaaSAndroid Build Coastguard Worker
1584*c2e18aaaSAndroid Build Coastguard Worker    atest_execution_info.AtestExecutionInfo.result_reporters.append(reporter)
1585*c2e18aaaSAndroid Build Coastguard Worker    return reporter.print_summary() | exit_code
1586*c2e18aaaSAndroid Build Coastguard Worker
1587*c2e18aaaSAndroid Build Coastguard Worker
1588*c2e18aaaSAndroid Build Coastguard Workerif __name__ == '__main__':
1589*c2e18aaaSAndroid Build Coastguard Worker  _AtestMain(sys.argv).run()
1590