#!/usr/bin/env vpython3 # Copyright 2015 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Runs a script that can run as an isolate (or not). If optional argument --isolated-script-test-output=[FILENAME] is passed to the script, json is written to that file in the format detailed in //docs/testing/json-test-results-format.md. If optional argument --isolated-script-test-filter=[TEST_NAMES] is passed to the script, it should be a double-colon-separated ("::") list of test names, to run just that subset of tests. This script is intended to be the base command invoked by the isolate, followed by a subsequent Python script. It could be generalized to invoke an arbitrary executable. """ import argparse import json import os import pprint import sys import tempfile # Add src/testing/ into sys.path for importing common. sys.path.append( os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) from scripts import common # Some harnesses understand the --isolated-script-test arguments # directly and prefer that they be passed through. KNOWN_ISOLATED_SCRIPT_TEST_RUNNERS = {'run_web_tests.py', 'run_webgpu_cts.py'} # Known typ test runners this script wraps. They need a different argument name # when selecting which tests to run. # TODO(dpranke): Detect if the wrapped test suite uses typ better. KNOWN_TYP_TEST_RUNNERS = { 'metrics_python_tests.py', 'monochrome_python_tests.py', 'run_blinkpy_tests.py', 'run_mac_signing_tests.py', 'run_mini_installer_tests.py', 'test_suite_all.py', # //tools/grit:grit_python_unittests } KNOWN_TYP_VPYTHON3_TEST_RUNNERS = { 'monochrome_python_tests.py', 'run_polymer_tools_tests.py', 'test_suite_all.py', # //tools/grit:grit_python_unittests } # pylint: disable=super-with-arguments class BareScriptTestAdapter(common.BaseIsolatedScriptArgsAdapter): def __init__(self): super().__init__() # Arguments that are ignored, but added here because it's easier to ignore # them than to update bot configs to not pass them. common.add_emulator_args(self._parser) self._parser.add_argument( '--coverage-dir', type=str, help='Unused') self._parser.add_argument( '--use-persistent-shell', action='store_true', help='Unused') class IsolatedScriptTestAdapter(common.BaseIsolatedScriptArgsAdapter): def generate_sharding_args(self, total_shards, shard_index): # This script only uses environment variable for sharding. del total_shards, shard_index # unused return [] def generate_test_also_run_disabled_tests_args(self): return ['--isolated-script-test-also-run-disabled-tests'] def generate_test_filter_args(self, test_filter_str): return ['--isolated-script-test-filter=%s' % test_filter_str] def generate_test_output_args(self, output): return ['--isolated-script-test-output=%s' % output] def generate_test_launcher_retry_limit_args(self, retry_limit): return ['--isolated-script-test-launcher-retry-limit=%d' % retry_limit] def generate_test_repeat_args(self, repeat_count): return ['--isolated-script-test-repeat=%d' % repeat_count] class TypUnittestAdapter(common.BaseIsolatedScriptArgsAdapter): def __init__(self): super(TypUnittestAdapter, self).__init__() self._temp_filter_file = None def generate_sharding_args(self, total_shards, shard_index): # This script only uses environment variable for sharding. del total_shards, shard_index # unused return [] def generate_test_filter_args(self, test_filter_str): filter_list = common.extract_filter_list(test_filter_str) self._temp_filter_file = tempfile.NamedTemporaryFile( mode='w', delete=False) self._temp_filter_file.write('\n'.join(filter_list)) self._temp_filter_file.close() arg_name = 'test-list' if any(r in self.rest_args[0] for r in KNOWN_TYP_TEST_RUNNERS): arg_name = 'file-list' return ['--%s=' % arg_name + self._temp_filter_file.name] def generate_test_output_args(self, output): return ['--write-full-results-to', output] def generate_test_launcher_retry_limit_args(self, retry_limit): return ['--isolated-script-test-launcher-retry-limit=%d' % retry_limit] def generate_test_repeat_args(self, repeat_count): return ['--isolated-script-test-repeat=%d' % repeat_count] def clean_up_after_test_run(self): if self._temp_filter_file: os.unlink(self._temp_filter_file.name) def select_python_executable(self): if any(r in self.rest_args[0] for r in KNOWN_TYP_VPYTHON3_TEST_RUNNERS): return 'vpython3.bat' if sys.platform == 'win32' else 'vpython3' return super(TypUnittestAdapter, self).select_python_executable() def main(): parser = argparse.ArgumentParser() parser.add_argument('--script-type', choices=['isolated', 'typ', 'bare']) args, _ = parser.parse_known_args() kind = args.script_type if not kind: if any(r in sys.argv[1] for r in KNOWN_ISOLATED_SCRIPT_TEST_RUNNERS): kind = 'isolated' else: kind = 'typ' if kind == 'isolated': adapter = IsolatedScriptTestAdapter() elif kind == 'typ': adapter = TypUnittestAdapter() else: adapter = BareScriptTestAdapter() return adapter.run_test() # This is not really a "script test" so does not need to manually add # any additional compile targets. def main_compile_targets(args): json.dump([], args.output) if __name__ == '__main__': # Conform minimally to the protocol defined by ScriptTest. if 'compile_targets' in sys.argv: funcs = { 'run': None, 'compile_targets': main_compile_targets, } sys.exit(common.run_script(sys.argv[1:], funcs)) sys.exit(main())