public void GetReplicaSetConfig_should_return_correct_info_when_the_server_is_a_replica_set()
        {
            var doc = new BsonDocument
            {
                { "ok", 1 },
                { "setName", "funny" },
                { "primary", "localhost:1000" },
                { "hosts", new BsonArray(new [] { "localhost:1000", "localhost:1001" })},
                { "passives", new BsonArray(new [] { "localhost:1002"}) },
                { "arbiters", new BsonArray(new [] { "localhost:1003"}) },
                { "version", 20 }
            };

            var subject = new IsMasterResult(doc);
            var config = subject.GetReplicaSetConfig();

            config.Name.Should().Be("funny");
            config.Primary.Should().Be(new DnsEndPoint("localhost", 1000));
            config.Members.Should().BeEquivalentTo(
                new DnsEndPoint("localhost", 1000),
                new DnsEndPoint("localhost", 1001),
                new DnsEndPoint("localhost", 1002),
                new DnsEndPoint("localhost", 1003));
            config.Version.Should().Be(20);
        }
        private void ApplyResponse(BsonArray response)
        {
            if (response.Count != 2)
            {
                throw new FormatException($"Invalid response count: {response.Count}.");
            }

            var address          = response[0].AsString;
            var isMasterDocument = response[1].AsBsonDocument;

            JsonDrivenHelper.EnsureAllFieldsAreValid(isMasterDocument, "hosts", "isWritablePrimary", OppressiveLanguageConstants.LegacyHelloResponseIsWritablePrimaryFieldName, "helloOk", "maxWireVersion", "minWireVersion", "ok", "primary", "secondary", "setName", "setVersion");

            var endPoint                 = EndPointHelper.Parse(address);
            var isMasterResult           = new IsMasterResult(isMasterDocument);
            var currentServerDescription = _serverFactory.GetServerDescription(endPoint);
            var newServerDescription     = currentServerDescription.With(
                canonicalEndPoint: isMasterResult.Me,
                electionId: isMasterResult.ElectionId,
                replicaSetConfig: isMasterResult.GetReplicaSetConfig(),
                state: isMasterResult.Wrapped.GetValue("ok", false).ToBoolean() ? ServerState.Connected : ServerState.Disconnected,
                type: isMasterResult.ServerType,
                wireVersionRange: new Range <int>(isMasterResult.MinWireVersion, isMasterResult.MaxWireVersion));

            var currentClusterDescription = _cluster.Description;

            _serverFactory.PublishDescription(newServerDescription);
            SpinWait.SpinUntil(() => !object.ReferenceEquals(_cluster.Description, currentClusterDescription), 100); // sometimes returns false and that's OK
        }
Beispiel #3
0
        private void ApplyResponse(BsonArray response)
        {
            if (response.Count != 2)
            {
                throw new FormatException($"Invalid response count: {response.Count}.");
            }

            var address          = response[0].AsString;
            var isMasterDocument = response[1].AsBsonDocument;

            VerifyFields(isMasterDocument, "arbiterOnly", "arbiters", "electionId", "hidden", "hosts", "ismaster", "isreplicaset", "logicalSessionTimeoutMinutes", "maxWireVersion", "me", "minWireVersion", "msg", "ok", "passive", "passives", "primary", "secondary", "setName", "setVersion");

            var endPoint                 = EndPointHelper.Parse(address);
            var isMasterResult           = new IsMasterResult(isMasterDocument);
            var currentServerDescription = _serverFactory.GetServerDescription(endPoint);
            var newServerDescription     = currentServerDescription.With(
                canonicalEndPoint: isMasterResult.Me,
                electionId: isMasterResult.ElectionId,
                logicalSessionTimeout: isMasterResult.LogicalSessionTimeout,
                replicaSetConfig: isMasterResult.GetReplicaSetConfig(),
                state: isMasterResult.Wrapped.GetValue("ok", false).ToBoolean() ? ServerState.Connected : ServerState.Disconnected,
                type: isMasterResult.ServerType,
                wireVersionRange: new Range <int>(isMasterResult.MinWireVersion, isMasterResult.MaxWireVersion));

            var currentClusterDescription = _cluster.Description;

            _serverFactory.PublishDescription(newServerDescription);
            SpinWait.SpinUntil(() => !object.ReferenceEquals(_cluster.Description, currentClusterDescription), 100); // sometimes returns false and that's OK
        }
        // methods
        /// <inheritdoc/>
        public void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));
            Ensure.IsNotNull(description, nameof(description));

            // If we don't have SaslSupportedMechs as part of the response, that means we didn't piggyback the initial
            // hello or legacy hello request and should query the server (provided that the server >= 4.0), merging results into
            // a new ConnectionDescription
            if (!description.IsMasterResult.HasSaslSupportedMechs &&
                Feature.ScramSha256Authentication.IsSupported(description.ServerVersion))
            {
                var command           = CustomizeInitialIsMasterCommand(HelloHelper.CreateCommand());
                var helloProtocol     = HelloHelper.CreateProtocol(command, _serverApi);
                var helloResult       = HelloHelper.GetResult(connection, helloProtocol, cancellationToken);
                var mergedHelloResult = new IsMasterResult(description.IsMasterResult.Wrapped.Merge(helloResult.Wrapped));
                description = new ConnectionDescription(
                    description.ConnectionId,
                    mergedHelloResult,
                    description.BuildInfoResult);
            }

            var authenticator = GetOrCreateAuthenticator(connection, description);

            authenticator.Authenticate(connection, description, cancellationToken);
        }
