blob: 4ceaf139970836e5e4d3d9bc7a4015b6bba69783 [file] [log] [blame]
import functools
import pprint
import util
import regen
def startswith(prefix):
return lambda s: s.startswith(prefix)
def endswith(suffix):
return lambda s: s.endswith(suffix)
# List of test groups. Each test group is of the following structure:
# (NAME, (PREDICATES, TARGETS, BUILD COMMAND))
# where:
# - NAME is a name for the group of tests. This name is used to explicitly
# invoke this test group on the command line (e.g. fidldev test foo would
# call fx test on the TARGETS for group foo)
# - PREDICATES is a list of predicates P such that P(file) returns true if the
# test group should run when |file| is changed
# - TARGETS is a list of test names as supported by `fx test`, e.g.
# fully-formed Fuchsia Package URLs, package names, or directories.
# - BUILD COMMAND is any command that should be run prior to running the test
# group. It can be None if no build step is required, and is skipped if the
# --no-build flag is passed in. It currently needs to be a List - run_tests
# needs to be updated to support strings
TEST_GROUPS = [
(
'fidlc', (
[
startswith('zircon/tools/fidl'),
startswith(util.FIDL_TESTDATA_DIR),
startswith(util.goldens_dir('fidlc')),
],
[util.TEST_FIDLC, util.FIDLC_GOLDEN_TEST_TARGET],
util.BUILD_FIDLC_TESTS)),
# it's possible to be more selective on which changes map to which tests,
# but since fidlgen tests are fast to build and run, just do a blanket
# check.
(
'fidlgen', (
[
*[startswith(p) for p in util.ALL_FIDLGEN_DIRS],
startswith(util.FIDL_TESTDATA_DIR)
],
util.FIDLGEN_TEST_TARGETS, None)),
(
'fidldoc', (
[startswith(util.FIDLDOC_DIR), startswith(util.FIDL_TESTDATA_DIR)],
[util.FIDLDOC_DIR], None)),
(
'hlcpp', (
[
startswith(util.goldens_dir('fidlgen_hlcpp')),
endswith('.tables.c.golden'),
startswith(util.HLCPP_RUNTIME),
startswith(util.C_RUNTIME),
], [util.HLCPP_TEST_TARGET], None)),
(
'llcpp', (
[
startswith(util.goldens_dir('fidlgen_llcpp')),
endswith('.tables.c.golden'),
startswith(util.LLCPP_RUNTIME),
startswith(util.C_RUNTIME)
], [util.LLCPP_TEST_TARGET], None)),
(
'c',
(
# normally, changes to the generated bindings are detected by looking at the
# goldens. Since we can't do this for C, we look at the coding table goldens
# and the c_generator instead.
[
endswith('.tables.c.golden'),
startswith('zircon/tools/fidl/include/fidl/c_generator.h'),
startswith('zircon/tools/fidl/lib/c_generator.cc'),
startswith(util.C_RUNTIME),
],
# NOTE: fidl-test should also run, but this script only supports component
# tests
[util.C_TEST_TARGET],
None)),
(
'go', (
[
startswith(util.goldens_dir('fidlgen_go')),
startswith(util.GO_RUNTIME)
],
util.GO_TEST_TARGETS + [util.GO_CONFORMANCE_TEST_TARGET], None)),
(
'rust', (
[
startswith(util.goldens_dir('fidlgen_rust')),
startswith(util.RUST_RUNTIME)
],
[util.RUST_TEST_TARGET], None)),
(
'dart', (
[
startswith(util.goldens_dir('fidlgen_dart')),
startswith(util.DART_RUNTIME)
],
[util.DART_TEST_TARGET], None)),
(
'gidl',
(
[startswith('tools/fidl/gidl')],
[
util.GIDL_TEST_TARGET,
util.GO_CONFORMANCE_TEST_TARGET,
util.HLCPP_CONFORMANCE_TEST_TARGET,
util.LLCPP_CONFORMANCE_TEST_TARGET,
util.RUST_CONFORMANCE_TEST_TARGET,
# dart conformance is bundled into the rest of the tests
util.DART_TEST_TARGET
],
None)),
]
def test_explicit(targets):
""" Return an explicit set of test groups """
tests = []
for name, test in TEST_GROUPS:
if name in targets or 'all' in targets:
tests.append(test)
return tests
def test_changed(changed_files):
""" Return relevant test groups given a set of changed files """
tests = []
for _, test in TEST_GROUPS:
(predicates, _, _) = test
for file_ in changed_files:
if any(p(file_) for p in predicates):
tests.append(test)
return tests
def run_tests(tests, dry_run, interactive, fx_test_args, gtest_filter):
already_built = set()
test_targets = set()
test_fidlc = False
for name, targets, build in tests:
if build is not None and tuple(build) not in already_built:
already_built.add(tuple(build))
util.run(build, dry_run, exit_on_failure=True)
for target in targets:
if target == util.TEST_FIDLC:
test_fidlc = True
else:
test_targets.add(target)
test_targets = list(test_targets)
if interactive:
print('all tests: ')
if test_fidlc:
print(util.TEST_FIDLC)
pprint.pprint(test_targets)
if test_fidlc:
if input('run {}? (Y/n)'.format(util.TEST_FIDLC)) == 'n':
test_fidlc = False
test_targets = interactive_filter(test_targets)
test_targets.sort()
success = True
if test_fidlc:
cmd = util.TEST_FIDLC
if gtest_filter:
cmd += f' --gtest_filter={gtest_filter}'
success = success and util.run(cmd, dry_run)
# print test line that can be copied into a commit message
# the absolute FUCHSIA_DIR paths are stripped for readability and
# because they are user specific
print('Test: ' + cmd.replace(str(util.FUCHSIA_DIR) + '/', ''))
if test_targets:
cmd = ['fx', 'test'] + fx_test_args.split()
# group all tests into a single `fx test` invocation so that the summary
# prints all results
cmd.extend(test_targets)
success = success and util.run(cmd, dry_run)
print('Test: ' + ' '.join(cmd))
return success
def interactive_filter(test_targets):
if not test_targets:
return []
filtered = []
for test in test_targets:
if input('run {}? (Y/n) '.format(test)) == 'n':
continue
filtered.append(test)
return filtered