Skip to content

Commit d1b229c

Browse files
cheenamalhotrapaulmedynski
authored andcommitted
Test | Fix Transient Fault handling and other flaky unit tests (#4080)
* Test | Fix Transient Fault handling flaky tests * Attempt to fix * Fix the MultiPartIdentifier tests getting skipped * Fix serialization issue of SqlTypeWorkaroundsTests * Fix one more cases of possible error scenarios
1 parent 864f666 commit d1b229c

8 files changed

Lines changed: 85 additions & 45 deletions

File tree

src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/Common/MultipartIdentifierTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static TheoryData<string, string[]> ValidSinglePartIdentifierVariations
2626
{
2727
ReadOnlySpan<string> part1Words = ["word1", "word 1"];
2828
TheoryData<string, string[]> data = [];
29+
HashSet<string> seen = [];
2930

3031
// Combination 1: embedded and non-embedded whitespace.
3132
// Combination 2: leading and/or trailing whitespace, and no whitespace
@@ -36,6 +37,13 @@ public static TheoryData<string, string[]> ValidSinglePartIdentifierVariations
3637
{
3738
foreach ((string p1Combination, string p1Expected) in GeneratePartCombinations(part1))
3839
{
40+
// Skip duplicates — different generation paths can produce
41+
// identical (input, expected) pairs, which xUnit rejects.
42+
if (!seen.Add(p1Combination))
43+
{
44+
continue;
45+
}
46+
3947
string onePartCombination = p1Combination;
4048
string[] onePartExpected = [p1Expected];
4149

src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlTypeWorkaroundsTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public void ByteArrayToSqlBinary_NullInput()
6363
};
6464

6565
[Theory]
66-
[MemberData(nameof(SqlDecimalWriteTdsValue_NonNullInput_Data))]
66+
[MemberData(nameof(SqlDecimalWriteTdsValue_NonNullInput_Data), DisableDiscoveryEnumeration = true)]
6767
public void SqlDecimalWriteTdsValue_NonNullInput(SqlDecimal input)
6868
{
6969
// Arrange
@@ -155,7 +155,7 @@ public void ByteArrayToSqlGuid_ValidInput(byte[] input)
155155
};
156156

157157
[Theory]
158-
[MemberData(nameof(LongToSqlMoney_Data))]
158+
[MemberData(nameof(LongToSqlMoney_Data), DisableDiscoveryEnumeration = true)]
159159
public void LongToSqlMoney(long input, SqlMoney expected)
160160
{
161161
// Act
@@ -176,7 +176,7 @@ public void LongToSqlMoney(long input, SqlMoney expected)
176176
};
177177

178178
[Theory]
179-
[MemberData(nameof(SqlMoneyToLong_NonNullInput_Data))]
179+
[MemberData(nameof(SqlMoneyToLong_NonNullInput_Data), DisableDiscoveryEnumeration = true)]
180180
public void SqlMoneyToLong_NonNullInput(SqlMoney input, long expected)
181181
{
182182
// Act

src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/ConnectionFailoverTests.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Microsoft.Data.SqlClient.UnitTests.SimulatedServerTests
1313
{
14-
[Trait("Category", "flaky")]
1514
[Collection("SimulatedServerTests")]
1615
public class ConnectionFailoverTests
1716
{
@@ -70,7 +69,7 @@ public void TransientFault_NoFailover_DoesNotClearPool(uint errorCode)
7069
Assert.Equal($"localhost,{initialServer.EndPoint.Port}", secondConnection.DataSource);
7170

7271
// 1 for the initial connection, 2 for the second connection
73-
Assert.Equal(3, initialServer.PreLoginCount);
72+
Assert.Equal(3, initialServer.PreLoginCount - initialServer.AbandonedPreLoginCount);
7473
// A failover should not be triggered, so prelogin count to the failover server should be 0
7574
Assert.Equal(0, failoverServer.PreLoginCount);
7675
}
@@ -219,6 +218,7 @@ public void NetworkDelay_ShouldConnectToPrimary()
219218
InitialCatalog = "master", // Required for failover partner to work
220219
ConnectTimeout = 5,
221220
Encrypt = false,
221+
Pooling = false, // Disable pooling to ensure a fresh connection attempt is made
222222
MultiSubnetFailover = false,
223223
#if NETFRAMEWORK
224224
TransparentNetworkIPResolution = false,
@@ -268,6 +268,7 @@ public void NetworkError_WithUserProvidedPartner_RetryDisabled_ShouldConnectToFa
268268
ConnectRetryCount = 0, // Disable retry
269269
FailoverPartner = $"localhost,{failoverServer.EndPoint.Port}", // User provided failover partner
270270
Encrypt = false,
271+
Pooling = false, // Disable pooling to ensure a fresh connection attempt is made on failover
271272
};
272273
using SqlConnection connection = new(builder.ConnectionString);
273274

@@ -313,6 +314,9 @@ public void NetworkError_WithUserProvidedPartner_RetryEnabled_ShouldConnectToFai
313314
ConnectRetryInterval = 1,
314315
FailoverPartner = $"localhost,{failoverServer.EndPoint.Port}", // User provided failover partner
315316
Encrypt = false,
317+
#if NETFRAMEWORK
318+
TransparentNetworkIPResolution = false,
319+
#endif
316320
};
317321
using SqlConnection connection = new(builder.ConnectionString);
318322
// Act
@@ -324,7 +328,8 @@ public void NetworkError_WithUserProvidedPartner_RetryEnabled_ShouldConnectToFai
324328
Assert.Equal(ConnectionState.Open, connection.State);
325329
Assert.Equal($"localhost,{failoverServer.EndPoint.Port}", connection.DataSource);
326330
Assert.Equal(1, server.PreLoginCount);
327-
Assert.Equal(1, failoverServer.PreLoginCount);
331+
Assert.Equal(0, server.Login7Count);
332+
Assert.Equal(1, failoverServer.PreLoginCount - failoverServer.AbandonedPreLoginCount);
328333
}
329334

330335
[Theory]
@@ -357,7 +362,8 @@ public void TransientFault_ShouldConnectToPrimary(uint errorCode)
357362
InitialCatalog = "master",
358363
ConnectTimeout = 30,
359364
ConnectRetryInterval = 1,
360-
Encrypt = false
365+
Encrypt = false,
366+
Pooling = false, // Disable pooling to ensure a fresh connection attempt is made
361367
};
362368
using SqlConnection connection = new(builder.ConnectionString);
363369

@@ -369,7 +375,7 @@ public void TransientFault_ShouldConnectToPrimary(uint errorCode)
369375
Assert.Equal($"localhost,{server.EndPoint.Port}", connection.DataSource);
370376

371377
// Failures should prompt the client to return to the original server, resulting in a login count of 2
372-
Assert.Equal(2, server.PreLoginCount);
378+
Assert.Equal(2, server.PreLoginCount - server.AbandonedPreLoginCount);
373379
}
374380

