public void Equals_should_be_true_when_both_have_the_same_result()
        {
            var subject1 = new BuildInfoResult(new BsonDocument("x", 1));
            var subject2 = new BuildInfoResult(new BsonDocument("x", 1));

            subject1.Equals(subject2).Should().BeTrue();
        }
        public void Wrapped_should_return_the_document_passed_in_the_constructor()
        {
            var doc = new BsonDocument();
            var subject = new BuildInfoResult(doc);

            subject.Wrapped.Should().BeSameAs(doc);
        }
        public void Equals_should_be_false_when_both_have_different_results()
        {
            var subject1 = new BuildInfoResult(new BsonDocument("x", 1));
            var subject2 = new BuildInfoResult(new BsonDocument("x", 2));

            subject1.Equals(subject2).Should().BeFalse();
        }
        public async Task<ConnectionDescription> InitializeConnectionAsync(IConnection connection, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));

            var isMasterProtocol = CreateIsMasterProtocol();
            var isMasterResult = new IsMasterResult(await isMasterProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false));

            var buildInfoProtocol = CreateBuildInfoProtocol();
            var buildInfoResult = new BuildInfoResult(await buildInfoProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false));

            var description = new ConnectionDescription(connection.ConnectionId, isMasterResult, buildInfoResult);

            await AuthenticationHelper.AuthenticateAsync(connection, description, cancellationToken).ConfigureAwait(false);

            try
            {
                var getLastErrorProtocol = CreateGetLastErrorProtocol();
                var getLastErrorResult = await getLastErrorProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);

                description = UpdateConnectionIdWithServerValue(description, getLastErrorResult);
            }
            catch
            {
                // if we couldn't get the server's connection id, so be it.
            }

            return description;
        }
        public void ServerVersion_should_get_the_semantic_version()
        {
            var doc = new BsonDocument
            {
                { "version", "2.6.3" }
            };
            var subject = new BuildInfoResult(doc);

            subject.ServerVersion.Should().Be(new SemanticVersion(2, 6, 3));
        }
        private async Task <HeartbeatInfo> GetHeartbeatInfoAsync(IConnection connection, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (_heartbeatStartedEventHandler != null)
            {
                _heartbeatStartedEventHandler(new ServerHeartbeatStartedEvent(connection.ConnectionId));
            }

            try
            {
                var isMasterCommand = new CommandWireProtocol <BsonDocument>(
                    DatabaseNamespace.Admin,
                    new BsonDocument("isMaster", 1),
                    true,
                    BsonDocumentSerializer.Instance,
                    null);

                var stopwatch = Stopwatch.StartNew();
                var isMasterResultDocument = await isMasterCommand.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);

                stopwatch.Stop();
                var isMasterResult = new IsMasterResult(isMasterResultDocument);

                var buildInfoCommand = new CommandWireProtocol <BsonDocument>(
                    DatabaseNamespace.Admin,
                    new BsonDocument("buildInfo", 1),
                    true,
                    BsonDocumentSerializer.Instance,
                    null);

                var buildInfoResultRocument = await buildInfoCommand.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);

                var buildInfoResult = new BuildInfoResult(buildInfoResultRocument);

                if (_heartbeatSucceededEventHandler != null)
                {
                    _heartbeatSucceededEventHandler(new ServerHeartbeatSucceededEvent(connection.ConnectionId, stopwatch.Elapsed));
                }

                return(new HeartbeatInfo
                {
                    RoundTripTime = stopwatch.Elapsed,
                    IsMasterResult = isMasterResult,
                    BuildInfoResult = buildInfoResult
                });
            }
            catch (Exception ex)
            {
                if (_heartbeatFailedEventHandler != null)
                {
                    _heartbeatFailedEventHandler(new ServerHeartbeatFailedEvent(connection.ConnectionId, ex));
                }
                throw;
            }
        }
        private async Task <HeartbeatInfo> GetHeartbeatInfoAsync(IConnection connection, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (_listener != null)
            {
                _listener.ServerBeforeHeartbeating(connection.ConnectionId);
            }

            try
            {
                var slidingTimeout = new SlidingTimeout(_settings.HeartbeatTimeout);

                var isMasterCommand = new CommandWireProtocol(
                    DatabaseNamespace.Admin,
                    new BsonDocument("isMaster", 1),
                    true,
                    null);

                var stopwatch = Stopwatch.StartNew();
                var isMasterResultDocument = await isMasterCommand.ExecuteAsync(connection, slidingTimeout, cancellationToken);

                stopwatch.Stop();
                var isMasterResult = new IsMasterResult(isMasterResultDocument);

                var buildInfoCommand = new CommandWireProtocol(
                    DatabaseNamespace.Admin,
                    new BsonDocument("buildInfo", 1),
                    true,
                    null);

                var buildInfoResultRocument = await buildInfoCommand.ExecuteAsync(connection, slidingTimeout, cancellationToken);

                var buildInfoResult = new BuildInfoResult(buildInfoResultRocument);

                if (_listener != null)
                {
                    _listener.ServerAfterHeartbeating(connection.ConnectionId, stopwatch.Elapsed);
                }

                return(new HeartbeatInfo
                {
                    RoundTripTime = stopwatch.Elapsed,
                    IsMasterResult = isMasterResult,
                    BuildInfoResult = buildInfoResult
                });
            }
            catch (Exception ex)
            {
                if (_listener != null)
                {
                    _listener.ServerErrorHeartbeating(connection.ConnectionId, ex);
                }
                throw;
            }
        }
        public async Task<ConnectionDescription> InitializeConnectionAsync(IConnection connection, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));

            var isMasterCommand = new BsonDocument("isMaster", 1);
            var isMasterProtocol = new CommandWireProtocol<BsonDocument>(
                DatabaseNamespace.Admin,
                isMasterCommand,
                true,
                BsonDocumentSerializer.Instance,
                null);
            var isMasterResult = new IsMasterResult(await isMasterProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false));

            var buildInfoCommand = new BsonDocument("buildInfo", 1);
            var buildInfoProtocol = new CommandWireProtocol<BsonDocument>(
                DatabaseNamespace.Admin,
                buildInfoCommand,
                true,
                BsonDocumentSerializer.Instance,
               null);
            var buildInfoResult = new BuildInfoResult(await buildInfoProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false));

            var connectionId = connection.ConnectionId;
            var description = new ConnectionDescription(connectionId, isMasterResult, buildInfoResult);

            await AuthenticationHelper.AuthenticateAsync(connection, description, cancellationToken).ConfigureAwait(false);

            try
            {
                var getLastErrorCommand = new BsonDocument("getLastError", 1);
                var getLastErrorProtocol = new CommandWireProtocol<BsonDocument>(
                    DatabaseNamespace.Admin,
                    getLastErrorCommand,
                    true,
                    BsonDocumentSerializer.Instance,
                    null);
                var getLastErrorResult = await getLastErrorProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);

                BsonValue connectionIdBsonValue;
                if (getLastErrorResult.TryGetValue("connectionId", out connectionIdBsonValue))
                {
                    connectionId = connectionId.WithServerValue(connectionIdBsonValue.ToInt32());
                    description = description.WithConnectionId(connectionId);
                }
            }
            catch
            {
                // if we couldn't get the server's connection id, so be it.
            }

            return description;
        }
        // private methods
        private ConnectionDescription CreateConnectionDescription(SemanticVersion serverVersion)
        {
            var clusterId       = new ClusterId(1);
            var serverId        = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
            var connectionId    = new ConnectionId(serverId, 1);
            var isMasterResult  = new IsMasterResult(new BsonDocument());
            var buildInfoResult = new BuildInfoResult(new BsonDocument
            {
                { "version", serverVersion.ToString() }
            });

            return(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult));
        }
        public static ConnectionDescription CreateConnectionDescription(SemanticVersion version = null, ServerType serverType = ServerType.Standalone, bool supportsSessions = true)
        {
            if (version == null)
            {
                version = new SemanticVersion(3, 6, 0);
            }

            var clusterId       = new ClusterId();
            var serverId        = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
            var connectionId    = new ConnectionId(serverId);
            var buildInfoResult = new BuildInfoResult(new BsonDocument("ok", 1).Add("version", version.ToString()));
            var isMasterResult  = CreateIsMasterResult(version, serverType, supportsSessions);

            return(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult));
        }
        // private methods
        private ConnectionDescription CreateConnectionDescriptionSupportingSession()
        {
            var clusterId        = new ClusterId(1);
            var endPoint         = new DnsEndPoint("localhost", 27017);
            var serverId         = new ServerId(clusterId, endPoint);
            var connectionId     = new ConnectionId(serverId, 1);
            var isMasterDocument = new BsonDocument
            {
                { "logicalSessionTimeoutMinutes", 30 }
            };
            var isMasterResult    = new IsMasterResult(isMasterDocument);
            var buildInfoDocument = new BsonDocument
            {
                { "version", "3.6.0" }
            };
            var buildInfoResult = new BuildInfoResult(buildInfoDocument);

            return(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult));
        }
        private ConnectionDescription CreateConnectionDescription(bool areRetryableWritesSupported)
        {
            var clusterId              = new ClusterId(1);
            var endPoint               = new DnsEndPoint("localhost", 27017);
            var serverId               = new ServerId(clusterId, endPoint);
            var connectionId           = new ConnectionId(serverId, 1);
            var isMasterResultDocument = BsonDocument.Parse("{ ok : 1 }");

            if (areRetryableWritesSupported)
            {
                isMasterResultDocument["logicalSessionTimeoutMinutes"] = 1;
                isMasterResultDocument["msg"] = "isdbgrid"; // mongos
            }
            var isMasterResult        = new IsMasterResult(isMasterResultDocument);
            var buildInfoResult       = new BuildInfoResult(BsonDocument.Parse("{ ok : 1, version : '4.2.0' }"));
            var connectionDescription = new ConnectionDescription(connectionId, isMasterResult, buildInfoResult);

            return(connectionDescription);
        }
        public void Equals_should_return_correct_results()
        {
            var connectionId1 = new ConnectionId(new ServerId(new ClusterId(), new DnsEndPoint("localhost", 27018)), 10);
            var connectionId2 = new ConnectionId(new ServerId(new ClusterId(), new DnsEndPoint("localhost", 27018)), 10);
            var isMasterResult1 = new IsMasterResult(new BsonDocument("x", 1));
            var isMasterResult2 = new IsMasterResult(new BsonDocument("x", 2));
            var buildInfoResult1 = new BuildInfoResult(new BsonDocument("version", "2.6.3"));
            var buildInfoResult2 = new BuildInfoResult(new BsonDocument("version", "2.4.10"));

            var subject1 = new ConnectionDescription(connectionId1, isMasterResult1, buildInfoResult1);
            var subject2 = new ConnectionDescription(connectionId1, isMasterResult1, buildInfoResult1);
            var subject3 = new ConnectionDescription(connectionId1, isMasterResult1, buildInfoResult2);
            var subject4 = new ConnectionDescription(connectionId1, isMasterResult2, buildInfoResult1);
            var subject5 = new ConnectionDescription(connectionId2, isMasterResult1, buildInfoResult1);

            subject1.Equals(subject2).Should().BeTrue();
            subject1.Equals(subject3).Should().BeFalse();
            subject1.Equals(subject4).Should().BeFalse();
            subject1.Equals(subject5).Should().BeFalse();
        }
