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. + } } }