Skip to content

Commit a11341f

Browse files
authored
Address flaky DEBUG assertions (#4085)
1 parent 75b33ad commit a11341f

24 files changed

Lines changed: 245 additions & 182 deletions

src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,9 @@ private static Task<string> AcquireTokenAsync(string authorityURL, string userID
302302
SecureString securePassword = new SecureString();
303303

304304
securePassword.MakeReadOnly();
305-
#pragma warning disable CS0618 // Type or member is obsolete
305+
#pragma warning disable CS0618 // Type or member is obsolete
306306
result = app.AcquireTokenByUsernamePassword(scopes, userID, password).ExecuteAsync().Result;
307-
#pragma warning restore CS0618 // Type or member is obsolete
307+
#pragma warning restore CS0618 // Type or member is obsolete
308308

309309
return result.AccessToken;
310310
});
@@ -389,7 +389,7 @@ public static string GetSqlServerProperty(SqlConnection connection, ServerProper
389389
}
390390
}
391391

392-
#nullable disable
392+
#nullable restore
393393

394394
private static bool GetSQLServerStatusOnTDS8(string connectionString)
395395
{
@@ -951,62 +951,89 @@ public static void AssertEqualsWithDescription(object expectedValue, object actu
951951
}
952952
}
953953

954-
public static TException AssertThrowsWrapper<TException>(Action actionThatFails, string exceptionMessage = null, bool innerExceptionMustBeNull = false, Func<TException, bool> customExceptionVerifier = null) where TException : Exception
954+
#nullable enable
955+
956+
/// <summary>
957+
/// Asserts that <paramref name="actionThatFails"/> throws an exception of type
958+
/// <typeparamref name="TException"/> and optionally verifies that its message contains
959+
/// <paramref name="exceptionMessage"/>.
960+
/// </summary>
961+
public static TException AssertThrows<TException>(
962+
Action actionThatFails,
963+
string? exceptionMessage = null)
964+
where TException : Exception
955965
{
956966
TException ex = Assert.Throws<TException>(actionThatFails);
967+
957968
if (exceptionMessage != null)
958969
{
959970
Assert.True(ex.Message.Contains(exceptionMessage),
960971
string.Format("FAILED: Exception did not contain expected message.\nExpected: {0}\nActual: {1}", exceptionMessage, ex.Message));
961972
}
962973

963-
if (innerExceptionMustBeNull)
964-
{
965-
Assert.True(ex.InnerException == null, "FAILED: Expected InnerException to be null.");
966-
}
967-
968-
if (customExceptionVerifier != null)
969-
{
970-
Assert.True(customExceptionVerifier(ex), "FAILED: Custom exception verifier returned false for this exception.");
971-
}
972-
973974
return ex;
974975
}
975976

976-
public static TException AssertThrowsWrapper<TException, TInnerException>(Action actionThatFails, string exceptionMessage = null, string innerExceptionMessage = null, bool innerExceptionMustBeNull = false, Func<TException, bool> customExceptionVerifier = null) where TException : Exception
977+
/// <summary>
978+
/// Asserts that <paramref name="actionThatFails"/> throws <typeparamref name="TException"/>
979+
/// whose <see cref="Exception.InnerException"/> is of type <typeparamref name="TInnerException"/>.
980+
/// Optionally verifies message text on both the outer and inner exceptions.
981+
/// </summary>
982+
public static TException AssertThrowsInner<TException, TInnerException>(
983+
Action actionThatFails,
984+
string? exceptionMessage = null,
985+
string? innerExceptionMessage = null)
986+
where TException : Exception
987+
where TInnerException : Exception
977988
{
978-
TException ex = AssertThrowsWrapper<TException>(actionThatFails, exceptionMessage, innerExceptionMustBeNull, customExceptionVerifier);
989+
TException ex = AssertThrows<TException>(actionThatFails, exceptionMessage);
990+
991+
Assert.NotNull(ex.InnerException);
992+
Assert.IsAssignableFrom<TInnerException>(ex.InnerException);
979993

980994
if (innerExceptionMessage != null)
981995
{
982-
Assert.True(ex.InnerException != null, "FAILED: Cannot check innerExceptionMessage because InnerException is null.");
983996
Assert.True(ex.InnerException.Message.Contains(innerExceptionMessage),
984997
string.Format("FAILED: Inner Exception did not contain expected message.\nExpected: {0}\nActual: {1}", innerExceptionMessage, ex.InnerException.Message));
985998
}
986999

9871000
return ex;
9881001
}
9891002