示例#14
0
        public void PublishDescription(ServerDescription description)
        {
            ServerTuple result;

            if (!_servers.TryGetValue(description.EndPoint, out result))
            {
                throw new InvalidOperationException("Server does not exist.");
            }

            var oldDescription = result.Server.Description;

            if (result.Monitor == null)
            {
                var mockServer = Mock.Get(result.Server);
                mockServer.SetupGet(s => s.Description).Returns(description);
                mockServer.Raise(s => s.DescriptionChanged += null, new ServerDescriptionChangedEventArgs(oldDescription, description));
            }
            else
            {
                if (description.Version != null || description.WireVersionRange != null)
                {
                    var version = description.Version?.ToString() ??
                                  WireVersionHelper.MapWireVersionToServerVersion(description.WireVersionRange.Max);
                    var server         = (Server)result.Server;
                    var isMasterResult = new IsMasterResult(new BsonDocument {
                        { "compressors", new BsonArray() }
                    });
                    var buildInfoResult = new BuildInfoResult(new BsonDocument {
                        { "version", version }
                    });
                    var mockConnection = Mock.Get(server._connectionPool().AcquireConnection(CancellationToken.None));
                    mockConnection.SetupGet(c => c.Description)
                    .Returns(new ConnectionDescription(new ConnectionId(description.ServerId, 0), isMasterResult, buildInfoResult));
                }
                var mockMonitor = Mock.Get(result.Monitor);
                mockMonitor.SetupGet(m => m.Description).Returns(description);
                mockMonitor.Raise(m => m.DescriptionChanged += null, new ServerDescriptionChangedEventArgs(oldDescription, description));
            }
        }
