Repository navigation
[AI-1294] Isolate MCP markers from the real ~/.kcap in unit tests - #358
Conversation
The kcap-cli unit suite flaked 1-3x per full parallel run in the MCP-marker/env plugin suites. Root cause: McpMarker's CENTRAL store is the real, process-global ~/.kcap/mcp-markers (via GetFolderPath(UserProfile), which ignores a redirected $HOME/KCAP_CONFIG_DIR). Tests that construct a real McpMarker — the plugin suites, UninstallCommandTests, and McpMarkerTests.Two_configs (unkeyed) — read/write/delete there, and FakeUserHome.Dispose ENUMERATED it to sweep leaked markers. A concurrent create/delete during that enumeration (e.g. Two_configs vs a plugin sweep) is the race; it also pollutes the developer's home. Fix (mirrors DaemonPathsGlobalSetup): add an McpMarker.OverrideCentralRootForTesting seam and pin the central root to a throwaway temp dir for the WHOLE test assembly via McpMarkerGlobalSetup [Before(Assembly)] — no per-test null window that could fall back to the real dir. So no test touches the real shared dir; the cross-suite race is structurally impossible and the real home is no longer polluted. Drop FakeUserHome's now-unnecessary central-marker sweep (the enumerate-shared-dir race) and its per-test override; the one real-resolution marker test no longer needs cleanup. Verified: after a full parallel run the real ~/.kcap/mcp-markers is byte-for-byte untouched (incl dir mtime); full-suite failure count is unchanged vs main (pre-existing local dev-home env collisions, green in CI). De-flake is a parallel-load property, confirmed by the mechanism (nothing touches the shared dir) + CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR Summary by QodoIsolate McpMarker central store from real ~/.kcap during unit tests
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo
1.
|
realtonyyoung
left a comment
There was a problem hiding this comment.
Static API review: one merge-blocking finding posted inline. The MCP-marker isolation and parallel-safety changes themselves look sound.
Code review of the MCP-marker test-isolation change: - [P1, required check] Remove the tracker issue id from the C# comments in McpMarker.cs, FakeUserHome.cs, McpMarkerTests.cs and McpMarkerGlobalSetup.cs — scripts/check-linear-ids.sh (the "No Linear issue IDs in C# source" gate) rejects AI-<digits> under src/** and test/**. The PR description keeps the link. - Trim McpMarkerGlobalSetup's XML doc to the essential rationale. - Cleanup no longer nulls the central-root override before deleting the temp dir: nulling reopened a window where a late/background McpMarker call falls back to the real ~/.kcap. Leaving it pinned means a late call recreates under the (removed) temp root instead. [After(Assembly)] now only deletes the dir. - Mark _centralRootOverride volatile so the [Before(Assembly)] write publishes to every test thread rather than relying on runner lifecycle ordering. check-linear-ids.sh passes; build clean; McpMarkerTests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
realtonyyoung
left a comment
There was a problem hiding this comment.
NO FINDINGS
Problem
The
Capacitor.Cli.Tests.Unitsuite shows 1–3 flaky failures per full parallel run, always in the MCP-marker / env plugin suites (PluginCommand{Cursor,Copilot,Gemini}Tests,McpMarkerTests) — every failing test passes in isolation. Intermittent red CI for the whole team.Root cause
McpMarker's central store is the real, process-global~/.kcap/mcp-markers, resolved viaGetFolderPath(UserProfile)— which ignores a redirected$HOME/KCAP_CONFIG_DIR. So any test that constructs a realMcpMarker(the plugin suites,UninstallCommandTests, andMcpMarkerTests.Two_configs_in_same_dir_have_independent_ownership, which had no[NotInParallel]key) reads/writes/deletes there, andFakeUserHome.Disposeenumerated that dir to sweep leaked markers. A concurrent create/delete during that enumeration — e.g. the unkeyedTwo_configstest racing a plugin suite'sFakeUserHomesweep — is the race. It also pollutes the developer's real~/.kcap.Fix
Mirrors the existing
DaemonPathsGlobalSetuppattern:McpMarker.OverrideCentralRootForTesting(string?)— a test seam for the central.kcaproot (analogous toDaemonLockPaths.OverrideDirectoryForTesting).McpMarkerGlobalSetup([Before(Assembly)]) pins that root to a throwaway temp dir for the whole test assembly, cleaned in[After(Assembly)]. Because it's set once for the process (never a per-testnullwindow), no test touches the real~/.kcap/mcp-markers— the cross-suite race is structurally impossible and the real home is no longer polluted. Marker files are keyed by config-path hash, so parallel tests write distinct files and nothing enumerates the dir.FakeUserHome's now-unnecessary central-marker sweep (the enumerate-shared-dir race) and per-test override; the one real-resolution marker test no longer needs cleanup or its own key.Verification
~/.kcap/mcp-markersis byte-for-byte untouched (incl. directory mtime) — proving no test touches the shared dir, so the race surface is gone.main(the remaining failures are pre-existing local dev-home environment collisions — unrelated home-writing tests — which are green in CI's clean home).Closes AI-1294.
🤖 Generated with Claude Code