[rust] Add `rust_unit_tests_group(...)` gni template.
This CL adds a `rust_unit_tests_group(...)` gni template that can
generate a Chromium-bot-friendly script that can run _all_ Rust unit
tests inside the transitive `deps` of the group.
Manual testing:
1. Checking that the tests can be run locally:
$ ninja -C out/rust build/rust/tests
$ out/rust/bin/run_native_rust_unittests__from__build_rust_tests
... the tests execute successfully ...
2. Checking that the tests can be run on the bots in a follow-up CL:
https://crrev.com/c/3322199/6
3. Checking that the runtime_deps are reasonable:
$ gn clean out/rust
$ gn desc out/rust \
build/rust/tests:native_rust_unittests__from__build_rust_tests \
runtime_deps
bin/run_native_rust_unittests__from__build_rust_tests
../../testing/scripts/rust/main_program.py
../../testing/scripts/rust/test_filtering.py
../../testing/scripts/rust/test_results.py
../../testing/scripts/rust/exe_util.py
../../testing/scripts/rust/rust_main_program.py
bin/run_test_mixed_component_rs_unittests
./test_mixed_component_rs_unittests
bin/run_test_mixed_source_set_rs_unittests
./test_mixed_source_set_rs_unittests
bin/run_test_rust_source_set_unittests
./test_rust_source_set_unittests
bin/run_foo_tests
./foo_tests
bin/run_test_rust_unittests
./test_rust_unittests
bin/run_test_variable_source_set_rs_unittests
./test_variable_source_set_rs_unittests
Bug: 1260120
Change-Id: I19a15581ced0da85c6ec50a95016f2a547a43600
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3327603
Reviewed-by: Adrian Taylor <adetaylor@google.com>
Commit-Queue: Ćukasz Anforowicz <lukasza@chromium.org>
Cr-Commit-Position: refs/heads/main@{#953019}
NOKEYCHECK=True
GitOrigin-RevId: 30500c5d5657387d3b4849d349037116c987e7ee
diff --git a/generate_bash_script.py b/generate_bash_script.py
index 86bd564..06414f5 100755
--- a/generate_bash_script.py
+++ b/generate_bash_script.py
@@ -32,19 +32,42 @@
metavar='PATH',
required=True)
- parser.add_argument('--rust-test-executable',
- action='append',
+ parser.add_argument('--rust-test-executables',
dest='rust_test_executables',
- default=[],
- help='One or more executables to wrap. ' \
- '(basename - no extension or directory)',
- metavar='BASENAME',
+ help='File listing one or more executables to wrap. ' \
+ '(basenames - no .exe extension or directory)',
+ metavar='FILEPATH',
required=True)
return parser.parse_args(args=args)
-def _generate_script(args):
+def _find_test_executables(args):
+ exes = set()
+ input_filepath = args.rust_test_executables
+ with open(input_filepath) as f:
+ for line in f:
+ exe_name = line.strip()
+ # TODO(https://crbug.com/1271215): Append ".exe" extension when
+ # *targeting* Windows. (The "targeting" part means that we can't
+ # just detect whether the build is *hosted* on Windows.)
+ if exe_name in exes:
+ raise ValueError("Duplicate entry ('{}') in {}".format(
+ exe_name, input_filepath))
+ exes.add(exe_name)
+ if not exes:
+ raise ValueError("Unexpectedly empty file: {}".format(input_filepath))
+ exes = sorted(exes) # For stable results in unit tests.
+ return exes
+
+
+def _validate_if_test_executables_exist(exes):
+ for exe in exes:
+ if not os.path.isfile(exe):
+ raise ValueError("File not found: {}".format(exe_path))
+
+
+def _generate_script(args, should_validate_if_exes_exist=True):
res = '#!/bin/bash\n'
script_dir = os.path.dirname(args.script_path)
@@ -59,8 +82,12 @@
lib_dir = os.path.normpath(lib_dir)
res += 'LIB_DIR="$SCRIPT_DIR/{}"\n'.format(lib_dir)
+ exes = _find_test_executables(args)
+ if should_validate_if_exes_exist:
+ _validate_if_test_executables_exist(exes)
+
res += 'env vpython3 "$LIB_DIR/rust_main_program.py" \\\n'
- for exe in args.rust_test_executables:
+ for exe in exes:
res += ' "--rust-test-executable=$EXE_DIR/{}" \\\n'.format(exe)
res += ' "$@"'
diff --git a/generate_bash_script_unittests.py b/generate_bash_script_unittests.py
index 89b8119..a81a9fc 100755
--- a/generate_bash_script_unittests.py
+++ b/generate_bash_script_unittests.py
@@ -5,22 +5,24 @@
# found in the LICENSE file.
import os
+from pyfakefs import fake_filesystem_unittest
+import tempfile
import unittest
from generate_bash_script import _parse_args
from generate_bash_script import _generate_script
-class Tests(unittest.TestCase):
+class Tests(fake_filesystem_unittest.TestCase):
def test_parse_args(self):
raw_args = [
'--script-path=./bin/run_foobar', '--exe-dir=.',
- '--rust-test-executable=foo', '--rust-test-executable=bar'
+ '--rust-test-executables=metadata.json'
]
parsed_args = _parse_args(raw_args)
self.assertEqual('./bin/run_foobar', parsed_args.script_path)
self.assertEqual('.', parsed_args.exe_dir)
- self.assertEqual(['foo', 'bar'], parsed_args.rust_test_executables)
+ self.assertEqual('metadata.json', parsed_args.rust_test_executables)
def test_generate_script(self):
lib_dir = os.path.dirname(__file__)
@@ -28,17 +30,29 @@
args = type('', (), {})()
args.script_path = os.path.join(out_dir, 'bin/run_foo_bar')
args.exe_dir = out_dir
- args.rust_test_executables = ['foo', 'bar']
- actual = _generate_script(args)
+ # pylint: disable=unexpected-keyword-arg
+ with tempfile.NamedTemporaryFile(delete=False,
+ mode='w',
+ encoding='utf-8') as f:
+ filepath = f.name
+ f.write("foo\n")
+ f.write("bar\n")
+ try:
+ args.rust_test_executables = filepath
+ actual = _generate_script(args,
+ should_validate_if_exes_exist=False)
+ finally:
+ os.remove(filepath)
+
expected = '''
#!/bin/bash
SCRIPT_DIR=`dirname $0`
EXE_DIR="$SCRIPT_DIR/.."
LIB_DIR="$SCRIPT_DIR/../../../testing/scripts/rust"
env vpython3 "$LIB_DIR/rust_main_program.py" \\
- "--rust-test-executable=$EXE_DIR/foo" \\
"--rust-test-executable=$EXE_DIR/bar" \\
+ "--rust-test-executable=$EXE_DIR/foo" \\
"$@"
'''.strip()
diff --git a/rust_main_program.py b/rust_main_program.py
index ba57b9d..556d797 100644
--- a/rust_main_program.py
+++ b/rust_main_program.py
@@ -124,6 +124,11 @@
Returns:
A list of test_results.TestResult objects.
"""
+ list_of_tests_to_run = _get_exe_specific_tests(
+ self._name_of_test_executable, list_of_tests_to_run)
+ if not list_of_tests_to_run:
+ return []
+
# TODO(lukasza): Avoid passing all test names on the cmdline (might
# require adding support to Rust test executables for reading cmdline
# args from a file).
@@ -134,10 +139,14 @@
self._path_to_test_executable, '--test', '--format=pretty',
'--exact'
]
- list_of_tests_to_run = _get_exe_specific_tests(
- self._name_of_test_executable, list_of_tests_to_run)
args.extend(list_of_tests_to_run)
+
+ print("Running tests from {}...".format(self._name_of_test_executable))
output = exe_util.run_and_tee_output(args)
+ print("Running tests from {}... DONE.".format(
+ self._name_of_test_executable))
+ print()
+
return _scrape_test_results(output, self._name_of_test_executable,
list_of_tests_to_run)
@@ -152,7 +161,7 @@
action='append',
dest='rust_test_executables',
default=[],
- help='Paths to one or more executables to wrap.',
+ help=argparse.SUPPRESS,
metavar='FILEPATH',
required=True)
diff --git a/test_filtering.py b/test_filtering.py
index 2e10c21..a386dd0 100644
--- a/test_filtering.py
+++ b/test_filtering.py
@@ -212,7 +212,8 @@
'a prefix plus a "*" on the end (to form a glob). If the ' \
'string has a "-" at the front, the test (or glob of ' \
'tests) will be skipped, not run.'
- argparse_parser.add_argument('--isolated-script-test-filter',
+ argparse_parser.add_argument('--test-filter',
+ '--isolated-script-test-filter',
action='append',
default=[],
dest='test_filters',
@@ -221,7 +222,8 @@
file_help = 'Path to a file with test filters in Chromium Test List ' \
'Format. See also //testing/buildbot/filters/README.md and ' \
'bit.ly/chromium-test-list-format'
- argparse_parser.add_argument('--isolated-script-test-filter-file',
+ argparse_parser.add_argument('--test-filter-file',
+ '--isolated-script-test-filter-file',
action='append',
default=[],
dest='test_filter_files',