Beispiel #5
0
        /// <inheritdoc/>
        public async Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));
            Ensure.IsNotNull(description, nameof(description));

            // If we don't have SaslSupportedMechs as part of the response, that means we didn't piggyback the initial
            // isMaster request and should query the server (provided that the server >= 4.0), merging results into
            // a new ConnectionDescription
            if (!description.IsMasterResult.HasSaslSupportedMechs &&
                Feature.ScramSha256Authentication.IsSupported(description.ServerVersion))
            {
                var command          = CustomizeInitialIsMasterCommand(IsMasterHelper.CreateCommand());
                var isMasterProtocol = IsMasterHelper.CreateProtocol(command);
                var isMasterResult   = await IsMasterHelper.GetResultAsync(connection, isMasterProtocol, cancellationToken).ConfigureAwait(false);

                var mergedIsMasterResult = new IsMasterResult(description.IsMasterResult.Wrapped.Merge(isMasterResult.Wrapped));
                description = new ConnectionDescription(
                    description.ConnectionId,
                    mergedIsMasterResult,
                    description.BuildInfoResult);
            }

            var authenticator = GetOrCreateAuthenticator(connection, description);
            await authenticator.AuthenticateAsync(connection, description, cancellationToken).ConfigureAwait(false);
        }
        public void Equals_should_be_true_when_both_have_the_same_result()
        {
            var subject1 = new IsMasterResult(new BsonDocument("x", 1));
            var subject2 = new IsMasterResult(new BsonDocument("x", 1));

            subject1.Equals(subject2).Should().BeTrue();
        }
        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 Equals_should_be_false_when_both_have_different_results()
        {
            var subject1 = new IsMasterResult(new BsonDocument("x", 1));
            var subject2 = new IsMasterResult(new BsonDocument("x", 2));

            subject1.Equals(subject2).Should().BeFalse();
        }
        public void ElectionId_should_parse_document_correctly(string json, string expectedObjectId)
        {
            var subject = new IsMasterResult(BsonDocument.Parse(json));
            var expected = expectedObjectId == null ? (ElectionId)null : new ElectionId(ObjectId.Parse(expectedObjectId));

            subject.ElectionId.Should().Be(expected);
        }
        public void Wrapped_should_return_the_document_passed_in_the_constructor()
        {
            var doc = new BsonDocument();
            var subject = new IsMasterResult(doc);

            subject.Wrapped.Should().BeSameAs(doc);
        }
        public void LastWriteTimestamp_should_parse_document_correctly(string json, int? expectedYear)
        {
            var subject = new IsMasterResult(BsonDocument.Parse(json));

            var result = subject.LastWriteTimestamp;

            var expectedResult = expectedYear.HasValue ? new DateTime(expectedYear.Value, 1, 1, 0, 0, 0, DateTimeKind.Utc) : (DateTime?)null;
            result.Should().Be(expectedResult);
        }
        public void TestMaxWriteBatchSizeWhenNotServerSupplied()
        {
            var document = new BsonDocument
            {
                { "ok", 1 }
            };
            var result = new IsMasterResult(document);

            Assert.AreEqual(1000, result.MaxWriteBatchSize);
        }
        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 void TestMaxMessageLengthWhenNotServerSuppliedUsesMaxBsonObjectSizeWhenLargerThanMongoDefaults()
        {
            var document = new BsonDocument
            {
                { "ok", 1 },
                { "maxBsonObjectSize", MongoDefaults.MaxMessageLength }
            };
            var result = new IsMasterResult(document);

            Assert.AreEqual(MongoDefaults.MaxMessageLength + 1024, result.MaxMessageLength);
        }
        public void TestMaxMessageLengthWhenServerSupplied()
        {
            var document = new BsonDocument
            {
                { "ok", 1 },
                { "maxMessageSizeBytes", 1000 },
                { "maxBsonObjectSize", 1000 }
            };
            var result = new IsMasterResult(document);

            Assert.AreEqual(1000, result.MaxMessageLength);
        }
        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;
        }
