• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env vpython3
2# Copyright 2015 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Runs a script that can run as an isolate (or not).
6
7If optional argument --isolated-script-test-output=[FILENAME] is passed
8to the script, json is written to that file in the format detailed in
9//docs/testing/json-test-results-format.md.
10
11If optional argument --isolated-script-test-filter=[TEST_NAMES] is passed to
12the script, it should be a  double-colon-separated ("::") list of test names,
13to run just that subset of tests.
14
15This script is intended to be the base command invoked by the isolate,
16followed by a subsequent Python script. It could be generalized to
17invoke an arbitrary executable.
18"""
19
20import argparse
21import json
22import os
23import sys
24import tempfile
25
26import common
27
28# Some harnesses understand the --isolated-script-test arguments
29# directly and prefer that they be passed through.
30KNOWN_ISOLATED_SCRIPT_TEST_RUNNERS = {'run_web_tests.py', 'run_webgpu_cts.py'}
31
32# Known typ test runners this script wraps. They need a different argument name
33# when selecting which tests to run.
34# TODO(dpranke): Detect if the wrapped test suite uses typ better.
35KNOWN_TYP_TEST_RUNNERS = {
36    'metrics_python_tests.py',
37    'monochrome_python_tests.py',
38    'run_blinkpy_tests.py',
39    'run_mac_signing_tests.py',
40    'run_mini_installer_tests.py',
41    'test_suite_all.py',  # //tools/grit:grit_python_unittests
42}
43
44KNOWN_TYP_VPYTHON3_TEST_RUNNERS = {
45    'monochrome_python_tests.py',
46    'run_polymer_tools_tests.py',
47    'test_suite_all.py',  # //tools/grit:grit_python_unittests
48}
49
50# pylint: disable=super-with-arguments
51
52
53class BareScriptTestAdapter(common.BaseIsolatedScriptArgsAdapter):
54
55  def __init__(self):
56    super().__init__()
57    # Arguments that are ignored, but added here because it's easier to ignore
58    # them than to update bot configs to not pass them.
59    common.add_emulator_args(self._parser)
60    self._parser.add_argument('--coverage-dir', type=str, help='Unused')
61    self._parser.add_argument('--use-persistent-shell',
62                              action='store_true',
63                              help='Unused')
64
65
66class IsolatedScriptTestAdapter(common.BaseIsolatedScriptArgsAdapter):
67
68  def generate_sharding_args(self, total_shards, shard_index):
69    # This script only uses environment variable for sharding.
70    del total_shards, shard_index  # unused
71    return []
72
73  def generate_test_also_run_disabled_tests_args(self):
74    return ['--isolated-script-test-also-run-disabled-tests']
75
76  def generate_test_filter_args(self, test_filter_str):
77    return ['--isolated-script-test-filter=%s' % test_filter_str]
78
79  def generate_test_output_args(self, output):
80    return ['--isolated-script-test-output=%s' % output]
81
82  def generate_test_launcher_retry_limit_args(self, retry_limit):
83    return ['--isolated-script-test-launcher-retry-limit=%d' % retry_limit]
84
85  def generate_test_repeat_args(self, repeat_count):
86    return ['--isolated-script-test-repeat=%d' % repeat_count]
87
88
89class TypUnittestAdapter(common.BaseIsolatedScriptArgsAdapter):
90
91  def __init__(self):
92    super(TypUnittestAdapter, self).__init__()
93    self._temp_filter_file = None
94
95  def generate_sharding_args(self, total_shards, shard_index):
96    # This script only uses environment variable for sharding.
97    del total_shards, shard_index  # unused
98    return []
99
100  def generate_test_filter_args(self, test_filter_str):
101    filter_list = common.extract_filter_list(test_filter_str)
102    self._temp_filter_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
103    self._temp_filter_file.write('\n'.join(filter_list))
104    self._temp_filter_file.close()
105    arg_name = 'test-list'
106    if any(r in self.rest_args[0] for r in KNOWN_TYP_TEST_RUNNERS):
107      arg_name = 'file-list'
108
109    return ['--%s=' % arg_name + self._temp_filter_file.name]
110
111  def generate_test_output_args(self, output):
112    return ['--write-full-results-to', output]
113
114  def generate_test_launcher_retry_limit_args(self, retry_limit):
115    return ['--isolated-script-test-launcher-retry-limit=%d' % retry_limit]
116
117  def generate_test_repeat_args(self, repeat_count):
118    return ['--isolated-script-test-repeat=%d' % repeat_count]
119
120  def clean_up_after_test_run(self):
121    if self._temp_filter_file:
122      os.unlink(self._temp_filter_file.name)
123
124  def select_python_executable(self):
125    if any(r in self.rest_args[0] for r in KNOWN_TYP_VPYTHON3_TEST_RUNNERS):
126      return 'vpython3.bat' if sys.platform == 'win32' else 'vpython3'
127    return super(TypUnittestAdapter, self).select_python_executable()
128
129
130def main():
131  parser = argparse.ArgumentParser()
132  parser.add_argument('--script-type', choices=['isolated', 'typ', 'bare'])
133  args, _ = parser.parse_known_args()
134
135  kind = args.script_type
136  if not kind:
137    if any(r in sys.argv[1] for r in KNOWN_ISOLATED_SCRIPT_TEST_RUNNERS):
138      kind = 'isolated'
139    else:
140      kind = 'typ'
141
142  if kind == 'isolated':
143    adapter = IsolatedScriptTestAdapter()
144  elif kind == 'typ':
145    adapter = TypUnittestAdapter()
146  else:
147    adapter = BareScriptTestAdapter()
148  return adapter.run_test()
149
150
151# This is not really a "script test" so does not need to manually add
152# any additional compile targets.
153def main_compile_targets(args):
154  json.dump([], args.output)
155
156
157if __name__ == '__main__':
158  # Conform minimally to the protocol defined by ScriptTest.
159  if 'compile_targets' in sys.argv:
160    funcs = {
161        'run': None,
162        'compile_targets': main_compile_targets,
163    }
164    sys.exit(common.run_script(sys.argv[1:], funcs))
165  sys.exit(main())
166