154 lines
5.0 KiB
C#
154 lines
5.0 KiB
C#
/*
|
|
* DynamORM - Dynamic Object-Relational Mapping library.
|
|
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
|
* All rights reserved.
|
|
*/
|
|
|
|
using System;
|
|
using System.Data;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using NUnit.Framework;
|
|
|
|
namespace DynamORM.Tests.Helpers
|
|
{
|
|
[TestFixture]
|
|
public class ConnectionPoolingAndLockingTests
|
|
{
|
|
private FakeProviderState _state;
|
|
private DynamicDatabase _db;
|
|
|
|
[TearDown]
|
|
public void TearDown()
|
|
{
|
|
if (_db != null)
|
|
_db.Dispose();
|
|
}
|
|
|
|
[Test]
|
|
public void TestConnectionPoolingReusesIdleConnection()
|
|
{
|
|
CreateDatabase(DynamicDatabaseOptions.ConnectionPooling);
|
|
|
|
using (_db.Open()) { }
|
|
using (_db.Open()) { }
|
|
|
|
Assert.AreEqual(1, _state.CreatedConnections);
|
|
Assert.AreEqual(1, _state.OpenCalls);
|
|
Assert.AreEqual(0, _state.CloseCalls);
|
|
}
|
|
|
|
[Test]
|
|
public void TestConnectionPoolingWaitsForReleasedConnectionWhenAtMaximum()
|
|
{
|
|
CreateDatabase(DynamicDatabaseOptions.ConnectionPooling);
|
|
_db.ConnectionPoolingKeepOpenCount = 1;
|
|
_db.ConnectionPoolingMaximumOpenCount = 1;
|
|
|
|
var first = _db.Open();
|
|
var started = new ManualResetEventSlim(false);
|
|
var completed = new ManualResetEventSlim(false);
|
|
|
|
var task = Task.Run(() =>
|
|
{
|
|
started.Set();
|
|
using (_db.Open()) { }
|
|
completed.Set();
|
|
});
|
|
|
|
Assert.IsTrue(started.Wait(TimeSpan.FromSeconds(2)));
|
|
Assert.IsFalse(completed.Wait(TimeSpan.FromMilliseconds(200)));
|
|
|
|
first.Dispose();
|
|
|
|
Assert.IsTrue(completed.Wait(TimeSpan.FromSeconds(2)));
|
|
task.Wait(TimeSpan.FromSeconds(2));
|
|
Assert.AreEqual(1, _state.CreatedConnections);
|
|
}
|
|
|
|
[Test]
|
|
public void TestConnectionPoolingClosesExpiredIdleConnections()
|
|
{
|
|
CreateDatabase(DynamicDatabaseOptions.ConnectionPooling);
|
|
_db.ConnectionPoolingConnectionLifetime = TimeSpan.Zero;
|
|
|
|
using (_db.Open()) { }
|
|
using (_db.Open()) { }
|
|
|
|
Assert.AreEqual(2, _state.CreatedConnections);
|
|
Assert.GreaterOrEqual(_state.CloseCalls, 1);
|
|
Assert.GreaterOrEqual(_state.DisposeCalls, 1);
|
|
}
|
|
|
|
[Test]
|
|
public void TestDirectTransactionUsesSameThreadConnectionAndSeparateThreadGetsDifferentOne()
|
|
{
|
|
CreateDatabase(DynamicDatabaseOptions.ConnectionPooling);
|
|
|
|
using (var trans = _db.BeginTransaction())
|
|
{
|
|
IDbConnection threadLocalA = _db.Open();
|
|
IDbConnection threadLocalB = _db.Open();
|
|
|
|
try
|
|
{
|
|
Assert.AreSame(((DynamicConnection)threadLocalA).Connection, ((DynamicConnection)threadLocalB).Connection);
|
|
|
|
IDbConnection otherThreadConnection = null;
|
|
var task = Task.Run(() =>
|
|
{
|
|
using (var other = _db.Open())
|
|
otherThreadConnection = ((DynamicConnection)other).Connection;
|
|
});
|
|
|
|
Assert.IsTrue(task.Wait(TimeSpan.FromSeconds(2)));
|
|
Assert.AreNotSame(((DynamicConnection)threadLocalA).Connection, otherThreadConnection);
|
|
}
|
|
finally
|
|
{
|
|
threadLocalA.Dispose();
|
|
threadLocalB.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestCase(DynamicDatabaseOptions.SingleConnection)]
|
|
[TestCase(DynamicDatabaseOptions.SingleTransaction)]
|
|
public void TestSingleModesSerializeCommandExecution(DynamicDatabaseOptions option)
|
|
{
|
|
CreateDatabase(option);
|
|
_state.BlockFirstExecution = true;
|
|
_state.AllowExecution.Reset();
|
|
|
|
Task task1 = Task.Run(() => ExecuteFakeCommand());
|
|
Assert.IsTrue(_state.FirstExecutionEntered.Wait(TimeSpan.FromSeconds(2)));
|
|
|
|
Task task2 = Task.Run(() => ExecuteFakeCommand());
|
|
Thread.Sleep(200);
|
|
|
|
Assert.AreEqual(1, _state.MaxConcurrentExecutions);
|
|
|
|
_state.AllowExecution.Set();
|
|
|
|
Assert.IsTrue(Task.WaitAll(new[] { task1, task2 }, TimeSpan.FromSeconds(5)));
|
|
Assert.AreEqual(1, _state.MaxConcurrentExecutions);
|
|
}
|
|
|
|
private void ExecuteFakeCommand()
|
|
{
|
|
using (var connection = _db.Open())
|
|
using (var command = connection.CreateCommand())
|
|
{
|
|
command.SetCommand("SELECT 1;");
|
|
command.ExecuteNonQuery();
|
|
}
|
|
}
|
|
|
|
private void CreateDatabase(DynamicDatabaseOptions options)
|
|
{
|
|
_state = new FakeProviderState();
|
|
_db = new DynamicDatabase(new FakeProviderFactory(_state), "fake", options);
|
|
}
|
|
}
|
|
}
|