375381
[Theory]
@@ -454,7 +460,7 @@ public void TransientFault_WithUserProvidedPartner_ShouldConnectToPrimary(uint e
454460
FailoverPartner = $"localhost:{failoverServer.EndPoint.Port}", // User provided failover partner
455461
};
456462
using SqlConnection connection = new(builder.ConnectionString);
457-
463+
458464
// Act
459465
connection.Open();
460466

@@ -463,7 +469,7 @@ public void TransientFault_WithUserProvidedPartner_ShouldConnectToPrimary(uint e
463469
Assert.Equal($"localhost,{server.EndPoint.Port}", connection.DataSource);
464470

465471
// Failures should prompt the client to return to the original server, resulting in a login count of 2
466-
Assert.Equal(2, server.PreLoginCount);
472+
Assert.Equal(2, server.PreLoginCount - server.AbandonedPreLoginCount);
467473
}
468474

469475
[Theory]
@@ -559,11 +565,14 @@ public void TransientFault_IgnoreServerProvidedFailoverPartner_ShouldConnectToUs
559565
// Close the connection to return it to the pool
560566
connection.Close();
561567

562-
563568
// Act
564569
// Dispose of the server to trigger a failover
565570
server.Dispose();
566571

572+
// Clear the pool to ensure the next connection attempt doesn't reuse
573+
// the pooled connection to the now-disposed primary server.
574+
SqlConnection.ClearAllPools();
575+
567576
// Opening a new connection will use the failover partner stored in the pool group.
568577
// This will fail if the server provided failover partner was stored to the pool group.
569578
using SqlConnection failoverConnection = new(builder.ConnectionString);
@@ -573,9 +582,9 @@ public void TransientFault_IgnoreServerProvidedFailoverPartner_ShouldConnectToUs
573582
Assert.Equal(ConnectionState.Open, failoverConnection.State);
574583
Assert.Equal($"localhost,{failoverServer.EndPoint.Port}", failoverConnection.DataSource);
575584
// 1 for the initial connection
576-
Assert.Equal(1, server.PreLoginCount);
585+
Assert.Equal(1, server.PreLoginCount - server.AbandonedPreLoginCount);
577586
// 1 for the failover connection
578-
Assert.Equal(1, failoverServer.PreLoginCount);
587+
Assert.Equal(1, failoverServer.PreLoginCount - failoverServer.AbandonedPreLoginCount);
579588
}
580589
}
581590
}

