using ClawdDotNet.Core.Storage; using Shouldly; namespace ClawdDotNet.Core.Tests.Storage; /// /// Releasing the pool of one database must leave every other database alone. The tests used /// the process-wide ClearAllPools to clean up, and a test running in parallel lost its /// connection in the middle of opening it — one red run in every few, always another test. /// public sealed class PoolReleaseTests : IDisposable { private readonly string _root = Path.Combine(Path.GetTempPath(), "clawd-tests", "pool-" + Guid.NewGuid().ToString("N")[..8]); public void Dispose() { SqliteStorage.ReleasePooledConnections(_root); try { Directory.Delete(_root, recursive: true); } catch { /* cleaning up is secondary */ } } private static async Task TouchAsync(SqliteStorage storage) => await storage.WriteAsync(async connection => { await using var cmd = connection.CreateCommand(); cmd.CommandText = "INSERT OR REPLACE INTO ToolState (Key, Value) VALUES ('k', 'v')"; await cmd.ExecuteNonQueryAsync(); }, default); [Fact] public async Task Releasing_one_directory_frees_its_files_and_nothing_else() { var first = new SqliteStorage(Path.Combine(_root, "a", "state.db")); var second = new SqliteStorage(Path.Combine(_root, "b", "state.db")); await TouchAsync(first); await TouchAsync(second); SqliteStorage.ReleasePooledConnections(Path.Combine(_root, "a")); // The released database can go — on Windows an open handle would prevent that. Should.NotThrow(() => Directory.Delete(Path.Combine(_root, "a"), recursive: true)); // The other one keeps working, and so does its pool. await TouchAsync(second); await using var connection = await second.OpenConnectionAsync(default); await using var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT Value FROM ToolState WHERE Key = 'k'"; (await cmd.ExecuteScalarAsync()).ShouldBe("v"); } [Fact] public async Task A_database_file_can_be_named_directly() { var path = Path.Combine(_root, "c", "state.db"); await TouchAsync(new SqliteStorage(path)); SqliteStorage.ReleasePooledConnections(path); Should.NotThrow(() => File.Delete(path)); } }