private MultiServerCluster CreateAndSetupCluster(ClusterDescription clusterDescription, OperationsCount[] operationsCounts) { #pragma warning disable CS0618 // Type or member is obsolete var clusterSettings = new ClusterSettings( connectionMode: clusterDescription.ConnectionMode, connectionModeSwitch: clusterDescription.ConnectionModeSwitch, serverSelectionTimeout: TimeSpan.FromSeconds(30), endPoints: new Optional <IEnumerable <EndPoint> >(clusterDescription.Servers.Select(s => s.EndPoint))); #pragma warning restore CS0618 // Type or member is obsolete var mockServerFactory = new Mock <IClusterableServerFactory>(); mockServerFactory .Setup(s => s.CreateServer(It.IsAny <ClusterType>(), It.IsAny <ClusterId>(), It.IsAny <IClusterClock>(), It.IsAny <EndPoint>())) .Returns <ClusterType, ClusterId, IClusterClock, EndPoint>((_, _, _, endpoint) => { var serverDescription = clusterDescription.Servers .Single(s => s.EndPoint == endpoint). With(state: ServerState.Connected); var operationsCount = operationsCounts.Single(o => endpoint.ToString().EndsWith(o.address)); var server = new Mock <IClusterableServer>(); server.Setup(s => s.ServerId).Returns(serverDescription.ServerId); server.Setup(s => s.Description).Returns(serverDescription); server.Setup(s => s.EndPoint).Returns(endpoint); server.Setup(s => s.OutstandingOperationsCount).Returns(operationsCount.operation_count); return(server.Object); }); var result = new MultiServerCluster(clusterSettings, mockServerFactory.Object, new EventCapturer()); result.Initialize(); return(result); }
public async Task RapidHeartbeatTimerCallback_should_ignore_reentrant_calls() { var clusterSettings = new ClusterSettings( connectionMode: __clusterConnectionMode, connectionModeSwitch: __connectionModeSwitch, serverSelectionTimeout: TimeSpan.FromSeconds(30), endPoints: new[] { __endPoint1 }); var allHeartbeatsReceived = new TaskCompletionSource <bool>(); const int heartbeatsExpectedMinCount = 3; int heartbeatsCount = 0, isInHeartbeat = 0; var calledReentrantly = false; var serverDescription = new ServerDescription( __serverId1, __endPoint1, type: ServerType.ReplicaSetPrimary, state: ServerState.Disconnected, replicaSetConfig: new ReplicaSetConfig(new[] { __endPoint1 }, "rs", __endPoint1, null)); var serverMock = new Mock <IClusterableServer>(); serverMock.Setup(s => s.EndPoint).Returns(__endPoint1); serverMock.Setup(s => s.IsInitialized).Returns(true); serverMock.Setup(s => s.Description).Returns(serverDescription); serverMock.Setup(s => s.RequestHeartbeat()).Callback(BlockHeartbeatRequested); var serverFactoryMock = new Mock <IClusterableServerFactory>(); serverFactoryMock .Setup(f => f.CreateServer(It.IsAny <ClusterType>(), It.IsAny <ClusterId>(), It.IsAny <IClusterClock>(), It.IsAny <EndPoint>())) .Returns(serverMock.Object); using (var cluster = new MultiServerCluster(clusterSettings, serverFactoryMock.Object, new EventCapturer())) { cluster._minHeartbeatInterval(TimeSpan.FromMilliseconds(10)); // _minHeartbeatInterval validation might not be necessary, and can be reconsidered along with Reflector testing cluster._minHeartbeatInterval().Should().Be(TimeSpan.FromMilliseconds(10)); ForceClusterId(cluster, __clusterId); cluster.Initialize(); // Trigger Cluster._rapidHeartbeatTimer var _ = cluster.SelectServerAsync(CreateWritableServerAndEndPointSelector(__endPoint1), CancellationToken.None); // Wait for all heartbeats to complete await Task.WhenAny(allHeartbeatsReceived.Task, Task.Delay(1000)); } allHeartbeatsReceived.Task.Status.Should().Be(TaskStatus.RanToCompletion); calledReentrantly.Should().Be(false); void BlockHeartbeatRequested() { // Validate BlockHeartbeatRequested is not running already calledReentrantly |= Interlocked.Exchange(ref isInHeartbeat, 1) != 0; // Block Cluster._rapidHeartbeatTimer timer Thread.Sleep(40); Interlocked.Exchange(ref isInHeartbeat, 0); if (Interlocked.Increment(ref heartbeatsCount) == heartbeatsExpectedMinCount) { allHeartbeatsReceived.SetResult(true); } } }