Commit a969fa4
feat(test): stream, time and bound
* feat(test): stream, time and bound `mcpp test` (2026.8.1.1)
`mcpp test --workspace` did not report time, did not set a deadline, and did
not flush. The three compound: a macOS CI lane spent 45 minutes in it, was
killed by the job timeout, and left a log containing not one line of mcpp's own
output — only the test binaries', which are separate processes that flush at
their own exit. Attributing the stall meant reverse-engineering log timestamps.
stdout: every status line was a bare std::println with no flush anywhere, and
the repo had no setvbuf — so *when* output became visible was decided by each
platform's libc buffer size, and that number differs everywhere: musl (the
Linux release linkage) hardcodes BUFSIZ = 1024 and ignores st_blksize, Apple
libc takes st_blksize which is 65536 for a pipe, MSVCRT uses 4096 and treats
_IOLBF as _IOFBF. Measured on one 97-member workspace, the same 13 639 bytes of
status output flushed 13 times on Linux and zero times on macOS. Fixed on both
legs (setvbuf in main, ui::flush from every stdout writer): 3 block writes
became 391 line writes.
Timing: the clock started after the package build and the bulk test build, so
`finished in` covered only the per-test loop — one member printed 6.53s against
93.5s actual, and the understatement is worst exactly on the build-heavy
members where the number matters. It now starts before Phase A and reports
`finished in 93.5s (build 87.0s + run 6.5s)`.
Bounds: --timeout only ever covered the test *run*; all three ninja drives had
no deadline at all, which is why a link that never returns could not be stopped
by any --timeout value. Adds --build-timeout (per drive, default 900, POSIX
only) and --workspace-timeout (whole fan-out), and makes --timeout default to
300 — `--timeout 0` still means no limit, it just has to be asked for.
Fan-out: per-member M/N progress, per-test durations, per-member elapsed, a
workspace-level summary and a `slowest:` list.
JSON: the fan-out header used to escape for member #1 and be suppressed from #2
on, because run_tests set the quiet flag itself — one stream, two behaviors,
and a stray non-JSON line. Silenced before the first member instead. Records
are now member-qualified and the stream ends with a workspace_summary.
Also surfaces the one silent platform difference in this path: macOS injects no
runtime library path for test binaries (deliberately — DYLD_LIBRARY_PATH would
reach every executable ninja launches), so a test needing [runtime]
library_dirs fails there with a dyld error naming neither cause nor platform.
Analysis and plan in .agents/docs/2026-07-31-test-workspace-observability-*.md.
* fix(main): move the stdout buffering call into mcpp.ui
`module;` opens a global module fragment, which is only legal in a module unit.
main.cpp is not one, so the fragment introduced for <cstdio> made it ill-formed:
GCC accepted it silently, Clang rejected it outright ("missing 'module'
declaration at end of global module fragment") and every macOS job — where the
toolchain is Clang — failed to build.
The policy belongs in mcpp.ui anyway: that module already owns "when does output
become visible", already has a legitimate global module fragment for <cstdio>,
and already exports flush() for the Windows half of the same guarantee.
Verified by building mcpp with llvm@22.1.8 locally, not just gcc — the class of
bug this was is invisible to a single-compiler check.
* fix(ui): do not call setvbuf on Windows — size 0 aborts the process
The UCRT documents setvbuf's size as `2 <= size <= INT_MAX`. Zero goes through
the invalid-parameter handler, whose default action terminates the process:
0xC0000409, which git-bash reports as a bare exit 127. The freshly built
mcpp.exe died on `--version` with no output at all, right after a green build —
the same mask mcpp#230 wore.
Passing a real size instead would buy nothing: MSVCRT has no line buffering, it
accepts _IOLBF and treats it as _IOFBF. Windows already gets the guarantee from
ui::flush(), which every stdout-writing function in this module calls and which
`mcpp test`'s result lines now route through. So the platform that cannot do
this cheaply is also the one that does not need it — and its 4096-byte block
was the smallest of the three to begin with.
Line-flushing on Linux re-verified after the change: 421 individual writes for
a 30-member workspace test, versus 3 block writes before this series.
* fix(test): make --build-timeout opt-in, and put the e2e's `requires` on line 2
Two defects in the previous commits, both caught by asking what the change does
to projects that are not this one.
--build-timeout defaulted to 900s. That would have turned slow-but-CORRECT
builds red: one mcpp-index member builds OpenCV from source and measures 1019s
on Linux and 1289s on Windows, so a fifteen-minute ceiling fails it and blames
mcpp. The asymmetry with --timeout is real and measured, not stylistic — a test
binary running over five minutes is unusual, a cold dependency build running
over fifteen is ordinary. How long a build may take is a property of the
project, so the project says it; mcpp only has to make saying it possible, and
that is what was missing. --timeout keeps its 300s default.
178_test_observability.sh carried `# requires: gcc unix-shell` inside the header
block. run_all.sh reads that line with `sed -n '2p'`, so it was inert: the test
ran on Windows, where <unistd.h> does not exist and where the deadline runner
has no kill-by-handle path, and failed for both reasons. Moved to line 2, and
narrowed to `unix-shell` — macOS is the platform this file exists for and it has
no GCC. The fixture's sleep is now <chrono>/<thread> so the fixture can never be
the reason a run fails.
---------
Co-authored-by: sunrisepeak <speakshen@163.com>mcpp test (2026.8.1.1) (#327)1 parent 0547324 commit a969fa4
22 files changed
Lines changed: 1157 additions & 48 deletions
File tree
- .agents/docs
- docs
- zh
- src
- build
- cli
- toolchain
- tests
- e2e
- unit
Lines changed: 106 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
0 commit comments