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