xref: /aosp_15_r20/external/cronet/build/lacros/test_runner.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker#
3*6777b538SAndroid Build Coastguard Worker# Copyright 2020 The Chromium Authors
4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
6*6777b538SAndroid Build Coastguard Worker"""This script facilitates running tests for lacros on Linux.
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker  In order to run lacros tests on Linux, please first follow bit.ly/3juQVNJ
9*6777b538SAndroid Build Coastguard Worker  to setup build directory with the lacros-chrome-on-linux build configuration,
10*6777b538SAndroid Build Coastguard Worker  and corresponding test targets are built successfully.
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard WorkerExample usages
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker  ./build/lacros/test_runner.py test out/lacros/url_unittests
15*6777b538SAndroid Build Coastguard Worker  ./build/lacros/test_runner.py test out/lacros/browser_tests
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker  The commands above run url_unittests and browser_tests respectively, and more
18*6777b538SAndroid Build Coastguard Worker  specifically, url_unitests is executed directly while browser_tests is
19*6777b538SAndroid Build Coastguard Worker  executed with the latest version of prebuilt ash-chrome, and the behavior is
20*6777b538SAndroid Build Coastguard Worker  controlled by |_TARGETS_REQUIRE_ASH_CHROME|, and it's worth noting that the
21*6777b538SAndroid Build Coastguard Worker  list is maintained manually, so if you see something is wrong, please upload a
22*6777b538SAndroid Build Coastguard Worker  CL to fix it.
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker  ./build/lacros/test_runner.py test out/lacros/browser_tests \\
25*6777b538SAndroid Build Coastguard Worker      --gtest_filter=BrowserTest.Title
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker  The above command only runs 'BrowserTest.Title', and any argument accepted by
28*6777b538SAndroid Build Coastguard Worker  the underlying test binary can be specified in the command.
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker  ./build/lacros/test_runner.py test out/lacros/browser_tests \\
31*6777b538SAndroid Build Coastguard Worker    --ash-chrome-version=120.0.6099.0
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker  The above command runs tests with a given version of ash-chrome, which is
34*6777b538SAndroid Build Coastguard Worker  useful to reproduce test failures. A list of prebuilt versions can
35*6777b538SAndroid Build Coastguard Worker  be found at:
36*6777b538SAndroid Build Coastguard Worker  https://chrome-infra-packages.appspot.com/p/chromium/testing/linux-ash-chromium/x86_64/ash.zip
37*6777b538SAndroid Build Coastguard Worker  Click on any instance, you should see the version number for that instance.
38*6777b538SAndroid Build Coastguard Worker  Also, there are refs, which points to the instance for that channel. It should
39*6777b538SAndroid Build Coastguard Worker  be close the prod version but no guarantee.
40*6777b538SAndroid Build Coastguard Worker  For legacy refs, like legacy119, it point to the latest version for that
41*6777b538SAndroid Build Coastguard Worker  milestone.
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker  ./testing/xvfb.py ./build/lacros/test_runner.py test out/lacros/browser_tests
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker  The above command starts ash-chrome with xvfb instead of an X11 window, and
46*6777b538SAndroid Build Coastguard Worker  it's useful when running tests without a display attached, such as sshing.
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Worker  For version skew testing when passing --ash-chrome-path-override, the runner
49*6777b538SAndroid Build Coastguard Worker  will try to find the ash major version and Lacros major version. If ash is
50*6777b538SAndroid Build Coastguard Worker  newer(major version larger), the runner will not run any tests and just
51*6777b538SAndroid Build Coastguard Worker  returns success.
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard WorkerInteractively debugging tests
54*6777b538SAndroid Build Coastguard Worker
55*6777b538SAndroid Build Coastguard Worker  Any of the previous examples accept the switches
56*6777b538SAndroid Build Coastguard Worker    --gdb
57*6777b538SAndroid Build Coastguard Worker    --lldb
58*6777b538SAndroid Build Coastguard Worker  to run the tests in the corresponding debugger.
59*6777b538SAndroid Build Coastguard Worker"""
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Workerimport argparse
62*6777b538SAndroid Build Coastguard Workerimport json
63*6777b538SAndroid Build Coastguard Workerimport os
64*6777b538SAndroid Build Coastguard Workerimport logging
65*6777b538SAndroid Build Coastguard Workerimport re
66*6777b538SAndroid Build Coastguard Workerimport shutil
67*6777b538SAndroid Build Coastguard Workerimport signal
68*6777b538SAndroid Build Coastguard Workerimport subprocess
69*6777b538SAndroid Build Coastguard Workerimport sys
70*6777b538SAndroid Build Coastguard Workerimport tempfile
71*6777b538SAndroid Build Coastguard Workerimport time
72*6777b538SAndroid Build Coastguard Workerimport zipfile
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker_SRC_ROOT = os.path.abspath(
75*6777b538SAndroid Build Coastguard Worker    os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))
76*6777b538SAndroid Build Coastguard Workersys.path.append(os.path.join(_SRC_ROOT, 'third_party', 'depot_tools'))
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker# The cipd path for prebuilt ash chrome.
80*6777b538SAndroid Build Coastguard Worker_ASH_CIPD_PATH = 'chromium/testing/linux-ash-chromium/x86_64/ash.zip'
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker
83*6777b538SAndroid Build Coastguard Worker# Directory to cache downloaded ash-chrome versions to avoid re-downloading.
84*6777b538SAndroid Build Coastguard Worker_PREBUILT_ASH_CHROME_DIR = os.path.join(os.path.dirname(__file__),
85*6777b538SAndroid Build Coastguard Worker                                        'prebuilt_ash_chrome')
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Worker# File path to the asan symbolizer executable.
88*6777b538SAndroid Build Coastguard Worker_ASAN_SYMBOLIZER_PATH = os.path.join(_SRC_ROOT, 'tools', 'valgrind', 'asan',
89*6777b538SAndroid Build Coastguard Worker                                     'asan_symbolize.py')
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker# Number of seconds to wait for ash-chrome to start.
92*6777b538SAndroid Build Coastguard WorkerASH_CHROME_TIMEOUT_SECONDS = (
93*6777b538SAndroid Build Coastguard Worker    300 if os.environ.get('ASH_WRAPPER', None) else 25)
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker# List of targets that require ash-chrome as a Wayland server in order to run.
96*6777b538SAndroid Build Coastguard Worker_TARGETS_REQUIRE_ASH_CHROME = [
97*6777b538SAndroid Build Coastguard Worker    'app_shell_unittests',
98*6777b538SAndroid Build Coastguard Worker    'aura_unittests',
99*6777b538SAndroid Build Coastguard Worker    'browser_tests',
100*6777b538SAndroid Build Coastguard Worker    'components_unittests',
101*6777b538SAndroid Build Coastguard Worker    'compositor_unittests',
102*6777b538SAndroid Build Coastguard Worker    'content_unittests',
103*6777b538SAndroid Build Coastguard Worker    'dbus_unittests',
104*6777b538SAndroid Build Coastguard Worker    'extensions_unittests',
105*6777b538SAndroid Build Coastguard Worker    'media_unittests',
106*6777b538SAndroid Build Coastguard Worker    'message_center_unittests',
107*6777b538SAndroid Build Coastguard Worker    'snapshot_unittests',
108*6777b538SAndroid Build Coastguard Worker    'sync_integration_tests',
109*6777b538SAndroid Build Coastguard Worker    'unit_tests',
110*6777b538SAndroid Build Coastguard Worker    'views_unittests',
111*6777b538SAndroid Build Coastguard Worker    'wm_unittests',
112*6777b538SAndroid Build Coastguard Worker
113*6777b538SAndroid Build Coastguard Worker    # regex patterns.
114*6777b538SAndroid Build Coastguard Worker    '.*_browsertests',
115*6777b538SAndroid Build Coastguard Worker    '.*interactive_ui_tests'
116*6777b538SAndroid Build Coastguard Worker]
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker# List of targets that require ash-chrome to support crosapi mojo APIs.
119*6777b538SAndroid Build Coastguard Worker_TARGETS_REQUIRE_MOJO_CROSAPI = [
120*6777b538SAndroid Build Coastguard Worker    # TODO(jamescook): Add 'browser_tests' after multiple crosapi connections
121*6777b538SAndroid Build Coastguard Worker    # are allowed. For now we only enable crosapi in targets that run tests
122*6777b538SAndroid Build Coastguard Worker    # serially.
123*6777b538SAndroid Build Coastguard Worker    'interactive_ui_tests',
124*6777b538SAndroid Build Coastguard Worker    'lacros_chrome_browsertests',
125*6777b538SAndroid Build Coastguard Worker]
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker# Default test filter file for each target. These filter files will be
128*6777b538SAndroid Build Coastguard Worker# used by default if no other filter file get specified.
129*6777b538SAndroid Build Coastguard Worker_DEFAULT_FILTER_FILES_MAPPING = {
130*6777b538SAndroid Build Coastguard Worker    'browser_tests': 'linux-lacros.browser_tests.filter',
131*6777b538SAndroid Build Coastguard Worker    'components_unittests': 'linux-lacros.components_unittests.filter',
132*6777b538SAndroid Build Coastguard Worker    'content_browsertests': 'linux-lacros.content_browsertests.filter',
133*6777b538SAndroid Build Coastguard Worker    'interactive_ui_tests': 'linux-lacros.interactive_ui_tests.filter',
134*6777b538SAndroid Build Coastguard Worker    'lacros_chrome_browsertests':
135*6777b538SAndroid Build Coastguard Worker    'linux-lacros.lacros_chrome_browsertests.filter',
136*6777b538SAndroid Build Coastguard Worker    'sync_integration_tests': 'linux-lacros.sync_integration_tests.filter',
137*6777b538SAndroid Build Coastguard Worker    'unit_tests': 'linux-lacros.unit_tests.filter',
138*6777b538SAndroid Build Coastguard Worker}
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker
141*6777b538SAndroid Build Coastguard Workerdef _GetAshChromeDirPath(version):
142*6777b538SAndroid Build Coastguard Worker  """Returns a path to the dir storing the downloaded version of ash-chrome."""
143*6777b538SAndroid Build Coastguard Worker  return os.path.join(_PREBUILT_ASH_CHROME_DIR, version)
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard Workerdef _remove_unused_ash_chrome_versions(version_to_skip):
147*6777b538SAndroid Build Coastguard Worker  """Removes unused ash-chrome versions to save disk space.
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker  Currently, when an ash-chrome zip is downloaded and unpacked, the atime/mtime
150*6777b538SAndroid Build Coastguard Worker  of the dir and the files are NOW instead of the time when they were built, but
151*6777b538SAndroid Build Coastguard Worker  there is no garanteen it will always be the behavior in the future, so avoid
152*6777b538SAndroid Build Coastguard Worker  removing the current version just in case.
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker  Args:
155*6777b538SAndroid Build Coastguard Worker    version_to_skip (str): the version to skip removing regardless of its age.
156*6777b538SAndroid Build Coastguard Worker  """
157*6777b538SAndroid Build Coastguard Worker  days = 7
158*6777b538SAndroid Build Coastguard Worker  expiration_duration = 60 * 60 * 24 * days
159*6777b538SAndroid Build Coastguard Worker
160*6777b538SAndroid Build Coastguard Worker  for f in os.listdir(_PREBUILT_ASH_CHROME_DIR):
161*6777b538SAndroid Build Coastguard Worker    if f == version_to_skip:
162*6777b538SAndroid Build Coastguard Worker      continue
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker    p = os.path.join(_PREBUILT_ASH_CHROME_DIR, f)
165*6777b538SAndroid Build Coastguard Worker    if os.path.isfile(p):
166*6777b538SAndroid Build Coastguard Worker      # The prebuilt ash-chrome dir is NOT supposed to contain any files, remove
167*6777b538SAndroid Build Coastguard Worker      # them to keep the directory clean.
168*6777b538SAndroid Build Coastguard Worker      os.remove(p)
169*6777b538SAndroid Build Coastguard Worker      continue
170*6777b538SAndroid Build Coastguard Worker    chrome_path = os.path.join(p, 'test_ash_chrome')
171*6777b538SAndroid Build Coastguard Worker    if not os.path.exists(chrome_path):
172*6777b538SAndroid Build Coastguard Worker      chrome_path = p
173*6777b538SAndroid Build Coastguard Worker    age = time.time() - os.path.getatime(chrome_path)
174*6777b538SAndroid Build Coastguard Worker    if age > expiration_duration:
175*6777b538SAndroid Build Coastguard Worker      logging.info(
176*6777b538SAndroid Build Coastguard Worker          'Removing ash-chrome: "%s" as it hasn\'t been used in the '
177*6777b538SAndroid Build Coastguard Worker          'past %d days', p, days)
178*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(p)
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Workerdef _GetLatestVersionOfAshChrome():
182*6777b538SAndroid Build Coastguard Worker  '''Get the latest ash chrome version.
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker  Get the package version info with canary ref.
185*6777b538SAndroid Build Coastguard Worker
186*6777b538SAndroid Build Coastguard Worker  Returns:
187*6777b538SAndroid Build Coastguard Worker    A string with the chrome version.
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker  Raises:
190*6777b538SAndroid Build Coastguard Worker    RuntimeError: if we can not get the version.
191*6777b538SAndroid Build Coastguard Worker  '''
192*6777b538SAndroid Build Coastguard Worker  cp = subprocess.run(
193*6777b538SAndroid Build Coastguard Worker      ['cipd', 'describe', _ASH_CIPD_PATH, '-version', 'canary'],
194*6777b538SAndroid Build Coastguard Worker      capture_output=True)
195*6777b538SAndroid Build Coastguard Worker  assert (cp.returncode == 0)
196*6777b538SAndroid Build Coastguard Worker  groups = re.search(r'version:(?P<version>[\d\.]+)', str(cp.stdout))
197*6777b538SAndroid Build Coastguard Worker  if not groups:
198*6777b538SAndroid Build Coastguard Worker    raise RuntimeError('Can not find the version. Error message: %s' %
199*6777b538SAndroid Build Coastguard Worker                       cp.stdout)
200*6777b538SAndroid Build Coastguard Worker  return groups.group('version')
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker
203*6777b538SAndroid Build Coastguard Workerdef _DownloadAshChromeFromCipd(path, version):
204*6777b538SAndroid Build Coastguard Worker  '''Download the ash chrome with the requested version.
205*6777b538SAndroid Build Coastguard Worker
206*6777b538SAndroid Build Coastguard Worker  Args:
207*6777b538SAndroid Build Coastguard Worker    path: string for the downloaded ash chrome folder.
208*6777b538SAndroid Build Coastguard Worker    version: string for the ash chrome version.
209*6777b538SAndroid Build Coastguard Worker
210*6777b538SAndroid Build Coastguard Worker  Returns:
211*6777b538SAndroid Build Coastguard Worker    A string representing the path for the downloaded ash chrome.
212*6777b538SAndroid Build Coastguard Worker  '''
213*6777b538SAndroid Build Coastguard Worker  with tempfile.TemporaryDirectory() as temp_dir:
214*6777b538SAndroid Build Coastguard Worker    ensure_file_path = os.path.join(temp_dir, 'ensure_file.txt')
215*6777b538SAndroid Build Coastguard Worker    f = open(ensure_file_path, 'w+')
216*6777b538SAndroid Build Coastguard Worker    f.write(_ASH_CIPD_PATH + ' version:' + version)
217*6777b538SAndroid Build Coastguard Worker    f.close()
218*6777b538SAndroid Build Coastguard Worker    subprocess.run(
219*6777b538SAndroid Build Coastguard Worker        ['cipd', 'ensure', '-ensure-file', ensure_file_path, '-root', path])
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Worker
222*6777b538SAndroid Build Coastguard Workerdef _DoubleCheckDownloadedAshChrome(path, version):
223*6777b538SAndroid Build Coastguard Worker  '''Check the downloaded ash is the expected version.
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker  Double check by running the chrome binary with --version.
226*6777b538SAndroid Build Coastguard Worker
227*6777b538SAndroid Build Coastguard Worker  Args:
228*6777b538SAndroid Build Coastguard Worker    path: string for the downloaded ash chrome folder.
229*6777b538SAndroid Build Coastguard Worker    version: string for the expected ash chrome version.
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker  Raises:
232*6777b538SAndroid Build Coastguard Worker    RuntimeError if no test_ash_chrome binary can be found.
233*6777b538SAndroid Build Coastguard Worker  '''
234*6777b538SAndroid Build Coastguard Worker  test_ash_chrome = os.path.join(path, 'test_ash_chrome')
235*6777b538SAndroid Build Coastguard Worker  if not os.path.exists(test_ash_chrome):
236*6777b538SAndroid Build Coastguard Worker    raise RuntimeError('Can not find test_ash_chrome binary under %s' % path)
237*6777b538SAndroid Build Coastguard Worker  cp = subprocess.run([test_ash_chrome, '--version'], capture_output=True)
238*6777b538SAndroid Build Coastguard Worker  assert (cp.returncode == 0)
239*6777b538SAndroid Build Coastguard Worker  if str(cp.stdout).find(version) == -1:
240*6777b538SAndroid Build Coastguard Worker    logging.warning(
241*6777b538SAndroid Build Coastguard Worker        'The downloaded ash chrome version is %s, but the '
242*6777b538SAndroid Build Coastguard Worker        'expected ash chrome is %s. There is a version mismatch. Please '
243*6777b538SAndroid Build Coastguard Worker        'file a bug to OS>Lacros so someone can take a look.' %
244*6777b538SAndroid Build Coastguard Worker        (cp.stdout, version))
245*6777b538SAndroid Build Coastguard Worker
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Workerdef _DownloadAshChromeIfNecessary(version):
248*6777b538SAndroid Build Coastguard Worker  """Download a given version of ash-chrome if not already exists.
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker  Args:
251*6777b538SAndroid Build Coastguard Worker    version: A string representing the version, such as "793554".
252*6777b538SAndroid Build Coastguard Worker
253*6777b538SAndroid Build Coastguard Worker  Raises:
254*6777b538SAndroid Build Coastguard Worker      RuntimeError: If failed to download the specified version, for example,
255*6777b538SAndroid Build Coastguard Worker          if the version is not present on gcs.
256*6777b538SAndroid Build Coastguard Worker  """
257*6777b538SAndroid Build Coastguard Worker
258*6777b538SAndroid Build Coastguard Worker  def IsAshChromeDirValid(ash_chrome_dir):
259*6777b538SAndroid Build Coastguard Worker    # This function assumes that once 'chrome' is present, other dependencies
260*6777b538SAndroid Build Coastguard Worker    # will be present as well, it's not always true, for example, if the test
261*6777b538SAndroid Build Coastguard Worker    # runner process gets killed in the middle of unzipping (~2 seconds), but
262*6777b538SAndroid Build Coastguard Worker    # it's unlikely for the assumption to break in practice.
263*6777b538SAndroid Build Coastguard Worker    return os.path.isdir(ash_chrome_dir) and os.path.isfile(
264*6777b538SAndroid Build Coastguard Worker        os.path.join(ash_chrome_dir, 'test_ash_chrome'))
265*6777b538SAndroid Build Coastguard Worker
266*6777b538SAndroid Build Coastguard Worker  ash_chrome_dir = _GetAshChromeDirPath(version)
267*6777b538SAndroid Build Coastguard Worker  if IsAshChromeDirValid(ash_chrome_dir):
268*6777b538SAndroid Build Coastguard Worker    return
269*6777b538SAndroid Build Coastguard Worker
270*6777b538SAndroid Build Coastguard Worker  shutil.rmtree(ash_chrome_dir, ignore_errors=True)
271*6777b538SAndroid Build Coastguard Worker  os.makedirs(ash_chrome_dir)
272*6777b538SAndroid Build Coastguard Worker  _DownloadAshChromeFromCipd(ash_chrome_dir, version)
273*6777b538SAndroid Build Coastguard Worker  _DoubleCheckDownloadedAshChrome(ash_chrome_dir, version)
274*6777b538SAndroid Build Coastguard Worker  _remove_unused_ash_chrome_versions(version)
275*6777b538SAndroid Build Coastguard Worker
276*6777b538SAndroid Build Coastguard Worker
277*6777b538SAndroid Build Coastguard Workerdef _WaitForAshChromeToStart(tmp_xdg_dir, lacros_mojo_socket_file,
278*6777b538SAndroid Build Coastguard Worker                             enable_mojo_crosapi, ash_ready_file):
279*6777b538SAndroid Build Coastguard Worker  """Waits for Ash-Chrome to be up and running and returns a boolean indicator.
280*6777b538SAndroid Build Coastguard Worker
281*6777b538SAndroid Build Coastguard Worker  Determine whether ash-chrome is up and running by checking whether two files
282*6777b538SAndroid Build Coastguard Worker  (lock file + socket) have been created in the |XDG_RUNTIME_DIR| and the lacros
283*6777b538SAndroid Build Coastguard Worker  mojo socket file has been created if enabling the mojo "crosapi" interface.
284*6777b538SAndroid Build Coastguard Worker  TODO(crbug.com/1107966): Figure out a more reliable hook to determine the
285*6777b538SAndroid Build Coastguard Worker  status of ash-chrome, likely through mojo connection.
286*6777b538SAndroid Build Coastguard Worker
287*6777b538SAndroid Build Coastguard Worker  Args:
288*6777b538SAndroid Build Coastguard Worker    tmp_xdg_dir (str): Path to the XDG_RUNTIME_DIR.
289*6777b538SAndroid Build Coastguard Worker    lacros_mojo_socket_file (str): Path to the lacros mojo socket file.
290*6777b538SAndroid Build Coastguard Worker    enable_mojo_crosapi (bool): Whether to bootstrap the crosapi mojo interface
291*6777b538SAndroid Build Coastguard Worker        between ash and the lacros test binary.
292*6777b538SAndroid Build Coastguard Worker    ash_ready_file (str): Path to a non-existing file. After ash is ready for
293*6777b538SAndroid Build Coastguard Worker        testing, the file will be created.
294*6777b538SAndroid Build Coastguard Worker
295*6777b538SAndroid Build Coastguard Worker  Returns:
296*6777b538SAndroid Build Coastguard Worker    A boolean indicating whether Ash-chrome is up and running.
297*6777b538SAndroid Build Coastguard Worker  """
298*6777b538SAndroid Build Coastguard Worker
299*6777b538SAndroid Build Coastguard Worker  def IsAshChromeReady(tmp_xdg_dir, lacros_mojo_socket_file,
300*6777b538SAndroid Build Coastguard Worker                       enable_mojo_crosapi, ash_ready_file):
301*6777b538SAndroid Build Coastguard Worker    # There should be 2 wayland files.
302*6777b538SAndroid Build Coastguard Worker    if len(os.listdir(tmp_xdg_dir)) < 2:
303*6777b538SAndroid Build Coastguard Worker      return False
304*6777b538SAndroid Build Coastguard Worker    if enable_mojo_crosapi and not os.path.exists(lacros_mojo_socket_file):
305*6777b538SAndroid Build Coastguard Worker      return False
306*6777b538SAndroid Build Coastguard Worker    return os.path.exists(ash_ready_file)
307*6777b538SAndroid Build Coastguard Worker
308*6777b538SAndroid Build Coastguard Worker  time_counter = 0
309*6777b538SAndroid Build Coastguard Worker  while not IsAshChromeReady(tmp_xdg_dir, lacros_mojo_socket_file,
310*6777b538SAndroid Build Coastguard Worker                             enable_mojo_crosapi, ash_ready_file):
311*6777b538SAndroid Build Coastguard Worker    time.sleep(0.5)
312*6777b538SAndroid Build Coastguard Worker    time_counter += 0.5
313*6777b538SAndroid Build Coastguard Worker    if time_counter > ASH_CHROME_TIMEOUT_SECONDS:
314*6777b538SAndroid Build Coastguard Worker      break
315*6777b538SAndroid Build Coastguard Worker
316*6777b538SAndroid Build Coastguard Worker  return IsAshChromeReady(tmp_xdg_dir, lacros_mojo_socket_file,
317*6777b538SAndroid Build Coastguard Worker                          enable_mojo_crosapi, ash_ready_file)
318*6777b538SAndroid Build Coastguard Worker
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Workerdef _ExtractAshMajorVersion(file_path):
321*6777b538SAndroid Build Coastguard Worker  """Extract major version from file_path.
322*6777b538SAndroid Build Coastguard Worker
323*6777b538SAndroid Build Coastguard Worker  File path like this:
324*6777b538SAndroid Build Coastguard Worker  ../../lacros_version_skew_tests_v94.0.4588.0/test_ash_chrome
325*6777b538SAndroid Build Coastguard Worker
326*6777b538SAndroid Build Coastguard Worker  Returns:
327*6777b538SAndroid Build Coastguard Worker    int representing the major version. Or 0 if it can't extract
328*6777b538SAndroid Build Coastguard Worker        major version.
329*6777b538SAndroid Build Coastguard Worker  """
330*6777b538SAndroid Build Coastguard Worker  m = re.search(
331*6777b538SAndroid Build Coastguard Worker      'lacros_version_skew_tests_v(?P<version>[0-9]+).[0-9]+.[0-9]+.[0-9]+/',
332*6777b538SAndroid Build Coastguard Worker      file_path)
333*6777b538SAndroid Build Coastguard Worker  if (m and 'version' in m.groupdict().keys()):
334*6777b538SAndroid Build Coastguard Worker    return int(m.group('version'))
335*6777b538SAndroid Build Coastguard Worker  logging.warning('Can not find the ash version in %s.' % file_path)
336*6777b538SAndroid Build Coastguard Worker  # Returns ash major version as 0, so we can still run tests.
337*6777b538SAndroid Build Coastguard Worker  # This is likely happen because user is running in local environments.
338*6777b538SAndroid Build Coastguard Worker  return 0
339*6777b538SAndroid Build Coastguard Worker
340*6777b538SAndroid Build Coastguard Worker
341*6777b538SAndroid Build Coastguard Workerdef _FindLacrosMajorVersionFromMetadata():
342*6777b538SAndroid Build Coastguard Worker  # This handles the logic on bots. When running on bots,
343*6777b538SAndroid Build Coastguard Worker  # we don't copy source files to test machines. So we build a
344*6777b538SAndroid Build Coastguard Worker  # metadata.json file which contains version information.
345*6777b538SAndroid Build Coastguard Worker  if not os.path.exists('metadata.json'):
346*6777b538SAndroid Build Coastguard Worker    logging.error('Can not determine current version.')
347*6777b538SAndroid Build Coastguard Worker    # Returns 0 so it can't run any tests.
348*6777b538SAndroid Build Coastguard Worker    return 0
349*6777b538SAndroid Build Coastguard Worker  version = ''
350*6777b538SAndroid Build Coastguard Worker  with open('metadata.json', 'r') as file:
351*6777b538SAndroid Build Coastguard Worker    content = json.load(file)
352*6777b538SAndroid Build Coastguard Worker    version = content['content']['version']
353*6777b538SAndroid Build Coastguard Worker  return int(version[:version.find('.')])
354*6777b538SAndroid Build Coastguard Worker
355*6777b538SAndroid Build Coastguard Worker
356*6777b538SAndroid Build Coastguard Workerdef _FindLacrosMajorVersion():
357*6777b538SAndroid Build Coastguard Worker  """Returns the major version in the current checkout.
358*6777b538SAndroid Build Coastguard Worker
359*6777b538SAndroid Build Coastguard Worker  It would try to read src/chrome/VERSION. If it's not available,
360*6777b538SAndroid Build Coastguard Worker  then try to read metadata.json.
361*6777b538SAndroid Build Coastguard Worker
362*6777b538SAndroid Build Coastguard Worker  Returns:
363*6777b538SAndroid Build Coastguard Worker    int representing the major version. Or 0 if it fails to
364*6777b538SAndroid Build Coastguard Worker    determine the version.
365*6777b538SAndroid Build Coastguard Worker  """
366*6777b538SAndroid Build Coastguard Worker  version_file = os.path.abspath(
367*6777b538SAndroid Build Coastguard Worker      os.path.join(os.path.abspath(os.path.dirname(__file__)),
368*6777b538SAndroid Build Coastguard Worker                   '../../chrome/VERSION'))
369*6777b538SAndroid Build Coastguard Worker  # This is mostly happens for local development where
370*6777b538SAndroid Build Coastguard Worker  # src/chrome/VERSION exists.
371*6777b538SAndroid Build Coastguard Worker  if os.path.exists(version_file):
372*6777b538SAndroid Build Coastguard Worker    lines = open(version_file, 'r').readlines()
373*6777b538SAndroid Build Coastguard Worker    return int(lines[0][lines[0].find('=') + 1:-1])
374*6777b538SAndroid Build Coastguard Worker  return _FindLacrosMajorVersionFromMetadata()
375*6777b538SAndroid Build Coastguard Worker
376*6777b538SAndroid Build Coastguard Worker
377*6777b538SAndroid Build Coastguard Workerdef _ParseSummaryOutput(forward_args):
378*6777b538SAndroid Build Coastguard Worker  """Find the summary output file path.
379*6777b538SAndroid Build Coastguard Worker
380*6777b538SAndroid Build Coastguard Worker  Args:
381*6777b538SAndroid Build Coastguard Worker    forward_args (list): Args to be forwarded to the test command.
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker  Returns:
384*6777b538SAndroid Build Coastguard Worker    None if not found, or str representing the output file path.
385*6777b538SAndroid Build Coastguard Worker  """
386*6777b538SAndroid Build Coastguard Worker  logging.warning(forward_args)
387*6777b538SAndroid Build Coastguard Worker  for arg in forward_args:
388*6777b538SAndroid Build Coastguard Worker    if arg.startswith('--test-launcher-summary-output='):
389*6777b538SAndroid Build Coastguard Worker      return arg[len('--test-launcher-summary-output='):]
390*6777b538SAndroid Build Coastguard Worker  return None
391*6777b538SAndroid Build Coastguard Worker
392*6777b538SAndroid Build Coastguard Worker
393*6777b538SAndroid Build Coastguard Workerdef _IsRunningOnBots(forward_args):
394*6777b538SAndroid Build Coastguard Worker  """Detects if the script is running on bots or not.
395*6777b538SAndroid Build Coastguard Worker
396*6777b538SAndroid Build Coastguard Worker  Args:
397*6777b538SAndroid Build Coastguard Worker    forward_args (list): Args to be forwarded to the test command.
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Worker  Returns:
400*6777b538SAndroid Build Coastguard Worker    True if the script is running on bots. Otherwise returns False.
401*6777b538SAndroid Build Coastguard Worker  """
402*6777b538SAndroid Build Coastguard Worker  return '--test-launcher-bot-mode' in forward_args
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker
405*6777b538SAndroid Build Coastguard Workerdef _KillNicely(proc, timeout_secs=2, first_wait_secs=0):
406*6777b538SAndroid Build Coastguard Worker  """Kills a subprocess nicely.
407*6777b538SAndroid Build Coastguard Worker
408*6777b538SAndroid Build Coastguard Worker  Args:
409*6777b538SAndroid Build Coastguard Worker    proc: The subprocess to kill.
410*6777b538SAndroid Build Coastguard Worker    timeout_secs: The timeout to wait in seconds.
411*6777b538SAndroid Build Coastguard Worker    first_wait_secs: The grace period before sending first SIGTERM in seconds.
412*6777b538SAndroid Build Coastguard Worker  """
413*6777b538SAndroid Build Coastguard Worker  if not proc:
414*6777b538SAndroid Build Coastguard Worker    return
415*6777b538SAndroid Build Coastguard Worker
416*6777b538SAndroid Build Coastguard Worker  if first_wait_secs:
417*6777b538SAndroid Build Coastguard Worker    try:
418*6777b538SAndroid Build Coastguard Worker      proc.wait(first_wait_secs)
419*6777b538SAndroid Build Coastguard Worker      return
420*6777b538SAndroid Build Coastguard Worker    except subprocess.TimeoutExpired:
421*6777b538SAndroid Build Coastguard Worker      pass
422*6777b538SAndroid Build Coastguard Worker
423*6777b538SAndroid Build Coastguard Worker  if proc.poll() is None:
424*6777b538SAndroid Build Coastguard Worker    proc.terminate()
425*6777b538SAndroid Build Coastguard Worker    try:
426*6777b538SAndroid Build Coastguard Worker      proc.wait(timeout_secs)
427*6777b538SAndroid Build Coastguard Worker    except subprocess.TimeoutExpired:
428*6777b538SAndroid Build Coastguard Worker      proc.kill()
429*6777b538SAndroid Build Coastguard Worker      proc.wait()
430*6777b538SAndroid Build Coastguard Worker
431*6777b538SAndroid Build Coastguard Worker
432*6777b538SAndroid Build Coastguard Workerdef _ClearDir(dirpath):
433*6777b538SAndroid Build Coastguard Worker  """Deletes everything within the directory.
434*6777b538SAndroid Build Coastguard Worker
435*6777b538SAndroid Build Coastguard Worker  Args:
436*6777b538SAndroid Build Coastguard Worker    dirpath: The path of the directory.
437*6777b538SAndroid Build Coastguard Worker  """
438*6777b538SAndroid Build Coastguard Worker  for e in os.scandir(dirpath):
439*6777b538SAndroid Build Coastguard Worker    if e.is_dir():
440*6777b538SAndroid Build Coastguard Worker      shutil.rmtree(e.path, ignore_errors=True)
441*6777b538SAndroid Build Coastguard Worker    elif e.is_file():
442*6777b538SAndroid Build Coastguard Worker      os.remove(e.path)
443*6777b538SAndroid Build Coastguard Worker
444*6777b538SAndroid Build Coastguard Worker
445*6777b538SAndroid Build Coastguard Workerdef _LaunchDebugger(args, forward_args, test_env):
446*6777b538SAndroid Build Coastguard Worker  """Launches the requested debugger.
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker  This is used to wrap the test invocation in a debugger. It returns the
449*6777b538SAndroid Build Coastguard Worker  created Popen class of the debugger process.
450*6777b538SAndroid Build Coastguard Worker
451*6777b538SAndroid Build Coastguard Worker  Args:
452*6777b538SAndroid Build Coastguard Worker      args (dict): Args for this script.
453*6777b538SAndroid Build Coastguard Worker      forward_args (list): Args to be forwarded to the test command.
454*6777b538SAndroid Build Coastguard Worker      test_env (dict): Computed environment variables for the test.
455*6777b538SAndroid Build Coastguard Worker  """
456*6777b538SAndroid Build Coastguard Worker  logging.info('Starting debugger.')
457*6777b538SAndroid Build Coastguard Worker
458*6777b538SAndroid Build Coastguard Worker  # Redirect fatal signals to "ignore." When running an interactive debugger,
459*6777b538SAndroid Build Coastguard Worker  # these signals should go only to the debugger so the user can break back out
460*6777b538SAndroid Build Coastguard Worker  # of the debugged test process into the debugger UI without killing this
461*6777b538SAndroid Build Coastguard Worker  # parent script.
462*6777b538SAndroid Build Coastguard Worker  for sig in (signal.SIGTERM, signal.SIGINT):
463*6777b538SAndroid Build Coastguard Worker    signal.signal(sig, signal.SIG_IGN)
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Worker  # Force the tests into single-process-test mode for debugging unless manually
466*6777b538SAndroid Build Coastguard Worker  # specified. Otherwise the tests will run in a child process that the debugger
467*6777b538SAndroid Build Coastguard Worker  # won't be attached to and the debugger won't do anything.
468*6777b538SAndroid Build Coastguard Worker  if not ("--single-process" in forward_args
469*6777b538SAndroid Build Coastguard Worker          or "--single-process-tests" in forward_args):
470*6777b538SAndroid Build Coastguard Worker    forward_args += ["--single-process-tests"]
471*6777b538SAndroid Build Coastguard Worker
472*6777b538SAndroid Build Coastguard Worker    # Adding --single-process-tests can cause some tests to fail when they're
473*6777b538SAndroid Build Coastguard Worker    # run in the same process. Forcing the user to specify a filter will prevent
474*6777b538SAndroid Build Coastguard Worker    # a later error.
475*6777b538SAndroid Build Coastguard Worker    if not [i for i in forward_args if i.startswith("--gtest_filter")]:
476*6777b538SAndroid Build Coastguard Worker      logging.error("""Interactive debugging requested without --gtest_filter
477*6777b538SAndroid Build Coastguard Worker
478*6777b538SAndroid Build Coastguard WorkerThis script adds --single-process-tests to support interactive debugging but
479*6777b538SAndroid Build Coastguard Workersome tests will fail in this mode unless run independently. To debug a test
480*6777b538SAndroid Build Coastguard Workerspecify a --gtest_filter=Foo.Bar to name the test you want to debug.
481*6777b538SAndroid Build Coastguard Worker""")
482*6777b538SAndroid Build Coastguard Worker      sys.exit(1)
483*6777b538SAndroid Build Coastguard Worker
484*6777b538SAndroid Build Coastguard Worker  # This code attempts to source the debugger configuration file. Some
485*6777b538SAndroid Build Coastguard Worker  # users will have this in their init but sourcing it more than once is
486*6777b538SAndroid Build Coastguard Worker  # harmless and helps people that haven't configured it.
487*6777b538SAndroid Build Coastguard Worker  if args.gdb:
488*6777b538SAndroid Build Coastguard Worker    gdbinit_file = os.path.normpath(
489*6777b538SAndroid Build Coastguard Worker        os.path.join(os.path.realpath(__file__), "../../../tools/gdb/gdbinit"))
490*6777b538SAndroid Build Coastguard Worker    debugger_command = [
491*6777b538SAndroid Build Coastguard Worker        'gdb', '--init-eval-command', 'source ' + gdbinit_file, '--args'
492*6777b538SAndroid Build Coastguard Worker    ]
493*6777b538SAndroid Build Coastguard Worker  else:
494*6777b538SAndroid Build Coastguard Worker    lldbinit_dir = os.path.normpath(
495*6777b538SAndroid Build Coastguard Worker        os.path.join(os.path.realpath(__file__), "../../../tools/lldb"))
496*6777b538SAndroid Build Coastguard Worker    debugger_command = [
497*6777b538SAndroid Build Coastguard Worker        'lldb', '-O',
498*6777b538SAndroid Build Coastguard Worker        "script sys.path[:0] = ['%s']" % lldbinit_dir, '-O',
499*6777b538SAndroid Build Coastguard Worker        'script import lldbinit', '--'
500*6777b538SAndroid Build Coastguard Worker    ]
501*6777b538SAndroid Build Coastguard Worker  debugger_command += [args.command] + forward_args
502*6777b538SAndroid Build Coastguard Worker  return subprocess.Popen(debugger_command, env=test_env)
503*6777b538SAndroid Build Coastguard Worker
504*6777b538SAndroid Build Coastguard Worker
505*6777b538SAndroid Build Coastguard Workerdef _RunTestWithAshChrome(args, forward_args):
506*6777b538SAndroid Build Coastguard Worker  """Runs tests with ash-chrome.
507*6777b538SAndroid Build Coastguard Worker
508*6777b538SAndroid Build Coastguard Worker  Args:
509*6777b538SAndroid Build Coastguard Worker    args (dict): Args for this script.
510*6777b538SAndroid Build Coastguard Worker    forward_args (list): Args to be forwarded to the test command.
511*6777b538SAndroid Build Coastguard Worker  """
512*6777b538SAndroid Build Coastguard Worker  if args.ash_chrome_path_override:
513*6777b538SAndroid Build Coastguard Worker    ash_chrome_file = args.ash_chrome_path_override
514*6777b538SAndroid Build Coastguard Worker    ash_major_version = _ExtractAshMajorVersion(ash_chrome_file)
515*6777b538SAndroid Build Coastguard Worker    lacros_major_version = _FindLacrosMajorVersion()
516*6777b538SAndroid Build Coastguard Worker    if ash_major_version > lacros_major_version:
517*6777b538SAndroid Build Coastguard Worker      logging.warning('''Not running any tests, because we do not \
518*6777b538SAndroid Build Coastguard Workersupport version skew testing for Lacros M%s against ash M%s''' %
519*6777b538SAndroid Build Coastguard Worker                      (lacros_major_version, ash_major_version))
520*6777b538SAndroid Build Coastguard Worker      # Create an empty output.json file so result adapter can read
521*6777b538SAndroid Build Coastguard Worker      # the file. Or else result adapter will report no file found
522*6777b538SAndroid Build Coastguard Worker      # and result infra failure.
523*6777b538SAndroid Build Coastguard Worker      output_json = _ParseSummaryOutput(forward_args)
524*6777b538SAndroid Build Coastguard Worker      if output_json:
525*6777b538SAndroid Build Coastguard Worker        with open(output_json, 'w') as f:
526*6777b538SAndroid Build Coastguard Worker          f.write("""{"all_tests":[],"disabled_tests":[],"global_tags":[],
527*6777b538SAndroid Build Coastguard Worker"per_iteration_data":[],"test_locations":{}}""")
528*6777b538SAndroid Build Coastguard Worker      # Although we don't run any tests, this is considered as success.
529*6777b538SAndroid Build Coastguard Worker      return 0
530*6777b538SAndroid Build Coastguard Worker    if not os.path.exists(ash_chrome_file):
531*6777b538SAndroid Build Coastguard Worker      logging.error("""Can not find ash chrome at %s. Did you download \
532*6777b538SAndroid Build Coastguard Workerthe ash from CIPD? If you don't plan to build your own ash, you need \
533*6777b538SAndroid Build Coastguard Workerto download first. Example commandlines:
534*6777b538SAndroid Build Coastguard Worker $ cipd auth-login
535*6777b538SAndroid Build Coastguard Worker $ echo "chromium/testing/linux-ash-chromium/x86_64/ash.zip \
536*6777b538SAndroid Build Coastguard Workerversion:92.0.4515.130" > /tmp/ensure-file.txt
537*6777b538SAndroid Build Coastguard Worker $ cipd ensure -ensure-file /tmp/ensure-file.txt \
538*6777b538SAndroid Build Coastguard Worker-root lacros_version_skew_tests_v92.0.4515.130
539*6777b538SAndroid Build Coastguard Worker Then you can use --ash-chrome-path-override=\
540*6777b538SAndroid Build Coastguard Workerlacros_version_skew_tests_v92.0.4515.130/test_ash_chrome
541*6777b538SAndroid Build Coastguard Worker""" % ash_chrome_file)
542*6777b538SAndroid Build Coastguard Worker      return 1
543*6777b538SAndroid Build Coastguard Worker  elif args.ash_chrome_path:
544*6777b538SAndroid Build Coastguard Worker    ash_chrome_file = args.ash_chrome_path
545*6777b538SAndroid Build Coastguard Worker  else:
546*6777b538SAndroid Build Coastguard Worker    ash_chrome_version = (args.ash_chrome_version
547*6777b538SAndroid Build Coastguard Worker                          or _GetLatestVersionOfAshChrome())
548*6777b538SAndroid Build Coastguard Worker    _DownloadAshChromeIfNecessary(ash_chrome_version)
549*6777b538SAndroid Build Coastguard Worker    logging.info('Ash-chrome version: %s', ash_chrome_version)
550*6777b538SAndroid Build Coastguard Worker
551*6777b538SAndroid Build Coastguard Worker    ash_chrome_file = os.path.join(_GetAshChromeDirPath(ash_chrome_version),
552*6777b538SAndroid Build Coastguard Worker                                   'test_ash_chrome')
553*6777b538SAndroid Build Coastguard Worker  try:
554*6777b538SAndroid Build Coastguard Worker    # Starts Ash-Chrome.
555*6777b538SAndroid Build Coastguard Worker    tmp_xdg_dir_name = tempfile.mkdtemp()
556*6777b538SAndroid Build Coastguard Worker    tmp_ash_data_dir_name = tempfile.mkdtemp()
557*6777b538SAndroid Build Coastguard Worker    tmp_unique_ash_dir_name = tempfile.mkdtemp()
558*6777b538SAndroid Build Coastguard Worker
559*6777b538SAndroid Build Coastguard Worker    # Please refer to below file for how mojo connection is set up in testing.
560*6777b538SAndroid Build Coastguard Worker    # //chrome/browser/ash/crosapi/test_mojo_connection_manager.h
561*6777b538SAndroid Build Coastguard Worker    lacros_mojo_socket_file = '%s/lacros.sock' % tmp_ash_data_dir_name
562*6777b538SAndroid Build Coastguard Worker    lacros_mojo_socket_arg = ('--lacros-mojo-socket-for-testing=%s' %
563*6777b538SAndroid Build Coastguard Worker                              lacros_mojo_socket_file)
564*6777b538SAndroid Build Coastguard Worker    ash_ready_file = '%s/ash_ready.txt' % tmp_ash_data_dir_name
565*6777b538SAndroid Build Coastguard Worker    enable_mojo_crosapi = any(t == os.path.basename(args.command)
566*6777b538SAndroid Build Coastguard Worker                              for t in _TARGETS_REQUIRE_MOJO_CROSAPI)
567*6777b538SAndroid Build Coastguard Worker    ash_wayland_socket_name = 'wayland-exo'
568*6777b538SAndroid Build Coastguard Worker
569*6777b538SAndroid Build Coastguard Worker    ash_process = None
570*6777b538SAndroid Build Coastguard Worker    ash_env = os.environ.copy()
571*6777b538SAndroid Build Coastguard Worker    ash_env['XDG_RUNTIME_DIR'] = tmp_xdg_dir_name
572*6777b538SAndroid Build Coastguard Worker    ash_cmd = [
573*6777b538SAndroid Build Coastguard Worker        ash_chrome_file,
574*6777b538SAndroid Build Coastguard Worker        '--user-data-dir=%s' % tmp_ash_data_dir_name,
575*6777b538SAndroid Build Coastguard Worker        '--enable-wayland-server',
576*6777b538SAndroid Build Coastguard Worker        '--no-startup-window',
577*6777b538SAndroid Build Coastguard Worker        '--disable-input-event-activation-protection',
578*6777b538SAndroid Build Coastguard Worker        '--disable-lacros-keep-alive',
579*6777b538SAndroid Build Coastguard Worker        '--disable-login-lacros-opening',
580*6777b538SAndroid Build Coastguard Worker        '--enable-field-trial-config',
581*6777b538SAndroid Build Coastguard Worker        '--enable-logging=stderr',
582*6777b538SAndroid Build Coastguard Worker        '--enable-features=LacrosSupport,LacrosPrimary,LacrosOnly',
583*6777b538SAndroid Build Coastguard Worker        '--ash-ready-file-path=%s' % ash_ready_file,
584*6777b538SAndroid Build Coastguard Worker        '--wayland-server-socket=%s' % ash_wayland_socket_name,
585*6777b538SAndroid Build Coastguard Worker    ]
586*6777b538SAndroid Build Coastguard Worker    if '--enable-pixel-output-in-tests' not in forward_args:
587*6777b538SAndroid Build Coastguard Worker      ash_cmd.append('--disable-gl-drawing-for-tests')
588*6777b538SAndroid Build Coastguard Worker
589*6777b538SAndroid Build Coastguard Worker    if enable_mojo_crosapi:
590*6777b538SAndroid Build Coastguard Worker      ash_cmd.append(lacros_mojo_socket_arg)
591*6777b538SAndroid Build Coastguard Worker
592*6777b538SAndroid Build Coastguard Worker    # Users can specify a wrapper for the ash binary to do things like
593*6777b538SAndroid Build Coastguard Worker    # attaching debuggers. For example, this will open a new terminal window
594*6777b538SAndroid Build Coastguard Worker    # and run GDB.
595*6777b538SAndroid Build Coastguard Worker    #   $ export ASH_WRAPPER="gnome-terminal -- gdb --ex=r --args"
596*6777b538SAndroid Build Coastguard Worker    ash_wrapper = os.environ.get('ASH_WRAPPER', None)
597*6777b538SAndroid Build Coastguard Worker    if ash_wrapper:
598*6777b538SAndroid Build Coastguard Worker      logging.info('Running ash with "ASH_WRAPPER": %s', ash_wrapper)
599*6777b538SAndroid Build Coastguard Worker      ash_cmd = list(ash_wrapper.split()) + ash_cmd
600*6777b538SAndroid Build Coastguard Worker
601*6777b538SAndroid Build Coastguard Worker    ash_process = None
602*6777b538SAndroid Build Coastguard Worker    ash_process_has_started = False
603*6777b538SAndroid Build Coastguard Worker    total_tries = 3
604*6777b538SAndroid Build Coastguard Worker    num_tries = 0
605*6777b538SAndroid Build Coastguard Worker    ash_start_time = None
606*6777b538SAndroid Build Coastguard Worker
607*6777b538SAndroid Build Coastguard Worker    # Create a log file if the user wanted to have one.
608*6777b538SAndroid Build Coastguard Worker    ash_log = None
609*6777b538SAndroid Build Coastguard Worker    ash_log_path = None
610*6777b538SAndroid Build Coastguard Worker
611*6777b538SAndroid Build Coastguard Worker    run_tests_in_debugger = args.gdb or args.lldb
612*6777b538SAndroid Build Coastguard Worker
613*6777b538SAndroid Build Coastguard Worker    if args.ash_logging_path:
614*6777b538SAndroid Build Coastguard Worker      ash_log_path = args.ash_logging_path
615*6777b538SAndroid Build Coastguard Worker    # Put ash logs in a separate file on bots.
616*6777b538SAndroid Build Coastguard Worker    # For asan builds, the ash log is not symbolized. In order to
617*6777b538SAndroid Build Coastguard Worker    # read the stack strace, we don't redirect logs to another file.
618*6777b538SAndroid Build Coastguard Worker    elif _IsRunningOnBots(forward_args) and not args.combine_ash_logs_on_bots:
619*6777b538SAndroid Build Coastguard Worker      summary_file = _ParseSummaryOutput(forward_args)
620*6777b538SAndroid Build Coastguard Worker      if summary_file:
621*6777b538SAndroid Build Coastguard Worker        ash_log_path = os.path.join(os.path.dirname(summary_file),
622*6777b538SAndroid Build Coastguard Worker                                    'ash_chrome.log')
623*6777b538SAndroid Build Coastguard Worker    elif run_tests_in_debugger:
624*6777b538SAndroid Build Coastguard Worker      # The debugger is unusable when all Ash logs are getting dumped to the
625*6777b538SAndroid Build Coastguard Worker      # same terminal. Redirect to a log file if there isn't one specified.
626*6777b538SAndroid Build Coastguard Worker      logging.info("Running in the debugger and --ash-logging-path is not " +
627*6777b538SAndroid Build Coastguard Worker                   "specified, defaulting to the current directory.")
628*6777b538SAndroid Build Coastguard Worker      ash_log_path = 'ash_chrome.log'
629*6777b538SAndroid Build Coastguard Worker
630*6777b538SAndroid Build Coastguard Worker    if ash_log_path:
631*6777b538SAndroid Build Coastguard Worker      ash_log = open(ash_log_path, 'a')
632*6777b538SAndroid Build Coastguard Worker      logging.info('Writing ash-chrome logs to: %s', ash_log_path)
633*6777b538SAndroid Build Coastguard Worker
634*6777b538SAndroid Build Coastguard Worker    ash_stdout = ash_log or None
635*6777b538SAndroid Build Coastguard Worker    test_stdout = None
636*6777b538SAndroid Build Coastguard Worker
637*6777b538SAndroid Build Coastguard Worker    # Setup asan symbolizer.
638*6777b538SAndroid Build Coastguard Worker    ash_symbolize_process = None
639*6777b538SAndroid Build Coastguard Worker    test_symbolize_process = None
640*6777b538SAndroid Build Coastguard Worker    should_symbolize = False
641*6777b538SAndroid Build Coastguard Worker    if args.asan_symbolize_output and os.path.exists(_ASAN_SYMBOLIZER_PATH):
642*6777b538SAndroid Build Coastguard Worker      should_symbolize = True
643*6777b538SAndroid Build Coastguard Worker      ash_symbolize_stdout = ash_stdout
644*6777b538SAndroid Build Coastguard Worker      ash_stdout = subprocess.PIPE
645*6777b538SAndroid Build Coastguard Worker      test_stdout = subprocess.PIPE
646*6777b538SAndroid Build Coastguard Worker
647*6777b538SAndroid Build Coastguard Worker    while not ash_process_has_started and num_tries < total_tries:
648*6777b538SAndroid Build Coastguard Worker      num_tries += 1
649*6777b538SAndroid Build Coastguard Worker      ash_start_time = time.monotonic()
650*6777b538SAndroid Build Coastguard Worker      logging.info('Starting ash-chrome: ' + ' '.join(ash_cmd))
651*6777b538SAndroid Build Coastguard Worker
652*6777b538SAndroid Build Coastguard Worker      # Using preexec_fn=os.setpgrp here will detach the forked process from
653*6777b538SAndroid Build Coastguard Worker      # this process group before exec-ing Ash. This prevents interactive
654*6777b538SAndroid Build Coastguard Worker      # Control-C from being seen by Ash. Otherwise Control-C in a debugger
655*6777b538SAndroid Build Coastguard Worker      # can kill Ash out from under the debugger. In non-debugger cases, this
656*6777b538SAndroid Build Coastguard Worker      # script attempts to clean up the spawned processes nicely.
657*6777b538SAndroid Build Coastguard Worker      ash_process = subprocess.Popen(ash_cmd,
658*6777b538SAndroid Build Coastguard Worker                                     env=ash_env,
659*6777b538SAndroid Build Coastguard Worker                                     preexec_fn=os.setpgrp,
660*6777b538SAndroid Build Coastguard Worker                                     stdout=ash_stdout,
661*6777b538SAndroid Build Coastguard Worker                                     stderr=subprocess.STDOUT)
662*6777b538SAndroid Build Coastguard Worker
663*6777b538SAndroid Build Coastguard Worker      if should_symbolize:
664*6777b538SAndroid Build Coastguard Worker        logging.info('Symbolizing ash logs with asan symbolizer.')
665*6777b538SAndroid Build Coastguard Worker        ash_symbolize_process = subprocess.Popen([_ASAN_SYMBOLIZER_PATH],
666*6777b538SAndroid Build Coastguard Worker                                                 stdin=ash_process.stdout,
667*6777b538SAndroid Build Coastguard Worker                                                 preexec_fn=os.setpgrp,
668*6777b538SAndroid Build Coastguard Worker                                                 stdout=ash_symbolize_stdout,
669*6777b538SAndroid Build Coastguard Worker                                                 stderr=subprocess.STDOUT)
670*6777b538SAndroid Build Coastguard Worker        # Allow ash_process to receive a SIGPIPE if symbolize process exits.
671*6777b538SAndroid Build Coastguard Worker        ash_process.stdout.close()
672*6777b538SAndroid Build Coastguard Worker
673*6777b538SAndroid Build Coastguard Worker      ash_process_has_started = _WaitForAshChromeToStart(
674*6777b538SAndroid Build Coastguard Worker          tmp_xdg_dir_name, lacros_mojo_socket_file, enable_mojo_crosapi,
675*6777b538SAndroid Build Coastguard Worker          ash_ready_file)
676*6777b538SAndroid Build Coastguard Worker      if ash_process_has_started:
677*6777b538SAndroid Build Coastguard Worker        break
678*6777b538SAndroid Build Coastguard Worker
679*6777b538SAndroid Build Coastguard Worker      logging.warning('Starting ash-chrome timed out after %ds',
680*6777b538SAndroid Build Coastguard Worker                      ASH_CHROME_TIMEOUT_SECONDS)
681*6777b538SAndroid Build Coastguard Worker      logging.warning('Are you using test_ash_chrome?')
682*6777b538SAndroid Build Coastguard Worker      logging.warning('Printing the output of "ps aux" for debugging:')
683*6777b538SAndroid Build Coastguard Worker      subprocess.call(['ps', 'aux'])
684*6777b538SAndroid Build Coastguard Worker      _KillNicely(ash_process)
685*6777b538SAndroid Build Coastguard Worker      _KillNicely(ash_symbolize_process, first_wait_secs=1)
686*6777b538SAndroid Build Coastguard Worker
687*6777b538SAndroid Build Coastguard Worker      # Clean up for retry.
688*6777b538SAndroid Build Coastguard Worker      _ClearDir(tmp_xdg_dir_name)
689*6777b538SAndroid Build Coastguard Worker      _ClearDir(tmp_ash_data_dir_name)
690*6777b538SAndroid Build Coastguard Worker
691*6777b538SAndroid Build Coastguard Worker    if not ash_process_has_started:
692*6777b538SAndroid Build Coastguard Worker      raise RuntimeError('Timed out waiting for ash-chrome to start')
693*6777b538SAndroid Build Coastguard Worker
694*6777b538SAndroid Build Coastguard Worker    ash_elapsed_time = time.monotonic() - ash_start_time
695*6777b538SAndroid Build Coastguard Worker    logging.info('Started ash-chrome in %.3fs on try %d.', ash_elapsed_time,
696*6777b538SAndroid Build Coastguard Worker                 num_tries)
697*6777b538SAndroid Build Coastguard Worker
698*6777b538SAndroid Build Coastguard Worker    # Starts tests.
699*6777b538SAndroid Build Coastguard Worker    if enable_mojo_crosapi:
700*6777b538SAndroid Build Coastguard Worker      forward_args.append(lacros_mojo_socket_arg)
701*6777b538SAndroid Build Coastguard Worker
702*6777b538SAndroid Build Coastguard Worker    forward_args.append('--ash-chrome-path=' + ash_chrome_file)
703*6777b538SAndroid Build Coastguard Worker    forward_args.append('--unique-ash-dir=' + tmp_unique_ash_dir_name)
704*6777b538SAndroid Build Coastguard Worker
705*6777b538SAndroid Build Coastguard Worker    test_env = os.environ.copy()
706*6777b538SAndroid Build Coastguard Worker    test_env['WAYLAND_DISPLAY'] = ash_wayland_socket_name
707*6777b538SAndroid Build Coastguard Worker    test_env['EGL_PLATFORM'] = 'surfaceless'
708*6777b538SAndroid Build Coastguard Worker    test_env['XDG_RUNTIME_DIR'] = tmp_xdg_dir_name
709*6777b538SAndroid Build Coastguard Worker
710*6777b538SAndroid Build Coastguard Worker    if run_tests_in_debugger:
711*6777b538SAndroid Build Coastguard Worker      test_process = _LaunchDebugger(args, forward_args, test_env)
712*6777b538SAndroid Build Coastguard Worker    else:
713*6777b538SAndroid Build Coastguard Worker      logging.info('Starting test process.')
714*6777b538SAndroid Build Coastguard Worker      test_process = subprocess.Popen([args.command] + forward_args,
715*6777b538SAndroid Build Coastguard Worker                                      env=test_env,
716*6777b538SAndroid Build Coastguard Worker                                      stdout=test_stdout,
717*6777b538SAndroid Build Coastguard Worker                                      stderr=subprocess.STDOUT)
718*6777b538SAndroid Build Coastguard Worker      if should_symbolize:
719*6777b538SAndroid Build Coastguard Worker        logging.info('Symbolizing test logs with asan symbolizer.')
720*6777b538SAndroid Build Coastguard Worker        test_symbolize_process = subprocess.Popen([_ASAN_SYMBOLIZER_PATH],
721*6777b538SAndroid Build Coastguard Worker                                                  stdin=test_process.stdout)
722*6777b538SAndroid Build Coastguard Worker        # Allow test_process to receive a SIGPIPE if symbolize process exits.
723*6777b538SAndroid Build Coastguard Worker        test_process.stdout.close()
724*6777b538SAndroid Build Coastguard Worker    return test_process.wait()
725*6777b538SAndroid Build Coastguard Worker
726*6777b538SAndroid Build Coastguard Worker  finally:
727*6777b538SAndroid Build Coastguard Worker    _KillNicely(ash_process)
728*6777b538SAndroid Build Coastguard Worker    # Give symbolizer processes time to finish writing with first_wait_secs.
729*6777b538SAndroid Build Coastguard Worker    _KillNicely(ash_symbolize_process, first_wait_secs=1)
730*6777b538SAndroid Build Coastguard Worker    _KillNicely(test_symbolize_process, first_wait_secs=1)
731*6777b538SAndroid Build Coastguard Worker
732*6777b538SAndroid Build Coastguard Worker    shutil.rmtree(tmp_xdg_dir_name, ignore_errors=True)
733*6777b538SAndroid Build Coastguard Worker    shutil.rmtree(tmp_ash_data_dir_name, ignore_errors=True)
734*6777b538SAndroid Build Coastguard Worker    shutil.rmtree(tmp_unique_ash_dir_name, ignore_errors=True)
735*6777b538SAndroid Build Coastguard Worker
736*6777b538SAndroid Build Coastguard Worker
737*6777b538SAndroid Build Coastguard Workerdef _RunTestDirectly(args, forward_args):
738*6777b538SAndroid Build Coastguard Worker  """Runs tests by invoking the test command directly.
739*6777b538SAndroid Build Coastguard Worker
740*6777b538SAndroid Build Coastguard Worker  args (dict): Args for this script.
741*6777b538SAndroid Build Coastguard Worker  forward_args (list): Args to be forwarded to the test command.
742*6777b538SAndroid Build Coastguard Worker  """
743*6777b538SAndroid Build Coastguard Worker  try:
744*6777b538SAndroid Build Coastguard Worker    p = None
745*6777b538SAndroid Build Coastguard Worker    p = subprocess.Popen([args.command] + forward_args)
746*6777b538SAndroid Build Coastguard Worker    return p.wait()
747*6777b538SAndroid Build Coastguard Worker  finally:
748*6777b538SAndroid Build Coastguard Worker    _KillNicely(p)
749*6777b538SAndroid Build Coastguard Worker
750*6777b538SAndroid Build Coastguard Worker
751*6777b538SAndroid Build Coastguard Workerdef _HandleSignal(sig, _):
752*6777b538SAndroid Build Coastguard Worker  """Handles received signals to make sure spawned test process are killed.
753*6777b538SAndroid Build Coastguard Worker
754*6777b538SAndroid Build Coastguard Worker  sig (int): An integer representing the received signal, for example SIGTERM.
755*6777b538SAndroid Build Coastguard Worker  """
756*6777b538SAndroid Build Coastguard Worker  logging.warning('Received signal: %d, killing spawned processes', sig)
757*6777b538SAndroid Build Coastguard Worker
758*6777b538SAndroid Build Coastguard Worker  # Don't do any cleanup here, instead, leave it to the finally blocks.
759*6777b538SAndroid Build Coastguard Worker  # Assumption is based on https://docs.python.org/3/library/sys.html#sys.exit:
760*6777b538SAndroid Build Coastguard Worker  # cleanup actions specified by finally clauses of try statements are honored.
761*6777b538SAndroid Build Coastguard Worker
762*6777b538SAndroid Build Coastguard Worker  # https://tldp.org/LDP/abs/html/exitcodes.html:
763*6777b538SAndroid Build Coastguard Worker  # Exit code 128+n -> Fatal error signal "n".
764*6777b538SAndroid Build Coastguard Worker  sys.exit(128 + sig)
765*6777b538SAndroid Build Coastguard Worker
766*6777b538SAndroid Build Coastguard Worker
767*6777b538SAndroid Build Coastguard Workerdef _ExpandFilterFileIfNeeded(test_target, forward_args):
768*6777b538SAndroid Build Coastguard Worker  if (test_target in _DEFAULT_FILTER_FILES_MAPPING.keys() and not any(
769*6777b538SAndroid Build Coastguard Worker      [arg.startswith('--test-launcher-filter-file') for arg in forward_args])):
770*6777b538SAndroid Build Coastguard Worker    file_path = os.path.abspath(
771*6777b538SAndroid Build Coastguard Worker        os.path.join(os.path.dirname(__file__), '..', '..', 'testing',
772*6777b538SAndroid Build Coastguard Worker                     'buildbot', 'filters',
773*6777b538SAndroid Build Coastguard Worker                     _DEFAULT_FILTER_FILES_MAPPING[test_target]))
774*6777b538SAndroid Build Coastguard Worker    forward_args.append(f'--test-launcher-filter-file={file_path}')
775*6777b538SAndroid Build Coastguard Worker
776*6777b538SAndroid Build Coastguard Worker
777*6777b538SAndroid Build Coastguard Workerdef _RunTest(args, forward_args):
778*6777b538SAndroid Build Coastguard Worker  """Runs tests with given args.
779*6777b538SAndroid Build Coastguard Worker
780*6777b538SAndroid Build Coastguard Worker  args (dict): Args for this script.
781*6777b538SAndroid Build Coastguard Worker  forward_args (list): Args to be forwarded to the test command.
782*6777b538SAndroid Build Coastguard Worker
783*6777b538SAndroid Build Coastguard Worker  Raises:
784*6777b538SAndroid Build Coastguard Worker      RuntimeError: If the given test binary doesn't exist or the test runner
785*6777b538SAndroid Build Coastguard Worker          doesn't know how to run it.
786*6777b538SAndroid Build Coastguard Worker  """
787*6777b538SAndroid Build Coastguard Worker
788*6777b538SAndroid Build Coastguard Worker  if not os.path.isfile(args.command):
789*6777b538SAndroid Build Coastguard Worker    raise RuntimeError('Specified test command: "%s" doesn\'t exist' %
790*6777b538SAndroid Build Coastguard Worker                       args.command)
791*6777b538SAndroid Build Coastguard Worker
792*6777b538SAndroid Build Coastguard Worker  test_target = os.path.basename(args.command)
793*6777b538SAndroid Build Coastguard Worker  _ExpandFilterFileIfNeeded(test_target, forward_args)
794*6777b538SAndroid Build Coastguard Worker
795*6777b538SAndroid Build Coastguard Worker  # |_TARGETS_REQUIRE_ASH_CHROME| may not always be accurate as it is updated
796*6777b538SAndroid Build Coastguard Worker  # with a best effort only, therefore, allow the invoker to override the
797*6777b538SAndroid Build Coastguard Worker  # behavior with a specified ash-chrome version, which makes sure that
798*6777b538SAndroid Build Coastguard Worker  # automated CI/CQ builders would always work correctly.
799*6777b538SAndroid Build Coastguard Worker  requires_ash_chrome = any(
800*6777b538SAndroid Build Coastguard Worker      re.match(t, test_target) for t in _TARGETS_REQUIRE_ASH_CHROME)
801*6777b538SAndroid Build Coastguard Worker  if not requires_ash_chrome and not args.ash_chrome_version:
802*6777b538SAndroid Build Coastguard Worker    return _RunTestDirectly(args, forward_args)
803*6777b538SAndroid Build Coastguard Worker
804*6777b538SAndroid Build Coastguard Worker  return _RunTestWithAshChrome(args, forward_args)
805*6777b538SAndroid Build Coastguard Worker
806*6777b538SAndroid Build Coastguard Worker
807*6777b538SAndroid Build Coastguard Workerdef Main():
808*6777b538SAndroid Build Coastguard Worker  for sig in (signal.SIGTERM, signal.SIGINT):
809*6777b538SAndroid Build Coastguard Worker    signal.signal(sig, _HandleSignal)
810*6777b538SAndroid Build Coastguard Worker
811*6777b538SAndroid Build Coastguard Worker  logging.basicConfig(level=logging.INFO)
812*6777b538SAndroid Build Coastguard Worker  arg_parser = argparse.ArgumentParser()
813*6777b538SAndroid Build Coastguard Worker  arg_parser.usage = __doc__
814*6777b538SAndroid Build Coastguard Worker
815*6777b538SAndroid Build Coastguard Worker  subparsers = arg_parser.add_subparsers()
816*6777b538SAndroid Build Coastguard Worker
817*6777b538SAndroid Build Coastguard Worker  test_parser = subparsers.add_parser('test', help='Run tests')
818*6777b538SAndroid Build Coastguard Worker  test_parser.set_defaults(func=_RunTest)
819*6777b538SAndroid Build Coastguard Worker
820*6777b538SAndroid Build Coastguard Worker  test_parser.add_argument(
821*6777b538SAndroid Build Coastguard Worker      'command',
822*6777b538SAndroid Build Coastguard Worker      help='A single command to invoke the tests, for example: '
823*6777b538SAndroid Build Coastguard Worker      '"./url_unittests". Any argument unknown to this test runner script will '
824*6777b538SAndroid Build Coastguard Worker      'be forwarded to the command, for example: "--gtest_filter=Suite.Test"')
825*6777b538SAndroid Build Coastguard Worker
826*6777b538SAndroid Build Coastguard Worker  version_group = test_parser.add_mutually_exclusive_group()
827*6777b538SAndroid Build Coastguard Worker  version_group.add_argument(
828*6777b538SAndroid Build Coastguard Worker      '--ash-chrome-version',
829*6777b538SAndroid Build Coastguard Worker      type=str,
830*6777b538SAndroid Build Coastguard Worker      help='Version of an prebuilt ash-chrome to use for testing, for example: '
831*6777b538SAndroid Build Coastguard Worker      '"120.0.6099.0", and the version corresponds to the commit position of '
832*6777b538SAndroid Build Coastguard Worker      'commits on the main branch. If not specified, will use the latest '
833*6777b538SAndroid Build Coastguard Worker      'version available')
834*6777b538SAndroid Build Coastguard Worker  version_group.add_argument(
835*6777b538SAndroid Build Coastguard Worker      '--ash-chrome-path',
836*6777b538SAndroid Build Coastguard Worker      type=str,
837*6777b538SAndroid Build Coastguard Worker      help='Path to an locally built ash-chrome to use for testing. '
838*6777b538SAndroid Build Coastguard Worker      'In general you should build //chrome/test:test_ash_chrome.')
839*6777b538SAndroid Build Coastguard Worker
840*6777b538SAndroid Build Coastguard Worker  debugger_group = test_parser.add_mutually_exclusive_group()
841*6777b538SAndroid Build Coastguard Worker  debugger_group.add_argument('--gdb',
842*6777b538SAndroid Build Coastguard Worker                              action='store_true',
843*6777b538SAndroid Build Coastguard Worker                              help='Run the test in GDB.')
844*6777b538SAndroid Build Coastguard Worker  debugger_group.add_argument('--lldb',
845*6777b538SAndroid Build Coastguard Worker                              action='store_true',
846*6777b538SAndroid Build Coastguard Worker                              help='Run the test in LLDB.')
847*6777b538SAndroid Build Coastguard Worker
848*6777b538SAndroid Build Coastguard Worker  # This is for version skew testing. The current CI/CQ builder builds
849*6777b538SAndroid Build Coastguard Worker  # an ash chrome and pass it using --ash-chrome-path. In order to use the same
850*6777b538SAndroid Build Coastguard Worker  # builder for version skew testing, we use a new argument to override
851*6777b538SAndroid Build Coastguard Worker  # the ash chrome.
852*6777b538SAndroid Build Coastguard Worker  test_parser.add_argument(
853*6777b538SAndroid Build Coastguard Worker      '--ash-chrome-path-override',
854*6777b538SAndroid Build Coastguard Worker      type=str,
855*6777b538SAndroid Build Coastguard Worker      help='The same as --ash-chrome-path. But this will override '
856*6777b538SAndroid Build Coastguard Worker      '--ash-chrome-path or --ash-chrome-version if any of these '
857*6777b538SAndroid Build Coastguard Worker      'arguments exist.')
858*6777b538SAndroid Build Coastguard Worker  test_parser.add_argument(
859*6777b538SAndroid Build Coastguard Worker      '--ash-logging-path',
860*6777b538SAndroid Build Coastguard Worker      type=str,
861*6777b538SAndroid Build Coastguard Worker      help='File & path to ash-chrome logging output while running Lacros '
862*6777b538SAndroid Build Coastguard Worker      'browser tests. If not provided, no output will be generated.')
863*6777b538SAndroid Build Coastguard Worker  test_parser.add_argument('--combine-ash-logs-on-bots',
864*6777b538SAndroid Build Coastguard Worker                           action='store_true',
865*6777b538SAndroid Build Coastguard Worker                           help='Whether to combine ash logs on bots.')
866*6777b538SAndroid Build Coastguard Worker  test_parser.add_argument(
867*6777b538SAndroid Build Coastguard Worker      '--asan-symbolize-output',
868*6777b538SAndroid Build Coastguard Worker      action='store_true',
869*6777b538SAndroid Build Coastguard Worker      help='Whether to run subprocess log outputs through the asan symbolizer.')
870*6777b538SAndroid Build Coastguard Worker
871*6777b538SAndroid Build Coastguard Worker  args = arg_parser.parse_known_args()
872*6777b538SAndroid Build Coastguard Worker  if not hasattr(args[0], "func"):
873*6777b538SAndroid Build Coastguard Worker    # No command specified.
874*6777b538SAndroid Build Coastguard Worker    print(__doc__)
875*6777b538SAndroid Build Coastguard Worker    sys.exit(1)
876*6777b538SAndroid Build Coastguard Worker
877*6777b538SAndroid Build Coastguard Worker  return args[0].func(args[0], args[1])
878*6777b538SAndroid Build Coastguard Worker
879*6777b538SAndroid Build Coastguard Worker
880*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
881*6777b538SAndroid Build Coastguard Worker  sys.exit(Main())
882