cargo-nextest
Goal
Route the Rust unit/integration/AOT legs of test-all.sh through cargo-nextest for its intra-binary process-per-test scheduling and native machine-readable output, replacing plain cargo test for those legs while keeping cargo test --doc for doctests (nextest cannot run doctests).
Scope distinction (no overlap, no contradiction):
test-all.shALREADY runs every Rust leg in parallel at the LEG level (Phase 2 background&+wait,compiler_repo/test-all.sh:527-564). nextest does NOT add leg-level parallelism — that exists today.- What nextest adds is INTRA-binary process-per-test scheduling: within a single test binary, one slow or hanging
#[test]no longer blocks the rest of that binary’s tests, and a crashing test is isolated to its own process rather than aborting the whole binary’s run. - This is distinct from the LLVM
Context-lock parallelism owned by sectionincremental-and-llvm-parallelism(s-… — LLVM-backendori testworker scheduling). That section parallelizes the Ori-LLVM leg; this section parallelizes within the Rust-cargo legs. The two do not touch the same code.
Implementation Sketch
The naive swap — replacing each cargo test ... call with cargo nextest run ... — is NOT correct and reintroduces a known race. test-all.sh deliberately splits into two phases (compiler_repo/test-all.sh:480-564):
- Phase 1 (serial,
compiler_repo/test-all.sh:482):cargo test --no-run -q --workspace --lib --bins --testspre-builds ALL debug test binaries serially, plus theoric/ori_rtbuilds (L492) and the LLVM release build (L499). - Phase 2 (parallel,
compiler_repo/test-all.sh:527-564): everyrun_rust_*function is RUN-ONLY — it executes the already-built binaries and never compiles into the sharedtarget/. This is what prevents thefailed to write ...rmeta: No such file (os error 2)build-artifact race (documented atcompiler_repo/test-all.sh:475-476) that concurrent compiling cargo invocations trigger.
A bare cargo nextest run COMPILES if anything is stale, so dropping it into Phase 2 reintroduces exactly that race. The correct shape preserves the pre-build/run split:
-
Phase 1 (serial pre-build): build the nextest binaries ONCE via
cargo nextest archive --archive-file build/nextest-archive.tar.zst --workspace --exclude ori_llvm --lib --bins --tests(plus the per-leg selectors forori_rt,ori_llvm --lib,ori_llvm --test aot), guarded oncommand -v cargo-nextest.archiveis nextest’s build-once-run-many mechanism (cargo nextest runhas NO--no-buildflag — the archive IS how compilation is hoisted out of the run phase). When cargo-nextest is absent, keep the existingcargo test --no-runpre-build unchanged. -
Phase 2 (run-only): rewrite
run_rust_workspace(compiler_repo/test-all.sh:161),run_rust_rt(:190),run_rust_llvm(:201), andrun_aot(:214) to callcargo nextest run --no-fail-fast --archive-file build/nextest-archive.tar.zst <same leg partition>when cargo-nextest is present —--archive-fileruns the pre-built archive with ZERO compilation (the true run-only step that preserves the race-free split), falling back to the currentcargo_race_retry "$OUTPUT" test <selector>wrapper form (retry-on-rmeta-race preserved) when absent.--no-fail-fastkeeps full-suite-run semantics (no leg aborts early on first failure). -
Leave
run_rust_doctests(compiler_repo/test-all.sh:175) oncargo test --workspace --docunchanged — nextest cannot run doctests, and the harness already documents this as the lone compiling invocation of Phase 2 (compiler_repo/test-all.sh:177-180). -
Summary parsing:
parse_rust_results(compiler_repo/test-all.sh:319-330) scrapes plaincargo test’s human^test result:lines via grep/sed/awk. cargo-nextest’s human summary uses a different shape (Summary [...] N tests run: N passed ...), so the existing parser returns zeros for nextest legs. The fix consumes nextest’s machine output instead: run withcargo nextest run --message-format libtest-json(libtest-compatible JSON, stable across nextest’sNEXTEST_EXPERIMENTAL_LIBTEST_JSONsurface) OR parse nextest’s own summary line, and route the per-leg counts into the same${prefix}_{PASSED,FAILED,IGNORED}variablesparse_rust_resultsalready populates. The doctest leg keeps the existingcargo test --docparse path.Two boundary constraints on this parse-path change:
- BUG-07-241 (live parse-path correctness gap): the existing
parse_rust_resultsscrape carries an open correctness gap tracked as BUG-07-241; the nextest libtest-json consumer added here is a SEPARATE machine-output path for the four nextest legs and MUST NOT inherit the text-scrape’s gap. Whichever path is active (nextest-json when present, the existing text scrape on fallback), a parse failure / unrecognized shape sets a HARD-failure sentinel + non-zero exit (never silent zero) — the same parse-error contract s-bec662fc established for the Ori runner. This section’s parse change is scoped to the Rust-leg nextest path only; it does NOT reach into the BUG-07-241 cargo-text-scrape fix (that remains its own tracked work). - Boundary vs s-5494ed74
w-1b3d6409: the metrics-ledger section’s deferredw-1b3d6409(“migrate parse_rust_results tocargo test --message-format json”) targets the CARGO text path; this section adds the NEXTEST libtest-json path. The two COEXIST (different runners, different machine formats) — this section does NOT subsumew-1b3d6409; both feed the same${prefix}_*vars via distinct parse branches selected bycommand -v cargo-nextest.
- BUG-07-241 (live parse-path correctness gap): the existing
No test is dropped: the same --workspace --exclude ori_llvm --lib --bins --tests, -p ori_rt, -p ori_llvm --lib, and -p ori_llvm --test aot selectors are preserved; only the runner and the summary-parse path for those four legs change.
Spec References
compiler_repo/test-all.sh:
run_rust_workspace—compiler_repo/test-all.sh:161run_rust_doctests—compiler_repo/test-all.sh:175(kept oncargo test --doc)run_rust_rt—compiler_repo/test-all.sh:190run_rust_llvm—compiler_repo/test-all.sh:201run_aot—compiler_repo/test-all.sh:214- Phase 1 serial pre-build —
compiler_repo/test-all.sh:480-503 - Phase 2 parallel run-only —
compiler_repo/test-all.sh:507-564 - rmeta build-artifact race rationale —
compiler_repo/test-all.sh:475-479 parse_rust_resultssummary parser —compiler_repo/test-all.sh:319-330
cargo-nextest docs: process-per-test execution model; cargo nextest archive --archive-file build-once-run-many (nextest has NO --no-build run flag); libtest-json machine output (NEXTEST_EXPERIMENTAL_LIBTEST_JSON).
Success Criteria
- [sc-187d8596]
test-all.shroutes the Rust unit (run_rust_workspace,compiler_repo/test-all.sh:161), runtime (run_rust_rt,:190), LLVM-lib (run_rust_llvm,:201), and AOT (run_aot,:214) legs throughcargo nextest run --archive-filewhencommand -v cargo-nextestsucceeds, falling back tocargo testwhen it does not, withrun_rust_doctests(:175) left oncargo test --doc. - The nextest run-only invocations live in Phase 2 (
compiler_repo/test-all.sh:507-564) and their compilation is hoisted into the Phase 1 serial pre-build (compiler_repo/test-all.sh:480-503) viacargo nextest archive --archive-file(Phase 1) consumed bycargo nextest run --archive-file(Phase 2 — zero compilation at run time), preserving the race-free pre-build/run split — verified by a full./test-all.shrun completing with NOfailed to write ...rmetaerror and NO suite CRASHED/ERR leg. - The harness summary reports per-leg PASSED/FAILED/IGNORED counts for the nextest legs equal to the counts the
cargo testpath reported before the swap (no test dropped, no count silently zeroed). Two granularities verify this: (a) the deterministicsc-187d8596probe assertscargo test --listcount ==cargo nextest listcount across the changed legs (no full run needed); (b) the L12 production-entry-point evidence is a full./test-all.shrun whosecompiler_repo/build/test-all-summary.jsonRust-leg totals match the pre-swap run on the same HEAD. The probe is the cheap per-leg gate; the live test-all run is the four-leg L12 confirmation. - With cargo-nextest uninstalled (or PATH-masked),
./test-all.shfalls back to the existingcargo testlegs and produces identical pass/fail verdicts — verified by a fallback-path run.
Work Items
- Route the Rust unit/integration/AOT legs through cargo-nextest with a guarded
command -v cargo-nextestfallback tocargo test, preserving the Phase 1 serial pre-build / Phase 2 run-only split via nextest’s build-once-run-many archive (Phase 1cargo nextest archive --archive-file build/nextest-archive.tar.zst, Phase 2cargo nextest run --archive-file ...= zero-compile run-only; nextest has NO--no-buildrun flag), keepingrun_rust_doctestsoncargo test --doc, and consuming nextest’s libtest-json machine output soparse_rust_resultsreports correct per-leg counts (the nextest parse path enforces the hard-failure-sentinel parse-error contract, scoped separate from the BUG-07-241 cargo-text-scrape gap, COEXISTing with s-5494ed74 w-1b3d6409). Anchors:compiler_repo/test-all.sh:161,175,190,201,214,319-330,480-564.