public void TestConnectionDoesNotLeak() { var applicationName = nameof(TestConnectionDoesNotLeak) + Guid.NewGuid(); var connectionString = new SqlConnectionStringBuilder(ConnectionStringProvider.ConnectionString) { ApplicationName = applicationName, } .ConnectionString; using (ConnectionStringProvider.UseConnectionString(connectionString)) using (var engine = this.CreateEngine()) { var @lock = engine.CreateLock(nameof(TestConnectionDoesNotLeak)); for (var i = 0; i < 30; ++i) { using (@lock.Acquire()) { CountActiveSessions().ShouldEqual(1, this.GetType().Name); } // still alive due to pooling CountActiveSessions().ShouldEqual(1, this.GetType().Name); } } using (var connection = SqlHelpers.CreateConnection(connectionString)) { SqlTestHelper.ClearPool(connection); // checking immediately seems flaky; likely clear pool finishing // doesn't guarantee that SQL will immediately reflect the clear var maxWaitForPoolsToClear = TimeSpan.FromSeconds(5); var stopwatch = Stopwatch.StartNew(); do { var activeCount = CountActiveSessions(); if (activeCount == 0) { return; } Thread.Sleep(25); }while (stopwatch.Elapsed < maxWaitForPoolsToClear); } int CountActiveSessions() { using var connection = SqlHelpers.CreateConnection(ConnectionStringProvider.ConnectionString); connection.Open(); using var command = connection.CreateCommand(); command.CommandText = $@"SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE program_name = '{applicationName}'"; return((int)command.ExecuteScalar()); } }
public void TestIsolationLevelLeakage() { const string IsolationLevelQuery = @" SELECT CASE transaction_isolation_level WHEN 0 THEN 'Unspecified' WHEN 1 THEN 'ReadUncommitted' WHEN 2 THEN 'ReadCommitted' WHEN 3 THEN 'RepeatableRead' WHEN 4 THEN 'Serializable' WHEN 5 THEN 'Snapshot' END AS isolationLevel FROM sys.dm_exec_sessions WHERE session_id = @@SPID"; var connectionString = new SqlConnectionStringBuilder(ConnectionStringProvider.ConnectionString) { ApplicationName = nameof(TestIsolationLevelLeakage), // makes it easy to test for leaks since all connections are the same MaxPoolSize = 1, } .ConnectionString; using (var connection = SqlHelpers.CreateConnection(connectionString)) { SqlTestHelper.ClearPool(connection); } using var engine = new TEngineFactory().Create <TransactionBasedConnectionStringProvider>(); var @lock = engine.CreateLock(nameof(TestIsolationLevelLeakage)); @lock.Acquire().Dispose(); using (var connection = SqlHelpers.CreateConnection(connectionString)) { connection.Open(); using var command = connection.CreateCommand(); command.CommandText = IsolationLevelQuery; command.ExecuteScalar().ShouldEqual(IsolationLevel.ReadCommitted.ToString()); } @lock.AcquireAsync().Result.Dispose(); using (var connection = SqlHelpers.CreateConnection(connectionString)) { connection.Open(); using var command = connection.CreateCommand(); command.CommandText = IsolationLevelQuery; command.ExecuteScalar().ShouldEqual(IsolationLevel.ReadCommitted.ToString()); } }