| 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 |