Skip to content

Commit

Permalink
SNOW-902611
Browse files Browse the repository at this point in the history
- removed singleton pattern from SessionPool; introduced new interface for ConnectionManager; split tests of ConnectionPool and some cleanup in the classes
SNOW-902608
- new Connection Pool Manager version implementation
- unit tests for new pool; introduction of SessionFactory for unit testing of new pool manager and session pooling
- integration tests for two versions of Connection Pool
  • Loading branch information
sfc-gh-mhofman committed Oct 16, 2023
1 parent 7ff70e4 commit 0612dc5
Show file tree
Hide file tree
Showing 12 changed files with 672 additions and 62 deletions.
175 changes: 153 additions & 22 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionPoolIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,46 @@
* Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
*/

using Snowflake.Data.Tests.Util;
using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Snowflake.Data.Core;
using Snowflake.Data.Client;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Log;
using NUnit.Framework;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
{
[TestFixture, NonParallelizable]
[TestFixture(ConnectionPoolType.SingleConnectionCache)]
[TestFixture(ConnectionPoolType.MultipleConnectionPool)]
[NonParallelizable]
class SFConnectionPoolIT : SFBaseTest
{
private readonly ConnectionPoolType _connectionPoolTypeUnderTest;
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<ConnectionPoolManager>();
private static PoolConfig s_previousPoolConfig;

[OneTimeSetUp]
public static void BeforeAllTests()
public SFConnectionPoolIT(ConnectionPoolType connectionPoolTypeUnderTest)
{
_connectionPoolTypeUnderTest = connectionPoolTypeUnderTest;
s_previousPoolConfig = new PoolConfig();
SnowflakeDbConnectionPool.SetConnectionPoolVersion(connectionPoolTypeUnderTest);
}

[SetUp]
public new void BeforeTest()
{
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.GetPool(ConnectionString); // to instantiate the pool used in tests
SnowflakeDbConnectionPool.GetPool(ConnectionString + " retryCount=1");
SnowflakeDbConnectionPool.GetPool(ConnectionString + " retryCount=2");
SnowflakeDbConnectionPool.SetPooling(true); // TODO: when no session pool created it doesn't do anything!!!! maybe this state should be at pool management layer, not session pool layer
SnowflakeDbConnectionPool.ClearAllPools();
s_logger.Debug($"---------------- BeforeTest ---------------------");
s_logger.Debug($"Testing Pool Type: {SnowflakeDbConnectionPool.GetConnectionPoolVersion()}");
}

[TearDown]
Expand Down Expand Up @@ -74,7 +85,10 @@ static void ConcurrentPoolingHelper(string connectionString, bool closeConnectio
const int PoolTimeout = 3;

// reset to default settings in case it changed by other test cases
SnowflakeDbConnectionPool.GetPool(connectionString); // to instantiate pool
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.SetMaxPoolSize(10);
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetTimeout(PoolTimeout);

var threads = new Task[ThreadNum];
Expand Down Expand Up @@ -140,57 +154,63 @@ public void TestBasicConnectionPool()
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
}

[Test]
public void TestConnectionPool()
{
SnowflakeDbConnectionPool.ClearAllPools();
var conn1 = new SnowflakeDbConnection(ConnectionString);
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);
conn1.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString;
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());

conn2.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestConnectionPoolIsFull()
public void TestNewConnectionPoolIsFull()
{
// TestOnlyForNewPool();

var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString + " retryCount=1";
conn2.ConnectionString = ConnectionString;
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);

var conn3 = new SnowflakeDbConnection();
conn3.ConnectionString = ConnectionString + " retryCount=2";
conn3.ConnectionString = ConnectionString;
conn3.Open();
Assert.AreEqual(ConnectionState.Open, conn3.State);
SnowflakeDbConnectionPool.ClearAllPools();

conn1.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, pool.GetCurrentPoolSize());
conn2.Close();
Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(2, pool.GetCurrentPoolSize());
conn3.Close();
Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(2, pool.GetCurrentPoolSize());

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Expand All @@ -201,8 +221,11 @@ public void TestConnectionPoolIsFull()
[Test]
public void TestConnectionPoolExpirationWorks()
{
Thread.Sleep(10000); // wait for 10 seconds, in case other test still running.
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
SnowflakeDbConnectionPool.SetTimeout(10);
SnowflakeDbConnectionPool.SetPooling(true);

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
Expand All @@ -223,13 +246,16 @@ public void TestConnectionPoolExpirationWorks()
// The pooling timeout should apply to all connections being pooled,
// not just the connections created after the new setting,
// so expected result should be 0
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
SnowflakeDbConnectionPool.SetPooling(false);
}