Beispiel #18
0
        private void ApplyResponse(BsonValue response)
        {
            var server             = (string)response[0];
            var endPoint           = EndPointHelper.Parse(server);
            var isMasterResult     = new IsMasterResult((BsonDocument)response[1]);
            var currentDescription = _serverFactory.GetServerDescription(endPoint);
            var description        = currentDescription.With(
                state: isMasterResult.Wrapped.GetValue("ok", false).ToBoolean() ? ServerState.Connected : ServerState.Disconnected,
                type: isMasterResult.ServerType,
                replicaSetConfig: isMasterResult.GetReplicaSetConfig());

            _serverFactory.PublishDescription(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));
        }
        private void ApplyResponse(BsonValue response)
        {
            var server = (string)response[0];
            var endPoint = EndPointHelper.Parse(server);
            var isMasterResult = new IsMasterResult((BsonDocument)response[1]);
            var currentDescription = _serverFactory.GetServerDescription(endPoint);
            var description = currentDescription.With(
                state: isMasterResult.Wrapped.GetValue("ok", false).ToBoolean() ? ServerState.Connected : ServerState.Disconnected,
                type: isMasterResult.ServerType,
                canonicalEndPoint: isMasterResult.Me,
                electionId: isMasterResult.ElectionId,
                replicaSetConfig: isMasterResult.GetReplicaSetConfig());

            _serverFactory.PublishDescription(description);
        }
Beispiel #21
0
        private void ApplyResponse(BsonValue response)
        {
            var server                   = (string)response[0];
            var endPoint                 = EndPointHelper.Parse(server);
            var isMasterResult           = new IsMasterResult((BsonDocument)response[1]);
            var currentServerDescription = _serverFactory.GetServerDescription(endPoint);
            var newServerDescription     = currentServerDescription.With(
                state: isMasterResult.Wrapped.GetValue("ok", false).ToBoolean() ? ServerState.Connected : ServerState.Disconnected,
                type: isMasterResult.ServerType,
                canonicalEndPoint: isMasterResult.Me,
                electionId: isMasterResult.ElectionId,
                replicaSetConfig: isMasterResult.GetReplicaSetConfig());

            var currentClusterDescription = _cluster.Description;

            _serverFactory.PublishDescription(newServerDescription);
            SpinWait.SpinUntil(() => !object.ReferenceEquals(_cluster.Description, currentClusterDescription), 100); // sometimes returns false and that's OK
        }
        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);
        }
        // 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));
        }
        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();
        }
Beispiel #25
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));
            }
        }
Beispiel #26
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;
            }
        }
        public void MaxDocumentSize_should_parse_document_correctly(string json, int expected)
        {
            var subject = new IsMasterResult(BsonDocument.Parse(json));

            subject.MaxDocumentSize.Should().Be(expected);
        }
 // 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);
        }
        public void Tags_should_parse_document_correctly()
        {
            var subject = new IsMasterResult(BsonDocument.Parse("{ tags: { a: \"one\", b: \"two\" } }"));
            var expected = new TagSet(new[] { new Tag("a", "one"), new Tag("b", "two") });

            subject.Tags.Should().Be(expected);
        }
        public void Tags_should_be_null_when_no_tags_exist()
        {
            var subject = new IsMasterResult(new BsonDocument());

            subject.Tags.Should().BeNull();
        }
        public void ServerType_should_parse_document_correctly(string json, ServerType expected)
        {
            var subject = new IsMasterResult(BsonDocument.Parse(json));

            subject.ServerType.Should().Be(expected);
        }
        public void Me_should_parse_document_correctly(string json, string expectedEndPoint)
        {
            var endPoint = expectedEndPoint == null ? (EndPoint)null : EndPointHelper.Parse(expectedEndPoint);

            var subject = new IsMasterResult(BsonDocument.Parse(json));

            subject.Me.Should().Be(endPoint);
        }
        public void MinWireVersion_should_parse_document_correctly(string json, int expected)
        {
            var subject = new IsMasterResult(BsonDocument.Parse(json));

            subject.MinWireVersion.Should().Be(expected);
        }
        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);
            }
        }
Beispiel #38
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.");
            }
        }
Beispiel #39
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);
            }
        }