示例#15
0
        private ConnectionDescription CreateConnectionDescription(bool withLogicalSessionTimeout, bool?serviceId = null)
        {
            var clusterId              = new ClusterId(1);
            var endPoint               = new DnsEndPoint("localhost", 27017);
            var serverId               = new ServerId(clusterId, endPoint);
            var connectionId           = new ConnectionId(serverId, 1);
            var isMasterResultDocument = BsonDocument.Parse("{ ok : 1 }");

            if (withLogicalSessionTimeout)
            {
                isMasterResultDocument["logicalSessionTimeoutMinutes"] = 1;
                isMasterResultDocument["msg"] = "isdbgrid"; // mongos
            }
            if (serviceId.HasValue)
            {
                isMasterResultDocument["serviceId"] = ObjectId.Empty; // load balancing mode
            }
            var isMasterResult        = new IsMasterResult(isMasterResultDocument);
            var buildInfoResult       = new BuildInfoResult(BsonDocument.Parse("{ ok : 1, version : '4.2.0' }"));
            var connectionDescription = new ConnectionDescription(connectionId, isMasterResult, buildInfoResult);

            return(connectionDescription);
        }
        public async Task<ConnectionDescription> InitializeConnectionAsync(IConnection connection, ConnectionId connectionId, TimeSpan timeout, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, "connection");
            Ensure.IsNotNull(connectionId, "connectionId");
            Ensure.IsInfiniteOrGreaterThanOrEqualToZero(timeout, "timeout");

            var slidingTimeout = new SlidingTimeout(timeout);

            var isMasterCommand = new BsonDocument("isMaster", 1);
            var isMasterProtocol = new CommandWireProtocol("admin", isMasterCommand, true);
            var isMasterResult = new IsMasterResult(await isMasterProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken));

            // authentication is currently broken on arbiters
            if (!isMasterResult.IsArbiter)
            {
                foreach (var authenticator in connection.Settings.Authenticators)
                {
                    await authenticator.AuthenticateAsync(connection, slidingTimeout, cancellationToken);
                }
            }

            var buildInfoCommand = new BsonDocument("buildInfo", 1);
            var buildInfoProtocol = new CommandWireProtocol("admin", buildInfoCommand, true);
            var buildInfoResult = new BuildInfoResult(await buildInfoProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken));

            var getLastErrorCommand = new BsonDocument("getLastError", 1);
            var getLastErrorProtocol = new CommandWireProtocol("admin", getLastErrorCommand, true);
            var getLastErrorResult = await getLastErrorProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken);

            BsonValue connectionIdBsonValue;
            if (getLastErrorResult.TryGetValue("connectionId", out connectionIdBsonValue))
            {
                connectionId = connectionId.WithServerValue(connectionIdBsonValue.ToInt32());
            }

            return new ConnectionDescription(connectionId, isMasterResult, buildInfoResult);
        }
        private async Task<HeartbeatInfo> GetHeartbeatInfoAsync(IConnection connection, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (_heartbeatStartedEventHandler != null)
            {
                _heartbeatStartedEventHandler(new ServerHeartbeatStartedEvent(connection.ConnectionId));
            }

            try
            {
                var isMasterCommand = new CommandWireProtocol<BsonDocument>(
                    DatabaseNamespace.Admin,
                    new BsonDocument("isMaster", 1),
                    true,
                    BsonDocumentSerializer.Instance,
                    null);

                var stopwatch = Stopwatch.StartNew();
                var isMasterResultDocument = await isMasterCommand.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);
                stopwatch.Stop();
                var isMasterResult = new IsMasterResult(isMasterResultDocument);

                var buildInfoCommand = new CommandWireProtocol<BsonDocument>(
                    DatabaseNamespace.Admin,
                    new BsonDocument("buildInfo", 1),
                    true,
                    BsonDocumentSerializer.Instance,
                    null);

                var buildInfoResultRocument = await buildInfoCommand.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);
                var buildInfoResult = new BuildInfoResult(buildInfoResultRocument);

                if (_heartbeatSucceededEventHandler != null)
                {
                    _heartbeatSucceededEventHandler(new ServerHeartbeatSucceededEvent(connection.ConnectionId, stopwatch.Elapsed));
                }

                return new HeartbeatInfo
                {
                    RoundTripTime = stopwatch.Elapsed,
                    IsMasterResult = isMasterResult,
                    BuildInfoResult = buildInfoResult
                };
            }
            catch (Exception ex)
            {
                if (_heartbeatFailedEventHandler != null)
                {
                    _heartbeatFailedEventHandler(new ServerHeartbeatFailedEvent(connection.ConnectionId, ex));
                }
                throw;
            }
        }
