Skip to content

Commit d7b0556

Browse files
CSHARP-4070: Fix flaky Ensure_command_network_error_before_hadnshake_is_correctly_handled test. (#743)
CSHARP-4070: Fix flaky Ensure_command_network_error_before_hadnshake_is_correctly_handled test.
1 parent d3ad5ae commit d7b0556

File tree

1 file changed

+36
-18
lines changed

1 file changed

+36
-18
lines changed

tests/MongoDB.Driver.Core.Tests/Jira/CSharp3173Tests.cs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ namespace MongoDB.Driver.Core.Tests.Jira
4141
{
4242
public class CSharp3173Tests
4343
{
44-
#if WINDOWS
4544
#pragma warning disable CS0618 // Type or member is obsolete
4645
private readonly static ClusterConnectionMode __clusterConnectionMode = ClusterConnectionMode.Sharded;
4746
private readonly static ConnectionModeSwitch __connectionModeSwitch = ConnectionModeSwitch.UseConnectionMode;
@@ -93,7 +92,7 @@ public void Ensure_command_network_error_before_hadnshake_is_correctly_handled([
9392
}
9493

9594
var e = exception.Should().BeOfType<MongoConnectionException>().Subject;
96-
e.Message.Should().Be("DnsException");
95+
e.Message.Should().Be("DnsException:pool");
9796

9897
// 2. Waiting for the hello or legacy hello check
9998
hasNetworkErrorBeenTriggered.SetResult(true); // unlock the in-progress hello or legacy hello response
@@ -129,22 +128,23 @@ public void Ensure_command_network_error_before_hadnshake_is_correctly_handled([
129128
AssertEvent(initialHeartbeatEvents[1], __endPoint2, ServerType.ShardRouter, "Heartbeat"); // the next 27018 events will be suppressed
130129

131130
AssertNextEvent(eventCapturer, initialSelectedEndpoint, ServerType.Unknown, "InvalidatedBecause:ChannelException during handshake: MongoDB.Driver.MongoConnectionException: DnsException");
132-
AssertNextEvent(eventCapturer, initialSelectedEndpoint, ServerType.Unknown, "Heartbeat", typeof(MongoConnectionException));
131+
AssertNextEvent(eventCapturer, initialSelectedEndpoint, ServerType.Unknown, "Heartbeat", (typeof(MongoConnectionException), "DnsException:sdam"));
133132
eventCapturer.Any().Should().BeFalse();
134133

135134
int GetPort(EndPoint endpoint) => ((DnsEndPoint)endpoint).Port;
136135
}
137136

138137
// private method
139-
private void AssertEvent(ServerDescriptionChangedEvent @event, EndPoint expectedEndPoint, ServerType expectedServerType, string expectedReasonStart, Type exceptionType = null)
138+
private void AssertEvent(ServerDescriptionChangedEvent @event, EndPoint expectedEndPoint, ServerType expectedServerType, string expectedReasonStart, (Type ExceptionType, string ExceptionMessage)? exceptionInfo = null)
140139
{
141140
@event.ServerId.ClusterId.Should().Be(__clusterId);
142141
@event.NewDescription.EndPoint.Should().Be(expectedEndPoint);
143142
@event.NewDescription.Type.Should().Be(expectedServerType);
144143
@event.NewDescription.State.Should().Be(expectedServerType == ServerType.Unknown ? ServerState.Disconnected : ServerState.Connected);
145-
if (exceptionType != null)
144+
if (exceptionInfo.HasValue)
146145
{
147-
@event.NewDescription.HeartbeatException.Should().BeOfType(exceptionType);
146+
@event.NewDescription.HeartbeatException.Should().BeOfType(exceptionInfo.Value.ExceptionType);
147+
@event.NewDescription.HeartbeatException.Message.Should().Be(exceptionInfo.Value.ExceptionMessage);
148148
}
149149
else
150150
{
@@ -153,10 +153,10 @@ private void AssertEvent(ServerDescriptionChangedEvent @event, EndPoint expected
153153
@event.NewDescription.ReasonChanged.Should().StartWith(expectedReasonStart);
154154
}
155155

156-
private void AssertNextEvent(EventCapturer eventCapturer, EndPoint expectedEndPoint, ServerType expectedServerType, string expectedReasonStart, Type exceptionType = null)
156+
private void AssertNextEvent(EventCapturer eventCapturer, EndPoint expectedEndPoint, ServerType expectedServerType, string expectedReasonStart, (Type ExceptionType, string ExceptionMessage)? exceptionInfo = null)
157157
{
158158
var @event = eventCapturer.Next().Should().BeOfType<ServerDescriptionChangedEvent>().Subject;
159-
AssertEvent(@event, expectedEndPoint, expectedServerType, expectedReasonStart, exceptionType);
159+
AssertEvent(@event, expectedEndPoint, expectedServerType, expectedReasonStart, exceptionInfo);
160160
}
161161

162162
private IConnectionPoolFactory CreateAndSetupConnectionPoolFactory(Func<ServerId, IConnectionExceptionHandler> exceptionHandlerProvider, params (ServerId ServerId, EndPoint Endpoint, bool IsHealthy)[] serverInfoCollection)
@@ -183,7 +183,7 @@ void SetupConnection(Mock<IConnectionHandle> mockConnectionHandle, ServerId serv
183183

184184
void SetupConnectionPool(Mock<IConnectionPool> mockConnectionPool, IConnectionHandle connection, Func<IConnectionExceptionHandler> exceptionHandlerProvider)
185185
{
186-
var dnsException = CreateDnsException(connection.ConnectionId);
186+
var dnsException = CreateDnsException(connection.ConnectionId, from: "pool");
187187
mockConnectionPool
188188
.Setup(c => c.AcquireConnection(It.IsAny<CancellationToken>()))
189189
.Callback(() => exceptionHandlerProvider().HandleExceptionOnOpen(dnsException))
@@ -210,17 +210,33 @@ private IConnectionFactory CreateAndSetupServerMonitorConnectionFactory(
210210

211211
foreach (var serverInfo in serverInfoCollection)
212212
{
213+
// configure ServerMonitor connections
213214
var mockServerMonitorConnection = new Mock<IConnection>();
214215
SetupServerMonitorConnection(mockServerMonitorConnection, serverInfo.ServerId, serverInfo.IsHealthy, hasNetworkErrorBeenTriggered, hasClusterBeenDisposed, streamable);
215216
mockConnectionFactory
217+
.When(() => !Environment.StackTrace.Contains(nameof(RoundTripTimeMonitor)))
216218
.Setup(c => c.CreateConnection(serverInfo.ServerId, serverInfo.Endpoint))
217219
.Returns(mockServerMonitorConnection.Object);
220+
221+
// configure healthy RTT connections
222+
var mockRttConnection = new Mock<IConnection>();
223+
SetupServerMonitorConnection(
224+
mockRttConnection,
225+
serverInfo.ServerId,
226+
isHealthy: true,
227+
hasNetworkErrorBeenTriggered: null, // has no role for RTT
228+
hasClusterBeenDisposed,
229+
streamable);
230+
mockConnectionFactory
231+
.When(() => Environment.StackTrace.Contains(nameof(RoundTripTimeMonitor)))
232+
.Setup(c => c.CreateConnection(serverInfo.ServerId, serverInfo.Endpoint))
233+
.Returns(mockRttConnection.Object);
218234
}
219235

220236
return mockConnectionFactory.Object;
221237
}
222238

223-
private MultiServerCluster CreateAndSetupCluster(TaskCompletionSource<bool> hasNetworkErrorBeenTriggered, TaskCompletionSource<bool> hasClusterBeenDisposed, EventCapturer eventCapturer, bool streamable)
239+
private MultiServerCluster CreateAndSetupCluster(TaskCompletionSource<bool> hasNetworkErrorBeenTriggered, TaskCompletionSource<bool> hasClusterBeenDisposed, IEventSubscriber eventCapturer, bool streamable)
224240
{
225241
(ServerId ServerId, EndPoint Endpoint, bool IsHealthy)[] serverInfoCollection = new[]
226242
{
@@ -253,9 +269,9 @@ private MultiServerCluster CreateAndSetupCluster(TaskCompletionSource<bool> hasN
253269
return cluster = new MultiServerCluster(clusterSettings, serverFactory, eventCapturer);
254270
}
255271

256-
private Exception CreateDnsException(ConnectionId connectionId)
272+
private Exception CreateDnsException(ConnectionId connectionId, string from)
257273
{
258-
return new MongoConnectionException(connectionId, "DnsException");
274+
return new MongoConnectionException(connectionId, $"DnsException:{from}");
259275
}
260276

261277
private IServerSelector CreateWritableServerAndEndPointSelector(EndPoint endPoint)
@@ -325,12 +341,13 @@ private void SetupServerMonitorConnection(
325341

326342
void SetupFailedConnection(Mock<IConnection> mockFaultyConnection)
327343
{
344+
Ensure.IsNotNull(hasNetworkErrorBeenTriggered, nameof(hasNetworkErrorBeenTriggered));
345+
328346
// async path is not used in serverMonitor
329347
var faultyConnectionResponses = new Queue<Action>(new Action[]
330348
{
331-
() => { /* no action needed*/ }, // the first hello or legacy hello configuration passes
332-
() => { /* no action needed*/ }, // RTT
333-
() => throw CreateDnsException(mockConnection.Object.ConnectionId), // the dns exception. Should be triggered after Invalidate
349+
() => { }, // the first hello or legacy hello configuration passes
350+
() => throw CreateDnsException(mockConnection.Object.ConnectionId, from: "sdam"), // the dns exception. Should be triggered after Invalidate
334351
() => WaitForTaskOrTimeout(hasClusterBeenDisposed.Task, TimeSpan.FromMinutes(1), "cluster dispose")
335352
});
336353
mockFaultyConnection
@@ -345,8 +362,10 @@ void SetupFailedConnection(Mock<IConnection> mockFaultyConnection)
345362
.Setup(c => c.ReceiveMessage(It.IsAny<int>(), It.IsAny<IMessageEncoderSelector>(), It.IsAny<MessageEncoderSettings>(), It.IsAny<CancellationToken>()))
346363
.Returns(() =>
347364
{
348-
// wait until the command network error has been triggered
349-
WaitForTaskOrTimeout(hasNetworkErrorBeenTriggered.Task, TimeSpan.FromMinutes(1), "network error");
365+
WaitForTaskOrTimeout(
366+
hasNetworkErrorBeenTriggered.Task,
367+
TimeSpan.FromMinutes(1),
368+
testTarget: "network error");
350369
return commandResponseAction();
351370
});
352371
}
@@ -372,6 +391,5 @@ private void WaitForTaskOrTimeout(Task task, TimeSpan timeout, string testTarget
372391
throw new Exception($"The waiting for {testTarget} is exceeded timeout {timeout}.");
373392
}
374393
}
375-
#endif
376394
}
377395
}

0 commit comments

Comments
 (0)