From 30325a93bbe9b90e0b8f5ab88b7057dae668df1c Mon Sep 17 00:00:00 2001 From: Widthdom Date: Sun, 2 Aug 2026 08:05:40 +0900 Subject: [PATCH] Isolate unreadable marker fixture from test outputs (#5019) --- TESTING_GUIDE.md | 2 ++ changelog.d/unreleased/5019.internal.md | 16 ++++++++++++++++ tests/CodeIndex.Tests/McpServerToolsCallTests.cs | 6 ++++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 changelog.d/unreleased/5019.internal.md diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md index 1eeaf64d9..1ba77abc5 100644 --- a/TESTING_GUIDE.md +++ b/TESTING_GUIDE.md @@ -765,6 +765,7 @@ Use the inventory below before adding or moving a test class: - Separate pure `ProcessStartInfo` construction contracts from subprocess-environment filtering tests; only the latter mutate the parent process environment and require the non-parallel collection. - Keep freshness diagnostic classification parallel; isolate only the stamped-case probe test that temporarily replaces `GitHelper` and `FileIndexer` test hooks. - Production source-policy scans for direct environment access are read-only and parallel-safe; isolate the separate `CdidxEnvironment` mutation contract that changes a real process variable. +- Fixtures that intentionally make a directory unreadable must own a unique `TestProjectHelper.CreateTempProject(...)` workspace outside the repository and test output trees. Default multi-target runs can execute target frameworks concurrently, so placing such a fixture under `bin` or `obj` can break another target's read-only source-policy scan before build-output filtering is applied (#5019). - Dependency-boundary source audits are also read-only and parallel-safe. Keep the CLI command metadata and config-source resolution assertions in the ordinary collection so changes that reconnect rendering, command routing, config loading, and environment access fail without adding process-global test state. - The reflection-only SQLite collection registration contract is parallel-safe; keep only fixture lifecycle tests that replace the global pool-clear callback in the sensitive collection. - Isolate config CLI cases that change current directory or real environment variables; ordinary config parsing and validation uses injected environment readers and independent temporary roots, so the main suite remains parallelizable. @@ -1718,6 +1719,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests" - pure な `ProcessStartInfo` construction contract と subprocess environment filtering test を分離する。parent process environment を変更して non-parallel collection が必要なのは後者だけである。 - freshness diagnostic classification は parallel 実行し、`GitHelper` / `FileIndexer` test hook を一時的に置き換える stamped-case probe test だけを隔離する。 - production source の direct environment access policy scan は read-only で parallel-safe である。実 process variable を変更する別の `CdidxEnvironment` mutation contract だけを隔離する。 +- directory を意図的に unreadable にする fixture は、repository と test output tree の外側にある一意な `TestProjectHelper.CreateTempProject(...)` workspace を所有する。default の multi-target 実行では target framework が並列に動くため、この種の fixture を `bin` / `obj` 配下に置くと、build-output filter が適用される前に別 target の read-only source-policy scan を失敗させる可能性がある (#5019)。 - dependency boundary の source audit も read-only で parallel-safe である。CLI command metadata と config-source resolution の assertion は通常の collection に置き、rendering、command routing、config loading、environment access を再接続する変更が process-global test state を追加せず失敗するようにする。 - reflection だけを行う SQLite collection registration contract は parallel-safe である。global pool-clear callback を置き換える fixture lifecycle test だけを sensitive collection に残す。 - current directory または実 environment variable を変更する config CLI case を隔離する。通常の config parse / validation は注入された environment reader と独立 temporary root を使うため、main suite は parallel 実行可能に保つ。 diff --git a/changelog.d/unreleased/5019.internal.md b/changelog.d/unreleased/5019.internal.md new file mode 100644 index 000000000..877626a6b --- /dev/null +++ b/changelog.d/unreleased/5019.internal.md @@ -0,0 +1,16 @@ +--- +category: internal +issues: + - 5019 +affected: + - tests/CodeIndex.Tests/McpServerToolsCallTests.cs + - TESTING_GUIDE.md +--- + +## English + +- **Unreadable marker fixtures no longer interfere with concurrent target-framework tests (#5019)** — the MCP marker-fingerprint fixture now uses an isolated temporary workspace outside repository build outputs, so a source-policy scan in another target framework cannot recurse into its intentionally unreadable directory. + +## 日本語 + +- **読取不能な marker fixture が target framework 間の並列テストへ干渉しないようになりました (#5019)** — MCP の marker-fingerprint fixture を repository の build output 外にある独立した一時 workspace へ移し、別 target framework の source-policy scan が意図的に unreadable にした directory へ再帰進入しないようにしました。 diff --git a/tests/CodeIndex.Tests/McpServerToolsCallTests.cs b/tests/CodeIndex.Tests/McpServerToolsCallTests.cs index 5aa622f94..d3c263cac 100644 --- a/tests/CodeIndex.Tests/McpServerToolsCallTests.cs +++ b/tests/CodeIndex.Tests/McpServerToolsCallTests.cs @@ -13407,10 +13407,10 @@ public void ToolsCall_Index_Rebuild_IgnoresUnreadableDirectoriesWhenCollectingMa if (OperatingSystem.IsWindows()) return; - var fixtureDir = Path.Combine(Path.GetFullPath("."), $"mcp_index_unreadable_marker_{Guid.NewGuid():N}"); - Directory.CreateDirectory(fixtureDir); + var fixtureDir = TestProjectHelper.CreateTempProject("mcp_index_unreadable_marker"); var dbPath = TestProjectHelper.CreateTempDbPath("cdidx_mcp_index_unreadable_marker"); var unreadableDir = Path.Combine(fixtureDir, "secret"); + var originalCurrentDirectory = Environment.CurrentDirectory; UnixFileMode? originalMode = null; try { @@ -13421,6 +13421,7 @@ public void ToolsCall_Index_Rebuild_IgnoresUnreadableDirectoriesWhenCollectingMa originalMode = File.GetUnixFileMode(unreadableDir); File.SetUnixFileMode(unreadableDir, UnixFileMode.None); + Environment.CurrentDirectory = fixtureDir; using var server = new McpServer(dbPath, ConsoleUi.LoadVersion()); var request = new JsonObject { @@ -13444,6 +13445,7 @@ public void ToolsCall_Index_Rebuild_IgnoresUnreadableDirectoriesWhenCollectingMa } finally { + Environment.CurrentDirectory = originalCurrentDirectory; if (originalMode.HasValue && Directory.Exists(unreadableDir)) File.SetUnixFileMode(unreadableDir, originalMode.Value); TestProjectHelper.DeleteSqliteDatabaseFiles(dbPath);