From 474642c931134d9bcad0e5f4918caab2823286f3 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 7 Jul 2021 16:30:50 -0700 Subject: [PATCH 01/15] connection pool tests --- .../Microsoft.Data.SqlClient.Tests.csproj | 2 +- .../SQL/AsyncTest/BeginExecAsyncTest.cs | 48 +--- .../SQL/Common/InternalConnectionWrapper.cs | 19 ++ .../SystemDataInternals/ConnectionHelper.cs | 21 ++ .../SystemDataInternals/TdsParserHelper.cs | 2 +- .../TdsParserStateObjectHelper.cs | 2 +- .../ConnectionPoolTest/ConnectionPoolTest.cs | 266 ++++++++++++++++++ 7 files changed, 317 insertions(+), 43 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 73d03ffe30..60adb8eb30 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -6,7 +6,7 @@ netcoreapp Debug;Release;net461-Release;net461-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;netcoreapp3.1-Debug;netcoreapp3.1-Release AnyCPU;x86;x64 - $(DefineConstants);NETFX + $(DefineConstants);NETFX $(DefineConstants);NETCOREAPP $(DefineConstants);NET50_OR_LATER $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs index 4f7956745f..19bfc3b62b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs @@ -36,36 +36,16 @@ public static void ExecuteTest() { using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) { - try - { - SqlCommand command = new SqlCommand(GenerateCommandText(), connection); - connection.Open(); - - IAsyncResult result = command.BeginExecuteNonQuery(); - while (!result.IsCompleted) - { - System.Threading.Thread.Sleep(100); - } + SqlCommand command = new SqlCommand(GenerateCommandText(), connection); + connection.Open(); - Assert.True(command.EndExecuteNonQuery(result) > 0, "FAILED: BeginExecuteNonQuery did not complete successfully."); - } - catch (SqlException ex) - { - Console.WriteLine("Error ({0}): {1}", ex.Number, ex.Message); - Assert.Null(ex); - } - catch (InvalidOperationException ex) - { - Console.WriteLine("Error: {0}", ex.Message); - Assert.Null(ex); - } - catch (Exception ex) + IAsyncResult result = command.BeginExecuteNonQuery(); + while (!result.IsCompleted) { - // You might want to pass these errors - // back out to the caller. - Console.WriteLine("Error: {0}", ex.Message); - Assert.Null(ex); + System.Threading.Thread.Sleep(100); } + + Assert.True(command.EndExecuteNonQuery(result) > 0, "FAILED: BeginExecuteNonQuery did not complete successfully."); } } @@ -75,24 +55,12 @@ public static void FailureTest() { using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) { - bool caughtException = false; SqlCommand command = new SqlCommand(GenerateCommandText(), connection); connection.Open(); //Try to execute a synchronous query on same command IAsyncResult result = command.BeginExecuteNonQuery(); - try - { - command.ExecuteNonQuery(); - } - catch (Exception ex) - { - Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for BeginExecuteNonQuery was not an InvalidOperationException"); - caughtException = true; - } - - Assert.True(caughtException, "FAILED: No exception thrown after trying second BeginExecuteNonQuery."); - caughtException = false; + InvalidOperationException ex = Assert.Throws(() => command.ExecuteNonQuery()); while (!result.IsCompleted) { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs index a26d42e02d..4e8740a4dc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs @@ -18,6 +18,25 @@ public class InternalConnectionWrapper private object _internalConnection = null; private object _spid = null; + /// + /// Is this internal connection enlisted in a distributed transaction? + /// + public bool IsEnlistedInTransaction + { get { return ConnectionHelper.IsEnlistedInTransaction(_internalConnection); } } + + /// + /// Is this internal connection the root of a distributed transaction? + /// + public bool IsTransactionRoot + { get { return ConnectionHelper.IsTransactionRoot(_internalConnection); } } + + /// + /// True if this connection is the root of a transaction AND it is waiting for the transaction + /// to complete (i.e. it has been 'aged' or 'put into stasis'), otherwise false + /// + public bool IsTxRootWaitingForTxEnd + { get { return ConnectionHelper.IsTxRootWaitingForTxEnd(_internalConnection); } } + /// /// Gets the internal connection associated with the given SqlConnection /// diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/ConnectionHelper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/ConnectionHelper.cs index 32bac50d08..4f83a8aeb7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/ConnectionHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/ConnectionHelper.cs @@ -32,6 +32,9 @@ internal static class ConnectionHelper private static PropertyInfo s_pendingSQLDNS_AddrIPv4 = s_SQLDNSInfo.GetProperty("AddrIPv4", BindingFlags.Instance | BindingFlags.Public); private static PropertyInfo s_pendingSQLDNS_AddrIPv6 = s_SQLDNSInfo.GetProperty("AddrIPv6", BindingFlags.Instance | BindingFlags.Public); private static PropertyInfo s_pendingSQLDNS_Port = s_SQLDNSInfo.GetProperty("Port", BindingFlags.Instance | BindingFlags.Public); + private static PropertyInfo dbConnectionInternalIsTransRoot = s_dbConnectionInternal.GetProperty("IsTransactionRoot", BindingFlags.Instance | BindingFlags.NonPublic); + private static PropertyInfo dbConnectionInternalEnlistedTrans = s_sqlInternalConnection.GetProperty("EnlistedTransaction", BindingFlags.Instance | BindingFlags.NonPublic); + private static PropertyInfo dbConnectionInternalIsTxRootWaitingForTxEnd = s_dbConnectionInternal.GetProperty("IsTxRootWaitingForTxEnd", BindingFlags.Instance | BindingFlags.NonPublic); public static object GetConnectionPool(object internalConnection) { @@ -69,6 +72,24 @@ private static void VerifyObjectIsConnection(object connection) throw new ArgumentException("Object provided was not a SqlConnection", nameof(connection)); } + public static bool IsEnlistedInTransaction(object internalConnection) + { + VerifyObjectIsInternalConnection(internalConnection); + return (dbConnectionInternalEnlistedTrans.GetValue(internalConnection, null) != null); + } + + public static bool IsTransactionRoot(object internalConnection) + { + VerifyObjectIsInternalConnection(internalConnection); + return (bool)dbConnectionInternalIsTransRoot.GetValue(internalConnection, null); + } + + public static bool IsTxRootWaitingForTxEnd(object internalConnection) + { + VerifyObjectIsInternalConnection(internalConnection); + return (bool)dbConnectionInternalIsTxRootWaitingForTxEnd.GetValue(internalConnection, null); + } + public static object GetParser(object internalConnection) { VerifyObjectIsInternalConnection(internalConnection); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserHelper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserHelper.cs index 9a736a4607..17f3a0244a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserHelper.cs @@ -18,7 +18,7 @@ private static void VerifyObjectIsTdsParser(object parser) if (parser == null) throw new ArgumentNullException("stateObject"); if (!s_tdsParser.IsInstanceOfType(parser)) - throw new ArgumentException("Object provided was not a DbConnectionInternal", "internalConnection"); + throw new ArgumentException("Object provided was not a TdsParser", nameof(parser)); } internal static object GetStateObject(object parser) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserStateObjectHelper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserStateObjectHelper.cs index 32dda71943..1a8bb2fd4e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserStateObjectHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/TdsParserStateObjectHelper.cs @@ -56,7 +56,7 @@ private static void VerifyObjectIsTdsParserStateObject(object stateObject) if (stateObject == null) throw new ArgumentNullException(nameof(stateObject)); if (!s_tdsParserStateObjectManaged.IsInstanceOfType(stateObject)) - throw new ArgumentException("Object provided was not a DbConnectionInternal", "internalConnection"); + throw new ArgumentException("Object provided was not a TdsParserStateObjectManaged", nameof(stateObject)); } internal static object GetSessionHandle(object stateObject) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index f86f71468f..0cb43f575a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -6,6 +6,8 @@ using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; +using System.Data; +using System.Transactions; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -33,10 +35,20 @@ private static void RunDataTestForSingleConnString(string tcpConnectionString) BasicConnectionPoolingTest(tcpConnectionString); ClearAllPoolsTest(tcpConnectionString); ReclaimEmancipatedOnOpenTest(tcpConnectionString); + SoftTcpShutdownConnectionTest(tcpConnectionString); + MaxPoolWaitForConnectionTest(tcpConnectionString); + +#if NETFRAMEWORK + TransactionCleanupTest(tcpConnectionString); + TransactionPoolTest(tcpConnectionString); +#endif if (DataTestUtility.IsUsingManagedSNI()) { KillConnectionTest(tcpConnectionString); + CleanupTest(tcpConnectionString); + ReplacementConnectionUsesSemaphoreTest(tcpConnectionString); + ReplacementConnectionObeys0TimeoutTest(tcpConnectionString); } } @@ -208,6 +220,8 @@ private static void ReclaimEmancipatedOnOpenTest(string connectionString) private static void ReplacementConnectionUsesSemaphoreTest(string connectionString) { +#if DEBUG + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -268,8 +282,242 @@ private static void ReplacementConnectionUsesSemaphoreTest(string connectionStri waitAllTask.Wait(); Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); +#endif + } + + /// + /// Tests if killing the connection using the ProxyServer is working + /// + private static void SoftTcpShutdownConnectionTest(string connectionString) + { + using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(connectionString, out connectionString)) + { + InternalConnectionWrapper wrapper = null; + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + wrapper = new InternalConnectionWrapper(connection); + + using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) + { + Assert.Equal(5, command.ExecuteScalar()); + } + } + + // Kill the connection softly + proxy.KillAllConnections(softKill: true); + Thread.Sleep(100); + using (SqlConnection connection2 = new SqlConnection(connectionString)) + { + connection2.Open(); + Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); + + using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) + { + Assert.Equal(5, command.ExecuteScalar()); + } + } + } } + /// + /// Tests that cleanup removes connections that are unused for two cleanups + /// + private static void CleanupTest(string connectionString) + { +#if DEBUG + SqlConnection.ClearAllPools(); + + SqlConnection conn1 = new SqlConnection(connectionString); + SqlConnection conn2 = new SqlConnection(connectionString); + conn1.Open(); + conn2.Open(); + ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(conn1); + Assert.Equal(2, connectionPool.ConnectionCount); + + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + conn1.Close(); + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + conn2.Close(); + connectionPool.Cleanup(); + Assert.Equal(1, connectionPool.ConnectionCount); + + connectionPool.Cleanup(); + Assert.Equal(0, connectionPool.ConnectionCount); + + SqlConnection conn3 = new SqlConnection(connectionString); + conn3.Open(); + InternalConnectionWrapper internalConnection3 = new InternalConnectionWrapper(conn3); + + conn3.Close(); + internalConnection3.KillConnection(); + Assert.Equal(1, connectionPool.ConnectionCount); + Assert.False(internalConnection3.IsConnectionAlive(), "Connection should not be alive"); + + connectionPool.Cleanup(); + Assert.Equal(1, connectionPool.ConnectionCount); +#endif + } + + /// + /// Tests if, when max pool size is reached, Open() will block until a connection becomes available + /// + /// + private static void MaxPoolWaitForConnectionTest(string connectionString) + { + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; + SqlConnection.ClearAllPools(); + + SqlConnection connection1 = new SqlConnection(newConnectionString); + connection1.Open(); + + InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); + ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); + ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); + + Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); + Thread.Sleep(200); + Assert.Equal(TaskStatus.Running, waitTask.Status); + + connection1.Close(); + taskAllowedToSpeak.Set(); + waitTask.Wait(); + Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); + } + + private static void ReplacementConnectionObeys0TimeoutTest(string connectionString) + { +#if DEBUG + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; + SqlConnection.ClearAllPools(); + + // Kick off proxy + using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnectionString, out newConnectionString)) + { + // Create one dead connection + SqlConnection deadConnection = new SqlConnection(newConnectionString); + deadConnection.Open(); + InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); + deadConnectionInternal.KillConnection(); + + // Block one live connection + proxy.PauseCopying(); + Task blockedConnectionTask = Task.Run(() => ReplacementConnectionObeys0TimeoutTask(newConnectionString)); + Thread.Sleep(100); + Assert.Equal(TaskStatus.Running, blockedConnectionTask.Status); + + // Close and re-open the dead connection + deadConnection.Close(); + Task newConnectionTask = Task.Run(() => ReplacementConnectionObeys0TimeoutTask(newConnectionString)); + Thread.Sleep(100); + Assert.Equal(TaskStatus.Running, blockedConnectionTask.Status); + Assert.Equal(TaskStatus.Running, newConnectionTask.Status); + + // restart the proxy + proxy.ResumeCopying(); + + Task.WaitAll(blockedConnectionTask, newConnectionTask); + blockedConnectionTask.Result.Close(); + newConnectionTask.Result.Close(); + } +#endif + } + +#if NETFRAMEWORK + + /// + /// Tests if connections in a distributed transaction are put into a transaction pool. Also checks that clearallpools + /// does not clear transaction connections and that the transaction root is put into "stasis" when closed + /// + /// + private static void TransactionPoolTest(string connectionString) + { + ConnectionPoolWrapper connectionPool = null; + + using (TransactionScope transScope = new TransactionScope()) + { + SqlConnection connection1 = new SqlConnection(connectionString); + SqlConnection connection2 = new SqlConnection(connectionString); + connection1.Open(); + connection2.Open(); + connectionPool = new ConnectionPoolWrapper(connection1); + + InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); + InternalConnectionWrapper internalConnection2 = new InternalConnectionWrapper(connection2); + + Assert.True(internalConnection1.IsEnlistedInTransaction, "First connection not in transaction"); + Assert.True(internalConnection1.IsTransactionRoot, "First connection not transaction root"); + Assert.True(internalConnection2.IsEnlistedInTransaction, "Second connection not in transaction"); + Assert.False(internalConnection2.IsTransactionRoot, "Second connection is transaction root"); + + // Attempt to re-use root connection + connection1.Close(); + SqlConnection connection3 = new SqlConnection(connectionString); + connection3.Open(); + + Assert.True(connectionPool.ContainsConnection(connection3), "New connection in wrong pool"); + Assert.True(internalConnection1.IsInternalConnectionOf(connection3), "Root connection was not re-used"); + + // Attempt to re-use non-root connection + connection2.Close(); + SqlConnection connection4 = new SqlConnection(connectionString); + connection4.Open(); + Assert.True(internalConnection2.IsInternalConnectionOf(connection4), "Connection did not re-use expected internal connection"); + Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in the wrong pool"); + connection4.Close(); + + // Use a different connection string + SqlConnection connection5 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); + connection5.Open(); + Assert.False(internalConnection2.IsInternalConnectionOf(connection5), "Connection with different connection string re-used internal connection"); + Assert.False(connectionPool.ContainsConnection(connection5), "Connection with different connection string is in same pool"); + connection5.Close(); + + transScope.Complete(); + } + + Assert.Equal(2, connectionPool.ConnectionCount); + } + + /// + /// Checks that connections in the transaction pool are not cleaned out, and the root transaction is put into "stasis" when it ages + /// + /// + private static void TransactionCleanupTest(string connectionString) + { + SqlConnection.ClearAllPools(); + ConnectionPoolWrapper connectionPool = null; + + using (TransactionScope transScope = new TransactionScope()) + { + SqlConnection connection1 = new SqlConnection(connectionString); + SqlConnection connection2 = new SqlConnection(connectionString); + connection1.Open(); + connection2.Open(); + InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); + connectionPool = new ConnectionPoolWrapper(connection1); + + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + connection1.Close(); + connection2.Close(); + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + transScope.Complete(); + } + } + +#endif + private static InternalConnectionWrapper ReplacementConnectionUsesSemaphoreTask(string connectionString, Barrier syncBarrier) { InternalConnectionWrapper internalConnection = null; @@ -299,5 +547,23 @@ private static InternalConnectionWrapper CreateEmancipatedConnection(string conn connection.Open(); return new InternalConnectionWrapper(connection); } + + private static void MaxPoolWaitForConnectionTask(string connectionString, InternalConnectionWrapper internalConnection, ConnectionPoolWrapper connectionPool, ManualResetEventSlim waitToSpeak) + { + SqlConnection connection = new SqlConnection(connectionString); + connection.Open(); + waitToSpeak.Wait(); + Assert.True(internalConnection.IsInternalConnectionOf(connection), "Connection has wrong internal connection"); + Assert.True(connectionPool.ContainsConnection(connection), "Connection is in wrong connection pool"); + connection.Close(); + } + + private static SqlConnection ReplacementConnectionObeys0TimeoutTask(string connectionString) + { + SqlConnection connection = null; + connection = new SqlConnection(connectionString); + connection.Open(); + return connection; + } } } From 41eb98315218290ab32b663ccbdf9d67dbf78d52 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 7 Jul 2021 16:32:57 -0700 Subject: [PATCH 02/15] typo --- .../tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 60adb8eb30..73d03ffe30 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -6,7 +6,7 @@ netcoreapp Debug;Release;net461-Release;net461-Debug;netcoreapp2.1-Debug;netcoreapp2.1-Release;netcoreapp3.1-Debug;netcoreapp3.1-Release AnyCPU;x86;x64 - $(DefineConstants);NETFX + $(DefineConstants);NETFX $(DefineConstants);NETCOREAPP $(DefineConstants);NET50_OR_LATER $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) From 8bccaec5bbf8edfda9c99051dba3be426df4921b Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 8 Jul 2021 11:49:47 -0700 Subject: [PATCH 03/15] separate into individual tests --- .../ConnectionPoolTest/ConnectionPoolTest.cs | 166 ++++++++++++------ 1 file changed, 108 insertions(+), 58 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 0cb43f575a..786e6e5ec3 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -3,61 +3,47 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; -using System.Data; using System.Transactions; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { - public static class ConnectionPoolTest + public class ConnectionPoolConnectionStringProvider : IEnumerable { private static readonly string _TCPConnectionString = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = false, Pooling = true }).ConnectionString; private static readonly string _tcpMarsConnStr = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = true, Pooling = true }).ConnectionString; + private static bool IsNotAzureSynapse = DataTestUtility.IsNotAzureSynapse(); - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - public static void ConnectionPool_NonMars() + public IEnumerator GetEnumerator() { - RunDataTestForSingleConnString(_TCPConnectionString); + yield return new object[] { _TCPConnectionString, false }; + yield return new object[] { _tcpMarsConnStr, IsNotAzureSynapse ? false : true }; } - // TODO Synapse: Fix this test for Azure Synapse. - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] - public static void ConnectionPool_Mars() - { - RunDataTestForSingleConnString(_tcpMarsConnStr); - } - - private static void RunDataTestForSingleConnString(string tcpConnectionString) - { - BasicConnectionPoolingTest(tcpConnectionString); - ClearAllPoolsTest(tcpConnectionString); - ReclaimEmancipatedOnOpenTest(tcpConnectionString); - SoftTcpShutdownConnectionTest(tcpConnectionString); - MaxPoolWaitForConnectionTest(tcpConnectionString); - -#if NETFRAMEWORK - TransactionCleanupTest(tcpConnectionString); - TransactionPoolTest(tcpConnectionString); -#endif - - if (DataTestUtility.IsUsingManagedSNI()) - { - KillConnectionTest(tcpConnectionString); - CleanupTest(tcpConnectionString); - ReplacementConnectionUsesSemaphoreTest(tcpConnectionString); - ReplacementConnectionObeys0TimeoutTest(tcpConnectionString); - } - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + // TODO Synapse: Fix these tests for Azure Synapse. + public static class ConnectionPoolTest + { /// /// Tests that using the same connection string results in the same pool\internal connection and a different string results in a different pool\internal connection /// - /// - private static void BasicConnectionPoolingTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void BasicConnectionPoolingTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + InternalConnectionWrapper internalConnection; ConnectionPoolWrapper connectionPool; using (SqlConnection connection = new SqlConnection(connectionString)) @@ -133,13 +119,19 @@ public static void AccessTokenConnectionPoolingTest() connection4.Close(); } +#if DEBUG /// /// Tests if killing the connection using the InternalConnectionWrapper is working /// - /// - private static void KillConnectionTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void KillConnectionTest(string connectionString, bool marsAndAzureSynapse) { -#if DEBUG + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } + InternalConnectionWrapper wrapper = null; using (SqlConnection connection = new SqlConnection(connectionString)) @@ -164,15 +156,21 @@ private static void KillConnectionTest(string connectionString) DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); } } -#endif } +#endif /// /// Tests if clearing all of the pools does actually remove the pools /// - /// - private static void ClearAllPoolsTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ClearAllPoolsTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + SqlConnection.ClearAllPools(); Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); @@ -196,9 +194,15 @@ private static void ClearAllPoolsTest(string connectionString) /// Checks if an 'emancipated' internal connection is reclaimed when a new connection is opened AND we hit max pool size /// NOTE: 'emancipated' means that the internal connection's SqlConnection has fallen out of scope and has no references, but was not explicitly disposed\closed /// - /// - private static void ReclaimEmancipatedOnOpenTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReclaimEmancipatedOnOpenTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -218,9 +222,15 @@ private static void ReclaimEmancipatedOnOpenTest(string connectionString) } } - private static void ReplacementConnectionUsesSemaphoreTest(string connectionString) - { #if DEBUG + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionUsesSemaphoreTest(string connectionString, bool marsAndAzureSynapse) + { + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -282,14 +292,21 @@ private static void ReplacementConnectionUsesSemaphoreTest(string connectionStri waitAllTask.Wait(); Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); -#endif } +#endif /// /// Tests if killing the connection using the ProxyServer is working /// - private static void SoftTcpShutdownConnectionTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void SoftTcpShutdownConnectionTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(connectionString, out connectionString)) { InternalConnectionWrapper wrapper = null; @@ -320,12 +337,19 @@ private static void SoftTcpShutdownConnectionTest(string connectionString) } } +#if DEBUG /// /// Tests that cleanup removes connections that are unused for two cleanups /// - private static void CleanupTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void CleanupTest(string connectionString, bool marsAndAzureSynapse) { -#if DEBUG + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } + SqlConnection.ClearAllPools(); SqlConnection conn1 = new SqlConnection(connectionString); @@ -360,15 +384,21 @@ private static void CleanupTest(string connectionString) connectionPool.Cleanup(); Assert.Equal(1, connectionPool.ConnectionCount); -#endif } +#endif /// /// Tests if, when max pool size is reached, Open() will block until a connection becomes available /// - /// - private static void MaxPoolWaitForConnectionTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void MaxPoolWaitForConnectionTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -389,9 +419,16 @@ private static void MaxPoolWaitForConnectionTest(string connectionString) Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); } - private static void ReplacementConnectionObeys0TimeoutTest(string connectionString) - { #if DEBUG + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionObeys0TimeoutTest(string connectionString, bool marsAndAzureSynapse) + { + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -424,8 +461,8 @@ private static void ReplacementConnectionObeys0TimeoutTest(string connectionStri blockedConnectionTask.Result.Close(); newConnectionTask.Result.Close(); } -#endif } +#endif #if NETFRAMEWORK @@ -433,9 +470,15 @@ private static void ReplacementConnectionObeys0TimeoutTest(string connectionStri /// Tests if connections in a distributed transaction are put into a transaction pool. Also checks that clearallpools /// does not clear transaction connections and that the transaction root is put into "stasis" when closed /// - /// - private static void TransactionPoolTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void TransactionPoolTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + ConnectionPoolWrapper connectionPool = null; using (TransactionScope transScope = new TransactionScope()) @@ -487,8 +530,15 @@ private static void TransactionPoolTest(string connectionString) /// Checks that connections in the transaction pool are not cleaned out, and the root transaction is put into "stasis" when it ages /// /// - private static void TransactionCleanupTest(string connectionString) + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void TransactionCleanupTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + SqlConnection.ClearAllPools(); ConnectionPoolWrapper connectionPool = null; From dc96f92dd2a9d8fdda72b290f9b3a06e69a9bc0a Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 14 Jul 2021 16:18:06 -0700 Subject: [PATCH 04/15] Update ConnectionPoolTest.cs --- .../SQL/ConnectionPoolTest/ConnectionPoolTest.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 786e6e5ec3..cf098782a1 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -307,10 +307,12 @@ public static void SoftTcpShutdownConnectionTest(string connectionString, bool m return; } - using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(connectionString, out connectionString)) + string newConnString = connectionString + ";TrustServerCertificate=true"; + + using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnString, out connectionString)) { InternalConnectionWrapper wrapper = null; - using (SqlConnection connection = new SqlConnection(connectionString)) + using (SqlConnection connection = new SqlConnection(newConnString)) { connection.Open(); wrapper = new InternalConnectionWrapper(connection); @@ -324,7 +326,7 @@ public static void SoftTcpShutdownConnectionTest(string connectionString, bool m // Kill the connection softly proxy.KillAllConnections(softKill: true); Thread.Sleep(100); - using (SqlConnection connection2 = new SqlConnection(connectionString)) + using (SqlConnection connection2 = new SqlConnection(newConnString)) { connection2.Open(); Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); From 276eaaf444cb4b2d4d3492f67e256f1c3a22dc45 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Wed, 14 Jul 2021 16:55:27 -0700 Subject: [PATCH 05/15] Update ConnectionPoolTest.cs --- .../ConnectionPoolTest/ConnectionPoolTest.cs | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index cf098782a1..9ec426e075 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -295,50 +295,6 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin } #endif - /// - /// Tests if killing the connection using the ProxyServer is working - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void SoftTcpShutdownConnectionTest(string connectionString, bool marsAndAzureSynapse) - { - if (marsAndAzureSynapse) - { - return; - } - - string newConnString = connectionString + ";TrustServerCertificate=true"; - - using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnString, out connectionString)) - { - InternalConnectionWrapper wrapper = null; - using (SqlConnection connection = new SqlConnection(newConnString)) - { - connection.Open(); - wrapper = new InternalConnectionWrapper(connection); - - using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) - { - Assert.Equal(5, command.ExecuteScalar()); - } - } - - // Kill the connection softly - proxy.KillAllConnections(softKill: true); - Thread.Sleep(100); - using (SqlConnection connection2 = new SqlConnection(newConnString)) - { - connection2.Open(); - Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); - - using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) - { - Assert.Equal(5, command.ExecuteScalar()); - } - } - } - } - #if DEBUG /// /// Tests that cleanup removes connections that are unused for two cleanups From 68dcbb6bded69244fdf9f206bde2913dec77c409 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 15 Jul 2021 17:09:35 -0700 Subject: [PATCH 06/15] cleanup --- src/Microsoft.Data.SqlClient.sln | 48 +++++ .../ConnectionPoolTest/ConnectionPoolTest.cs | 201 +++++++----------- 2 files changed, 122 insertions(+), 127 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index a03e196464..e2ed615b45 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1128,6 +1128,54 @@ Global {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x64.Build.0 = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.ActiveCfg = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.Build.0 = Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.ActiveCfg = Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.Build.0 = Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.ActiveCfg = Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.Build.0 = Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.ActiveCfg = net461-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.Build.0 = net461-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.ActiveCfg = net461-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.Build.0 = net461-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.ActiveCfg = net461-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.Build.0 = net461-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.ActiveCfg = net461-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.Build.0 = net461-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.ActiveCfg = net461-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.Build.0 = net461-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.ActiveCfg = net461-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.Build.0 = net461-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.ActiveCfg = netcoreapp2.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.Build.0 = netcoreapp2.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.ActiveCfg = netcoreapp2.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.Build.0 = netcoreapp2.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.ActiveCfg = netcoreapp2.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.Build.0 = netcoreapp2.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.ActiveCfg = netcoreapp2.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.Build.0 = netcoreapp2.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.ActiveCfg = netcoreapp2.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.Build.0 = netcoreapp2.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.ActiveCfg = netcoreapp2.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.Build.0 = netcoreapp2.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.ActiveCfg = netcoreapp3.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.Build.0 = netcoreapp3.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.ActiveCfg = netcoreapp3.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.Build.0 = netcoreapp3.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.ActiveCfg = netcoreapp3.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.Build.0 = netcoreapp3.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.ActiveCfg = netcoreapp3.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.Build.0 = netcoreapp3.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.ActiveCfg = netcoreapp3.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.Build.0 = netcoreapp3.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.ActiveCfg = netcoreapp3.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.Build.0 = netcoreapp3.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.Build.0 = Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.ActiveCfg = Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.Build.0 = Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.ActiveCfg = Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 9ec426e075..d67899e46c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -18,12 +18,14 @@ public class ConnectionPoolConnectionStringProvider : IEnumerable { private static readonly string _TCPConnectionString = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = false, Pooling = true }).ConnectionString; private static readonly string _tcpMarsConnStr = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = true, Pooling = true }).ConnectionString; - private static bool IsNotAzureSynapse = DataTestUtility.IsNotAzureSynapse(); public IEnumerator GetEnumerator() { - yield return new object[] { _TCPConnectionString, false }; - yield return new object[] { _tcpMarsConnStr, IsNotAzureSynapse ? false : true }; + yield return new object[] { _TCPConnectionString}; + if (DataTestUtility.IsNotAzureSynapse()) + { + yield return new object[] { _tcpMarsConnStr}; + } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -37,13 +39,8 @@ public static class ConnectionPoolTest /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void BasicConnectionPoolingTest(string connectionString, bool marsAndAzureSynapse) + public static void BasicConnectionPoolingTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - InternalConnectionWrapper internalConnection; ConnectionPoolWrapper connectionPool; using (SqlConnection connection = new SqlConnection(connectionString)) @@ -119,58 +116,13 @@ public static void AccessTokenConnectionPoolingTest() connection4.Close(); } -#if DEBUG - /// - /// Tests if killing the connection using the InternalConnectionWrapper is working - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void KillConnectionTest(string connectionString, bool marsAndAzureSynapse) - { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) - { - return; - } - - InternalConnectionWrapper wrapper = null; - - using (SqlConnection connection = new SqlConnection(connectionString)) - { - connection.Open(); - wrapper = new InternalConnectionWrapper(connection); - - using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - - wrapper.KillConnection(); - } - - using (SqlConnection connection2 = new SqlConnection(connectionString)) - { - connection2.Open(); - Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); - using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - } - } -#endif - /// /// Tests if clearing all of the pools does actually remove the pools /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ClearAllPoolsTest(string connectionString, bool marsAndAzureSynapse) + public static void ClearAllPoolsTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - SqlConnection.ClearAllPools(); Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); @@ -196,13 +148,8 @@ public static void ClearAllPoolsTest(string connectionString, bool marsAndAzureS /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReclaimEmancipatedOnOpenTest(string connectionString, bool marsAndAzureSynapse) + public static void ReclaimEmancipatedOnOpenTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -222,16 +169,39 @@ public static void ReclaimEmancipatedOnOpenTest(string connectionString, bool ma } } -#if DEBUG + /// + /// Tests if, when max pool size is reached, Open() will block until a connection becomes available + /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionUsesSemaphoreTest(string connectionString, bool marsAndAzureSynapse) + public static void MaxPoolWaitForConnectionTest(string connectionString) { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) - { - return; - } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; + SqlConnection.ClearAllPools(); + + SqlConnection connection1 = new SqlConnection(newConnectionString); + connection1.Open(); + + InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); + ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); + ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); + + Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); + Thread.Sleep(200); + Assert.Equal(TaskStatus.Running, waitTask.Status); + connection1.Close(); + taskAllowedToSpeak.Set(); + waitTask.Wait(); + Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); + } + +#if DEBUG + + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionUsesSemaphoreTest(string connectionString) + { string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -293,21 +263,47 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin waitAllTask.Wait(); Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); } -#endif -#if DEBUG /// - /// Tests that cleanup removes connections that are unused for two cleanups + /// Tests if killing the connection using the InternalConnectionWrapper is working /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void CleanupTest(string connectionString, bool marsAndAzureSynapse) + public static void KillConnectionTest(string connectionString) { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + InternalConnectionWrapper wrapper = null; + + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + wrapper = new InternalConnectionWrapper(connection); + + using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } + + wrapper.KillConnection(); + } + + using (SqlConnection connection2 = new SqlConnection(connectionString)) { - return; + connection2.Open(); + Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); + using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } } + } + /// + /// Tests that cleanup removes connections that are unused for two cleanups + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void CleanupTest(string connectionString) + { SqlConnection.ClearAllPools(); SqlConnection conn1 = new SqlConnection(connectionString); @@ -343,50 +339,11 @@ public static void CleanupTest(string connectionString, bool marsAndAzureSynapse connectionPool.Cleanup(); Assert.Equal(1, connectionPool.ConnectionCount); } -#endif - /// - /// Tests if, when max pool size is reached, Open() will block until a connection becomes available - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void MaxPoolWaitForConnectionTest(string connectionString, bool marsAndAzureSynapse) + public static void ReplacementConnectionObeys0TimeoutTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; - SqlConnection.ClearAllPools(); - - SqlConnection connection1 = new SqlConnection(newConnectionString); - connection1.Open(); - - InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); - ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); - ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); - - Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); - Thread.Sleep(200); - Assert.Equal(TaskStatus.Running, waitTask.Status); - - connection1.Close(); - taskAllowedToSpeak.Set(); - waitTask.Wait(); - Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); - } - -#if DEBUG - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionObeys0TimeoutTest(string connectionString, bool marsAndAzureSynapse) - { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) - { - return; - } - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -430,13 +387,8 @@ public static void ReplacementConnectionObeys0TimeoutTest(string connectionStrin /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionPoolTest(string connectionString, bool marsAndAzureSynapse) + public static void TransactionPoolTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - ConnectionPoolWrapper connectionPool = null; using (TransactionScope transScope = new TransactionScope()) @@ -490,13 +442,8 @@ public static void TransactionPoolTest(string connectionString, bool marsAndAzur /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionCleanupTest(string connectionString, bool marsAndAzureSynapse) + public static void TransactionCleanupTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - SqlConnection.ClearAllPools(); ConnectionPoolWrapper connectionPool = null; From ffcf0849c7a1b3218f3d744aa5afbc57fc5d9052 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 15 Jul 2021 17:10:04 -0700 Subject: [PATCH 07/15] Revert "cleanup" This reverts commit 68dcbb6bded69244fdf9f206bde2913dec77c409. --- src/Microsoft.Data.SqlClient.sln | 48 ----- .../ConnectionPoolTest/ConnectionPoolTest.cs | 201 +++++++++++------- 2 files changed, 127 insertions(+), 122 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index e2ed615b45..a03e196464 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1128,54 +1128,6 @@ Global {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x64.Build.0 = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.ActiveCfg = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.Build.0 = Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.ActiveCfg = Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.Build.0 = Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.ActiveCfg = Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.Build.0 = Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.ActiveCfg = net461-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.Build.0 = net461-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.ActiveCfg = net461-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.Build.0 = net461-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.ActiveCfg = net461-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.Build.0 = net461-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.ActiveCfg = net461-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.Build.0 = net461-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.ActiveCfg = net461-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.Build.0 = net461-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.ActiveCfg = net461-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.Build.0 = net461-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.ActiveCfg = netcoreapp2.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.Build.0 = netcoreapp2.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.ActiveCfg = netcoreapp2.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.Build.0 = netcoreapp2.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.ActiveCfg = netcoreapp2.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.Build.0 = netcoreapp2.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.ActiveCfg = netcoreapp2.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.Build.0 = netcoreapp2.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.ActiveCfg = netcoreapp2.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.Build.0 = netcoreapp2.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.ActiveCfg = netcoreapp2.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.Build.0 = netcoreapp2.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.ActiveCfg = netcoreapp3.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.Build.0 = netcoreapp3.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.ActiveCfg = netcoreapp3.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.Build.0 = netcoreapp3.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.ActiveCfg = netcoreapp3.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.Build.0 = netcoreapp3.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.ActiveCfg = netcoreapp3.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.Build.0 = netcoreapp3.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.ActiveCfg = netcoreapp3.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.Build.0 = netcoreapp3.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.ActiveCfg = netcoreapp3.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.Build.0 = netcoreapp3.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.Build.0 = Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.ActiveCfg = Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.Build.0 = Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.ActiveCfg = Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index d67899e46c..9ec426e075 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -18,14 +18,12 @@ public class ConnectionPoolConnectionStringProvider : IEnumerable { private static readonly string _TCPConnectionString = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = false, Pooling = true }).ConnectionString; private static readonly string _tcpMarsConnStr = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = true, Pooling = true }).ConnectionString; + private static bool IsNotAzureSynapse = DataTestUtility.IsNotAzureSynapse(); public IEnumerator GetEnumerator() { - yield return new object[] { _TCPConnectionString}; - if (DataTestUtility.IsNotAzureSynapse()) - { - yield return new object[] { _tcpMarsConnStr}; - } + yield return new object[] { _TCPConnectionString, false }; + yield return new object[] { _tcpMarsConnStr, IsNotAzureSynapse ? false : true }; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -39,8 +37,13 @@ public static class ConnectionPoolTest /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void BasicConnectionPoolingTest(string connectionString) + public static void BasicConnectionPoolingTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + InternalConnectionWrapper internalConnection; ConnectionPoolWrapper connectionPool; using (SqlConnection connection = new SqlConnection(connectionString)) @@ -116,13 +119,58 @@ public static void AccessTokenConnectionPoolingTest() connection4.Close(); } +#if DEBUG + /// + /// Tests if killing the connection using the InternalConnectionWrapper is working + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void KillConnectionTest(string connectionString, bool marsAndAzureSynapse) + { + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } + + InternalConnectionWrapper wrapper = null; + + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + wrapper = new InternalConnectionWrapper(connection); + + using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } + + wrapper.KillConnection(); + } + + using (SqlConnection connection2 = new SqlConnection(connectionString)) + { + connection2.Open(); + Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); + using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } + } + } +#endif + /// /// Tests if clearing all of the pools does actually remove the pools /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ClearAllPoolsTest(string connectionString) + public static void ClearAllPoolsTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + SqlConnection.ClearAllPools(); Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); @@ -148,8 +196,13 @@ public static void ClearAllPoolsTest(string connectionString) /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReclaimEmancipatedOnOpenTest(string connectionString) + public static void ReclaimEmancipatedOnOpenTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -169,39 +222,16 @@ public static void ReclaimEmancipatedOnOpenTest(string connectionString) } } - /// - /// Tests if, when max pool size is reached, Open() will block until a connection becomes available - /// +#if DEBUG [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void MaxPoolWaitForConnectionTest(string connectionString) + public static void ReplacementConnectionUsesSemaphoreTest(string connectionString, bool marsAndAzureSynapse) { - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; - SqlConnection.ClearAllPools(); - - SqlConnection connection1 = new SqlConnection(newConnectionString); - connection1.Open(); - - InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); - ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); - ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); - - Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); - Thread.Sleep(200); - Assert.Equal(TaskStatus.Running, waitTask.Status); - - connection1.Close(); - taskAllowedToSpeak.Set(); - waitTask.Wait(); - Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); - } - -#if DEBUG + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionUsesSemaphoreTest(string connectionString) - { string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -263,47 +293,21 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin waitAllTask.Wait(); Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); } +#endif +#if DEBUG /// - /// Tests if killing the connection using the InternalConnectionWrapper is working + /// Tests that cleanup removes connections that are unused for two cleanups /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void KillConnectionTest(string connectionString) + public static void CleanupTest(string connectionString, bool marsAndAzureSynapse) { - InternalConnectionWrapper wrapper = null; - - using (SqlConnection connection = new SqlConnection(connectionString)) - { - connection.Open(); - wrapper = new InternalConnectionWrapper(connection); - - using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - - wrapper.KillConnection(); - } - - using (SqlConnection connection2 = new SqlConnection(connectionString)) + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) { - connection2.Open(); - Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); - using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } + return; } - } - /// - /// Tests that cleanup removes connections that are unused for two cleanups - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void CleanupTest(string connectionString) - { SqlConnection.ClearAllPools(); SqlConnection conn1 = new SqlConnection(connectionString); @@ -339,11 +343,50 @@ public static void CleanupTest(string connectionString) connectionPool.Cleanup(); Assert.Equal(1, connectionPool.ConnectionCount); } +#endif - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + /// + /// Tests if, when max pool size is reached, Open() will block until a connection becomes available + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionObeys0TimeoutTest(string connectionString) + public static void MaxPoolWaitForConnectionTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; + SqlConnection.ClearAllPools(); + + SqlConnection connection1 = new SqlConnection(newConnectionString); + connection1.Open(); + + InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); + ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); + ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); + + Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); + Thread.Sleep(200); + Assert.Equal(TaskStatus.Running, waitTask.Status); + + connection1.Close(); + taskAllowedToSpeak.Set(); + waitTask.Wait(); + Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); + } + +#if DEBUG + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionObeys0TimeoutTest(string connectionString, bool marsAndAzureSynapse) + { + if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + { + return; + } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -387,8 +430,13 @@ public static void ReplacementConnectionObeys0TimeoutTest(string connectionStrin /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionPoolTest(string connectionString) + public static void TransactionPoolTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + ConnectionPoolWrapper connectionPool = null; using (TransactionScope transScope = new TransactionScope()) @@ -442,8 +490,13 @@ public static void TransactionPoolTest(string connectionString) /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionCleanupTest(string connectionString) + public static void TransactionCleanupTest(string connectionString, bool marsAndAzureSynapse) { + if (marsAndAzureSynapse) + { + return; + } + SqlConnection.ClearAllPools(); ConnectionPoolWrapper connectionPool = null; From 9eda3769e101bf094fc8ad022d26b30447d58b97 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Thu, 15 Jul 2021 17:10:32 -0700 Subject: [PATCH 08/15] cleanup --- .../ConnectionPoolTest/ConnectionPoolTest.cs | 201 +++++++----------- 1 file changed, 74 insertions(+), 127 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 9ec426e075..1feeea0174 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -18,12 +18,14 @@ public class ConnectionPoolConnectionStringProvider : IEnumerable { private static readonly string _TCPConnectionString = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = false, Pooling = true }).ConnectionString; private static readonly string _tcpMarsConnStr = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = true, Pooling = true }).ConnectionString; - private static bool IsNotAzureSynapse = DataTestUtility.IsNotAzureSynapse(); public IEnumerator GetEnumerator() { - yield return new object[] { _TCPConnectionString, false }; - yield return new object[] { _tcpMarsConnStr, IsNotAzureSynapse ? false : true }; + yield return new object[] { _TCPConnectionString }; + if (DataTestUtility.IsNotAzureSynapse()) + { + yield return new object[] { _tcpMarsConnStr }; + } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -37,13 +39,8 @@ public static class ConnectionPoolTest /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void BasicConnectionPoolingTest(string connectionString, bool marsAndAzureSynapse) + public static void BasicConnectionPoolingTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - InternalConnectionWrapper internalConnection; ConnectionPoolWrapper connectionPool; using (SqlConnection connection = new SqlConnection(connectionString)) @@ -119,58 +116,13 @@ public static void AccessTokenConnectionPoolingTest() connection4.Close(); } -#if DEBUG - /// - /// Tests if killing the connection using the InternalConnectionWrapper is working - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void KillConnectionTest(string connectionString, bool marsAndAzureSynapse) - { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) - { - return; - } - - InternalConnectionWrapper wrapper = null; - - using (SqlConnection connection = new SqlConnection(connectionString)) - { - connection.Open(); - wrapper = new InternalConnectionWrapper(connection); - - using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - - wrapper.KillConnection(); - } - - using (SqlConnection connection2 = new SqlConnection(connectionString)) - { - connection2.Open(); - Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); - using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - } - } -#endif - /// /// Tests if clearing all of the pools does actually remove the pools /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ClearAllPoolsTest(string connectionString, bool marsAndAzureSynapse) + public static void ClearAllPoolsTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - SqlConnection.ClearAllPools(); Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); @@ -196,13 +148,8 @@ public static void ClearAllPoolsTest(string connectionString, bool marsAndAzureS /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReclaimEmancipatedOnOpenTest(string connectionString, bool marsAndAzureSynapse) + public static void ReclaimEmancipatedOnOpenTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -222,16 +169,39 @@ public static void ReclaimEmancipatedOnOpenTest(string connectionString, bool ma } } -#if DEBUG + /// + /// Tests if, when max pool size is reached, Open() will block until a connection becomes available + /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionUsesSemaphoreTest(string connectionString, bool marsAndAzureSynapse) + public static void MaxPoolWaitForConnectionTest(string connectionString) { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) - { - return; - } + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; + SqlConnection.ClearAllPools(); + + SqlConnection connection1 = new SqlConnection(newConnectionString); + connection1.Open(); + + InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); + ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); + ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); + + Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); + Thread.Sleep(200); + Assert.Equal(TaskStatus.Running, waitTask.Status); + connection1.Close(); + taskAllowedToSpeak.Set(); + waitTask.Wait(); + Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); + } + +#if DEBUG + + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionUsesSemaphoreTest(string connectionString) + { string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -293,21 +263,47 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin waitAllTask.Wait(); Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); } -#endif -#if DEBUG /// - /// Tests that cleanup removes connections that are unused for two cleanups + /// Tests if killing the connection using the InternalConnectionWrapper is working /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void CleanupTest(string connectionString, bool marsAndAzureSynapse) + public static void KillConnectionTest(string connectionString) { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) + InternalConnectionWrapper wrapper = null; + + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + wrapper = new InternalConnectionWrapper(connection); + + using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } + + wrapper.KillConnection(); + } + + using (SqlConnection connection2 = new SqlConnection(connectionString)) { - return; + connection2.Open(); + Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); + using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } } + } + /// + /// Tests that cleanup removes connections that are unused for two cleanups + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void CleanupTest(string connectionString) + { SqlConnection.ClearAllPools(); SqlConnection conn1 = new SqlConnection(connectionString); @@ -343,50 +339,11 @@ public static void CleanupTest(string connectionString, bool marsAndAzureSynapse connectionPool.Cleanup(); Assert.Equal(1, connectionPool.ConnectionCount); } -#endif - /// - /// Tests if, when max pool size is reached, Open() will block until a connection becomes available - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void MaxPoolWaitForConnectionTest(string connectionString, bool marsAndAzureSynapse) + public static void ReplacementConnectionObeys0TimeoutTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; - SqlConnection.ClearAllPools(); - - SqlConnection connection1 = new SqlConnection(newConnectionString); - connection1.Open(); - - InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); - ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection1); - ManualResetEventSlim taskAllowedToSpeak = new ManualResetEventSlim(false); - - Task waitTask = Task.Factory.StartNew(() => MaxPoolWaitForConnectionTask(newConnectionString, internalConnection, connectionPool, taskAllowedToSpeak)); - Thread.Sleep(200); - Assert.Equal(TaskStatus.Running, waitTask.Status); - - connection1.Close(); - taskAllowedToSpeak.Set(); - waitTask.Wait(); - Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); - } - -#if DEBUG - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionObeys0TimeoutTest(string connectionString, bool marsAndAzureSynapse) - { - if (marsAndAzureSynapse || !DataTestUtility.IsUsingManagedSNI()) - { - return; - } - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; SqlConnection.ClearAllPools(); @@ -430,13 +387,8 @@ public static void ReplacementConnectionObeys0TimeoutTest(string connectionStrin /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionPoolTest(string connectionString, bool marsAndAzureSynapse) + public static void TransactionPoolTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - ConnectionPoolWrapper connectionPool = null; using (TransactionScope transScope = new TransactionScope()) @@ -490,13 +442,8 @@ public static void TransactionPoolTest(string connectionString, bool marsAndAzur /// [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionCleanupTest(string connectionString, bool marsAndAzureSynapse) + public static void TransactionCleanupTest(string connectionString) { - if (marsAndAzureSynapse) - { - return; - } - SqlConnection.ClearAllPools(); ConnectionPoolWrapper connectionPool = null; From f5ca07713d14b59469a80b08c59f908726e9a0e7 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 27 Jul 2021 14:28:56 -0700 Subject: [PATCH 09/15] Update ConnectionPoolTest.cs --- .../ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 1feeea0174..fab54a11a7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -505,7 +505,7 @@ private static InternalConnectionWrapper CreateEmancipatedConnection(string conn private static void MaxPoolWaitForConnectionTask(string connectionString, InternalConnectionWrapper internalConnection, ConnectionPoolWrapper connectionPool, ManualResetEventSlim waitToSpeak) { - SqlConnection connection = new SqlConnection(connectionString); + using SqlConnection connection = new SqlConnection(connectionString); connection.Open(); waitToSpeak.Wait(); Assert.True(internalConnection.IsInternalConnectionOf(connection), "Connection has wrong internal connection"); From bd534ad36b6cdbc1de272e95cb6b2c9cef1aef7b Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 27 Jul 2021 14:31:07 -0700 Subject: [PATCH 10/15] Apply suggestions from code review Co-authored-by: Cheena Malhotra --- .../SQL/AsyncTest/BeginExecAsyncTest.cs | 2 +- .../ConnectionPoolTest/ConnectionPoolTest.cs | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs index 19bfc3b62b..f44aab4b0f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs @@ -36,7 +36,7 @@ public static void ExecuteTest() { using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) { - SqlCommand command = new SqlCommand(GenerateCommandText(), connection); + using SqlCommand command = new SqlCommand(GenerateCommandText(), connection); connection.Open(); IAsyncResult result = command.BeginExecuteNonQuery(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 1feeea0174..455c1e32c6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -179,7 +179,7 @@ public static void MaxPoolWaitForConnectionTest(string connectionString) string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 1 }).ConnectionString; SqlConnection.ClearAllPools(); - SqlConnection connection1 = new SqlConnection(newConnectionString); + using SqlConnection connection1 = new SqlConnection(newConnectionString); connection1.Open(); InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection1); @@ -306,8 +306,8 @@ public static void CleanupTest(string connectionString) { SqlConnection.ClearAllPools(); - SqlConnection conn1 = new SqlConnection(connectionString); - SqlConnection conn2 = new SqlConnection(connectionString); + using SqlConnection conn1 = new SqlConnection(connectionString); + using SqlConnection conn2 = new SqlConnection(connectionString); conn1.Open(); conn2.Open(); ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(conn1); @@ -327,7 +327,7 @@ public static void CleanupTest(string connectionString) connectionPool.Cleanup(); Assert.Equal(0, connectionPool.ConnectionCount); - SqlConnection conn3 = new SqlConnection(connectionString); + using SqlConnection conn3 = new SqlConnection(connectionString); conn3.Open(); InternalConnectionWrapper internalConnection3 = new InternalConnectionWrapper(conn3); @@ -393,8 +393,8 @@ public static void TransactionPoolTest(string connectionString) using (TransactionScope transScope = new TransactionScope()) { - SqlConnection connection1 = new SqlConnection(connectionString); - SqlConnection connection2 = new SqlConnection(connectionString); + using SqlConnection connection1 = new SqlConnection(connectionString); + using SqlConnection connection2 = new SqlConnection(connectionString); connection1.Open(); connection2.Open(); connectionPool = new ConnectionPoolWrapper(connection1); @@ -409,7 +409,7 @@ public static void TransactionPoolTest(string connectionString) // Attempt to re-use root connection connection1.Close(); - SqlConnection connection3 = new SqlConnection(connectionString); + using SqlConnection connection3 = new SqlConnection(connectionString); connection3.Open(); Assert.True(connectionPool.ContainsConnection(connection3), "New connection in wrong pool"); @@ -417,7 +417,7 @@ public static void TransactionPoolTest(string connectionString) // Attempt to re-use non-root connection connection2.Close(); - SqlConnection connection4 = new SqlConnection(connectionString); + using SqlConnection connection4 = new SqlConnection(connectionString); connection4.Open(); Assert.True(internalConnection2.IsInternalConnectionOf(connection4), "Connection did not re-use expected internal connection"); Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in the wrong pool"); @@ -449,8 +449,8 @@ public static void TransactionCleanupTest(string connectionString) using (TransactionScope transScope = new TransactionScope()) { - SqlConnection connection1 = new SqlConnection(connectionString); - SqlConnection connection2 = new SqlConnection(connectionString); + using SqlConnection connection1 = new SqlConnection(connectionString); + using SqlConnection connection2 = new SqlConnection(connectionString); connection1.Open(); connection2.Open(); InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); @@ -515,8 +515,7 @@ private static void MaxPoolWaitForConnectionTask(string connectionString, Intern private static SqlConnection ReplacementConnectionObeys0TimeoutTask(string connectionString) { - SqlConnection connection = null; - connection = new SqlConnection(connectionString); + SqlConnection connection = new SqlConnection(connectionString); connection.Open(); return connection; } From fff6641f7cc1d69667b63f168c4dd4e3891e2caf Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 27 Jul 2021 14:32:58 -0700 Subject: [PATCH 11/15] Update src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs Co-authored-by: Cheena Malhotra --- .../ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 455c1e32c6..752a1cfb56 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -424,7 +424,7 @@ public static void TransactionPoolTest(string connectionString) connection4.Close(); // Use a different connection string - SqlConnection connection5 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); + using SqlConnection connection5 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); connection5.Open(); Assert.False(internalConnection2.IsInternalConnectionOf(connection5), "Connection with different connection string re-used internal connection"); Assert.False(connectionPool.ContainsConnection(connection5), "Connection with different connection string is in same pool"); From ccb7c6947c2c49b7fd0d358cd80d19735ffdf1ca Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Fri, 6 Aug 2021 14:47:37 -0700 Subject: [PATCH 12/15] address feedback --- ....Data.SqlClient.ManualTesting.Tests.csproj | 4 + .../ConnectionPoolTest.Debug.cs | 191 ++++++++++++ .../ConnectionPoolTest/ConnectionPoolTest.cs | 288 +----------------- .../ConnectionPoolTest/TransactionPoolTest.cs | 99 ++++++ 4 files changed, 300 insertions(+), 282 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index a8e23c7e75..a720a27650 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -265,6 +265,10 @@ + + + + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs new file mode 100644 index 0000000000..d9e1dcd097 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs @@ -0,0 +1,191 @@ +using System; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; +using static Microsoft.Data.SqlClient.ManualTesting.Tests.ConnectionPoolTest; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public static class ConnectionPoolTestDebug + { + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionUsesSemaphoreTest(string connectionString) + { + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; + SqlConnection.ClearAllPools(); + + SqlConnection liveConnection = new SqlConnection(newConnectionString); + SqlConnection deadConnection = new SqlConnection(newConnectionString); + liveConnection.Open(); + deadConnection.Open(); + InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); + InternalConnectionWrapper liveConnectionInternal = new InternalConnectionWrapper(liveConnection); + deadConnectionInternal.KillConnection(); + deadConnection.Close(); + liveConnection.Close(); + + Task[] tasks = new Task[3]; + Barrier syncBarrier = new Barrier(tasks.Length); + Func taskFunction = (() => ReplacementConnectionUsesSemaphoreTask(newConnectionString, syncBarrier)); + for (int i = 0; i < tasks.Length; i++) + { + tasks[i] = Task.Factory.StartNew(taskFunction); + } + + bool taskWithLiveConnection = false; + bool taskWithNewConnection = false; + bool taskWithCorrectException = false; + + Task waitAllTask = Task.Factory.ContinueWhenAll(tasks, (completedTasks) => + { + foreach (var item in completedTasks) + { + if (item.Status == TaskStatus.Faulted) + { + // One task should have a timeout exception + if ((!taskWithCorrectException) && (item.Exception.InnerException is InvalidOperationException) && (item.Exception.InnerException.Message.StartsWith(SystemDataResourceManager.Instance.ADP_PooledOpenTimeout))) + taskWithCorrectException = true; + else if (!taskWithCorrectException) + { + // Rethrow the unknown exception + ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(item.Exception); + exceptionInfo.Throw(); + } + } + else if (item.Status == TaskStatus.RanToCompletion) + { + // One task should get the live connection + if (item.Result.Equals(liveConnectionInternal)) + { + if (!taskWithLiveConnection) + taskWithLiveConnection = true; + } + else if (!item.Result.Equals(deadConnectionInternal) && !taskWithNewConnection) + taskWithNewConnection = true; + } + else + Console.WriteLine("ERROR: Task in unknown state: {0}", item.Status); + } + }); + + waitAllTask.Wait(); + Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); + } + + /// + /// Tests if killing the connection using the InternalConnectionWrapper is working + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void KillConnectionTest(string connectionString) + { + InternalConnectionWrapper wrapper = null; + + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + wrapper = new InternalConnectionWrapper(connection); + + using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } + + wrapper.KillConnection(); + } + + using (SqlConnection connection2 = new SqlConnection(connectionString)) + { + connection2.Open(); + Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); + using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) + { + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); + } + } + } + + /// + /// Tests that cleanup removes connections that are unused for two cleanups + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void CleanupTest(string connectionString) + { + SqlConnection.ClearAllPools(); + + using SqlConnection conn1 = new SqlConnection(connectionString); + using SqlConnection conn2 = new SqlConnection(connectionString); + conn1.Open(); + conn2.Open(); + ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(conn1); + Assert.Equal(2, connectionPool.ConnectionCount); + + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + conn1.Close(); + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + conn2.Close(); + connectionPool.Cleanup(); + Assert.Equal(1, connectionPool.ConnectionCount); + + connectionPool.Cleanup(); + Assert.Equal(0, connectionPool.ConnectionCount); + + using SqlConnection conn3 = new SqlConnection(connectionString); + conn3.Open(); + InternalConnectionWrapper internalConnection3 = new InternalConnectionWrapper(conn3); + + conn3.Close(); + internalConnection3.KillConnection(); + Assert.Equal(1, connectionPool.ConnectionCount); + Assert.False(internalConnection3.IsConnectionAlive(), "Connection should not be alive"); + + connectionPool.Cleanup(); + Assert.Equal(1, connectionPool.ConnectionCount); + } + + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void ReplacementConnectionObeys0TimeoutTest(string connectionString) + { + string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; + SqlConnection.ClearAllPools(); + + // Kick off proxy + using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnectionString, out newConnectionString)) + { + // Create one dead connection + SqlConnection deadConnection = new SqlConnection(newConnectionString); + deadConnection.Open(); + InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); + deadConnectionInternal.KillConnection(); + + // Block one live connection + proxy.PauseCopying(); + Task blockedConnectionTask = Task.Run(() => ReplacementConnectionObeys0TimeoutTask(newConnectionString)); + Thread.Sleep(100); + Assert.Equal(TaskStatus.Running, blockedConnectionTask.Status); + + // Close and re-open the dead connection + deadConnection.Close(); + Task newConnectionTask = Task.Run(() => ReplacementConnectionObeys0TimeoutTask(newConnectionString)); + Thread.Sleep(100); + Assert.Equal(TaskStatus.Running, blockedConnectionTask.Status); + Assert.Equal(TaskStatus.Running, newConnectionTask.Status); + + // restart the proxy + proxy.ResumeCopying(); + + Task.WaitAll(blockedConnectionTask, newConnectionTask); + blockedConnectionTask.Result.Close(); + newConnectionTask.Result.Close(); + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index f90860c40e..5bab69b4d8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -5,11 +5,8 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Data; -using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; -using System.Transactions; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -41,6 +38,8 @@ public static class ConnectionPoolTest [ClassData(typeof(ConnectionPoolConnectionStringProvider))] public static void BasicConnectionPoolingTest(string connectionString) { + SqlConnection.ClearAllPools(); + InternalConnectionWrapper internalConnection; ConnectionPoolWrapper connectionPool; using (SqlConnection connection = new SqlConnection(connectionString)) @@ -81,6 +80,8 @@ public static void BasicConnectionPoolingTest(string connectionString) [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAADPasswordConnStrSetup), nameof(DataTestUtility.IsAADAuthorityURLSetup))] public static void AccessTokenConnectionPoolingTest() { + SqlConnection.ClearAllPools(); + // Remove cred info and add invalid token string[] credKeys = { "User ID", "Password", "UID", "PWD", "Authentication" }; string connectionString = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys); @@ -196,284 +197,7 @@ public static void MaxPoolWaitForConnectionTest(string connectionString) Assert.Equal(TaskStatus.RanToCompletion, waitTask.Status); } -#if DEBUG - - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionUsesSemaphoreTest(string connectionString) - { - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; - SqlConnection.ClearAllPools(); - - SqlConnection liveConnection = new SqlConnection(newConnectionString); - SqlConnection deadConnection = new SqlConnection(newConnectionString); - liveConnection.Open(); - deadConnection.Open(); - InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); - InternalConnectionWrapper liveConnectionInternal = new InternalConnectionWrapper(liveConnection); - deadConnectionInternal.KillConnection(); - deadConnection.Close(); - liveConnection.Close(); - - Task[] tasks = new Task[3]; - Barrier syncBarrier = new Barrier(tasks.Length); - Func taskFunction = (() => ReplacementConnectionUsesSemaphoreTask(newConnectionString, syncBarrier)); - for (int i = 0; i < tasks.Length; i++) - { - tasks[i] = Task.Factory.StartNew(taskFunction); - } - - - bool taskWithLiveConnection = false; - bool taskWithNewConnection = false; - bool taskWithCorrectException = false; - - Task waitAllTask = Task.Factory.ContinueWhenAll(tasks, (completedTasks) => - { - foreach (var item in completedTasks) - { - if (item.Status == TaskStatus.Faulted) - { - // One task should have a timeout exception - if ((!taskWithCorrectException) && (item.Exception.InnerException is InvalidOperationException) && (item.Exception.InnerException.Message.StartsWith(SystemDataResourceManager.Instance.ADP_PooledOpenTimeout))) - taskWithCorrectException = true; - else if (!taskWithCorrectException) - { - // Rethrow the unknown exception - ExceptionDispatchInfo exceptionInfo = ExceptionDispatchInfo.Capture(item.Exception); - exceptionInfo.Throw(); - } - } - else if (item.Status == TaskStatus.RanToCompletion) - { - // One task should get the live connection - if (item.Result.Equals(liveConnectionInternal)) - { - if (!taskWithLiveConnection) - taskWithLiveConnection = true; - } - else if (!item.Result.Equals(deadConnectionInternal) && !taskWithNewConnection) - taskWithNewConnection = true; - } - else - Console.WriteLine("ERROR: Task in unknown state: {0}", item.Status); - } - }); - - waitAllTask.Wait(); - Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); - } - - /// - /// Tests if killing the connection using the InternalConnectionWrapper is working - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void KillConnectionTest(string connectionString) - { - InternalConnectionWrapper wrapper = null; - - using (SqlConnection connection = new SqlConnection(connectionString)) - { - connection.Open(); - wrapper = new InternalConnectionWrapper(connection); - - using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - - wrapper.KillConnection(); - } - - using (SqlConnection connection2 = new SqlConnection(connectionString)) - { - connection2.Open(); - Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); - using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } - } - } - - /// - /// Tests that cleanup removes connections that are unused for two cleanups - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void CleanupTest(string connectionString) - { - SqlConnection.ClearAllPools(); - - using SqlConnection conn1 = new SqlConnection(connectionString); - using SqlConnection conn2 = new SqlConnection(connectionString); - conn1.Open(); - conn2.Open(); - ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(conn1); - Assert.Equal(2, connectionPool.ConnectionCount); - - connectionPool.Cleanup(); - Assert.Equal(2, connectionPool.ConnectionCount); - - conn1.Close(); - connectionPool.Cleanup(); - Assert.Equal(2, connectionPool.ConnectionCount); - - conn2.Close(); - connectionPool.Cleanup(); - Assert.Equal(1, connectionPool.ConnectionCount); - - connectionPool.Cleanup(); - Assert.Equal(0, connectionPool.ConnectionCount); - - using SqlConnection conn3 = new SqlConnection(connectionString); - conn3.Open(); - InternalConnectionWrapper internalConnection3 = new InternalConnectionWrapper(conn3); - - conn3.Close(); - internalConnection3.KillConnection(); - Assert.Equal(1, connectionPool.ConnectionCount); - Assert.False(internalConnection3.IsConnectionAlive(), "Connection should not be alive"); - - connectionPool.Cleanup(); - Assert.Equal(1, connectionPool.ConnectionCount); - } - - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsUsingManagedSNI))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void ReplacementConnectionObeys0TimeoutTest(string connectionString) - { - string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { ConnectTimeout = 0 }).ConnectionString; - SqlConnection.ClearAllPools(); - - // Kick off proxy - using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnectionString, out newConnectionString)) - { - // Create one dead connection - SqlConnection deadConnection = new SqlConnection(newConnectionString); - deadConnection.Open(); - InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); - deadConnectionInternal.KillConnection(); - - // Block one live connection - proxy.PauseCopying(); - Task blockedConnectionTask = Task.Run(() => ReplacementConnectionObeys0TimeoutTask(newConnectionString)); - Thread.Sleep(100); - Assert.Equal(TaskStatus.Running, blockedConnectionTask.Status); - - // Close and re-open the dead connection - deadConnection.Close(); - Task newConnectionTask = Task.Run(() => ReplacementConnectionObeys0TimeoutTask(newConnectionString)); - Thread.Sleep(100); - Assert.Equal(TaskStatus.Running, blockedConnectionTask.Status); - Assert.Equal(TaskStatus.Running, newConnectionTask.Status); - - // restart the proxy - proxy.ResumeCopying(); - - Task.WaitAll(blockedConnectionTask, newConnectionTask); - blockedConnectionTask.Result.Close(); - newConnectionTask.Result.Close(); - } - } -#endif - -#if NETFRAMEWORK - - /// - /// Tests if connections in a distributed transaction are put into a transaction pool. Also checks that clearallpools - /// does not clear transaction connections and that the transaction root is put into "stasis" when closed - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionPoolTest(string connectionString) - { - ConnectionPoolWrapper connectionPool = null; - - using (TransactionScope transScope = new TransactionScope()) - { - using SqlConnection connection1 = new SqlConnection(connectionString); - using SqlConnection connection2 = new SqlConnection(connectionString); - connection1.Open(); - connection2.Open(); - connectionPool = new ConnectionPoolWrapper(connection1); - - InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); - InternalConnectionWrapper internalConnection2 = new InternalConnectionWrapper(connection2); - - Assert.True(internalConnection1.IsEnlistedInTransaction, "First connection not in transaction"); - Assert.True(internalConnection1.IsTransactionRoot, "First connection not transaction root"); - Assert.True(internalConnection2.IsEnlistedInTransaction, "Second connection not in transaction"); - Assert.False(internalConnection2.IsTransactionRoot, "Second connection is transaction root"); - - // Attempt to re-use root connection - connection1.Close(); - using SqlConnection connection3 = new SqlConnection(connectionString); - connection3.Open(); - - Assert.True(connectionPool.ContainsConnection(connection3), "New connection in wrong pool"); - Assert.True(internalConnection1.IsInternalConnectionOf(connection3), "Root connection was not re-used"); - - // Attempt to re-use non-root connection - connection2.Close(); - using SqlConnection connection4 = new SqlConnection(connectionString); - connection4.Open(); - Assert.True(internalConnection2.IsInternalConnectionOf(connection4), "Connection did not re-use expected internal connection"); - Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in the wrong pool"); - connection4.Close(); - - // Use a different connection string - using SqlConnection connection5 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); - connection5.Open(); - Assert.False(internalConnection2.IsInternalConnectionOf(connection5), "Connection with different connection string re-used internal connection"); - Assert.False(connectionPool.ContainsConnection(connection5), "Connection with different connection string is in same pool"); - connection5.Close(); - - transScope.Complete(); - } - - Assert.Equal(2, connectionPool.ConnectionCount); - } - - /// - /// Checks that connections in the transaction pool are not cleaned out, and the root transaction is put into "stasis" when it ages - /// - /// - [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - [ClassData(typeof(ConnectionPoolConnectionStringProvider))] - public static void TransactionCleanupTest(string connectionString) - { - SqlConnection.ClearAllPools(); - ConnectionPoolWrapper connectionPool = null; - - using (TransactionScope transScope = new TransactionScope()) - { - using SqlConnection connection1 = new SqlConnection(connectionString); - using SqlConnection connection2 = new SqlConnection(connectionString); - connection1.Open(); - connection2.Open(); - InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); - connectionPool = new ConnectionPoolWrapper(connection1); - - connectionPool.Cleanup(); - Assert.Equal(2, connectionPool.ConnectionCount); - - connection1.Close(); - connection2.Close(); - connectionPool.Cleanup(); - Assert.Equal(2, connectionPool.ConnectionCount); - - connectionPool.Cleanup(); - Assert.Equal(2, connectionPool.ConnectionCount); - - transScope.Complete(); - } - } - -#endif - - private static InternalConnectionWrapper ReplacementConnectionUsesSemaphoreTask(string connectionString, Barrier syncBarrier) + internal static InternalConnectionWrapper ReplacementConnectionUsesSemaphoreTask(string connectionString, Barrier syncBarrier) { InternalConnectionWrapper internalConnection = null; @@ -513,7 +237,7 @@ private static void MaxPoolWaitForConnectionTask(string connectionString, Intern connection.Close(); } - private static SqlConnection ReplacementConnectionObeys0TimeoutTask(string connectionString) + internal static SqlConnection ReplacementConnectionObeys0TimeoutTask(string connectionString) { SqlConnection connection = new SqlConnection(connectionString); connection.Open(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs new file mode 100644 index 0000000000..e7e2172e03 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs @@ -0,0 +1,99 @@ +using System.Transactions; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public static class TransactionPoolTest + { + /// + /// Tests if connections in a distributed transaction are put into a transaction pool. Also checks that clearallpools + /// does not clear transaction connections and that the transaction root is put into "stasis" when closed + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void BasicTransactionPoolTest(string connectionString) + { + SqlConnection.ClearAllPools(); + ConnectionPoolWrapper connectionPool = null; + + using (TransactionScope transScope = new TransactionScope()) + { + using SqlConnection connection1 = new SqlConnection(connectionString); + using SqlConnection connection2 = new SqlConnection(connectionString); + connection1.Open(); + connection2.Open(); + connectionPool = new ConnectionPoolWrapper(connection1); + + InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); + InternalConnectionWrapper internalConnection2 = new InternalConnectionWrapper(connection2); + + Assert.True(internalConnection1.IsEnlistedInTransaction, "First connection not in transaction"); + Assert.True(internalConnection1.IsTransactionRoot, "First connection not transaction root"); + Assert.True(internalConnection2.IsEnlistedInTransaction, "Second connection not in transaction"); + Assert.False(internalConnection2.IsTransactionRoot, "Second connection is transaction root"); + + // Attempt to re-use root connection + connection1.Close(); + using SqlConnection connection3 = new SqlConnection(connectionString); + connection3.Open(); + + Assert.True(connectionPool.ContainsConnection(connection3), "New connection in wrong pool"); + Assert.True(internalConnection1.IsInternalConnectionOf(connection3), "Root connection was not re-used"); + + // Attempt to re-use non-root connection + connection2.Close(); + using SqlConnection connection4 = new SqlConnection(connectionString); + connection4.Open(); + Assert.True(internalConnection2.IsInternalConnectionOf(connection4), "Connection did not re-use expected internal connection"); + Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in the wrong pool"); + connection4.Close(); + + // Use a different connection string + using SqlConnection connection5 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); + connection5.Open(); + Assert.False(internalConnection2.IsInternalConnectionOf(connection5), "Connection with different connection string re-used internal connection"); + Assert.False(connectionPool.ContainsConnection(connection5), "Connection with different connection string is in same pool"); + connection5.Close(); + + transScope.Complete(); + } + + Assert.Equal(2, connectionPool.ConnectionCount); + } + + /// + /// Checks that connections in the transaction pool are not cleaned out, and the root transaction is put into "stasis" when it ages + /// + /// + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ClassData(typeof(ConnectionPoolConnectionStringProvider))] + public static void TransactionCleanupTest(string connectionString) + { + SqlConnection.ClearAllPools(); + ConnectionPoolWrapper connectionPool = null; + + using (TransactionScope transScope = new TransactionScope()) + { + using SqlConnection connection1 = new SqlConnection(connectionString); + using SqlConnection connection2 = new SqlConnection(connectionString); + connection1.Open(); + connection2.Open(); + InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); + connectionPool = new ConnectionPoolWrapper(connection1); + + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + connection1.Close(); + connection2.Close(); + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + connectionPool.Cleanup(); + Assert.Equal(2, connectionPool.ConnectionCount); + + transScope.Complete(); + } + } + } +} From abf15bfe9593fd4b3a130a5220cb95f482567c80 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 10 Aug 2021 12:17:51 -0700 Subject: [PATCH 13/15] address feedback --- .../ConnectionPoolTest/ConnectionPoolTest.Debug.cs | 6 +++--- .../SQL/ConnectionPoolTest/ConnectionPoolTest.cs | 14 +++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs index d9e1dcd097..9173c93192 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs @@ -16,8 +16,8 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); - SqlConnection liveConnection = new SqlConnection(newConnectionString); - SqlConnection deadConnection = new SqlConnection(newConnectionString); + using SqlConnection liveConnection = new SqlConnection(newConnectionString); + using SqlConnection deadConnection = new SqlConnection(newConnectionString); liveConnection.Open(); deadConnection.Open(); InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); @@ -161,7 +161,7 @@ public static void ReplacementConnectionObeys0TimeoutTest(string connectionStrin using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnectionString, out newConnectionString)) { // Create one dead connection - SqlConnection deadConnection = new SqlConnection(newConnectionString); + using SqlConnection deadConnection = new SqlConnection(newConnectionString); deadConnection.Open(); InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); deadConnectionInternal.KillConnection(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 5bab69b4d8..41a6404a20 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -47,7 +47,6 @@ public static void BasicConnectionPoolingTest(string connectionString) connection.Open(); internalConnection = new InternalConnectionWrapper(connection); connectionPool = new ConnectionPoolWrapper(connection); - connection.Close(); } using (SqlConnection connection2 = new SqlConnection(connectionString)) @@ -55,7 +54,6 @@ public static void BasicConnectionPoolingTest(string connectionString) connection2.Open(); Assert.True(internalConnection.IsInternalConnectionOf(connection2), "New connection does not use same internal connection"); Assert.True(connectionPool.ContainsConnection(connection2), "New connection is in a different pool"); - connection2.Close(); } using (SqlConnection connection3 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;")) @@ -63,7 +61,6 @@ public static void BasicConnectionPoolingTest(string connectionString) connection3.Open(); Assert.False(internalConnection.IsInternalConnectionOf(connection3), "Connection with different connection string uses same internal connection"); Assert.False(connectionPool.ContainsConnection(connection3), "Connection with different connection string uses same connection pool"); - connection3.Close(); } connectionPool.Cleanup(); @@ -73,7 +70,6 @@ public static void BasicConnectionPoolingTest(string connectionString) connection4.Open(); Assert.True(internalConnection.IsInternalConnectionOf(connection4), "New connection does not use same internal connection"); Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in a different pool"); - connection4.Close(); } } @@ -86,21 +82,21 @@ public static void AccessTokenConnectionPoolingTest() string[] credKeys = { "User ID", "Password", "UID", "PWD", "Authentication" }; string connectionString = DataTestUtility.RemoveKeysInConnStr(DataTestUtility.AADPasswordConnectionString, credKeys); - SqlConnection connection = new SqlConnection(connectionString); + using SqlConnection connection = new SqlConnection(connectionString); connection.AccessToken = DataTestUtility.GetAccessToken(); connection.Open(); InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection); ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection); connection.Close(); - SqlConnection connection2 = new SqlConnection(connectionString); + using SqlConnection connection2 = new SqlConnection(connectionString); connection2.AccessToken = DataTestUtility.GetAccessToken(); connection2.Open(); Assert.True(internalConnection.IsInternalConnectionOf(connection2), "New connection does not use same internal connection"); Assert.True(connectionPool.ContainsConnection(connection2), "New connection is in a different pool"); connection2.Close(); - SqlConnection connection3 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); + using SqlConnection connection3 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); connection3.AccessToken = DataTestUtility.GetAccessToken(); connection3.Open(); Assert.False(internalConnection.IsInternalConnectionOf(connection3), "Connection with different connection string uses same internal connection"); @@ -109,7 +105,7 @@ public static void AccessTokenConnectionPoolingTest() connectionPool.Cleanup(); - SqlConnection connection4 = new SqlConnection(connectionString); + using SqlConnection connection4 = new SqlConnection(connectionString); connection4.AccessToken = DataTestUtility.GetAccessToken(); connection4.Open(); Assert.True(internalConnection.IsInternalConnectionOf(connection4), "New connection does not use same internal connection"); @@ -133,6 +129,7 @@ public static void ClearAllPoolsTest(string connectionString) ConnectionPoolWrapper pool = new ConnectionPoolWrapper(connection); connection.Close(); ConnectionPoolWrapper[] allPools = ConnectionPoolWrapper.AllConnectionPools(); + DataTestUtility.AssertEqualsWithDescription(1, allPools.Length, "Incorrect number of pools exist."); Assert.True(allPools[0].Equals(pool), "Saved pool is not in the list of all pools"); DataTestUtility.AssertEqualsWithDescription(1, pool.ConnectionCount, "Saved pool has incorrect number of connections"); @@ -234,7 +231,6 @@ private static void MaxPoolWaitForConnectionTask(string connectionString, Intern waitToSpeak.Wait(); Assert.True(internalConnection.IsInternalConnectionOf(connection), "Connection has wrong internal connection"); Assert.True(connectionPool.ContainsConnection(connection), "Connection is in wrong connection pool"); - connection.Close(); } internal static SqlConnection ReplacementConnectionObeys0TimeoutTask(string connectionString) From ef3fba3b1b6483eb04a936aa6cb5530221eeb637 Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Tue, 17 Aug 2021 13:08:00 -0700 Subject: [PATCH 14/15] style changes --- .../SQL/AsyncTest/BeginExecAsyncTest.cs | 20 ++++---- .../SQL/Common/InternalConnectionWrapper.cs | 9 ++-- .../ConnectionPoolTest.Debug.cs | 50 ++++++++++--------- .../ConnectionPoolTest/TransactionPoolTest.cs | 22 ++++---- 4 files changed, 49 insertions(+), 52 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs index b4522b9bdf..cdf89fbac1 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs @@ -34,20 +34,18 @@ private static string GenerateCommandText() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public static void ExecuteTest() { - using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) - { + using SqlConnection connection = new(DataTestUtility.TCPConnectionString); - using SqlCommand command = new SqlCommand(GenerateCommandText(), connection); - connection.Open(); + using SqlCommand command = new(GenerateCommandText(), connection); + connection.Open(); - IAsyncResult result = command.BeginExecuteNonQuery(); - while (!result.IsCompleted) - { - System.Threading.Thread.Sleep(100); - } - - Assert.True(command.EndExecuteNonQuery(result) > 0, "FAILED: BeginExecuteNonQuery did not complete successfully."); + IAsyncResult result = command.BeginExecuteNonQuery(); + while (!result.IsCompleted) + { + System.Threading.Thread.Sleep(100); } + + Assert.True(command.EndExecuteNonQuery(result) > 0, "FAILED: BeginExecuteNonQuery did not complete successfully."); } // Synapse: Parse error at line: 1, column: 201: Incorrect syntax near ';'. diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs index 4e8740a4dc..38c62d69e9 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/InternalConnectionWrapper.cs @@ -21,21 +21,18 @@ public class InternalConnectionWrapper /// /// Is this internal connection enlisted in a distributed transaction? /// - public bool IsEnlistedInTransaction - { get { return ConnectionHelper.IsEnlistedInTransaction(_internalConnection); } } + public bool IsEnlistedInTransaction => ConnectionHelper.IsEnlistedInTransaction(_internalConnection); /// /// Is this internal connection the root of a distributed transaction? /// - public bool IsTransactionRoot - { get { return ConnectionHelper.IsTransactionRoot(_internalConnection); } } + public bool IsTransactionRoot => ConnectionHelper.IsTransactionRoot(_internalConnection); /// /// True if this connection is the root of a transaction AND it is waiting for the transaction /// to complete (i.e. it has been 'aged' or 'put into stasis'), otherwise false /// - public bool IsTxRootWaitingForTxEnd - { get { return ConnectionHelper.IsTxRootWaitingForTxEnd(_internalConnection); } } + public bool IsTxRootWaitingForTxEnd => ConnectionHelper.IsTxRootWaitingForTxEnd(_internalConnection); /// /// Gets the internal connection associated with the given SqlConnection diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs index 9173c93192..8f911fc2a8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.Debug.cs @@ -16,22 +16,22 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin string newConnectionString = (new SqlConnectionStringBuilder(connectionString) { MaxPoolSize = 2, ConnectTimeout = 5 }).ConnectionString; SqlConnection.ClearAllPools(); - using SqlConnection liveConnection = new SqlConnection(newConnectionString); - using SqlConnection deadConnection = new SqlConnection(newConnectionString); + using SqlConnection liveConnection = new(newConnectionString); + using SqlConnection deadConnection = new(newConnectionString); liveConnection.Open(); deadConnection.Open(); - InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); - InternalConnectionWrapper liveConnectionInternal = new InternalConnectionWrapper(liveConnection); + InternalConnectionWrapper deadConnectionInternal = new(deadConnection); + InternalConnectionWrapper liveConnectionInternal = new(liveConnection); deadConnectionInternal.KillConnection(); deadConnection.Close(); liveConnection.Close(); Task[] tasks = new Task[3]; - Barrier syncBarrier = new Barrier(tasks.Length); + Barrier syncBarrier = new(tasks.Length); Func taskFunction = (() => ReplacementConnectionUsesSemaphoreTask(newConnectionString, syncBarrier)); for (int i = 0; i < tasks.Length; i++) { - tasks[i] = Task.Factory.StartNew(taskFunction); + tasks[i] = Task.Factory.StartNew(taskFunction); } bool taskWithLiveConnection = false; @@ -71,7 +71,11 @@ public static void ReplacementConnectionUsesSemaphoreTest(string connectionStrin }); waitAllTask.Wait(); - Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, string.Format("Tasks didn't finish as expected.\nTask with live connection: {0}\nTask with new connection: {1}\nTask with correct exception: {2}\n", taskWithLiveConnection, taskWithNewConnection, taskWithCorrectException)); + Assert.True(taskWithLiveConnection && taskWithNewConnection && taskWithCorrectException, + $"Tasks didn't finish as expected.\n" + + $"Task with live connection: {taskWithLiveConnection}\n" + + $"Task with new connection: {taskWithNewConnection}\n" + + $"Task with correct exception: {taskWithCorrectException}\n"); } /// @@ -83,27 +87,25 @@ public static void KillConnectionTest(string connectionString) { InternalConnectionWrapper wrapper = null; - using (SqlConnection connection = new SqlConnection(connectionString)) + using (SqlConnection connection = new(connectionString)) { connection.Open(); wrapper = new InternalConnectionWrapper(connection); - using (SqlCommand command = new SqlCommand("SELECT 5;", connection)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } + using SqlCommand command = new("SELECT 5;", connection); + + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); wrapper.KillConnection(); } - using (SqlConnection connection2 = new SqlConnection(connectionString)) + using (SqlConnection connection2 = new(connectionString)) { connection2.Open(); Assert.False(wrapper.IsInternalConnectionOf(connection2), "New connection has internal connection that was just killed"); - using (SqlCommand command = new SqlCommand("SELECT 5;", connection2)) - { - DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); - } + using SqlCommand command = new("SELECT 5;", connection2); + + DataTestUtility.AssertEqualsWithDescription(5, command.ExecuteScalar(), "Incorrect scalar result."); } } @@ -116,11 +118,11 @@ public static void CleanupTest(string connectionString) { SqlConnection.ClearAllPools(); - using SqlConnection conn1 = new SqlConnection(connectionString); - using SqlConnection conn2 = new SqlConnection(connectionString); + using SqlConnection conn1 = new(connectionString); + using SqlConnection conn2 = new(connectionString); conn1.Open(); conn2.Open(); - ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(conn1); + ConnectionPoolWrapper connectionPool = new(conn1); Assert.Equal(2, connectionPool.ConnectionCount); connectionPool.Cleanup(); @@ -137,9 +139,9 @@ public static void CleanupTest(string connectionString) connectionPool.Cleanup(); Assert.Equal(0, connectionPool.ConnectionCount); - using SqlConnection conn3 = new SqlConnection(connectionString); + using SqlConnection conn3 = new(connectionString); conn3.Open(); - InternalConnectionWrapper internalConnection3 = new InternalConnectionWrapper(conn3); + InternalConnectionWrapper internalConnection3 = new(conn3); conn3.Close(); internalConnection3.KillConnection(); @@ -161,9 +163,9 @@ public static void ReplacementConnectionObeys0TimeoutTest(string connectionStrin using (ProxyServer proxy = ProxyServer.CreateAndStartProxy(newConnectionString, out newConnectionString)) { // Create one dead connection - using SqlConnection deadConnection = new SqlConnection(newConnectionString); + using SqlConnection deadConnection = new(newConnectionString); deadConnection.Open(); - InternalConnectionWrapper deadConnectionInternal = new InternalConnectionWrapper(deadConnection); + InternalConnectionWrapper deadConnectionInternal = new(deadConnection); deadConnectionInternal.KillConnection(); // Block one live connection diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs index e7e2172e03..65ace84d11 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs @@ -16,16 +16,16 @@ public static void BasicTransactionPoolTest(string connectionString) SqlConnection.ClearAllPools(); ConnectionPoolWrapper connectionPool = null; - using (TransactionScope transScope = new TransactionScope()) + using (TransactionScope transScope = new()) { - using SqlConnection connection1 = new SqlConnection(connectionString); - using SqlConnection connection2 = new SqlConnection(connectionString); + using SqlConnection connection1 = new(connectionString); + using SqlConnection connection2 = new(connectionString); connection1.Open(); connection2.Open(); connectionPool = new ConnectionPoolWrapper(connection1); - InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); - InternalConnectionWrapper internalConnection2 = new InternalConnectionWrapper(connection2); + InternalConnectionWrapper internalConnection1 = new(connection1); + InternalConnectionWrapper internalConnection2 = new(connection2); Assert.True(internalConnection1.IsEnlistedInTransaction, "First connection not in transaction"); Assert.True(internalConnection1.IsTransactionRoot, "First connection not transaction root"); @@ -34,7 +34,7 @@ public static void BasicTransactionPoolTest(string connectionString) // Attempt to re-use root connection connection1.Close(); - using SqlConnection connection3 = new SqlConnection(connectionString); + using SqlConnection connection3 = new(connectionString); connection3.Open(); Assert.True(connectionPool.ContainsConnection(connection3), "New connection in wrong pool"); @@ -42,14 +42,14 @@ public static void BasicTransactionPoolTest(string connectionString) // Attempt to re-use non-root connection connection2.Close(); - using SqlConnection connection4 = new SqlConnection(connectionString); + using SqlConnection connection4 = new(connectionString); connection4.Open(); Assert.True(internalConnection2.IsInternalConnectionOf(connection4), "Connection did not re-use expected internal connection"); Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in the wrong pool"); connection4.Close(); // Use a different connection string - using SqlConnection connection5 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); + using SqlConnection connection5 = new(connectionString + ";App=SqlConnectionPoolUnitTest;"); connection5.Open(); Assert.False(internalConnection2.IsInternalConnectionOf(connection5), "Connection with different connection string re-used internal connection"); Assert.False(connectionPool.ContainsConnection(connection5), "Connection with different connection string is in same pool"); @@ -74,11 +74,11 @@ public static void TransactionCleanupTest(string connectionString) using (TransactionScope transScope = new TransactionScope()) { - using SqlConnection connection1 = new SqlConnection(connectionString); - using SqlConnection connection2 = new SqlConnection(connectionString); + using SqlConnection connection1 = new(connectionString); + using SqlConnection connection2 = new(connectionString); connection1.Open(); connection2.Open(); - InternalConnectionWrapper internalConnection1 = new InternalConnectionWrapper(connection1); + InternalConnectionWrapper internalConnection1 = new(connection1); connectionPool = new ConnectionPoolWrapper(connection1); connectionPool.Cleanup(); From 8cb4f605c085df832730ffefa93ae3cdd42e9d2b Mon Sep 17 00:00:00 2001 From: Johnny Pham Date: Fri, 17 Sep 2021 15:07:28 -0700 Subject: [PATCH 15/15] trigger ci --- .../ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs index 65ace84d11..7b7193db5b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs @@ -72,7 +72,7 @@ public static void TransactionCleanupTest(string connectionString) SqlConnection.ClearAllPools(); ConnectionPoolWrapper connectionPool = null; - using (TransactionScope transScope = new TransactionScope()) + using (TransactionScope transScope = new()) { using SqlConnection connection1 = new(connectionString); using SqlConnection connection2 = new(connectionString);