990-
public static TException AssertThrowsWrapper<TException, TInnerException, TInnerInnerException>(Action actionThatFails, string exceptionMessage = null, string innerExceptionMessage = null, string innerInnerExceptionMessage = null, bool innerInnerInnerExceptionMustBeNull = false) where TException : Exception where TInnerException : Exception where TInnerInnerException : Exception
1003+
/// <summary>
1004+
/// Asserts that <paramref name="actionThatFails"/> throws <typeparamref name="TException"/>
1005+
/// whose <see cref="Exception.InnerException"/> is either <typeparamref name="TInnerException"/>
1006+
/// or <typeparamref name="TAlternateInnerException"/>. Use this when a race condition
1007+
/// (e.g. disposal during an async read) may cause the inner exception type to vary
1008+
/// between runs. The <paramref name="innerExceptionMessage"/> is only verified when the
1009+
/// inner exception is <typeparamref name="TInnerException"/>.
1010+
/// </summary>
1011+
public static TException AssertThrowsInnerWithAlternate<TException, TInnerException, TAlternateInnerException>(
1012+
Action actionThatFails,
1013+
string? exceptionMessage = null,
1014+
string? innerExceptionMessage = null)
1015+
where TException : Exception
1016+
where TInnerException : Exception
1017+
where TAlternateInnerException : Exception
9911018
{
992-
TException ex = AssertThrowsWrapper<TException, TInnerException>(actionThatFails, exceptionMessage, innerExceptionMessage);
993-
if (innerInnerInnerExceptionMustBeNull)
994-
{
995-
Assert.True(ex.InnerException != null, "FAILED: Cannot check innerInnerInnerExceptionMustBeNull since InnerException is null");
996-
Assert.True(ex.InnerException.InnerException == null, "FAILED: Expected InnerInnerException to be null.");
997-
}
1019+
TException ex = AssertThrows<TException>(actionThatFails, exceptionMessage);
9981020

999-
if (innerInnerExceptionMessage != null)
1021+
Assert.NotNull(ex.InnerException);
1022+
Assert.True(
1023+
ex.InnerException is TInnerException or TAlternateInnerException,
1024+
$"Expected {typeof(TInnerException).Name} or {typeof(TAlternateInnerException).Name}, got: {ex.InnerException?.GetType()}");
1025+
1026+
if (innerExceptionMessage != null && ex.InnerException is TInnerException)
10001027
{
1001-
Assert.True(ex.InnerException != null, "FAILED: Cannot check innerInnerExceptionMessage since InnerException is null");
1002-
Assert.True(ex.InnerException.InnerException != null, "FAILED: Cannot check innerInnerExceptionMessage since InnerInnerException is null");
1003-
Assert.True(ex.InnerException.InnerException.Message.Contains(innerInnerExceptionMessage),
1004-
string.Format("FAILED: Inner Exception did not contain expected message.\nExpected: {0}\nActual: {1}", innerInnerExceptionMessage, ex.InnerException.InnerException.Message));
1028+
Assert.True(ex.InnerException.Message.Contains(innerExceptionMessage),
1029+
string.Format("FAILED: Inner Exception did not contain expected message.\nExpected: {0}\nActual: {1}", innerExceptionMessage, ex.InnerException.Message));
10051030
}
10061031

10071032
return ex;
10081033
}
10091034

1035+
#nullable restore
1036+
10101037
public static TException ExpectFailure<TException>(Action actionThatFails, string[] exceptionMessages, bool innerExceptionMustBeNull = false, Func<TException, bool> customExceptionVerifier = null) where TException : Exception
10111038
{
10121039
try
@@ -1320,7 +1347,7 @@ public static string GetMachineFQDN(string hostname)
13201347
}
13211348
return fqdn.ToString();
13221349
}
1323-
}
13241350

1325-
#nullable disable
1351+
#nullable restore
1352+
}
13261353
}

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,13 +1318,13 @@ public void TestDeriveParameters()
13181318
using (SqlCommand cmd = new SqlCommand(procName, connection))
13191319
{
13201320
string errorMessage = string.Format(SystemDataResourceManager.Instance.ADP_DeriveParametersNotSupported, "SqlCommand", cmd.CommandType);
1321-
DataTestUtility.AssertThrowsWrapper<InvalidOperationException>(
1321+
DataTestUtility.AssertThrows<InvalidOperationException>(
13221322
() => SqlCommandBuilder.DeriveParameters(cmd),
13231323
errorMessage);
13241324

13251325
errorMessage = string.Format(SystemDataResourceManager.Instance.ADP_OpenConnectionRequired, "DeriveParameters", "");
13261326
cmd.CommandType = CommandType.StoredProcedure;
1327-
DataTestUtility.AssertThrowsWrapper<InvalidOperationException>(
1327+
DataTestUtility.AssertThrows<InvalidOperationException>(
13281328
() => SqlCommandBuilder.DeriveParameters(cmd),
13291329
errorMessage);
13301330

@@ -1335,7 +1335,7 @@ public void TestDeriveParameters()
13351335

13361336
cmd.CommandText = "Test_EmployeeSalesBy";
13371337
errorMessage = string.Format(SystemDataResourceManager.Instance.ADP_NoStoredProcedureExists, cmd.CommandText);
1338-
DataTestUtility.AssertThrowsWrapper<InvalidOperationException>(
1338+
DataTestUtility.AssertThrows<InvalidOperationException>(
13391339
() => SqlCommandBuilder.DeriveParameters(cmd),
13401340
errorMessage);
13411341

0 commit comments

Comments
 (0)