diff --git a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs index 43c7bde4bd..dd2dcb0d4b 100644 --- a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs +++ b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Threading; +using System.Threading.Tasks; + namespace Microsoft.Data.SqlClient.Tests.Common { /// @@ -13,14 +16,55 @@ public static class SqlDataReaderExtensions /// Reads all result sets in the provided and discards them. /// /// Reader to flush results from. - public static void FlushAllResults(this SqlDataReader dataReader) + /// + /// If true, the records in each result set will be flushed, too. If false + /// only will be the only method called. + /// + public static void FlushAllResults(this SqlDataReader dataReader, bool flushResults = true) { do { - dataReader.FlushResultSet(); + if (flushResults) + { + dataReader.FlushResultSet(); + } } while (dataReader.NextResult()); } + /// + /// Reads all result sets in the provided and discards them. + /// + /// Reader to flush results from. + /// + /// If true, the records in each result set will be flushed, too. If false + /// only will be the only method called. + /// + public static Task FlushAllResultsAsync(this SqlDataReader dataReader, bool flushResults = true) => + FlushAllResultsAsync(dataReader, CancellationToken.None, flushResults); + + /// + /// Reads all result sets in the provided and discards them. + /// + /// Reader to flush results from. + /// Token to use for premature cancellation of the task. + /// + /// If true, the records in each result set will be flushed, too. If false + /// only will be the only method called. + /// + public static async Task FlushAllResultsAsync( + this SqlDataReader dataReader, + CancellationToken cancellationToken, + bool flushResults = true) + { + do + { + if (flushResults) + { + await dataReader.FlushResultSetAsync(cancellationToken).ConfigureAwait(false); + } + } while (await dataReader.NextResultAsync(cancellationToken).ConfigureAwait(false)); + } + /// /// Reads all results in the current result set of the provided /// and discards them. @@ -33,5 +77,27 @@ public static void FlushResultSet(this SqlDataReader dataReader) // Discard results. } } + + /// + /// Reads all results in the current result set of the provided + /// and discards them. + /// + /// Reader to flush results from. + public static Task FlushResultSetAsync(this SqlDataReader dataReader) => + FlushResultSetAsync(dataReader, CancellationToken.None); + + /// + /// Reads all results in the current result set of the provided + /// and discards them. + /// + /// Reader to flush results from. + /// Token to use for premature cancellation of the task. + public static async Task FlushResultSetAsync(this SqlDataReader dataReader, CancellationToken cancellationToken) + { + while (await dataReader.ReadAsync(cancellationToken).ConfigureAwait(false)) + { + // Discard results. + } + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj index 7f6d8abd2c..99287f012d 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.FunctionalTests.csproj @@ -47,14 +47,12 @@ - - diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/MultiplexerTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/MultiplexerTests.cs index efa7962d28..76270480bf 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/MultiplexerTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/MultiplexerTests.cs @@ -53,7 +53,7 @@ public static void PassThroughSinglePacket(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -67,7 +67,7 @@ public static void PassThroughMultiplePacket(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -81,7 +81,7 @@ public static void PassThroughMultiplePacketWithShortEnd(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -96,7 +96,7 @@ public static void ReconstructSinglePacket(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -115,7 +115,7 @@ public static void Reconstruct2Packets_Part_PartFull(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -134,7 +134,7 @@ public static void Reconstruct2Packets_Full_FullPart_Part(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -154,7 +154,7 @@ public static void ReconstructMultiplePacketSequence(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -173,7 +173,7 @@ public static void ReconstructMultiplePacketSequenceWithShortEnd(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalTheory(nameof(IsUsingModernProcessSni)), MemberData(nameof(IsAsync))] @@ -189,7 +189,7 @@ public static void Reconstruct3Packets_PartPartPart(bool isAsync) var output = MultiplexPacketList(isAsync, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalFact(nameof(IsUsingModernProcessSni))] @@ -208,7 +208,7 @@ public static void TrailingPartialPacketInSnapshotNotDuplicated() var output = MultiplexPacketList(true, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ConditionalFact(nameof(IsUsingModernProcessSni))] @@ -252,7 +252,7 @@ public static void MultipleFullPacketsInRemainderAreSplitCorrectly() var output = MultiplexPacketList(false, dataSize, input); - ComparePacketLists(dataSize, expected, output); + ComparePacketLists(expected, output); } [ExcludeFromCodeCoverage] @@ -269,16 +269,14 @@ private static List MultiplexPacketList(bool isAsync, int dataSize, if (stateObject._inBytesRead > 0) { - if ( - stateObject._inBytesRead < TdsEnums.HEADER_LEN - || - stateObject._inBytesRead != (TdsEnums.HEADER_LEN + - Packet.GetDataLengthFromHeader( - stateObject._inBuff.AsSpan(0, TdsEnums.HEADER_LEN))) - ) - { - Assert.Fail("incomplete packet exposed after call to ProcessSniPacket"); - } + // At least the header must be read + Assert.False(stateObject._inBytesRead < TdsEnums.HEADER_LEN); + + // The full packet must be read, too + Span header = stateObject._inBuff.AsSpan(0, TdsEnums.HEADER_LEN); + int packetLength = Packet.GetDataLengthFromHeader(header); + int expectedLength = TdsEnums.HEADER_LEN + packetLength; + Assert.Equal(expectedLength, stateObject._inBytesRead); if (!isAsync) { @@ -299,17 +297,14 @@ private static List MultiplexPacketList(bool isAsync, int dataSize, if (stateObject._inBytesRead > 0) { - if ( - stateObject._inBytesRead < TdsEnums.HEADER_LEN - || - stateObject._inBytesRead != (TdsEnums.HEADER_LEN + - Packet.GetDataLengthFromHeader( - stateObject._inBuff.AsSpan(0, TdsEnums.HEADER_LEN))) - ) - { - Assert.Fail( - "incomplete packet exposed after call to ProcessSniPacket with usePartialPacket"); - } + // Header must at least have been read + Assert.False(stateObject._inBytesRead < TdsEnums.HEADER_LEN); + + // Full packet must have been read + Span header = stateObject._inBuff.AsSpan(0, TdsEnums.HEADER_LEN); + int packetLength = Packet.GetDataLengthFromHeader(header); + int expectedLength = TdsEnums.HEADER_LEN + packetLength; + Assert.Equal(expectedLength, stateObject._inBytesRead); output.Add(PacketData.Copy(stateObject._inBuff, stateObject._inBytesUsed, stateObject._inBytesRead)); @@ -326,7 +321,7 @@ private static List MultiplexPacketList(bool isAsync, int dataSize, } [ExcludeFromCodeCoverage] - private static void ComparePacketLists(int dataSize, List expected, List output) + private static void ComparePacketLists(List expected, List output) { Assert.NotNull(expected); Assert.NotNull(output); @@ -334,15 +329,10 @@ private static void ComparePacketLists(int dataSize, List expected, for (int index = 0; index < expected.Count; index++) { - var a = expected[index]; - var b = output[index]; - - var compare = a.AsSpan().SequenceCompareTo(b.AsSpan()); - - if (compare != 0) - { - Assert.Fail($"expected data does not match output data at packet index {index}"); - } + Span a = expected[index].AsSpan(); + Span b = output[index].AsSpan(); + + Assert.True(a.SequenceEqual(b), $"Packet data was not equal at index {index}"); } } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorCollectionTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorCollectionTest.cs deleted file mode 100644 index 32f236c761..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorCollectionTest.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections; -using Xunit; - -namespace Microsoft.Data.SqlClient.Tests -{ - public class SqlErrorCollectionTest - { - private const string badServer = "92B96911A0BD43E8ADA4451031F7E7CF"; - - [Fact] - public void IsSynchronized_Success() - { - ICollection c = CreateCollection(); - Assert.False(c.IsSynchronized); - } - - [Fact] - public void SyncRoot_Success() - { - ICollection c = CreateCollection(); - Assert.Same(c, c.SyncRoot); - } - - [Fact] - public void Indexer_Success() - { - SqlErrorCollection c = CreateCollection(); - Assert.NotNull(c[0]); - Assert.Same(c[0], c[0]); - } - - [Fact] - public void Indexer_Throws() - { - SqlErrorCollection c = CreateCollection(); - - AssertExtensions.Throws("index", () => c[-1]); - AssertExtensions.Throws("index", () => c[c.Count]); - } - - [Fact] - public void CopyTo_Success() - { - ValidateCopyTo((collection, array, index) => collection.CopyTo(array, index)); - } - - [Fact] - public void CopyTo_NonGeneric_Success() - { - ValidateCopyTo((collection, array, index) => ((ICollection)collection).CopyTo(array, index)); - } - - private static void ValidateCopyTo(Action copyTo) - { - SqlErrorCollection c = CreateCollection(); - SqlError[] destination = new SqlError[5]; - - copyTo(c, destination, 2); - - Assert.Null(destination[0]); - Assert.Null(destination[1]); - Assert.Same(c[0], destination[2]); - Assert.Null(destination[3]); - Assert.Null(destination[4]); - } - - [Fact] - public void CopyTo_Throws() - { - ValidateCopyToThrows((collection, array, index) => collection.CopyTo(array, index)); - } - - [Fact] - public void CopyTo_NonGeneric_Throws() - { - ValidateCopyToThrows((collection, array, index) => ((ICollection)collection).CopyTo(array, index), c => - { - ICollection ic = c; - AssertExtensions.Throws(null, () => ic.CopyTo(new SqlError[4, 3], 0)); - Assert.Throws(() => ic.CopyTo(new string[10], 0)); - }); - } - - private static void ValidateCopyToThrows( - Action copyTo, - Action additionalValidation = null) - { - SqlErrorCollection c = CreateCollection(); - - Assert.Throws(() => copyTo(c, null, 0)); - Assert.Throws(() => copyTo(c, null, -1)); - Assert.Throws(() => copyTo(c, new SqlError[10], -1)); - AssertExtensions.Throws("destinationArray", "", () => copyTo(c, new SqlError[10], 1000)); - - additionalValidation?.Invoke(c); - } - - [Fact] - public void GetEnumerator_Success() - { - SqlErrorCollection c = CreateCollection(); - - IEnumerator e = c.GetEnumerator(); - - Assert.NotNull(e); - Assert.NotSame(e, c.GetEnumerator()); - - for (int i = 0; i < 2; i++) - { - Assert.Throws(() => e.Current); - - Assert.True(e.MoveNext()); - Assert.Same(c[0], e.Current); - - Assert.False(e.MoveNext()); - Assert.False(e.MoveNext()); - Assert.False(e.MoveNext()); - - Assert.Throws(() => e.Current); - - e.Reset(); - } - } - - private static SqlErrorCollection CreateCollection() - { - var builder = new SqlConnectionStringBuilder() - { - DataSource = badServer, - ConnectTimeout = 1, - Pooling = false - }; - - using (var connection = new SqlConnection(builder.ConnectionString)) - { - try - { - connection.Open(); - } - catch (SqlException ex) - { - Assert.NotNull(ex.Errors); - Assert.Single(ex.Errors); - - return ex.Errors; - } - } - - throw new InvalidOperationException("SqlException.Errors should have been returned."); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs deleted file mode 100644 index ee05379870..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.IO; -using System.Reflection; -using System.Runtime.Serialization; -using Xunit; - -namespace Microsoft.Data.SqlClient.Tests -{ - public class SqlErrorTest - { - private const string SQLMSF_FailoverPartnerNotSupported = - "Connecting to a mirrored SQL Server instance using the MultiSubnetFailover connection option is not supported."; - private const byte FATAL_ERROR_CLASS = 20; - -#if NETFRAMEWORK - [Fact] - public static void SqlErrorSerializationTest() - { - DataContractSerializer serializer = new DataContractSerializer(typeof(SqlError)); - SqlError expected = CreateError(); - SqlError actual = null; - using (var stream = new MemoryStream()) - { - try - { - serializer.WriteObject(stream, expected); - stream.Position = 0; - actual = (SqlError)serializer.ReadObject(stream); - } - catch (Exception ex) - { - Assert.Fail($"Unexpected Exception occurred: {ex.Message}"); - } - } - - Assert.Equal(expected.Message, actual.Message); - Assert.Equal(expected.Number, actual.Number); - Assert.Equal(expected.State, actual.State); - Assert.Equal(expected.Class, actual.Class); - Assert.Equal(expected.Server, actual.Server); - Assert.Equal(expected.Procedure, actual.Procedure); - Assert.Equal(expected.LineNumber, actual.LineNumber); - Assert.Equal(expected.Source, actual.Source); - } -#endif - - - private static SqlError CreateError() - { - string msg = SQLMSF_FailoverPartnerNotSupported; - - Type sqlErrorType = typeof(SqlError); - - // SqlError only has internal constructors, in order to instantiate this, we use reflection - SqlError sqlError = (SqlError)sqlErrorType.Assembly.CreateInstance( - sqlErrorType.FullName, - false, - BindingFlags.Instance | BindingFlags.NonPublic, - null, - new object[] { 100, (byte)0x00, FATAL_ERROR_CLASS, "ServerName", msg, "ProcedureName", 10, null, -1 }, - null, - null); - - return sqlError; - } - } -} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs index 7d63e9b98f..5fab83f925 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs @@ -14,6 +14,7 @@ using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; using Microsoft.Data.SqlClient.ManualTesting.Tests.SystemDataInternals; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted @@ -2455,7 +2456,6 @@ public void TestRetryWhenAEParameterMetadataCacheIsStale(string connectionString { Assert.Equal(customerId, (int)reader[0]); } - reader.Close(); }; // change the CEK for the CustomerId column from ColumnEncryptionKey1 to ColumnEncryptionKey2 @@ -2474,7 +2474,6 @@ public void TestRetryWhenAEParameterMetadataCacheIsStale(string connectionString { Assert.Equal(customerId, (int)reader[0]); } - reader.Close(); } // revert the CEK change to the CustomerId column @@ -2522,7 +2521,6 @@ public void TestRetryWhenAEEnclaveCacheIsStale(string connectionString) { Assert.Equal(customerId, (int)reader[0]); } - reader.Close(); } CommandHelper.InvalidateEnclaveSession(cmd); @@ -2534,7 +2532,6 @@ public void TestRetryWhenAEEnclaveCacheIsStale(string connectionString) { Assert.Equal(customerId, (int)reader[0]); } - reader.Close(); } CommandHelper.InvalidateEnclaveSession(cmd); @@ -2568,7 +2565,6 @@ public void TestRetryWhenAEEnclaveCacheIsStale(string connectionString) { Assert.Equal(customerId, (int)reader[0]); } - reader.Close(); } CommandHelper.ForceThrowDuringGenerateEnclavePackage(cmd); @@ -2863,11 +2859,8 @@ private async Task ExecuteScalarAsync(SqlCommand sqlCommand, CancellationToken c /// private async Task ExecuteReaderAsync(SqlCommand sqlCommand, CancellationToken cancellationToken) { - using (SqlDataReader reader = await sqlCommand.ExecuteReaderAsync(cancellationToken)) - { - while (await reader.ReadAsync()) - { } - } + using SqlDataReader reader = await sqlCommand.ExecuteReaderAsync(cancellationToken); + await reader.FlushResultSetAsync(); } /// @@ -3027,7 +3020,7 @@ private void EndExecuteReaderAsyncCallBack(IAsyncResult asyncResult) catch (Exception e) { testAsyncCallBackStateObject.Completion.SetException(e); - Assert.Fail($"{e.Message}"); + throw; } } @@ -3183,9 +3176,10 @@ private void TestCancellationToken(FieldInfo failpoint, SqlCommand sqlCommand, i Console.WriteLine($"Cancellation produced non-SqlException: {ex}"); } } + if (unexpected) { - Assert.Fail("Unexpected exceptions encountered; see console for details."); + throw; } } @@ -3221,7 +3215,6 @@ private void Thread_ExecuteReader(object state) { TestCommandCancelParams cancelCommandTestParamsObject = state as TestCommandCancelParams; SqlCommand sqlCommand = cancelCommandTestParamsObject?.SqlCommand; - SqlDataReader reader = null; Assert.True(cancelCommandTestParamsObject != null, @"cancelCommandTestParamsObject should not be null."); Assert.True(sqlCommand != null, "sqlCommand should not be null."); @@ -3233,24 +3226,21 @@ private void Thread_ExecuteReader(object state) Exception ex = Assert.ThrowsAny(() => { - reader = sqlCommand.ExecuteReader(); - while (reader.Read()) - { } + using SqlDataReader reader = sqlCommand.ExecuteReader(); + reader.FlushResultSet(); }); // We don't use Assert.Contains() here because it truncates the // actual and expected strings when outputting a failure. if (!_cancellationExceptionMessages.Contains(ex.Message)) { - Assert.Fail( - $"Exception message \"{ex.Message}\" not found in: [\"" + - string.Join("\", \"", _cancellationExceptionMessages) + "\"]"); + string joinedExceptionList = string.Join("\", \"", _cancellationExceptionMessages); + Assert.Fail($"Exception message \"{ex.Message}\" not found in: [\"{joinedExceptionList}\"]"); } } finally { - reader?.Dispose(); - // ...and unlock the cancellation thread once we finish. + // Unlock the cancellation thread once we finish. cancelCommandTestParamsObject.WorkloadCompleteSignal.Set(); } } @@ -3274,9 +3264,8 @@ private void Thread_ExecuteNonQuery(object state) // actual and expected strings when outputting a failure. if (!_cancellationExceptionMessages.Contains(ex.Message)) { - Assert.Fail( - $"Exception message \"{ex.Message}\" not found in: [\"" + - string.Join("\", \"", _cancellationExceptionMessages) + "\"]"); + string joinedExceptions = string.Join("\", \"", _cancellationExceptionMessages); + Assert.Fail($"Exception message \"{ex.Message}\" not found in: [\"{joinedExceptions}\"]"); } } finally diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ConversionTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ConversionTests.cs index f54609e2c0..90d7a9fadb 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ConversionTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ConversionTests.cs @@ -28,6 +28,17 @@ public sealed class ConversionTests : IDisposable, IClassFixture GenerateOutOfRangeValuesForType(SqlDbType type, int length return list; } - /// - /// Check if this exception is expected. - /// - /// - /// - private bool IsExpectedException(Exception e) - { - return e is OverflowException || - e is InvalidCastException || - e is SqlTypeException || - e is ArgumentException || - e is FormatException || - e is SqlException; - } - /// /// Try to execute the command and check if there was an error if one was expected. /// @@ -581,32 +577,9 @@ private void ExecuteAndCheckForError(SqlCommand sqlCmd, bool expectError) } else { - try - { - sqlCmd.ExecuteNonQuery(); - StringBuilder builder = new( - "We should have gotten an error but passed instead; " + - $"command: {sqlCmd.CommandText}; parameters: "); - foreach (SqlParameter param in sqlCmd.Parameters) - { - builder.Append('('); - builder.Append(param.ParameterName); - builder.Append(' '); - builder.Append(param.SqlDbType); - builder.Append(' '); - builder.Append(param.Value); - builder.Append(") "); - } - Assert.Fail(builder.ToString()); - } - catch (Exception e) - { - Type exceptionType = e.GetType(); - if (!IsExpectedException(e)) - { - throw; - } - } + Action action = () => sqlCmd.ExecuteNonQuery(); + Exception exception = Assert.ThrowsAny(action); + Assert.Contains(exception.GetType(), ExpectedExceptionTypes); } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 0bb9654efc..9bcde64e27 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -999,27 +999,6 @@ public static TException AssertThrowsWrapper(Action actionThatFails, string[] exceptionMessages, bool innerExceptionMustBeNull = false, Func customExceptionVerifier = null) where TException : Exception - { - try - { - actionThatFails(); - Assert.Fail("ERROR: Did not get expected exception"); - return null; - } - catch (Exception ex) - { - foreach (string exceptionMessage in exceptionMessages) - { - if ((CheckException(ex, exceptionMessage, innerExceptionMustBeNull)) && ((customExceptionVerifier == null) || (customExceptionVerifier(ex as TException)))) - { - return (ex as TException); - } - } - throw; - } - } - public static string GenerateObjectName() { return string.Format("TEST_{0}{1}{2}", Environment.GetEnvironmentVariable("ComputerName"), Environment.TickCount, Guid.NewGuid()).Replace('-', '_'); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs index 9dd87d8f21..e637015b15 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs @@ -5,6 +5,7 @@ using System; using System.Text; using System.Threading.Tasks; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -140,7 +141,7 @@ private async Task RunCommand(SqlConnection connection, string commandText, bool Task timeBombTask = null; try { - // Set us up the (time) bomb + // Set up us the (time) bomb if (poison) { timeBombTask = TimeBombAsync(command); @@ -164,10 +165,7 @@ private async Task RunCommand(SqlConnection connection, string commandText, bool // This looks a little strange, we failed to read above so this should // fail too. But consider the case where this code is elsewhere (in the // Dispose method of a class holding this logic) - while (await reader.NextResultAsync()) - { - // Discard all results - } + await reader.FlushAllResultsAsync(flushResults: false); throw; } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTimeoutTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTimeoutTest.cs index 834157aeec..7ad21e5d41 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTimeoutTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTimeoutTest.cs @@ -166,39 +166,23 @@ private static async Task QueryAndValidate(AsyncAPI api, int index, string delay case AsyncAPI.ExecuteXmlReaderAsync: using (XmlReader reader = await cmd.ExecuteXmlReaderAsync().ConfigureAwait(false)) { - try - { - Assert.True(reader.Settings.Async); - reader.ReadToDescendant("Id"); - result = reader.ReadElementContentAsInt(); - } - catch (Exception ex) - { - Assert.Fail("Exception occurred: " + ex.Message); - } + Assert.NotNull(reader.Settings); + Assert.True(reader.Settings.Async); + + reader.ReadToDescendant("Id"); + result = reader.ReadElementContentAsInt(); } break; } - if (result != index) - { - throw new Exception("High Alert! Wrong data received for index: " + index); - } - else - { - Assert.True(!timeoutExExpected && result == index); - } + Assert.False(timeoutExExpected); + Assert.Equal(index, result); } catch (SqlException e) { - if (!timeoutExExpected) - { - throw new Exception("Index " + index + " failed with: " + e.Message); - } - else - { - Assert.True(timeoutExExpected && e.Class == 11 && e.Number == -2); - } + Assert.True(timeoutExExpected); + Assert.Equal(11, e.Class); + Assert.Equal(-2, e.Number); } finally { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs index 8be5437b9f..b7811c40ac 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs @@ -74,26 +74,15 @@ public static void ExceptionTest() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public static async Task MoveToContentAsyncTest() { - using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) - using (SqlCommand command = new SqlCommand(CommandText, connection)) - { - connection.Open(); + using SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString); + using SqlCommand command = new SqlCommand(CommandText, connection); + connection.Open(); - using (XmlReader xmlReader = await command.ExecuteXmlReaderAsync().ConfigureAwait(false)) - { - try - { - // Issue #781: Test failed here as xmlReader.Settings.Async was set to false - Assert.True(xmlReader.Settings.Async); - xmlReader.ReadToDescendant("dbo.Customers"); - Assert.Equal("ALFKI", xmlReader["CustomerID"]); - } - catch (Exception ex) - { - Assert.Fail("Exception occurred: " + ex.Message); - } - } - } + using XmlReader xmlReader = await command.ExecuteXmlReaderAsync().ConfigureAwait(false); + // Issue #781: Test failed here as xmlReader.Settings.Async was set to false + Assert.True(xmlReader.Settings.Async); + xmlReader.ReadToDescendant("dbo.Customers"); + Assert.Equal("ALFKI", xmlReader["CustomerID"]); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectionBehaviorTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectionBehaviorTest.cs index 5b108400b0..cce54d9aaf 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectionBehaviorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectionBehaviorTest.cs @@ -4,6 +4,7 @@ using System.Data; using System.Threading.Tasks; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -13,51 +14,43 @@ public class ConnectionBehaviorTest [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] public void ConnectionBehaviorClose() { - using (SqlConnection sqlConnection = new SqlConnection((new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MaxPoolSize = 1 }).ConnectionString)) + // Arrange + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString) { MaxPoolSize = 1 }; + using SqlConnection sqlConnection = new SqlConnection(builder.ConnectionString); + sqlConnection.Open(); + + using SqlCommand command = sqlConnection.CreateCommand(); + command.CommandText = "SELECT 1"; + + // Act + using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection)) { - using (SqlCommand command = new SqlCommand("SELECT '1'", sqlConnection)) - { - sqlConnection.Open(); - using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection)) - { - while (reader.Read()) - { - string result = reader[0].ToString(); - } - } - - Assert.Equal(ConnectionState.Closed, sqlConnection.State); - } + reader.FlushResultSet(); } + + // Assert + Assert.Equal(ConnectionState.Closed, sqlConnection.State); } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - public void ConnectionBehaviorCloseAsync() + public async Task ConnectionBehaviorCloseAsync() { - using (SqlConnection sqlConnection = new SqlConnection((new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MaxPoolSize = 1 }).ConnectionString)) - { - Task result = VerifyConnectionBehaviorCloseAsync(sqlConnection); - bool value = result.Result; - } - } + // Arrange + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString) { MaxPoolSize = 1 }; + using SqlConnection sqlConnection = new SqlConnection(builder.ConnectionString); + await sqlConnection.OpenAsync(); - private async Task VerifyConnectionBehaviorCloseAsync(SqlConnection sqlConnection) - { - using (SqlCommand command = new SqlCommand("SELECT '1'", sqlConnection)) + using SqlCommand command = sqlConnection.CreateCommand(); + command.CommandText = "SELECT 1"; + + // Act + using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.CloseConnection)) { - await sqlConnection.OpenAsync(); - using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.CloseConnection)) - { - while (reader.Read()) - { - string result = reader[0].ToString(); - } - } - - Assert.Equal(ConnectionState.Closed, sqlConnection.State); + await reader.FlushResultSetAsync(); } - return true; + // Assert + Assert.Equal(ConnectionState.Closed, sqlConnection.State); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs index a500055490..0812ea21e2 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs @@ -84,6 +84,8 @@ public static void EnvironmentHostNameSPIDTest() // Confirm Server Process Id stays the same after query execution Assert.Equal(sessionSpid, sqlConnection.ServerProcessId); } + + // @TODO: Test that *returns* to indicate success is all kinds of messed up. Assert.Fail("No non-empty hostname found for the application"); } @@ -305,15 +307,11 @@ public static void ConnectionResiliencySPIDTest() int clientSPID = conn.ServerProcessId; int serverSPID = 0; InternalConnectionWrapper wrapper = new(conn, true, builder.ConnectionString); + using SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "SELECT @@SPID"; - using (SqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - serverSPID = reader.GetInt16(0); - } - } + + serverSPID = (int)cmd.ExecuteScalar()!; Assert.Equal(serverSPID, clientSPID); // Also check SPID after query execution @@ -322,13 +320,7 @@ public static void ConnectionResiliencySPIDTest() wrapper.KillConnectionByTSql(); // Connection resiliency should reconnect transparently - using (SqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - serverSPID = reader.GetInt16(0); - } - } + serverSPID = (int)cmd.ExecuteScalar()!; // SPID should match server's SPID Assert.Equal(serverSPID, conn.ServerProcessId); @@ -426,17 +418,14 @@ public static void ConnectionAliasTest() { DataSource = DataTestUtility.AliasName }; + using SqlConnection sqlConnection = new(builder.ConnectionString); + + // @TODO: This should be tested in connection string builder tests Assert.Equal(DataTestUtility.AliasName, builder.DataSource); - try - { - sqlConnection.Open(); - Assert.Equal(ConnectionState.Open, sqlConnection.State); - } - catch (SqlException ex) - { - Assert.Fail(ex.Message); - } + + sqlConnection.Open(); + Assert.Equal(ConnectionState.Open, sqlConnection.State); } private static bool CanUseDacConnection() diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs index 5199922174..cef8fb2278 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs @@ -2,15 +2,41 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { public class DataReaderCancellationTest { + // @TODO: Make this a commonly used long running query? + // This query generates a billion results by performing a cross join on 10 rows 3 times (1k + // records), then cross joining that set 3 times (1b records). + private const string LongRunningQuery = + @"WITH " + + @" TenRows AS ( " + + @" SELECT value " + + @" FROM ( " + + @" VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10) " + + @" ) AS TenRows (value) " + + @" ), " + + @" ThousandRows AS ( " + + @" SELECT A.value AS A, B.value AS B, C.value AS C " + + @" FROM " + + @" TenRows AS A, " + + @" TenRows AS B, " + + @" TenRows AS C, " + + @" ) " + + @"SELECT * " + + @"FROM " + + @" ThousandRows AS A, " + + @" ThousandRows AS B, " + + @" ThousandRows AS C"; + /// /// Test ensures cancellation token is registered before ReadAsync starts processing results from TDS Stream, /// such that when Cancel is triggered, the token is capable of canceling reading further results. @@ -20,31 +46,37 @@ public class DataReaderCancellationTest [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public static async Task CancellationTokenIsRespected_ReadAsync() { - const string longRunningQuery = @" -with TenRows as (select Value from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) as TenRows (Value)), - ThousandRows as (select A.Value as A, B.Value as B, C.Value as C from TenRows as A, TenRows as B, TenRows as C) -select * -from ThousandRows as A, ThousandRows as B, ThousandRows as C;"; - - using (var source = new CancellationTokenSource()) - using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + // Arrange + using CancellationTokenSource source = new(); + + using SqlConnection connection = new(DataTestUtility.TCPConnectionString); + await connection.OpenAsync(source.Token); + + // - Set up command that returns millions of rows + using SqlCommand command = connection.CreateCommand(); + command.CommandText = LongRunningQuery; + + // Act + Func action = async () => { - await connection.OpenAsync(source.Token); + // - Execute query + using SqlDataReader reader = await command.ExecuteReaderAsync(source.Token); - Stopwatch stopwatch = Stopwatch.StartNew(); - await Assert.ThrowsAsync(async () => + // - Cancel after each record is read (should cancel after first record) + while (await reader.ReadAsync(source.Token)) { - using (var command = new SqlCommand(longRunningQuery, connection)) - using (var reader = await command.ExecuteReaderAsync(source.Token)) - { - while (await reader.ReadAsync(source.Token)) - { - source.Cancel(); - } - } - }); - Assert.True(stopwatch.ElapsedMilliseconds < 10000, "Cancellation did not trigger on time."); - } + source.Cancel(); + } + }; + + // Assert + // - Action should throw task cancelled exception + Stopwatch stopwatch = Stopwatch.StartNew(); + await Assert.ThrowsAsync(action); + stopwatch.Stop(); + + // - Ensure exception was thrown within 10 seconds of execution + Assert.True(stopwatch.ElapsedMilliseconds < 10000, "Cancellation did not trigger on time"); } /// @@ -56,30 +88,37 @@ await Assert.ThrowsAsync(async () => [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public static async Task CancelledCancellationTokenIsRespected_ReadAsync() { - const string longRunningQuery = @" -with TenRows as (select Value from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) as TenRows (Value)), - ThousandRows as (select A.Value as A, B.Value as B, C.Value as C from TenRows as A, TenRows as B, TenRows as C) -select * -from ThousandRows as A, ThousandRows as B, ThousandRows as C;"; - - using (var source = new CancellationTokenSource()) - using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + // Arrange + using CancellationTokenSource source = new(); + + using SqlConnection connection = new(DataTestUtility.TCPConnectionString); + await connection.OpenAsync(source.Token); + + // - Set up command that returns millions of rows + using SqlCommand command = connection.CreateCommand(); + command.CommandText = LongRunningQuery; + + // Act + Func action = async () => { - await connection.OpenAsync(source.Token); + // - Execute query + using SqlDataReader reader = await command.ExecuteReaderAsync(source.Token); - Stopwatch stopwatch = Stopwatch.StartNew(); - await Assert.ThrowsAsync(async () => - { - using (var command = new SqlCommand(longRunningQuery, connection)) - using (var reader = await command.ExecuteReaderAsync(source.Token)) - { - source.Cancel(); - while (await reader.ReadAsync(source.Token)) - { } - } - }); - Assert.True(stopwatch.ElapsedMilliseconds < 10000, "Cancellation did not trigger on time."); - } + // - Cancel before reading + source.Cancel(); + + // - Read all results (should cancel before first record is read) + await reader.FlushResultSetAsync(source.Token); + }; + + // Assert + // - Action should throw task cancelled exception + Stopwatch stopwatch = Stopwatch.StartNew(); + await Assert.ThrowsAsync(action); + stopwatch.Stop(); + + // - Ensure exception was thrown within 10 seconds of execution + Assert.True(stopwatch.ElapsedMilliseconds < 10000, "Cancellation did not trigger on time"); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderTest.cs index 040119616e..97b15ec25a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderTest.cs @@ -733,16 +733,10 @@ public static async Task CanGetCharsSequentially() if (await sqlReader.ReadAsync()) { long id = sqlReader.GetInt64(0); - if (id != 1) - { - Assert.Fail("Id not 1"); - } + Assert.Equal(1, id); var sliced = GetPooledChars(sqlReader, 1, input); - if (!sliced.SequenceEqual(input.ToCharArray())) - { - Assert.Fail("sliced != input"); - } + Assert.Equal(input.ToCharArray(), sliced); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs index 74423f9f13..61dbd9d594 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; +using Microsoft.Data.SqlClient.Tests.Common; using Microsoft.Data.SqlClient.TestUtilities; using Xunit; using Xunit.Abstractions; @@ -1215,25 +1216,18 @@ private static void SqlCharsBytesTest(string connectionString) private static void CloseConnection(string connectionString) { - using (SqlConnection conn = new SqlConnection(connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand("select * from orders where orderid < 10253", conn)) - using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) - { - DataTestUtility.AssertEqualsWithDescription(ConnectionState.Open, conn.State, "FAILED: Connection should be in open state"); + using SqlConnection conn = new SqlConnection(connectionString); + conn.Open(); - while (reader.Read()) - { - for (int i = 0; i < reader.FieldCount; i++) - { - reader.GetValue(i); - } - } - } + using SqlCommand cmd = new SqlCommand("select * from orders where orderid < 10253", conn); + using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) + { + DataTestUtility.AssertEqualsWithDescription(ConnectionState.Open, conn.State, "FAILED: Connection should be in open state"); - DataTestUtility.AssertEqualsWithDescription(ConnectionState.Closed, conn.State, "FAILED: Connection should be in closed state after reader close"); + reader.FlushResultSet(); } + + DataTestUtility.AssertEqualsWithDescription(ConnectionState.Closed, conn.State, "FAILED: Connection should be in closed state after reader close"); } private static void OpenConnection(string connectionString) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs index 4179b7bf4b..637061597a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs @@ -8,6 +8,7 @@ using System.Data; using System.Globalization; using System.Threading.Tasks; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -288,6 +289,7 @@ public static void EnclavesConnectionExceptionTest() } } + // @TODO: Verify this test is doing what we expect it to do. [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] public static async Task UnobservedTaskExceptionTest() { @@ -308,15 +310,8 @@ public static async Task UnobservedTaskExceptionTest() { try { - using (var reader = await command.ExecuteReaderAsync()) - { - do - { - while (await reader.ReadAsync()) - { - } - } while (await reader.NextResultAsync()); - } + using SqlDataReader reader = await command.ExecuteReaderAsync(); + await reader.FlushAllResultsAsync(); } catch (SqlException ex) { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs index 03c5f794c0..3b8107d324 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs @@ -214,10 +214,6 @@ private void BulkCopyData(CommandBehavior cb, bool enableStraming, int expectedT { bulkCopy.WriteToServer(reader); } - catch (Exception ex) - { - Assert.Fail(ex.Message); - } finally { reader.Close(); @@ -252,10 +248,6 @@ private async Task BulkCopyDataAsync(CommandBehavior cb, bool enableStraming, in { await bulkCopy.WriteToServerAsync(reader); } - catch (Exception ex) - { - Assert.Fail(ex.Message); - } finally { reader.Close(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/MARSTest/MARSTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/MARSTest/MARSTest.cs index 69265c4e75..0a2ed2a276 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/MARSTest/MARSTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/MARSTest/MARSTest.cs @@ -690,10 +690,6 @@ FROM [{table}] AS [l] }); } } - catch (Exception e) - { - Assert.Fail("CRITIAL: Test should not fail randomly. Exception occurred: " + e.Message); - } finally { using var dropConn = new SqlConnection(DataTestUtility.TCPConnectionString); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs index 4574f81a93..72c3ac31bf 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs @@ -1017,13 +1017,12 @@ private static void RunParameterTest() { connection.Close(); } - if (cm.Parameters["@id2"].Value == null) - { - return; - } - else if ((Guid)cm.Parameters["@id2"].Value != expectedGuid) + + object id2Value = cm.Parameters["@id2"].Value; + if (id2Value is not null) { - Assert.Fail("CRITICAL : Unexpected data found in SqlCommand parameters, this is a MAJOR issue."); + // Null values are allowed, but if it is not null, the expected guid must be set. + Assert.Equal(expectedGuid, (Guid)id2Value); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs index 9e7a6612a7..4008567b11 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs @@ -96,6 +96,7 @@ public void TestConnectionIsSafeToReuse() { using SqlConnection connection = new(DataTestUtility.TCPConnectionString); + // @TODO: Split into two tests // Bad Scenario - exception expected. try { @@ -133,7 +134,7 @@ public void TestConnectionIsSafeToReuse() catch (Exception e) { // Ignore this exception as it's deliberately introduced. - Assert.True(e.Message.Contains("Object reference not set to an instance of an object"), "Expected exception did not occur"); + Assert.Contains("Object reference not set to an instance of an object", e.Message); } // Good Scenario - No failure expected. diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/TestBulkCopyWithUTF8.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/TestBulkCopyWithUTF8.cs index 5b7112476d..1cd0a69aad 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/TestBulkCopyWithUTF8.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/TestBulkCopyWithUTF8.cs @@ -104,16 +104,8 @@ public void BulkCopy_Utf8Data_ShouldMatchSource(bool isMarsEnabled, bool enableS DestinationTableName = s_destinationTable }; - try - { - // Perform bulk copy from source to destination table - bulkCopy.WriteToServer(reader); - } - catch (Exception ex) - { - // If bulk copy fails, fail the test with the exception message - Assert.Fail($"Bulk copy failed: {ex.Message}"); - } + // Perform bulk copy from source to destination table + bulkCopy.WriteToServer(reader); // Verify that the 1 row from the source table has been copied into our destination table. Assert.Equal(1, Convert.ToInt16(countCommand.ExecuteScalar())); @@ -167,17 +159,9 @@ public async Task BulkCopy_Utf8Data_ShouldMatchSource_Async(bool isMarsEnabled, EnableStreaming = enableStreaming, DestinationTableName = s_destinationTable }; - - try - { - // Perform bulk copy from source to destination table - await bulkCopy.WriteToServerAsync(reader); - } - catch (Exception ex) - { - // If bulk copy fails, fail the test with the exception message - Assert.Fail($"Bulk copy failed: {ex.Message}"); - } + + // Perform bulk copy from source to destination table + await bulkCopy.WriteToServerAsync(reader); // Verify that the 1 row from the source table has been copied into our destination table. Assert.Equal(1, Convert.ToInt16(await countCommand.ExecuteScalarAsync())); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs index 9f20521f08..1ca4885ce5 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs @@ -6,6 +6,7 @@ using System.Data; using System.Threading; using System.Threading.Tasks; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -46,80 +47,86 @@ public static void PlainMARSCancelTestNP() // Synapse: Remove dependency on Northwind database + WAITFOR not supported + ';' not supported [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] - public static void PlainCancelTestAsync() - { + public static Task PlainCancelTestAsync() => PlainCancelAsync(tcp_connStr); - } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] [PlatformSpecific(TestPlatforms.Windows)] - public static void PlainCancelTestAsyncNP() - { + public static Task PlainCancelTestAsyncNP() => PlainCancelAsync(np_connStr); - } // Synapse: Remove dependency from Northwind database + WAITFOR not supported + ';' not supported. [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] - public static void PlainMARSCancelTestAsync() - { + public static Task PlainMARSCancelTestAsync() => PlainCancelAsync((new SqlConnectionStringBuilder(tcp_connStr) { MultipleActiveResultSets = true }).ConnectionString); - } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] [PlatformSpecific(TestPlatforms.Windows)] - public static void PlainMARSCancelTestAsyncNP() - { + public static Task PlainMARSCancelTestAsyncNP() => PlainCancelAsync((new SqlConnectionStringBuilder(np_connStr) { MultipleActiveResultSets = true }).ConnectionString); - } private static void PlainCancel(string connString) { - using (SqlConnection conn = new SqlConnection(connString)) - using (SqlCommand cmd = new SqlCommand("select * from dbo.Orders; waitfor delay '00:00:10'; select * from dbo.Orders", conn)) + // Arrange + using SqlConnection conn = new SqlConnection(connString); + conn.Open(); + + using SqlCommand command = conn.CreateCommand(); + command.CommandText = + @"SELECT * FROM dbo.Orders; " + + @"WAITFOR DELAY '00:00:10'; " + + @"SELECT * FROM dbo.Orders;"; + + // Act + Action action = () => { - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - cmd.Cancel(); - DataTestUtility.AssertThrowsWrapper( - () => - { - do - { - while (reader.Read()) - { - } - } - while (reader.NextResult()); - }, - "A severe error occurred on the current command. The results, if any, should be discarded."); - } - } + // - Execute reader + using SqlDataReader reader = command.ExecuteReader(); + + // - Cancel command + command.Cancel(); + + // - Flush results - should throw + reader.FlushAllResults(); + }; + + // Assert + SqlException exception = Assert.Throws(action); + Assert.Contains( + "A severe error occurred on the current command. The results, if any, should be discarded.", + exception.Message); } - private static void PlainCancelAsync(string connString) + private static async Task PlainCancelAsync(string connString) { - using (SqlConnection conn = new SqlConnection(connString)) - using (SqlCommand cmd = new SqlCommand("select * from dbo.Orders; waitfor delay '00:00:10'; select * from dbo.Orders", conn)) + // Arrange + using SqlConnection conn = new SqlConnection(connString); + conn.Open(); + + using SqlCommand command = conn.CreateCommand(); + command.CommandText = + @"SELECT * FROM dbo.Orders; " + + @"WAITFOR DELAY '00:00:10'; " + + @"SELECT * FROM dbo.Orders;"; + + // Act + Func action = async () => { - conn.Open(); - Task readerTask = cmd.ExecuteReaderAsync(); - DataTestUtility.AssertThrowsWrapper( - () => - { - readerTask.Wait(2000); - SqlDataReader reader = readerTask.Result; - cmd.Cancel(); - do - { - while (reader.Read()) - { - } - } - while (reader.NextResult()); - }, - "A severe error occurred on the current command. The results, if any, should be discarded."); - } + // - Execute reader + SqlDataReader reader = await command.ExecuteReaderAsync(); + + // - Cancel command + command.Cancel(); + + // - Flush results - should throw + await reader.FlushAllResultsAsync(); + }; + + // Assert + SqlException exception = await Assert.ThrowsAsync(action); + Assert.Contains( + "A severe error occurred on the current command. The results, if any, should be discarded.", + exception.Message); } // Synapse: Remove dependency from Northwind database + WAITFOR not supported + ';' not supported. @@ -424,20 +431,16 @@ private static void ExecuteCommandCancelExpected(object state) string errorMessage = SystemDataResourceManager.Instance.SQL_OperationCancelled; string errorMessageSevereFailure = SystemDataResourceManager.Instance.SQL_SevereError; - DataTestUtility.ExpectFailure(() => + Action action = () => { threadsReady.SignalAndWait(); - using (SqlDataReader r = command.ExecuteReader()) - { - do - { - while (r.Read()) - { - } - } while (r.NextResult()); - } - }, new string[] { errorMessage, errorMessageSevereFailure }); + using SqlDataReader reader = command.ExecuteReader(); + reader.FlushAllResults(); + }; + + SqlException exception = Assert.Throws(action); + Assert.Contains(exception.Message, new[] { errorMessage, errorMessageSevereFailure }); } private static void CancelSharedCommand(object state) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDependencyTest/SqlDependencyTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDependencyTest/SqlDependencyTest.cs index c2a4ab79e8..ac73e52b3a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDependencyTest/SqlDependencyTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDependencyTest/SqlDependencyTest.cs @@ -115,15 +115,8 @@ public void OnChangeAddHasChanges() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] public void SqlDependencyStartStopTest() { - try - { - SqlDependency.Start(DataTestUtility.TCPConnectionString); - SqlDependency.Stop(DataTestUtility.TCPConnectionString); - } - catch (Exception e) - { - Assert.Fail(e.Message); - } + SqlDependency.Start(DataTestUtility.TCPConnectionString); + SqlDependency.Stop(DataTestUtility.TCPConnectionString); } [Fact] @@ -145,15 +138,8 @@ public void SqlDepdencyStartNullConnectionString_Throws() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] public void SqlDependencyStartStopDefaultTest() { - try - { - SqlDependency.Start(DataTestUtility.TCPConnectionString, null); - SqlDependency.Stop(DataTestUtility.TCPConnectionString, null); - } - catch (Exception e) - { - Assert.Fail(e.Message); - } + SqlDependency.Start(DataTestUtility.TCPConnectionString, null); + SqlDependency.Stop(DataTestUtility.TCPConnectionString, null); } [Fact] diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs index f04bc38a4d..c035532229 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs @@ -6,6 +6,7 @@ using System.Data; using System.Data.Common; using System.Collections; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -37,11 +38,7 @@ public static void TestRetrieveStatistics() clientConnectionId = connection.ClientConnectionId; Assert.True(clientConnectionId != Guid.Empty); - int row = 0; - while (dr.Read()) - { - row++; - } + dr.FlushResultSet(); } } // Ensure calling RetrieveStatistics multiple times do not affect the ConnectionTime diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/NativeVectorFloat32Tests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/NativeVectorFloat32Tests.cs index 2ff72bba06..82f5a34a71 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/NativeVectorFloat32Tests.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/NativeVectorFloat32Tests.cs @@ -416,25 +416,17 @@ public void TestBulkCopyFromSqlTable(int bulkCopySourceMode) { DestinationTableName = s_tableName, }; - - try - { - switch (bulkCopySourceMode) - { - case 1: - bulkCopy.WriteToServer(reader); - break; - case 2: - bulkCopy.WriteToServer(table); - break; - default: - throw new ArgumentOutOfRangeException(nameof(bulkCopySourceMode), $"Unsupported bulk copy source mode: {bulkCopySourceMode}"); - } - } - catch (Exception ex) + + switch (bulkCopySourceMode) { - // If bulk copy fails, fail the test with the exception message - Assert.Fail($"Bulk copy failed: {ex.Message}"); + case 1: + bulkCopy.WriteToServer(reader); + break; + case 2: + bulkCopy.WriteToServer(table); + break; + default: + throw new ArgumentOutOfRangeException(nameof(bulkCopySourceMode), $"Unsupported bulk copy source mode: {bulkCopySourceMode}"); } // Verify that the 2 rows from the source table have been copied into the destination table. @@ -514,25 +506,18 @@ public async Task TestBulkCopyFromSqlTableAsync(int bulkCopySourceMode) { DestinationTableName = s_tableName, }; - - try - { // Perform bulkcopy - switch (bulkCopySourceMode) - { - case 1: - await bulkCopy.WriteToServerAsync(reader); - break; - case 2: - await bulkCopy.WriteToServerAsync(table); - break; - default: - throw new ArgumentOutOfRangeException(nameof(bulkCopySourceMode), $"Unsupported bulk copy source mode: {bulkCopySourceMode}"); - } - } - catch (Exception ex) + + // Perform bulkcopy + switch (bulkCopySourceMode) { - // If bulk copy fails, fail the test with the exception message - Assert.Fail($"Bulk copy failed: {ex.Message}"); + case 1: + await bulkCopy.WriteToServerAsync(reader); + break; + case 2: + await bulkCopy.WriteToServerAsync(table); + break; + default: + throw new ArgumentOutOfRangeException(nameof(bulkCopySourceMode), $"Unsupported bulk copy source mode: {bulkCopySourceMode}"); } // Verify that the 2 rows from the source table have been copied into the destination table. diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/VectorTypeBackwardCompatibilityTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/VectorTypeBackwardCompatibilityTests.cs index b3f42a5617..33f6109dc8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/VectorTypeBackwardCompatibilityTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/VectorTest/VectorTypeBackwardCompatibilityTests.cs @@ -488,17 +488,9 @@ public void TestSqlBulkCopyForVectorAsVarchar() { DestinationTableName = s_tableName, }; - - try - { - // Perform bulk copy from source to destination table - bulkCopy.WriteToServer(reader); - } - catch (Exception ex) - { - // If bulk copy fails, fail the test with the exception message - Assert.Fail($"Bulk copy failed: {ex.Message}"); - } + + // Perform bulk copy from source to destination table + bulkCopy.WriteToServer(reader); // Verify that the 2 rows from the source table have been copied into the destination table. Assert.Equal(2, Convert.ToInt16(countCommand.ExecuteScalar())); @@ -553,17 +545,9 @@ public async Task TestSqlBulkCopyForVectorAsVarcharAsync() { DestinationTableName = s_tableName, }; - - try - { - // Perform bulk copy from source to destination table - await bulkCopy.WriteToServerAsync(reader); - } - catch (Exception ex) - { - // If bulk copy fails, fail the test with the exception message - Assert.Fail($"Bulk copy failed: {ex.Message}"); - } + + // Perform bulk copy from source to destination table + await bulkCopy.WriteToServerAsync(reader); // Verify that the 2 rows from the source table have been copied into the destination table. Assert.Equal(2, Convert.ToInt16(await countCommand.ExecuteScalarAsync())); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs index 96108636d0..ee65271ac3 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs @@ -23,6 +23,7 @@ using System.Runtime.CompilerServices; using System; using System.Data; +using Microsoft.Data.SqlClient.Tests.Common; using Microsoft.DotNet.RemoteExecutor; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -143,10 +144,7 @@ public void ExecuteReaderTest() conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); - while (reader.Read()) - { - // Read until end. - } + reader.FlushResultSet(); } }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]); return RemoteExecutor.SuccessExitCode; @@ -190,10 +188,7 @@ public void ExecuteReaderWithCommandBehaviorTest() conn.Open(); SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default); - while (reader.Read()) - { - // Read to end - } + reader.FlushResultSet(); } }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]); return RemoteExecutor.SuccessExitCode; @@ -219,7 +214,7 @@ public void ExecuteXmlReaderTest() XmlReader reader = cmd.ExecuteXmlReader(); while (reader.Read()) { - // Read to end + // Flush results } } }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]); @@ -373,10 +368,7 @@ public void ExecuteReaderAsyncTest() conn.Open(); SqlDataReader reader = await cmd.ExecuteReaderAsync(); - while (reader.Read()) - { - // Read to end - } + reader.FlushResultSet(); } }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait(); return RemoteExecutor.SuccessExitCode; @@ -434,7 +426,7 @@ public void ExecuteXmlReaderAsyncTest() XmlReader reader = await cmd.ExecuteXmlReaderAsync(); while (reader.Read()) { - // Read to end + // Flush results } } }, [WriteConnectionOpenBefore, WriteConnectionOpenAfter, WriteCommandBefore, WriteCommandAfter, WriteConnectionCloseBefore, WriteConnectionCloseAfter]).Wait(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs index 4992c55974..df6ca2a37e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventSourceTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Linq; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -18,10 +19,7 @@ public void EventSourceTestAll() connection.Open(); using SqlCommand command = new("SELECT @@VERSION", connection); using SqlDataReader reader = command.ExecuteReader(); - while (reader.Read()) - { - // Flush data - } + reader.FlushResultSet(); } // Need to investigate better way of validating traces in sequential runs, diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs index ffd6c8ff79..5381f661ba 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Xml; using System.Xml.XPath; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; using Xunit.Abstractions; @@ -51,10 +52,7 @@ ADD EVENT RPC_STARTING (ACTION (client_connection_id) WHERE (client_connection_i { using SqlCommand command = new(query, activityConnection) { CommandType = commandType }; using SqlDataReader reader = command.ExecuteReader(); - while (reader.Read()) - { - // Flush data - } + reader.FlushResultSet(); ids = TraceListener.ActivityIDs; } diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlErrorCollectionTests.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlErrorCollectionTests.cs new file mode 100644 index 0000000000..f9ea12027a --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlErrorCollectionTests.cs @@ -0,0 +1,241 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests.Microsoft.Data.SqlClient +{ + public class SqlErrorCollectionTests + { + private const int ErrorsInTestCollection = 3; + + [Fact] + public void Constructor_PropertiesInitialized() + { + // Act + SqlErrorCollection collection = new(); + + // Assert + Assert.Empty(collection); + + // - ICollection properties + ICollection collection2 = collection; + Assert.Same(collection2, collection2.SyncRoot); + Assert.False(collection2.IsSynchronized); + } + + [Theory] + [InlineData(1)] + [InlineData(2)] + [InlineData(10)] + public void Add(int itemsToAdd) + { + // Arrange + SqlErrorCollection collection = new(); + SqlError error = GetTestError(); + + // Act + for (int i = 0; i < itemsToAdd; i++) + { + collection.Add(error); + } + + // Assert + Assert.Equal(itemsToAdd, collection.Count); + } + + [Theory] + [InlineData(ErrorsInTestCollection, 0)] // Destination just right size + [InlineData(ErrorsInTestCollection + 10, 0)] // Null elements at end + [InlineData(ErrorsInTestCollection + 2, 2)] // Null elements at beginning + [InlineData(ErrorsInTestCollection + 10, 1)] // Null elements at beginning and end + public void CopyTo_SqlErrorArray_WithinRange(int destinationSize, int offset) + { + // Arrange + (SqlErrorCollection collection, SqlError[] errors) = GetTestErrorCollection(); + SqlError[] copyDestination = new SqlError[destinationSize]; + + // Act + // - Uses SqlErrorCollection.CopyTo + collection.CopyTo(copyDestination, offset); + + // Assert + AssertCopiedCollection(errors, copyDestination, offset); + } + + [Theory] + [InlineData(ErrorsInTestCollection, -1)] // Offset is negative + [InlineData(ErrorsInTestCollection - 1, 0)] // Destination is too small + [InlineData(ErrorsInTestCollection, 1)] // Destination is big enough, but offset pushes it over edge + public void CopyTo_SqlErrorArray_OutOfRange(int destinationSize, int offset) + { + // Arrange + (SqlErrorCollection collection, SqlError[] _) = GetTestErrorCollection(); + SqlError[] copyDestination = new SqlError[destinationSize]; + + // Act + // - Uses ICollection.CopyTo + Action action = () => collection.CopyTo(copyDestination, offset); + + // Assert + Assert.ThrowsAny(action); + } + + [Theory] + [InlineData(ErrorsInTestCollection, 0)] // Destination just right size + [InlineData(ErrorsInTestCollection + 10, 0)] // Null elements at end + [InlineData(ErrorsInTestCollection + 2, 2)] // Null elements at beginning + [InlineData(ErrorsInTestCollection + 10, 1)] // Null elements at beginning and end + public void CopyTo_ObjectArray_WithinRange(int destinationSize, int offset) + { + // Arrange + (SqlErrorCollection collection, SqlError[] errors) = GetTestErrorCollection(); + object[] copyDestination = new object[destinationSize]; + + // Act + // - Uses ICollection.CopyTo + collection.CopyTo(copyDestination, offset); + + // Assert + AssertCopiedCollection(errors, copyDestination, offset); + } + + [Theory] + [InlineData(ErrorsInTestCollection, -1)] // Offset is negative + [InlineData(ErrorsInTestCollection - 1, 0)] // Destination is too small + [InlineData(ErrorsInTestCollection, 1)] // Destination is big enough, but offset pushes it over edge + public void CopyTo_ObjectArray_OutOfRange(int destinationSize, int offset) + { + // Arrange + (SqlErrorCollection collection, SqlError[] _) = GetTestErrorCollection(); + SqlError[] copyDestination = new SqlError[destinationSize]; + + // Act + // - Uses ICollection.CopyTo + Action action = () => collection.CopyTo(copyDestination, offset); + + // Assert + Assert.ThrowsAny(action); + } + + [Fact] + public void CopyTo_ObjectArray_WrongType() + { + // Arrange + (SqlErrorCollection collection, SqlError[] errors) = GetTestErrorCollection(); + int[] destination = new int[errors.Length]; + + // Act + Action action = () => collection.CopyTo(destination, 0); + + // Assert + Assert.Throws(action); + } + + [Fact] + public void GetEnumerator() + { + // Arrange + (SqlErrorCollection collection, SqlError[] errors) = GetTestErrorCollection(); + List output = new(); + + // Act + foreach (SqlError error in collection) + { + output.Add(error); + } + + // Assert + for (int i = 0; i < errors.Length; i++) + { + Assert.Same(errors[i], output[i]); + } + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public void Indexer_InRange(int index) + { + // Arrange + (SqlErrorCollection collection, SqlError[] errors) = GetTestErrorCollection(); + + // Act + SqlError result = collection[index]; + + // Assert + Assert.Same(errors[index], result); + } + + [Theory] + [InlineData(-1)] + [InlineData(123)] + public void Indexer_OutOfRange(int index) + { + // Arrange + (SqlErrorCollection collection, _) = GetTestErrorCollection(); + + // Act + Action action = () => _ = collection[index]; + + // Assert + Assert.Throws(action); + } + + private static void AssertCopiedCollection(SqlError[] source, IReadOnlyList destination, int offset) + { + for (int i = 0; i < destination.Count; i++) + { + if (i < offset) + { + // - Elements before the offset should be null + Assert.Null(destination[i]); + } + else if (i >= offset && i < source.Length + offset) + { + // - Elements after the offset but within the range of original elements should match + Assert.Same(source[i - offset], destination[i]); + } + else + { + // - Elements after the offset and original elements should be null + Assert.Null(destination[i]); + } + } + } + + private static SqlError GetTestError() + { + return new SqlError( + infoNumber: 123, + errorState: 0x02, + errorClass: 0x03, + server: "foo", + errorMessage: "bar", + procedure: "baz", + lineNumber: 234, + exception: new Exception(), + batchIndex: 345); + } + + private static (SqlErrorCollection collection, SqlError[] errors) GetTestErrorCollection() + { + SqlErrorCollection collection = new(); + SqlError[] errors = new SqlError[ErrorsInTestCollection]; + + for (int i = 0; i < ErrorsInTestCollection; i++) + { + SqlError error = GetTestError(); + errors[i] = error; + collection.Add(error); + } + + return (collection, errors); + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlErrorTests.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlErrorTests.cs new file mode 100644 index 0000000000..f6ef6bef1a --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlErrorTests.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Runtime.Serialization; +using Xunit; + +namespace Microsoft.Data.SqlClient.UnitTests.Microsoft.Data.SqlClient +{ + public class SqlErrorTests + { + [Fact] + public void SerializationRoundTrip() + { + // Arrange + DataContractSerializer serializer = new(typeof(SqlError)); + using MemoryStream stream = new(); + + // - Create the test error + SqlError originalError = new( + infoNumber: 123, + errorState: 0x02, + errorClass: 0x03, + server: "foo", + errorMessage: "bar", + procedure: "baz", + lineNumber: 234, + exception: new Exception(), + batchIndex: 345); + + // Act - Serialize and deserialize + serializer.WriteObject(stream, originalError); + stream.Position = 0; + SqlError? actualError = serializer.ReadObject(stream) as SqlError; + + // Assert + Assert.NotNull(actualError); + Assert.Equal(originalError.Source, actualError.Source); + Assert.Equal(originalError.Number, actualError.Number); + Assert.Equal(originalError.State, actualError.State); + Assert.Equal(originalError.Class, actualError.Class); + Assert.Equal(originalError.Server, actualError.Server); + Assert.Equal(originalError.Message, actualError.Message); + Assert.Equal(originalError.Procedure, actualError.Procedure); + Assert.Equal(originalError.LineNumber, actualError.LineNumber); + Assert.Equal(originalError.Win32ErrorCode, actualError.Win32ErrorCode); + Assert.Equal(originalError.BatchIndex, actualError.BatchIndex); + + Assert.NotNull(actualError.Exception); + Assert.Equal(originalError.Exception.Message, actualError.Exception.Message); + Assert.Equal(originalError.Exception.HResult, actualError.Exception.HResult); + } + } +}