示例#18
0
        public void HandleChannelException_should_update_topology_as_expected_on_network_error_or_timeout(
            string errorType, bool shouldUpdateTopology)
        {
            var       serverId     = new ServerId(_clusterId, _endPoint);
            var       connectionId = new ConnectionId(serverId);
            Exception innerMostException;

            switch (errorType)
            {
            case "MongoConnectionExceptionWithSocketTimeout":
                innerMostException = new SocketException((int)SocketError.TimedOut);
                break;

            case nameof(MongoConnectionException):
                innerMostException = new SocketException((int)SocketError.NetworkUnreachable);
                break;

            default: throw new ArgumentException("Unknown error type.");
            }

            var operationUsingChannelException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException));
            var mockConnection = new Mock <IConnectionHandle>();
            var isMasterResult = new IsMasterResult(new BsonDocument {
                { "compressors", new BsonArray() }
            });
            // the server version doesn't matter when we're not testing MongoNotPrimaryExceptions, but is needed when
            // Server calls ShouldClearConnectionPoolForException
            var buildInfoResult = new BuildInfoResult(new BsonDocument {
                { "version", "4.4.0" }
            });

            mockConnection.SetupGet(c => c.Description)
            .Returns(new ConnectionDescription(new ConnectionId(serverId, 0), isMasterResult, buildInfoResult));
            var mockConnectionPool = new Mock <IConnectionPool>();

            mockConnectionPool.Setup(p => p.AcquireConnection(It.IsAny <CancellationToken>())).Returns(mockConnection.Object);
            mockConnectionPool.Setup(p => p.AcquireConnectionAsync(It.IsAny <CancellationToken>())).ReturnsAsync(mockConnection.Object);
            var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>();

            mockConnectionPoolFactory
            .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint))
            .Returns(mockConnectionPool.Object);
            var mockMonitorServerInitialDescription = new ServerDescription(serverId, _endPoint).With(reasonChanged: "Initial D", type: ServerType.Unknown);
            var mockServerMonitor = new Mock <IServerMonitor>();

            mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerInitialDescription);
            mockServerMonitor.SetupGet(m => m.Lock).Returns(new object());
            var mockServerMonitorFactory = new Mock <IServerMonitorFactory>();

            mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object);
            var subject = new DefaultServer(_clusterId, _clusterClock, _clusterConnectionMode, _connectionModeSwitch, _directConnection, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents, _serverApi);

            subject.Initialize();
            var heartbeatDescription = mockMonitorServerInitialDescription.With(reasonChanged: "Heartbeat", type: ServerType.Standalone);

            mockServerMonitor.Setup(m => m.Description).Returns(heartbeatDescription);
            mockServerMonitor.Raise(
                m => m.DescriptionChanged += null,
                new ServerDescriptionChangedEventArgs(mockMonitorServerInitialDescription, heartbeatDescription));
            subject.Description.Should().Be(heartbeatDescription);

            subject.HandleChannelException(mockConnection.Object, operationUsingChannelException);

            if (shouldUpdateTopology)
            {
                subject.Description.Type.Should().Be(ServerType.Unknown);
                subject.Description.ReasonChanged.Should().Contain("ChannelException");
            }
            else
            {
                subject.Description.Should().Be(heartbeatDescription);
            }
        }
