Skip to content

ci: fail rust_test targets that ran zero tests - #650

Merged
rusty1968 merged 1 commit into
OpenPRoT:mainfrom
EnmanuelParache:zero-test-audit
Nov 3, 2026
Merged

rusty1968 merged 1 commit into
OpenPRoT:mainfrom
EnmanuelParache:zero-test-audit

Conversation

@EnmanuelParache

@EnmanuelParache EnmanuelParache commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Check 2 of #462. Follows #648 (check 1), which has merged.

rust_test reports PASSED when its binary contains no tests, so a target whose sources are stripped by cfg (or that has no tests at all) looks the same as one that ran.

  • ci_tests now passes --build_event_json_file=${BUILD_ROOT}/pw_ci_tests_bep.json, so the Bazel Build Event Protocol (BEP) file lands in pw's output directory (out/ci_tests_config/), not the source tree.
  • New zero_test_audit analyzer in the ci group runs //presubmit:zero_tests after the builds. It reads each rust_test's test.log from the BEP file and fails if the summed test result: ... N passed count is 0 (or no summary line exists).
  • Reading logs from BEP rather than bazel-testlogs: BEP names the log for cached results too, and pw runs bazel with --symlink_prefix=${BUILD_ROOT}/bazel-, so the symlink isn't where one would expect.
  • pw expands ${BUILD_ROOT} only inside a config's own args (not in tool args), canonicalize-flags rejects --run_env, and --client_env does not reach the program. The analyzer therefore has its own config (zero_test_audit_config) whose --run_under=env ZERO_TESTS_BEP=${BUILD_ROOT}/../ci_tests_config/pw_ci_tests_bep.json hands the script the path of ci_tests' build directory. This relies on pw laying out each config's build directory as a sibling under --output-dir.
  • Guards: a BEP stream without buildFinished is rejected as incomplete, and results whose status is not PASSED are skipped, so a target whose tests all failed is not misreported as having run none (Bazel already fails the run for it).
  • A missing file exits 2, so an analyzer that runs before ci_tests fails instead of passing on stale data.
  • Unit tests: //presubmit:zero_tests_test.

Existing zero-test targets. The audit found two with no tests in their crates: //services/pldm:pldm_service_test and //services/spdm/transport-mctp:spdm_transport_mctp_test. They are allowlisted in zero_tests.py for now. Better to delete those targets or add tests; I'd like a maintainer's view.

Tested. CI ran the audit end to end on an earlier revision of this branch: it ran after ci_tests and reported audited 39 rust_test targets, 0 ran zero tests. Locally, ./pw presubmit and the unit tests pass, and ./pw zero_test_audit receives the expanded path. The final squashed and rebased revision has only had the unit tests re-run locally; CI on this PR is its end-to-end run.

Not covered. A stale BEP file left in out/ci_tests_config/ by an earlier local run would be re-read if the analyzer is launched alone. CI starts from a clean tree, so this only affects local runs.

Does not close #462 on its own; together with #648 it covers both checks proposed there.

🤖 Generated with Claude Code

@EnmanuelParache
EnmanuelParache marked this pull request as ready for review November 2, 2026 18:27
@EnmanuelParache

Copy link
Copy Markdown
Contributor Author

@rusty1968 with these changes ci can now detect empty rust tests

