From 25f07f89ddea82e9e5b2ac9fc930ae429b3c607c Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 15 Aug 2026 20:04:59 -0400 Subject: [PATCH] =?UTF-8?q?fix(tests):=20clear=20the=20SQLite=20pool=20bef?= =?UTF-8?q?ore=20deleting=20the=20secrets=20path-guard=20temp=20dir=20?= =?UTF-8?q?=E2=80=94=20Windows=20sharing=20violation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/GatewayTesting.md | 12 ++++++------ .../SecretsStorePathGuardTests.cs | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/GatewayTesting.md b/docs/GatewayTesting.md index a543d02..8679b12 100644 --- a/docs/GatewayTesting.md +++ b/docs/GatewayTesting.md @@ -557,12 +557,12 @@ real-clock deadlines into failures. ### Two more findings from the 2026-08-15 windev gate - `SecretsStorePathGuardTests.CreateBuilder_AcceptsSecretsStoreOutsideContentRoot_AndCreatesIt` - fails **deterministically on Windows, on `main` as well as on any branch**, so it is not a - signal about the change under test. Creating the builder opens `secrets.db`, and - `Microsoft.Data.Sqlite`'s connection pool keeps the file handle alive past the test body, - so the recursive directory delete in the cleanup hits a still-open file — a sharing - violation Windows enforces and Unix does not. Pre-existing and tracked separately; do not - chase it as a regression. Subtract it from the expected pass count on Windows. + used to fail deterministically on Windows: creating the builder opens `secrets.db`, + `Microsoft.Data.Sqlite`'s connection pool kept the file handle alive past the test body, and + the cleanup's recursive directory delete hit a sharing violation Windows enforces and Unix + does not. The cleanup now clears the SQLite connection pool before deleting the temp + directory (the same pattern as `TempDatabaseDirectory` and `PreHostSecretExpansionTests`), + so the test passes on Windows and macOS alike — count it as a pass on both. - The `StaWaitHelper` timing tests (`WaitForSignalOrMessages_*`) flake on a loaded box with a signature that reads like a broken wait but is not: the helper wakes on *input being present*, so a message posted to the test thread ends the wait early. That is the helper diff --git a/src/ZB.MOM.WW.MxGateway.Tests/Configuration/SecretsStorePathGuardTests.cs b/src/ZB.MOM.WW.MxGateway.Tests/Configuration/SecretsStorePathGuardTests.cs index d5aabcd..44da881 100644 --- a/src/ZB.MOM.WW.MxGateway.Tests/Configuration/SecretsStorePathGuardTests.cs +++ b/src/ZB.MOM.WW.MxGateway.Tests/Configuration/SecretsStorePathGuardTests.cs @@ -100,7 +100,24 @@ public sealed class SecretsStorePathGuardTests finally { Environment.SetEnvironmentVariable(SqlitePathVariable, original); - Directory.Delete(directory, recursive: true); + + // The store runs in WAL mode with connection pooling, so a pooled handle can outlive the + // migration and keep secrets.db (plus its -wal/-shm sidecars) open. Windows refuses to + // delete a directory holding open files where Unix does not, so clear the pool first; + // the catch is belt-and-braces for a sidecar whose handle outlasts even that. + Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools(); + try + { + Directory.Delete(directory, recursive: true); + } + catch (IOException) + { + // Best-effort cleanup of the temp store; a locked file must not fail the test. + } + catch (UnauthorizedAccessException) + { + // Best-effort cleanup of the temp store; a locked file must not fail the test. + } } }