示例#19
0
        private void ApplyApplicationError(BsonDocument applicationError)
        {
            var expectedKeys = new[]
            {
                "address",
                "generation", // optional
                "maxWireVersion",
                "when",
                "type",
                "response" // optional
            };

            JsonDrivenHelper.EnsureAllFieldsAreValid(applicationError, expectedKeys);
            var       address            = applicationError["address"].AsString;
            var       endPoint           = EndPointHelper.Parse(address);
            var       server             = (Server)_serverFactory.GetServer(endPoint);
            var       connectionId       = new ConnectionId(server.ServerId);
            var       type               = applicationError["type"].AsString;
            var       maxWireVersion     = applicationError["maxWireVersion"].AsInt32;
            Exception simulatedException = null;

            switch (type)
            {
            case "command":
                var response = applicationError["response"].AsBsonDocument;
                var command  = new BsonDocument("Link", "start!");
                simulatedException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, command, response, "errmsg");
                Ensure.IsNotNull(simulatedException, nameof(simulatedException));
                break;

            case "network":
            {
                var innerException = CoreExceptionHelper.CreateException("IOExceptionWithNetworkUnreachableSocketException");
                simulatedException = new MongoConnectionException(connectionId, "Ignorance, yet knowledge.", innerException);
                break;
            }

            case "timeout":
            {
                var innerException = CoreExceptionHelper.CreateException("IOExceptionWithTimedOutSocketException");
                simulatedException = new MongoConnectionException(connectionId, "Chaos, yet harmony.", innerException);
                break;
            }

            default:
                throw new ArgumentException($"Unsupported value of {type} for type");
            }

            var mockConnection = new Mock <IConnectionHandle>();
            var isMasterResult = new IsMasterResult(new BsonDocument {
                { "compressors", new BsonArray() }
            });
            var serverVersion   = WireVersionHelper.MapWireVersionToServerVersion(maxWireVersion);
            var buildInfoResult = new BuildInfoResult(new BsonDocument {
                { "version", serverVersion }
            });

            mockConnection.SetupGet(c => c.Description)
            .Returns(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult));
            var generation = applicationError.Contains("generation") ? applicationError["generation"].AsInt32 : 0;

            mockConnection.SetupGet(c => c.Generation).Returns(generation);
            var when = applicationError["when"].AsString;

            switch (when)
            {
            case "beforeHandshakeCompletes":
                server.HandleBeforeHandshakeCompletesException(mockConnection.Object, simulatedException);
                break;

            case "afterHandshakeCompletes":
                server.HandleChannelException(mockConnection.Object, simulatedException);
                break;

            default:
                throw new ArgumentException($"Unsupported value of {when} for when.");
            }
        }
        private async Task HeartbeatAsync(CancellationToken cancellationToken)
        {
            CommandWireProtocol <BsonDocument> isMasterProtocol = null;

            bool processAnother = true;

            while (processAnother && !cancellationToken.IsCancellationRequested)
            {
                IsMasterResult heartbeatIsMasterResult = null;
                Exception      heartbeatException      = null;
                var            previousDescription     = _currentDescription;

                try
                {
                    IConnection connection;
                    lock (_lock)
                    {
                        connection = _connection;
                    }
                    if (connection == null)
                    {
                        var initializedConnection = await InitializeConnectionAsync(cancellationToken).ConfigureAwait(false);

                        lock (_lock)
                        {
                            if (_state.Value == State.Disposed)
                            {
                                try { initializedConnection.Dispose(); } catch { }
                                throw new OperationCanceledException("The ServerMonitor has been disposed.");
                            }
                            _connection = initializedConnection;
                            _handshakeBuildInfoResult = _connection.Description.BuildInfoResult;
                            heartbeatIsMasterResult   = _connection.Description.IsMasterResult;
                        }
                    }
                    else
                    {
                        isMasterProtocol        = isMasterProtocol ?? InitializeIsMasterProtocol(connection);
                        heartbeatIsMasterResult = await GetIsMasterResultAsync(connection, isMasterProtocol, cancellationToken).ConfigureAwait(false);
                    }
                }
                catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
                {
                    return;
                }
                catch (Exception ex)
                {
                    IConnection toDispose = null;

                    lock (_lock)
                    {
                        isMasterProtocol = null;

                        heartbeatException = ex;
                        _roundTripTimeMonitor.Reset();

                        toDispose   = _connection;
                        _connection = null;
                    }
                    toDispose?.Dispose();
                }

                lock (_lock)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }
                }

                ServerDescription newDescription;
                if (heartbeatIsMasterResult != null)
                {
                    if (_handshakeBuildInfoResult == null)
                    {
                        // we can be here only if there is a bug in the driver
                        throw new ArgumentNullException("BuildInfo has been lost.");
                    }

                    var averageRoundTripTime        = _roundTripTimeMonitor.Average;
                    var averageRoundTripTimeRounded = TimeSpan.FromMilliseconds(Math.Round(averageRoundTripTime.TotalMilliseconds));

                    newDescription = _baseDescription.With(
                        averageRoundTripTime: averageRoundTripTimeRounded,
                        canonicalEndPoint: heartbeatIsMasterResult.Me,
                        electionId: heartbeatIsMasterResult.ElectionId,
                        lastWriteTimestamp: heartbeatIsMasterResult.LastWriteTimestamp,
                        logicalSessionTimeout: heartbeatIsMasterResult.LogicalSessionTimeout,
                        maxBatchCount: heartbeatIsMasterResult.MaxBatchCount,
                        maxDocumentSize: heartbeatIsMasterResult.MaxDocumentSize,
                        maxMessageSize: heartbeatIsMasterResult.MaxMessageSize,
                        replicaSetConfig: heartbeatIsMasterResult.GetReplicaSetConfig(),
                        state: ServerState.Connected,
                        tags: heartbeatIsMasterResult.Tags,
                        topologyVersion: heartbeatIsMasterResult.TopologyVersion,
                        type: heartbeatIsMasterResult.ServerType,
                        version: _handshakeBuildInfoResult.ServerVersion,
                        wireVersionRange: new Range <int>(heartbeatIsMasterResult.MinWireVersion, heartbeatIsMasterResult.MaxWireVersion));
                }
                else
                {
                    newDescription = _baseDescription.With(lastUpdateTimestamp: DateTime.UtcNow);
                }

                if (heartbeatException != null)
                {
                    var topologyVersion = default(Optional <TopologyVersion>);
                    if (heartbeatException is MongoCommandException heartbeatCommandException)
                    {
                        topologyVersion = TopologyVersion.FromMongoCommandException(heartbeatCommandException);
                    }
                    newDescription = newDescription.With(heartbeatException: heartbeatException, topologyVersion: topologyVersion);
                }

                newDescription = newDescription.With(reasonChanged: "Heartbeat", lastHeartbeatTimestamp: DateTime.UtcNow);

                lock (_lock)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    SetDescription(newDescription);
                }

                processAnother =
                    // serverSupportsStreaming
                    (newDescription.Type != ServerType.Unknown && heartbeatIsMasterResult != null && heartbeatIsMasterResult.TopologyVersion != null) ||
                    // connectionIsStreaming
                    (isMasterProtocol != null && isMasterProtocol.MoreToCome) ||
                    // transitionedWithNetworkError
                    (IsNetworkError(heartbeatException) && previousDescription.Type != ServerType.Unknown);
            }

            bool IsNetworkError(Exception ex)
            {
                return(ex is MongoConnectionException mongoConnectionException && mongoConnectionException.IsNetworkException);
            }
        }
 // private methods
 private ConnectionDescription CreateConnectionDescription(SemanticVersion serverVersion)
 {
     var clusterId = new ClusterId(1);
     var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
     var connectionId = new ConnectionId(serverId, 1);
     var isMasterResult = new IsMasterResult(new BsonDocument());
     var buildInfoResult = new BuildInfoResult(new BsonDocument
     {
         { "version", serverVersion.ToString() }
     });
     return new ConnectionDescription(connectionId, isMasterResult, buildInfoResult);
 }
        public void WithConnectionId_should_return_new_instance_even_when_only_the_serverValue_differs()
        {
            var clusterId = new ClusterId();
            var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 1));
            var connectionId1 = new ConnectionId(serverId, 1);
            var connectionId2 = new ConnectionId(serverId, 1).WithServerValue(2);
            var isMasterResult = new IsMasterResult(new BsonDocument());
            var buildInfoResult = new BuildInfoResult(new BsonDocument("version", "2.6.0"));
            var subject = new ConnectionDescription(connectionId1, isMasterResult, buildInfoResult);

            var result = subject.WithConnectionId(connectionId2);

            result.Should().NotBeSameAs(subject);
            result.ConnectionId.Should().BeSameAs(connectionId2);
        }