ZERO TESTS: //services/pldm:pldm_service_test ran no tests
audited 39 rust_test targets, 2 ran zero tests
ZERO TESTS: //services/spdm/transport-mctp:spdm_transport_mctp_test ran no tests
20261102 18:13:48 ERR [6/6] Finished ==> Recipe: check zero_test_audit (FAIL)
20261102 18:13:48 INF  ╔════════════════════════════════════
20261102 18:13:48 INF  ║
20261102 18:13:48 INF  ║   #1  OK    build ci_tests                 -//third_party/caliptra/... //...
20261102 18:13:48 INF  ║   #2  OK    build ast10x0_qemu_tests       //target/ast10x0/...
20261102 18:13:48 INF  ║   #3  OK    build earlgrey_qemu_tests      //target/earlgrey/...
20261102 18:13:48 INF  ║   #4  OK    build caliptra_emulator_tests  //target/veer/...
20261102 18:13:48 INF  ║   #5  OK    build caliptra_fpga_build      //target/veer/unittest_runner:fpga_test
20261102 18:13:48 INF  ║   #6  FAIL  check zero_test_audit          //presubmit:zero_tests
20261102 18:13:48 INF  ║
20261102 18:13:48 INF  ╚════════════════════════════════════
20261102 18:13:48 INF 
20261102 18:13:48 INF    ▄██████▒░▄▄▄       ██▓  ░██▓
20261102 18:13:48 INF   ▓█▓     ░▒████▄    ▓██▒  ░▓██▒
20261102 18:13:48 INF   ▒████▒   ░▒█▀  ▀█▄  ▒██▒ ▒██░
20261102 18:13:48 INF   ░▓█▒    ░░██▄▄▄▄██ ░██░  ▒██░
20261102 18:13:48 INF   ░▒█░      ▓█   ▓██▒░██░░ ████████▒
20261102 18:13:48 INF    ▒█░      ▒▒   ▓▒█░░▓  ░  ▒░▓  ░
20261102 18:13:48 INF    ░▒        ▒   ▒▒ ░ ▒ ░░  ░ ▒  ░
20261102 18:13:48 INF    ░ ░       ░   ▒    ▒ ░   ░ ░
20261102 18:13:48 INF                  ░  ░ ░       ░  ░
Error: Process completed with exit code 1.

@chrysh chrysh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified the mechanism by running it locally: bazel test --build_event_json_file=... emits targetKind: "rust_test rule", matching _RUST_TEST_KIND exactly, and a fully cached re-run still emits a testResult event naming test.log (with cachedLocally: true), so the docstring's claim about cached results holds. The testResult event also carries a status field, which the second inline comment relies on.

Three comments inline. Two more points that have no line to sit on:

  • The first two commits (bd258d9a4, 11fa722a7) are PR 648, so this diff currently shows both PRs. A rebase once 648 lands trims it to the audit.
  • ${PROJECT_ROOT}/.pw_ci_tests_bep.json puts a build output into the source tree. Nothing breaks today (the root BUILD.bazel declares no glob, and .gitignore covers git), but a path under Bazel's output base would keep the workspace clean.

Comment thread workflows.json Resolved
Comment thread presubmit/zero_tests.py Resolved
Comment thread presubmit/zero_tests.py Resolved
@EnmanuelParache
EnmanuelParache force-pushed the zero-test-audit branch 2 times, most recently from 316d655 to 9ea94de Compare November 3, 2026 14:46
@EnmanuelParache

Copy link
Copy Markdown
Contributor Author

@chrysh thank you for taking the time reviewing these changes. I pushed a few more commits based on your observations.

`rust_test` reports PASSED when its binary contains no tests, so a target
whose sources are stripped by `cfg` (or that has no tests at all) looks the
same as one that ran.

- `ci_tests` writes a Bazel Build Event Protocol file to
  `${BUILD_ROOT}/pw_ci_tests_bep.json`, under pw's output directory rather
  than the source tree.
- New `zero_test_audit` analyzer in the `ci` group runs
  `//presubmit:zero_tests` after the builds. It reads each `rust_test`'s
  `test.log` from the BEP file and fails if the summed
  `test result: ... N passed` count is 0 or no summary line exists. BEP names
  the log for cached results too, and pw moves the `bazel-*` symlinks, so
  `bazel-testlogs` is not used.
- pw expands `${BUILD_ROOT}` only inside a config's own args, so the analyzer
  gets its own config whose `--run_under=env ZERO_TESTS_BEP=...` points at
  the `ci_tests_config` build directory. A missing file exits 2, so an
  analyzer that runs before `ci_tests` fails instead of passing on stale data.
- A BEP stream without `buildFinished` is rejected as incomplete, and results
  whose status is not PASSED are skipped, since Bazel already fails the run
  for them and "0 passed; 5 failed" is not "ran no tests".
- Unit tests: `//presubmit:zero_tests_test`.

`//services/pldm:pldm_service_test` and
`//services/spdm/transport-mctp:spdm_transport_mctp_test` have no tests in
their crates; they are allowlisted until the targets are deleted or given
tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@rusty1968
rusty1968 merged commit 067dd36 into OpenPRoT:main Nov 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A rust_test that compiles to nothing passes CI

3 participants