src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/ConnectionRoutingTests.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
namespace Microsoft.Data.SqlClient.UnitTests.SimulatedServerTests
1212
{
13-
[Trait("Category", "flaky")]
1413
[Collection("SimulatedServerTests")]
1514
public class ConnectionRoutingTests
1615
{
@@ -58,8 +57,8 @@ public void TransientFaultAtRoutedLocation_ShouldReturnToGateway(uint errorCode)
5857
Assert.Equal($"localhost,{router.EndPoint.Port}", connection.DataSource);
5958

6059
// Failures should prompt the client to return to the original server, resulting in a login count of 2
61-
Assert.Equal(2, router.PreLoginCount);
62-
Assert.Equal(2, server.PreLoginCount);
60+
Assert.Equal(2, router.PreLoginCount - router.AbandonedPreLoginCount);
61+
Assert.Equal(2, server.PreLoginCount - server.AbandonedPreLoginCount);
6362
}
6463

6564
[Theory]

src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/ConnectionRoutingTestsAzure.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
namespace Microsoft.Data.SqlClient.UnitTests.SimulatedServerTests
1212
{
13-
[Trait("Category", "flaky")]
1413
[Collection("SimulatedServerTests")]
1514
public class ConnectionRoutingTestsAzure : IDisposable
1615
{
@@ -76,8 +75,8 @@ public void TransientFaultAtRoutedLocation_ShouldReturnToGateway(uint errorCode)
7675
Assert.Equal($"localhost,{router.EndPoint.Port}", connection.DataSource);
7776

7877
// Failures should prompt the client to return to the original server, resulting in a login count of 2
79-
Assert.Equal(2, router.PreLoginCount);
80-
Assert.Equal(2, server.PreLoginCount);
78+
Assert.Equal(2, router.PreLoginCount - router.AbandonedPreLoginCount);
79+
Assert.Equal(2, server.PreLoginCount - server.AbandonedPreLoginCount);
8180
}
8281

8382
[Theory]

src/Microsoft.Data.SqlClient/tests/UnitTests/SimulatedServerTests/ConnectionTests.cs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public void ConnectionTest()
2929
{
3030
using TdsServer server = new(new TdsServerArguments() { });
3131
server.Start();
32-
var connStr = new SqlConnectionStringBuilder() {
32+
var connStr = new SqlConnectionStringBuilder()
33+
{
3334
DataSource = $"localhost,{server.EndPoint.Port}",
3435
Encrypt = SqlConnectionEncryptOption.Optional,
3536
}.ConnectionString;
@@ -43,7 +44,8 @@ public void IntegratedAuthConnectionTest()
4344
{
4445
using TdsServer server = new(new TdsServerArguments() { });
4546
server.Start();
46-
var connStr = new SqlConnectionStringBuilder() {
47+
var connStr = new SqlConnectionStringBuilder()
48+
{
4749
DataSource = $"localhost,{server.EndPoint.Port}",
4850
Encrypt = SqlConnectionEncryptOption.Optional,
4951
}.ConnectionString;
@@ -61,9 +63,10 @@ public void IntegratedAuthConnectionTest()
6163
[Fact]
6264
public async Task RequestEncryption_ServerDoesNotSupportEncryption_ShouldFail()
6365
{
64-
using TdsServer server = new(new TdsServerArguments() {Encryption = TDSPreLoginTokenEncryptionType.None });
66+
using TdsServer server = new(new TdsServerArguments() { Encryption = TDSPreLoginTokenEncryptionType.None });
6567
server.Start();
66-
var connStr = new SqlConnectionStringBuilder() {
68+
var connStr = new SqlConnectionStringBuilder()
69+
{
6770
DataSource = $"localhost,{server.EndPoint.Port}"
6871
}.ConnectionString;
6972

@@ -72,34 +75,35 @@ public async Task RequestEncryption_ServerDoesNotSupportEncryption_ShouldFail()
7275
Assert.Contains("The instance of SQL Server you attempted to connect to does not support encryption.", ex.Message, StringComparison.OrdinalIgnoreCase);
7376
}
7477

75-
[Trait("Category", "flaky")]
7678
[Theory]
7779
[InlineData(40613)]
7880
[InlineData(42108)]
7981
[InlineData(42109)]
8082
public async Task TransientFault_RetryEnabled_ShouldSucceed_Async(uint errorCode)
8183
{
8284
using TransientTdsErrorTdsServer server = new(
83-
new TransientTdsErrorTdsServerArguments()
85+
new TransientTdsErrorTdsServerArguments()
8486
{
85-
IsEnabledTransientError = true,
86-
Number = errorCode,
87+
IsEnabledTransientError = true,
88+
Number = errorCode,
8789
});
8890
server.Start();
8991
SqlConnectionStringBuilder builder = new()
9092
{
9193
DataSource = "localhost," + server.EndPoint.Port,
92-
Encrypt = SqlConnectionEncryptOption.Optional
94+
Encrypt = SqlConnectionEncryptOption.Optional,
95+
#if NETFRAMEWORK
96+
TransparentNetworkIPResolution = false
97+
#endif
9398
};
9499

95100
using SqlConnection connection = new(builder.ConnectionString);
96101
await connection.OpenAsync();
97102
Assert.Equal(ConnectionState.Open, connection.State);
98103
Assert.Equal($"localhost,{server.EndPoint.Port}", connection.DataSource);
99-
Assert.Equal(2, server.PreLoginCount);
104+
Assert.Equal(2, server.PreLoginCount - server.AbandonedPreLoginCount);
100105
}
101106

102-
[Trait("Category", "flaky")]
103107
[Theory]
104108
[InlineData(40613)]
105109
[InlineData(42108)]
@@ -123,10 +127,9 @@ public void TransientFault_RetryEnabled_ShouldSucceed(uint errorCode)
123127
connection.Open();
124128
Assert.Equal(ConnectionState.Open, connection.State);
125129
Assert.Equal($"localhost,{server.EndPoint.Port}", connection.DataSource);
126-
Assert.Equal(2, server.PreLoginCount);
130+
Assert.Equal(2, server.PreLoginCount - server.AbandonedPreLoginCount);
127131
}
128132

129-
[Trait("Category", "flaky")]
130133
[Theory]
131134
[InlineData(40613)]
132135
[InlineData(42108)]
@@ -151,10 +154,9 @@ public async Task TransientFault_RetryDisabled_ShouldFail_Async(uint errorCode)
151154
SqlException e = await Assert.ThrowsAsync<SqlException>(async () => await connection.OpenAsync());
152155
Assert.Equal((int)errorCode, e.Number);
153156
Assert.Equal(ConnectionState.Closed, connection.State);
154-
Assert.Equal(1, server.PreLoginCount);
157+
Assert.Equal(1, server.PreLoginCount - server.AbandonedPreLoginCount);
155158
}
156159

157-
[Trait("Category", "flaky")]
158160
[Theory]
159161
[InlineData(40613)]
160162
[InlineData(42108)]
@@ -179,10 +181,9 @@ public void TransientFault_RetryDisabled_ShouldFail(uint errorCode)
179181
SqlException e = Assert.Throws<SqlException>(() => connection.Open());
180182
Assert.Equal((int)errorCode, e.Number);
181183
Assert.Equal(ConnectionState.Closed, connection.State);
182-
Assert.Equal(1, server.PreLoginCount);
184+
Assert.Equal(1, server.PreLoginCount - server.AbandonedPreLoginCount);
183185
}
184186

185-
[Trait("Category", "flaky")]
186187
[Theory]
187188
[InlineData(false)]
188189
[InlineData(true)]
@@ -200,6 +201,7 @@ public async Task NetworkError_RetryEnabled_ShouldSucceed_Async(bool multiSubnet
200201
DataSource = "localhost," + server.EndPoint.Port,
201202
Encrypt = SqlConnectionEncryptOption.Optional,
202203
ConnectTimeout = 5,
204+
Pooling = false, // Disable pooling to ensure a fresh connection attempt is made
203205
MultiSubnetFailover = multiSubnetFailoverEnabled,
204206
#if NETFRAMEWORK
205207
TransparentNetworkIPResolution = multiSubnetFailoverEnabled
@@ -216,11 +218,10 @@ public async Task NetworkError_RetryEnabled_ShouldSucceed_Async(bool multiSubnet
216218
}
217219
else
218220
{
219-
Assert.Equal(1, server.PreLoginCount);
221+
Assert.Equal(1, server.PreLoginCount - server.AbandonedPreLoginCount);
220222
}
221223
}
222224

223-
[Trait("Category", "flaky")]
224225
[Theory]
225226
[InlineData(true)]
226227
[InlineData(false)]
@@ -261,11 +262,10 @@ public async Task NetworkDelay_RetryDisabled_Async(bool multiSubnetFailoverEnabl
261262
}
262263
else
263264
{
264-
Assert.Equal(1, server.PreLoginCount);
265+
Assert.Equal(1, server.PreLoginCount - server.AbandonedPreLoginCount);
265266
}
266267
}
267268

268-
[Trait("Category", "flaky")]
269269
[Theory]
270270
[InlineData(true)]
271271
[InlineData(false)]
@@ -306,7 +306,7 @@ public void NetworkDelay_RetryDisabled(bool multiSubnetFailoverEnabled)
306306
}
307307
else
308308
{
309-
Assert.Equal(1, server.PreLoginCount);
309+
Assert.Equal(1, server.PreLoginCount - server.AbandonedPreLoginCount);
310310
}
311311
}
312312

@@ -467,7 +467,8 @@ public void ConnectionTimeoutTest(int timeout)
467467
//TODO: do we even need a server for this test?
468468
using TdsServer server = new();
469469
server.Start();
470-
var connStr = new SqlConnectionStringBuilder() {
470+
var connStr = new SqlConnectionStringBuilder()
471+
{
471472
DataSource = $"localhost,{server.EndPoint.Port}",
472473
ConnectTimeout = timeout,
473474
Encrypt = SqlConnectionEncryptOption.Optional

0 commit comments

Comments
 (0)