Fixed issue and added Manual Test.
authorKeerat Singh <v-kesin@microsoft.com>
Sat, 4 Aug 2018 01:14:58 +0000 (18:14 -0700)
committerKeerat Singh <v-kesin@microsoft.com>
Sat, 4 Aug 2018 01:14:58 +0000 (18:14 -0700)
Commit migrated from https://github.com/dotnet/corefx/commit/dd49053b9c379dd3c0f470762343345e23c9d97c

src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNITcpHandle.cs
src/libraries/System.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
src/libraries/System.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs

index 448a48a..5c49c70 100644 (file)
@@ -561,7 +561,17 @@ namespace System.Data.SqlClient.SNI
         {
             try
             {
-                if (!_socket.Connected || _socket.Poll(0, SelectMode.SelectError))
+                // _socket.Poll method with argument SelectMode.SelectRead returns 
+                //      True : if Listen has been called and a connection is pending, or
+                //      True : if data is available for reading, or
+                //      True : if the connection has been closed, reset, or terminated, i.e no active connection.
+                //      False : otherwise.
+                // _socket.Available property returns the number of bytes of data available to read.
+                //
+                // Since _socket.Connected alone doesn't guarantee if the connection is still active, we use it in 
+                // combination with _socket.Poll method and _socket.Available == 0 check. When both of them 
+                // return true we can safely determine that the connection is no longer active.
+                if (!_socket.Connected || (_socket.Poll(100, SelectMode.SelectRead) && _socket.Available == 0))
                 {
                     return TdsEnums.SNI_ERROR;
                 }
index 07ed683..f1160fb 100644 (file)
@@ -264,13 +264,11 @@ namespace System.Data.SqlClient.ManualTesting.Tests
         public static void RunNonQuery(string connectionString, string sql)
         {
             using (SqlConnection connection = new SqlConnection(connectionString))
+            using (SqlCommand command = connection.CreateCommand())
             {
                 connection.Open();
-                using (SqlCommand command = connection.CreateCommand())
-                {
-                    command.CommandText = sql;
-                    command.ExecuteNonQuery();
-                }
+                command.CommandText = sql;
+                command.ExecuteNonQuery();
             }
         }
 
index 1ccfd69..510d489 100644 (file)
@@ -13,6 +13,16 @@ namespace System.Data.SqlClient.ManualTesting.Tests
     {
         private const string COL_PROGRAM_NAME = "ProgramName";
         private const string COL_HOSTNAME = "HostName";
+        private static readonly string s_databaseName = "d_" + Guid.NewGuid().ToString().Replace('-', '_');
+        private static readonly string s_tableName = "Person";
+        private static readonly string s_connectionString = DataTestUtility.TcpConnStr;
+        private static readonly string s_dbConnectionString = new SqlConnectionStringBuilder(s_connectionString) { InitialCatalog = s_databaseName }.ConnectionString;
+        private static readonly string s_createDatabaseCmd = $"CREATE DATABASE {s_databaseName}";
+        private static readonly string s_createTableCmd = $"CREATE TABLE {s_tableName} (NAME NVARCHAR(40), AGE INT)";
+        private static readonly string s_alterDatabaseSingleCmd = $"ALTER DATABASE {s_databaseName} SET SINGLE_USER WITH ROLLBACK IMMEDIATE;";
+        private static readonly string s_alterDatabaseMultiCmd = $"ALTER DATABASE {s_databaseName} SET MULTI_USER WITH ROLLBACK IMMEDIATE;";
+        private static readonly string s_selectTableCmd = $"SELECT COUNT(*) FROM {s_tableName}";
+        private static readonly string s_dropDatabaseCmd = $"DROP DATABASE {s_databaseName}";
 
         [CheckConnStrSetupFact]
         public static void EnvironmentHostNameTest()
@@ -169,5 +179,35 @@ namespace System.Data.SqlClient.ManualTesting.Tests
                 _doneEvent.Set();
             }
         }
+
+        [CheckConnStrSetupFact]
+        public static void ConnectionKilledTest()
+        {
+            try
+            {
+                // Setup Database and Table.
+                DataTestUtility.RunNonQuery(s_connectionString, s_createDatabaseCmd);
+                DataTestUtility.RunNonQuery(s_dbConnectionString, s_createTableCmd);
+
+                // Kill all the connections and set Database to SINGLE_USER Mode.
+                DataTestUtility.RunNonQuery(s_connectionString, s_alterDatabaseSingleCmd);
+                // Set Database back to MULTI_USER Mode
+                DataTestUtility.RunNonQuery(s_connectionString, s_alterDatabaseMultiCmd);
+
+                // Execute SELECT statement.
+                DataTestUtility.RunNonQuery(s_dbConnectionString, s_selectTableCmd);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error: {ex.Message}");
+                Assert.Null(ex);
+            }
+            finally
+            {
+                // Kill all the connections, set Database to SINGLE_USER Mode and drop Database
+                DataTestUtility.RunNonQuery(s_connectionString, s_alterDatabaseSingleCmd);
+                DataTestUtility.RunNonQuery(s_connectionString, s_dropDatabaseCmd);
+            }
+        }
     }
 }