diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 86da91f0e..4e9c4c0fb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,9 +3,9 @@ name: DotNet Build and Test # Triggers the workflow on push or pull request events but only for the master branch on: push: - branches: [ master ] + branches: [ master, pool/SNOW-860872-connection-pool ] pull_request: - branches: [ master ] + branches: [ master, pool/SNOW-860872-connection-pool ] workflow_dispatch: inputs: logLevel: diff --git a/CodingConventions.md b/CodingConventions.md index 19ca8fc75..0242f583e 100644 --- a/CodingConventions.md +++ b/CodingConventions.md @@ -85,6 +85,18 @@ public class ExampleClass } ``` +#### Property + +Use PascalCase, eg. `SomeProperty`. + +```csharp +public ExampleProperty +{ + get; + set; +} +``` + ### Local variables Use camelCase, eg. `someVariable`. diff --git a/Snowflake.Data.Tests/IntegrationTests/ConnectingThreads.cs b/Snowflake.Data.Tests/IntegrationTests/ConnectingThreads.cs new file mode 100644 index 000000000..be33f1ce5 --- /dev/null +++ b/Snowflake.Data.Tests/IntegrationTests/ConnectingThreads.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Snowflake.Data.Client; + +namespace Snowflake.Data.Tests.IntegrationTests +{ + class ConnectingThreads + { + private string _connectionString; + + private ConcurrentQueue _events = new ConcurrentQueue(); + + private List threads = new List(); + + public ConnectingThreads(string connectionString) + { + _connectionString = connectionString; + } + + public ConnectingThreads NewThread(string name, + long waitBeforeConnectMillis, + long waitAfterConnectMillis, + bool closeOnExit) + { + var thread = new ConnectingThread( + name, + _events, + _connectionString, + waitBeforeConnectMillis, + waitAfterConnectMillis, + closeOnExit).Build(); + threads.Add(thread); + return this; + } + + public ConnectingThreads StartAll() + { + threads.ForEach(thread => thread.Start()); + return this; + } + + public ConnectingThreads JoinAll() + { + threads.ForEach(thread => thread.Join()); + return this; + } + + public IEnumerable Events() => _events.ToArray().OfType(); + } + + class ConnectingThread + { + private string _name; + + private ConcurrentQueue _events; + + private string _connectionString; + + private long _waitBeforeConnectMillis; + + private long _waitAfterConnectMillis; + + private bool _closeOnExit; + + public ConnectingThread( + string name, + ConcurrentQueue events, + string connectionString, + long waitBeforeConnectMillis, + long waitAfterConnectMillis, + bool closeOnExit) + { + _name = name; + _events = events; + _connectionString = connectionString; + _waitBeforeConnectMillis = waitBeforeConnectMillis; + _waitAfterConnectMillis = waitAfterConnectMillis; + _closeOnExit = closeOnExit; + } + + public Thread Build() + { + var thread = new Thread(Execute); + thread.Name = "thread_" + _name; + return thread; + } + + private void Execute() + { + var connection = new SnowflakeDbConnection(); + connection.ConnectionString = _connectionString; + Sleep(_waitBeforeConnectMillis); + var watch = new Stopwatch(); + watch.Start(); + var connected = false; + try + { + connection.Open(); + connected = true; + } + catch (Exception exception) + { + watch.Stop(); + _events.Enqueue(ThreadEvent.EventConnectingFailed(_name, exception, watch.ElapsedMilliseconds)); + } + if (connected) + { + watch.Stop(); + _events.Enqueue(ThreadEvent.EventConnected(_name, watch.ElapsedMilliseconds)); + } + Sleep(_waitAfterConnectMillis); + if (_closeOnExit) + { + connection.Close(); + } + } + + private void Sleep(long millis) + { + if (millis <= 0) + { + return; + } + System.Threading.Thread.Sleep((int) millis); + } + } + + class ThreadEvent + { + public string ThreadName { get; set; } + + public string EventName { get; set; } + + public Exception Error { get; set; } + + public long Timestamp { get; set; } + + public long Duration { get; set; } + + public ThreadEvent(string threadName, string eventName, Exception error, long duration) + { + ThreadName = threadName; + EventName = eventName; + Error = error; + Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + Duration = duration; + } + + public static ThreadEvent EventConnected(string threadName, long duration) => + new ThreadEvent(threadName, "CONNECTED", null, duration); + + public static ThreadEvent EventConnectingFailed(string threadName, Exception exception, long duration) => + new ThreadEvent(threadName, "FAILED_TO_CONNECT", exception, duration); + } +} diff --git a/Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsIT.cs b/Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsIT.cs new file mode 100644 index 000000000..ffd97b781 --- /dev/null +++ b/Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsIT.cs @@ -0,0 +1,266 @@ +using System; +using System.Data; +using System.Diagnostics; +using System.Linq; +using NUnit.Framework; +using Snowflake.Data.Client; +using Snowflake.Data.Core.Session; +using Snowflake.Data.Tests.Util; + +namespace Snowflake.Data.Tests.IntegrationTests +{ + [TestFixture] + [NonParallelizable] + public class ConnectionMultiplePoolsIT: SFBaseTest + { + private readonly PoolConfig _previousPoolConfig = new PoolConfig(); + + [SetUp] + public new void BeforeTest() + { + SnowflakeDbConnectionPool.SetConnectionPoolVersion(ConnectionPoolType.MultipleConnectionPool); + SnowflakeDbConnectionPool.ClearAllPools(); + SnowflakeDbConnectionPool.SetPooling(true); + } + + [TearDown] + public new void AfterTest() + { + _previousPoolConfig.Reset(); + } + + [OneTimeTearDown] + public static void AfterAllTests() + { + SnowflakeDbConnectionPool.ClearAllPools(); + } + + [Test] + public void TestReuseSessionInConnectionPool() // old name: TestConnectionPool + { + var conn1 = new SnowflakeDbConnection(ConnectionString); + conn1.Open(); + Assert.AreEqual(ConnectionState.Open, conn1.State); + conn1.Close(); + Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize()); + + var conn2 = new SnowflakeDbConnection(); + conn2.ConnectionString = ConnectionString; + conn2.Open(); + Assert.AreEqual(ConnectionState.Open, conn2.State); + Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize()); + + conn2.Close(); + Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize()); + Assert.AreEqual(ConnectionState.Closed, conn1.State); + Assert.AreEqual(ConnectionState.Closed, conn2.State); + } + + [Test] + public void TestReuseSessionInConnectionPoolReachingMaxConnections() // old name: TestConnectionPoolFull + { + var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString); + pool.SetMaxPoolSize(2); + + 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(2, pool.GetCurrentPoolSize()); + conn1.Close(); + conn2.Close(); + Assert.AreEqual(2, pool.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(2, pool.GetCurrentPoolSize()); + conn4.Close(); + Assert.AreEqual(2, pool.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); + } + + [Test] + public void TestWaitForTheIdleConnectionWhenExceedingMaxConnectionsLimit() + { + // arrange + var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString); + pool.SetMaxPoolSize(2); + pool.SetWaitingTimeout(1000); + var conn1 = OpenedConnection(); + var conn2 = OpenedConnection(); + var watch = new Stopwatch(); + + // act + watch.Start(); + var thrown = Assert.Throws(() => OpenedConnection()); + watch.Stop(); + + // assert + Assert.That(thrown.Message, Does.Contain("Unable to connect. Could not obtain a connection from the pool within a given timeout")); + Assert.GreaterOrEqual(watch.ElapsedMilliseconds, 1000); + Assert.LessOrEqual(watch.ElapsedMilliseconds, 1500); + Assert.AreEqual(pool.GetCurrentPoolSize(), 2); + + // cleanup + conn1.Close(); + conn2.Close(); + } + + [Test] + public void TestWaitInAQueueForAnIdleSession() + { + // arrange + var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString); + pool.SetMaxPoolSize(2); + pool.SetWaitingTimeout(3000); + var threads = new ConnectingThreads(ConnectionString) + .NewThread("A", 0, 2000, true) + .NewThread("B", 50, 2000, true) + .NewThread("C", 100, 0, true) + .NewThread("D", 150, 0, true); + var watch = new Stopwatch(); + + // act + watch.Start(); + threads.StartAll().JoinAll(); + watch.Stop(); + + // assert + var events = threads.Events().ToList(); + Assert.AreEqual(4, events.Count); + CollectionAssert.AreEqual( + new[] + { + Tuple.Create("A", "CONNECTED"), + Tuple.Create("B", "CONNECTED"), + Tuple.Create("C", "CONNECTED"), + Tuple.Create("D", "CONNECTED") + }, + events.Select(e => Tuple.Create(e.ThreadName, e.EventName))); + Assert.LessOrEqual(events[0].Duration, 1000); + Assert.LessOrEqual(events[1].Duration, 1000); + Assert.GreaterOrEqual(events[2].Duration, 2000); + Assert.LessOrEqual(events[2].Duration, 3100); + Assert.GreaterOrEqual(events[3].Duration, 2000); + Assert.LessOrEqual(events[3].Duration, 3100); + } + + [Test] + public void TestBusyAndIdleConnectionsCountedInPoolSize() + { + // arrange + var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString); + pool.SetMaxPoolSize(2); + var connection = new SnowflakeDbConnection(); + connection.ConnectionString = ConnectionString; + + // act + connection.Open(); + + // assert + Assert.AreEqual(1, pool.GetCurrentPoolSize()); + + // act + connection.Close(); + + // assert + Assert.AreEqual(1, pool.GetCurrentPoolSize()); + } + + [Test] + [Ignore("Enable when disabling pooling in connection string enabled - SNOW-902632")] + public void TestConnectionPoolNotPossibleToDisableForAllPools() + { + // act + var thrown = Assert.Throws(() => SnowflakeDbConnectionPool.SetPooling(false)); + + // assert + Assert.IsNotNull(thrown); + } + + [Test] + public void TestConnectionPoolDisable() + { + // arrange + var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString); + pool.SetPooling(false); + var conn1 = new SnowflakeDbConnection(); + conn1.ConnectionString = ConnectionString; + + // act + conn1.Open(); + + // assert + Assert.AreEqual(ConnectionState.Open, conn1.State); + Assert.AreEqual(0, pool.GetCurrentPoolSize()); + + // act + conn1.Close(); + + // assert + Assert.AreEqual(ConnectionState.Closed, conn1.State); + Assert.AreEqual(0, pool.GetCurrentPoolSize()); + } + + [Test] + public void TestNewConnectionPoolClean() + { + 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); + } + + private SnowflakeDbConnection OpenedConnection() + { + var connection = new SnowflakeDbConnection(); + connection.ConnectionString = ConnectionString; + connection.Open(); + return connection; + } + } +} diff --git a/Snowflake.Data.Tests/IntegrationTests/ConnectionPoolCommonIT.cs b/Snowflake.Data.Tests/IntegrationTests/ConnectionPoolCommonIT.cs new file mode 100644 index 000000000..a75c19790 --- /dev/null +++ b/Snowflake.Data.Tests/IntegrationTests/ConnectionPoolCommonIT.cs @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. + */ + +using System.Data; +using System.Threading; +using NUnit.Framework; +using Snowflake.Data.Core; +using Snowflake.Data.Client; +using Snowflake.Data.Core.Session; +using Snowflake.Data.Log; +using Snowflake.Data.Tests.Util; + +namespace Snowflake.Data.Tests.IntegrationTests +{ + [TestFixture(ConnectionPoolType.SingleConnectionCache)] + [TestFixture(ConnectionPoolType.MultipleConnectionPool)] + [NonParallelizable] + class ConnectionPoolCommonIT : SFBaseTest + { + private readonly ConnectionPoolType _connectionPoolTypeUnderTest; + private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger(); + private readonly PoolConfig _previousPoolConfig; + + public ConnectionPoolCommonIT(ConnectionPoolType connectionPoolTypeUnderTest) + { + _connectionPoolTypeUnderTest = connectionPoolTypeUnderTest; + _previousPoolConfig = new PoolConfig(); + } + + [SetUp] + public new void BeforeTest() + { + SnowflakeDbConnectionPool.SetConnectionPoolVersion(_connectionPoolTypeUnderTest); + SnowflakeDbConnectionPool.ClearAllPools(); + SnowflakeDbConnectionPool.SetPooling(true); + s_logger.Debug($"---------------- BeforeTest ---------------------"); + s_logger.Debug($"Testing Pool Type: {SnowflakeDbConnectionPool.GetConnectionPoolVersion()}"); + } + + [TearDown] + public new void AfterTest() + { + _previousPoolConfig.Reset(); + } + + [OneTimeTearDown] + public static void AfterAllTests() + { + SnowflakeDbConnectionPool.ClearAllPools(); + } + + [Test] + public void TestBasicConnectionPool() + { + SnowflakeDbConnectionPool.SetMaxPoolSize(1); + + var conn1 = new SnowflakeDbConnection(ConnectionString); + conn1.Open(); + Assert.AreEqual(ConnectionState.Open, conn1.State); + conn1.Close(); + + Assert.AreEqual(ConnectionState.Closed, conn1.State); + Assert.AreEqual(1, SnowflakeDbConnectionPool.GetPool(ConnectionString).GetCurrentPoolSize()); + } + + [Test] + public void TestConnectionPoolExpirationWorks() + { + SnowflakeDbConnectionPool.SetMaxPoolSize(2); + SnowflakeDbConnectionPool.SetTimeout(10); + + var conn1 = new SnowflakeDbConnection(); + conn1.ConnectionString = ConnectionString; + + conn1.Open(); + conn1.Close(); + SnowflakeDbConnectionPool.SetTimeout(-1); + + var conn2 = new SnowflakeDbConnection(); + conn2.ConnectionString = ConnectionString; + conn2.Open(); + conn2.Close(); + var conn3 = new SnowflakeDbConnection(); + conn3.ConnectionString = ConnectionString; + conn3.Open(); + conn3.Close(); + + // 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.GetPool(ConnectionString).GetCurrentPoolSize()); + } + + [Test] + public void TestConnectionPoolMultiThreading() + { + Thread t1 = new Thread(() => ThreadProcess1(ConnectionString)); + Thread t2 = new Thread(() => ThreadProcess2(ConnectionString)); + + t1.Start(); + t2.Start(); + + t1.Join(); + t2.Join(); + } + + void ThreadProcess1(string connstr) + { + var conn1 = new SnowflakeDbConnection(); + conn1.ConnectionString = connstr; + conn1.Open(); + Thread.Sleep(1000); + conn1.Close(); + Thread.Sleep(4000); + Assert.AreEqual(ConnectionState.Closed, conn1.State); + } + + void ThreadProcess2(string connstr) + { + var conn1 = new SnowflakeDbConnection(); + conn1.ConnectionString = connstr; + conn1.Open(); + + Thread.Sleep(5000); + SFStatement statement = new SFStatement(conn1.SfSession); + SFBaseResultSet resultSet = statement.Execute(0, "select 1", null, false); + Assert.AreEqual(true, resultSet.Next()); + Assert.AreEqual("1", resultSet.GetString(0)); + conn1.Close(); + SnowflakeDbConnectionPool.ClearAllPools(); + SnowflakeDbConnectionPool.SetMaxPoolSize(0); + SnowflakeDbConnectionPool.SetPooling(true); + } + + [Test] + public void TestConnectionPoolWithDispose() + { + SnowflakeDbConnectionPool.SetMaxPoolSize(1); + + var conn1 = new SnowflakeDbConnection(); + conn1.ConnectionString = "bad connection string"; + Assert.Throws(() => conn1.Open()); + conn1.Close(); + + Assert.AreEqual(ConnectionState.Closed, conn1.State); + Assert.AreEqual(0, SnowflakeDbConnectionPool.GetPool(conn1.ConnectionString).GetCurrentPoolSize()); + } + } +} diff --git a/Snowflake.Data.Tests/IntegrationTests/SFConnectionPoolIT.cs b/Snowflake.Data.Tests/IntegrationTests/ConnectionSinglePoolCacheIT.cs similarity index 56% rename from Snowflake.Data.Tests/IntegrationTests/SFConnectionPoolIT.cs rename to Snowflake.Data.Tests/IntegrationTests/ConnectionSinglePoolCacheIT.cs index 5c4529225..42ae22b74 100644 --- a/Snowflake.Data.Tests/IntegrationTests/SFConnectionPoolIT.cs +++ b/Snowflake.Data.Tests/IntegrationTests/ConnectionSinglePoolCacheIT.cs @@ -1,52 +1,41 @@ -/* - * 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 Snowflake.Data.Core; -using Snowflake.Data.Client; -using Snowflake.Data.Log; using NUnit.Framework; +using Snowflake.Data.Client; +using Snowflake.Data.Core.Session; +using Snowflake.Data.Tests.Util; namespace Snowflake.Data.Tests.IntegrationTests { - [TestFixture, NonParallelizable] - class SFConnectionPoolIT : SFBaseTest + [TestFixture] + [NonParallelizable] + public class ConnectionSinglePoolCacheIT: SFBaseTest { - private static PoolConfig s_previousPoolConfig; + private readonly PoolConfig _previousPoolConfig = new PoolConfig(); - [OneTimeSetUp] - public static void BeforeAllTests() - { - s_previousPoolConfig = new PoolConfig(); - } - [SetUp] public new void BeforeTest() { - SnowflakeDbConnectionPool.SetPooling(true); + SnowflakeDbConnectionPool.SetConnectionPoolVersion(ConnectionPoolType.SingleConnectionCache); SnowflakeDbConnectionPool.ClearAllPools(); + SnowflakeDbConnectionPool.SetPooling(true); } - + [TearDown] public new void AfterTest() { - s_previousPoolConfig.Reset(); + _previousPoolConfig.Reset(); } - + [OneTimeTearDown] public static void AfterAllTests() { SnowflakeDbConnectionPool.ClearAllPools(); - } - + } + [Test] - // test connection pooling with concurrent connection public void TestConcurrentConnectionPooling() { // add test case name in connection string to make in unique for each test case @@ -74,6 +63,7 @@ static void ConcurrentPoolingHelper(string connectionString, bool closeConnectio const int PoolTimeout = 3; // reset to default settings in case it changed by other test cases + Assert.AreEqual(true, SnowflakeDbConnectionPool.GetPool(connectionString).GetPooling()); // to instantiate pool SnowflakeDbConnectionPool.SetMaxPoolSize(10); SnowflakeDbConnectionPool.SetTimeout(PoolTimeout); @@ -86,10 +76,8 @@ static void ConcurrentPoolingHelper(string connectionString, bool closeConnectio }); } Task.WaitAll(threads); - // set pooling timeout back to default to avoid impact on other test cases - SnowflakeDbConnectionPool.SetTimeout(3600); } - + // thead to execute query with new connection in a loop static void QueryExecutionThread(string connectionString, bool closeConnection) { @@ -130,45 +118,31 @@ static void QueryExecutionThread(string connectionString, bool closeConnection) } [Test] - public void TestBasicConnectionPool() + public void TestPoolContainsClosedConnections() // old name: TestConnectionPool { - SnowflakeDbConnectionPool.SetMaxPoolSize(1); - var conn1 = new SnowflakeDbConnection(ConnectionString); conn1.Open(); Assert.AreEqual(ConnectionState.Open, conn1.State); conn1.Close(); - - Assert.AreEqual(ConnectionState.Closed, conn1.State); - Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - } - - [Test] - public void TestConnectionPool() - { - 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 TestPoolContainsAtMostMaxPoolSizeConnections() // old name: TestConnectionPoolFull { SnowflakeDbConnectionPool.SetMaxPoolSize(2); + var conn1 = new SnowflakeDbConnection(); conn1.ConnectionString = ConnectionString; conn1.Open(); @@ -178,93 +152,83 @@ public void TestConnectionPoolIsFull() conn2.ConnectionString = ConnectionString + " retryCount=1"; conn2.Open(); Assert.AreEqual(ConnectionState.Open, conn2.State); - + Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); + conn1.Close(); + conn2.Close(); + Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); var conn3 = new SnowflakeDbConnection(); conn3.ConnectionString = ConnectionString + " retryCount=2"; conn3.Open(); Assert.AreEqual(ConnectionState.Open, conn3.State); - SnowflakeDbConnectionPool.ClearAllPools(); - conn1.Close(); - Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - conn2.Close(); - Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); + var conn4 = new SnowflakeDbConnection(); + conn4.ConnectionString = ConnectionString + " retryCount=3"; + conn4.Open(); + Assert.AreEqual(ConnectionState.Open, conn4.State); + conn3.Close(); Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); + conn4.Close(); + Assert.AreEqual(2, SnowflakeDbConnectionPool.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 TestConnectionPoolExpirationWorks() + public void TestConnectionPoolDisableFromPoolManagerLevel() { - SnowflakeDbConnectionPool.SetMaxPoolSize(2); - SnowflakeDbConnectionPool.SetTimeout(10); - + // arrange + SnowflakeDbConnectionPool.SetPooling(false); var conn1 = new SnowflakeDbConnection(); conn1.ConnectionString = ConnectionString; - + + // act conn1.Open(); + + // assert + Assert.AreEqual(ConnectionState.Open, conn1.State); + Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); + + // act conn1.Close(); - SnowflakeDbConnectionPool.SetTimeout(-1); - - var conn2 = new SnowflakeDbConnection(); - conn2.ConnectionString = ConnectionString; - conn2.Open(); - conn2.Close(); - var conn3 = new SnowflakeDbConnection(); - conn3.ConnectionString = ConnectionString; - conn3.Open(); - conn3.Close(); - // 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 + Assert.AreEqual(ConnectionState.Closed, conn1.State); Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - SnowflakeDbConnectionPool.SetPooling(false); } - + [Test] - public void TestConnectionPoolClean() + public void TestConnectionPoolDisable() { - SnowflakeDbConnectionPool.SetMaxPoolSize(2); + // arrange + var pool = SnowflakeDbConnectionPool.GetPool(ConnectionString); + pool.SetPooling(false); var conn1 = new SnowflakeDbConnection(); conn1.ConnectionString = ConnectionString; + + // act conn1.Open(); + + // assert 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); - + Assert.AreEqual(0, pool.GetCurrentPoolSize()); + + // act conn1.Close(); - conn2.Close(); - Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - SnowflakeDbConnectionPool.ClearAllPools(); - Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - conn3.Close(); - Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize()); + // assert Assert.AreEqual(ConnectionState.Closed, conn1.State); - Assert.AreEqual(ConnectionState.Closed, conn2.State); - Assert.AreEqual(ConnectionState.Closed, conn3.State); - SnowflakeDbConnectionPool.ClearAllPools(); + Assert.AreEqual(0, pool.GetCurrentPoolSize()); } [Test] - public void TestConnectionPoolFull() + public void TestConnectionPoolClean() { SnowflakeDbConnectionPool.SetMaxPoolSize(2); - var conn1 = new SnowflakeDbConnection(); conn1.ConnectionString = ConnectionString; conn1.Open(); @@ -274,126 +238,23 @@ public void TestConnectionPoolFull() conn2.ConnectionString = ConnectionString + " retryCount=1"; conn2.Open(); Assert.AreEqual(ConnectionState.Open, conn2.State); - Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - conn1.Close(); - conn2.Close(); - Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); + var conn3 = new SnowflakeDbConnection(); conn3.ConnectionString = ConnectionString + " retryCount=2"; conn3.Open(); Assert.AreEqual(ConnectionState.Open, conn3.State); - var conn4 = new SnowflakeDbConnection(); - conn4.ConnectionString = ConnectionString + " retryCount=3"; - conn4.Open(); - Assert.AreEqual(ConnectionState.Open, conn4.State); - - conn3.Close(); - Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - conn4.Close(); - Assert.AreEqual(2, SnowflakeDbConnectionPool.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() - { - Thread t1 = new Thread(() => ThreadProcess1(ConnectionString)); - Thread t2 = new Thread(() => ThreadProcess2(ConnectionString)); - - t1.Start(); - t2.Start(); - - t1.Join(); - t2.Join(); - } - - void ThreadProcess1(string connstr) - { - var conn1 = new SnowflakeDbConnection(); - conn1.ConnectionString = connstr; - conn1.Open(); - Thread.Sleep(1000); conn1.Close(); - Thread.Sleep(4000); - Assert.AreEqual(ConnectionState.Closed, conn1.State); - } - - void ThreadProcess2(string connstr) - { - var conn1 = new SnowflakeDbConnection(); - conn1.ConnectionString = connstr; - conn1.Open(); - - Thread.Sleep(5000); - SFStatement statement = new SFStatement(conn1.SfSession); - SFBaseResultSet resultSet = statement.Execute(0, "select 1", null, false); - Assert.AreEqual(true, resultSet.Next()); - Assert.AreEqual("1", resultSet.GetString(0)); + conn2.Close(); + Assert.AreEqual(2, SnowflakeDbConnectionPool.GetCurrentPoolSize()); SnowflakeDbConnectionPool.ClearAllPools(); - SnowflakeDbConnectionPool.SetMaxPoolSize(0); - SnowflakeDbConnectionPool.SetPooling(false); - } - - [Test] - public void TestConnectionPoolDisable() - { - SnowflakeDbConnectionPool.SetPooling(false); - - var conn1 = new SnowflakeDbConnection(); - conn1.ConnectionString = ConnectionString; - conn1.Open(); - Assert.AreEqual(ConnectionState.Open, conn1.State); - conn1.Close(); - - Assert.AreEqual(ConnectionState.Closed, conn1.State); - Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - } - - [Test] - public void TestConnectionPoolWithDispose() - { - SnowflakeDbConnectionPool.SetMaxPoolSize(1); - - var conn1 = new SnowflakeDbConnection(); - conn1.ConnectionString = ""; - try - { - conn1.Open(); - } - catch (SnowflakeDbException ex) - { - conn1.Close(); - } - - Assert.AreEqual(ConnectionState.Closed, conn1.State); Assert.AreEqual(0, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - } - - [Test] - public void TestConnectionPoolTurnOff() - { - SnowflakeDbConnectionPool.SetPooling(false); - SnowflakeDbConnectionPool.SetPooling(true); - SnowflakeDbConnectionPool.SetMaxPoolSize(1); - SnowflakeDbConnectionPool.ClearAllPools(); - - var conn1 = new SnowflakeDbConnection(); - conn1.ConnectionString = ConnectionString; - conn1.Open(); - Assert.AreEqual(ConnectionState.Open, conn1.State); - conn1.Close(); - - Assert.AreEqual(ConnectionState.Closed, conn1.State); + conn3.Close(); Assert.AreEqual(1, SnowflakeDbConnectionPool.GetCurrentPoolSize()); - SnowflakeDbConnectionPool.SetPooling(false); - //Put a breakpoint at SFSession close function, after connection pool is off, it will send close session request. + Assert.AreEqual(ConnectionState.Closed, conn1.State); + Assert.AreEqual(ConnectionState.Closed, conn2.State); + Assert.AreEqual(ConnectionState.Closed, conn3.State); } } } diff --git a/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs b/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs deleted file mode 100644 index eea852af2..000000000 --- a/Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs +++ /dev/null @@ -1,2018 +0,0 @@ -/* - * Copyright (c) 2012-2021 Snowflake Computing Inc. All rights reserved. - */ - -using System.Data.Common; - -namespace Snowflake.Data.Tests.IntegrationTests -{ - using NUnit.Framework; - using Snowflake.Data.Client; - using System.Data; - using System; - using Snowflake.Data.Core; - using System.Threading.Tasks; - using System.Threading; - using Snowflake.Data.Log; - using System.Diagnostics; - using Snowflake.Data.Tests.Mock; - using System.Runtime.InteropServices; - - [TestFixture] - class SFConnectionIT : SFBaseTest - { - private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger(); - - [Test] - public void TestBasicConnection() - { - using (IDbConnection conn = new SnowflakeDbConnection()) - { - conn.ConnectionString = ConnectionString; - conn.Open(); - Assert.AreEqual(ConnectionState.Open, conn.State); - - Assert.AreEqual(SFSessionHttpClientProperties.s_retryTimeoutDefault, conn.ConnectionTimeout); - // Data source is empty string for now - Assert.AreEqual("", ((SnowflakeDbConnection)conn).DataSource); - - string serverVersion = ((SnowflakeDbConnection)conn).ServerVersion; - if (!string.Equals(serverVersion, "Dev")) - { - string[] versionElements = serverVersion.Split('.'); - Assert.AreEqual(3, versionElements.Length); - } - - conn.Close(); - Assert.AreEqual(ConnectionState.Closed, conn.State); - } - } - - [Test] - public void TestApplicationName() - { - string[] validApplicationNames = { "test1234", "test_1234", "test-1234", "test.1234"}; - string[] invalidApplicationNames = { "1234test", "test$A", "test