[Test]
public void TestConnectionPoolClean()
{
TestOnlyForOldPool();

SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
Expand Down Expand Up @@ -260,10 +286,52 @@ public void TestConnectionPoolClean()
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestNewConnectionPoolClean()
{
TestOnlyForNewPool();

SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString + " retryCount=1";
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);

var conn3 = new SnowflakeDbConnection();
conn3.ConnectionString = ConnectionString + " retryCount=2";
conn3.Open();
Assert.AreEqual(ConnectionState.Open, conn3.State);

conn1.Close();
conn2.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(conn2.ConnectionString).GetCurrentPoolSize());
SnowflakeDbConnectionPool.ClearAllPools();
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn2.ConnectionString).GetCurrentPoolSize());
conn3.Close();
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(conn3.ConnectionString).GetCurrentPoolSize());

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Assert.AreEqual(ConnectionState.Closed, conn3.State);
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestConnectionPoolFull()
{
TestOnlyForOldPool();

SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
SnowflakeDbConnectionPool.SetPooling(true);

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
Expand Down Expand Up @@ -300,6 +368,53 @@ public void TestConnectionPoolFull()
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestNewConnectionPoolFull()
{
TestOnlyForNewPool();

var sessionPool = SnowflakeDbConnectionPool.GetPool(ConnectionString);
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetMaxPoolSize(2);
SnowflakeDbConnectionPool.SetPooling(true);

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = ConnectionString;
conn1.Open();
Assert.AreEqual(ConnectionState.Open, conn1.State);

var conn2 = new SnowflakeDbConnection();
conn2.ConnectionString = ConnectionString;
conn2.Open();
Assert.AreEqual(ConnectionState.Open, conn2.State);

Assert.AreEqual(0, sessionPool.GetCurrentPoolSize());
conn1.Close();
conn2.Close();
Assert.AreEqual(2, sessionPool.GetCurrentPoolSize());

var conn3 = new SnowflakeDbConnection();
conn3.ConnectionString = ConnectionString;
conn3.Open();
Assert.AreEqual(ConnectionState.Open, conn3.State);

var conn4 = new SnowflakeDbConnection();
conn4.ConnectionString = ConnectionString;
conn4.Open();
Assert.AreEqual(ConnectionState.Open, conn4.State);

conn3.Close();
Assert.AreEqual(1, sessionPool.GetCurrentPoolSize()); // TODO: when SNOW-937189 complete should be 2
conn4.Close();
Assert.AreEqual(2, sessionPool.GetCurrentPoolSize());

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(ConnectionState.Closed, conn2.State);
Assert.AreEqual(ConnectionState.Closed, conn3.State);
Assert.AreEqual(ConnectionState.Closed, conn4.State);
SnowflakeDbConnectionPool.ClearAllPools();
}

[Test]
public void TestConnectionPoolMultiThreading()
{
Expand Down Expand Up @@ -343,6 +458,7 @@ void ThreadProcess2(string connstr)
[Test]
public void TestConnectionPoolDisable()
{
SnowflakeDbConnectionPool.ClearAllPools();
SnowflakeDbConnectionPool.SetPooling(false);

var conn1 = new SnowflakeDbConnection();
Expand All @@ -352,27 +468,30 @@ public void TestConnectionPoolDisable()
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());
}

[Test]
public void TestConnectionPoolWithDispose()
{
SnowflakeDbConnectionPool.SetPooling(true);
SnowflakeDbConnectionPool.SetMaxPoolSize(1);
SnowflakeDbConnectionPool.ClearAllPools();

var conn1 = new SnowflakeDbConnection();
conn1.ConnectionString = "";
conn1.ConnectionString = "bad connection string";
try
{
conn1.Open();
}
catch (SnowflakeDbException ex)
{
Console.WriteLine("connection failed:" + ex);
conn1.Close();
}

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize());
}

[Test]
Expand All @@ -390,10 +509,22 @@ public void TestConnectionPoolTurnOff()
conn1.Close();

Assert.AreEqual(ConnectionState.Closed, conn1.State);
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize());
Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize());

SnowflakeDbConnectionPool.SetPooling(false);
//Put a breakpoint at SFSession close function, after connection pool is off, it will send close session request.
}

private void TestOnlyForOldPool()
{
if (_connectionPoolTypeUnderTest != ConnectionPoolType.SingleConnectionCache)
Assert.Ignore($"Test case relates only to {ConnectionPoolType.SingleConnectionCache} pool type");
}

private void TestOnlyForNewPool()
{
if (_connectionPoolTypeUnderTest != ConnectionPoolType.MultipleConnectionPool)
Assert.Ignore($"Test case relates only to {ConnectionPoolType.MultipleConnectionPool} pool type");
}
}
}
Loading

0 comments on commit 0612dc5

Please sign in to comment.