Repository navigation
docs-tests: fixture robustness + coverage follow-ups from PR #227 ultrareview #238
Description
Follow-up tracker for MEDIUM findings surfaced by the 6-agent Ultrareview of PR #227 (fix/docs-tests-baseline-failures) that were intentionally deferred so the atomic fix (timeout + handle-disposal + stale-doc sync) could ship on its own. Each item is scoped, has a concrete sketch, and is small enough to land as an independent PR.
Robustness
- Node preflight on
RunVitepressBuild.FileName = "node"fails withWin32Exception: No such file or directorywhen node is not on PATH — mirror the vitepress-entry existence check with aProcess.Start("node", "--version")probe that throws an actionableInvalidOperationExceptionpointing at the Node prerequisites indocs/development/docs-site.md. (F-IMP-002) - Concurrent-invocation
dist/lock. Twodotnet testinvocations running in parallel both write todocs/.vitepress/dist/— torn writes / half-empty tree. Guard the producer-mode rebuild with aFileStream(lockPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)ondocs/.vitepress/.build.lockso the second invocation blocks and observes fresh dist. Needs a companion FLOOR test per §1.0d-trigies-novodecies. (F-IMP-003) - Bounded stdout/stderr capture.
ReadToEndAsyncaccumulates the full child output in a single string. A vitepress printing MB of warnings (orphaned pages, missing links) balloons the test host. Cap at ~4 MB viaOutputDataReceivedhandlers writing to a size-cappedStringBuilder. (F-IMP-004)
Ergonomics
- Env-tunable Node memory budget.
--max-old-space-size=8192is hard-coded; make itMTCONNECT_DOCS_NODE_MAX_OLD_SPACE_MB(default 8192) so a constrained CI runner or a larger docs tree can override. (F-IMP-006) - Producer/consumer trace log. Emit
TestContext.Progress.WriteLine($"[docs-tests] mode={(isConsumerShard ? \"consumer\" : \"producer\")} shardTotal={shardTotal} dist-exists={File.Exists(distIndex)}")before the rebuild guard so the decision is visible in CI logs. (F-IMP-007) - Async-Task shape for RunVitepressBuild.
OneTimeSetUpis alreadyasync Task; switchRunVitepressBuildtoasync Task RunVitepressBuildAsyncand useWhenAll+WaitForExitAsyncto stop blocking a threadpool thread. (F-IMP-005)
Simplification
- Extract
RunProcess(fileName, args, workingDirectory, label)helper soRunVitepressBuildandRunNpmshare their concurrent-drain + exit-check + error-format logic. Also lets a future third caller inherit the pipe-deadlock and disposal contracts for free. (F-SIMP-001)
Test coverage
Extract the producer/consumer branching predicate as a pure helper and cover the four-quadrant truth table plus the two RunVitepressBuild failure paths that the XML-doc <exception> block already promises. Concrete tests:
tests/MTConnect.NET-Docs-Tests/RouteCheckHelpers.cs—public static bool ShouldRebuildDist(bool distIndexExists, int shardTotal) => shardTotal <= 1 || !distIndexExists;RouteCheckHelpersTests.cs— sixShouldRebuildDist_*unit tests covering(distExists ∈ {T, F}, shardTotal ∈ {0, 1, 2, 4}).RouteCheckHelpersTests.cs—RunVitepressBuild_MissingEntryPoint_ThrowsWithDiagnosticMessage(reflection-invoke against an empty tempdocsRoot; assert the exception message contains "expected entry point at" AND "npm ci" AND the exactPath.Combineresult).RouteCheckHelpersTests.cs—RunVitepressBuild_NonZeroExit_ThrowsWithCapturedOutput(mkdirnode_modules/vitepress/binunder a temp docsRoot, write avitepress.jsthatconsole.error('oops'); process.exit(2);, assert the exception message containsexited 2,oops,stderr:).RouteCheckTests.cs—OneTimeSetUp_SkipsRebuild_When_Fixture_Is_Consumer_And_Dist_Exists(gated onshardTotal > 1 && File.Exists(distIndex); assertsdistMtime < _fixtureStartTime— dist was untouched by the fixture). Complements the existing producer-mode mtime invariant that goesAssert.Inconclusiveunder shard mode. (F-TEST-001..004)
Provenance
Every bullet cross-references an Ultrareview finding id (F-IMP-, F-SIMP-, F-TEST-*) so the eventual implementation PR can quote the audit rationale rather than re-derive it. The atomic parent PR (#227) closes the four convergent MEDIUM findings around child-process timeout, Process disposal, kill-on-timeout, and the stale npm run build / sentinel-honouring-producer doc references (F-SEC-001, F-SEC-002, F-IMP-001, F-CR-001, F-DOC-001..006) inline.
Activity
harden(docs-tests): bound vitepress build + dispose Process + sync docs
harden(docs-tests): bound vitepress build + dispose Process + sync docs
harden(docs-tests): bound vitepress build + dispose Process + sync docs
harden(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs
fix(docs-tests): bound vitepress build + dispose Process + sync docs