Example #1
0
        public void Should_call_custom_server_selector()
        {
            var eventCapturer = new EventCapturer()
                                .Capture <ClusterSelectingServerEvent>()
                                .Capture <ClusterSelectedServerEvent>();
            var customServerSelector = new CustomServerSelector();

            using (var client = DriverTestConfiguration.CreateDisposableClient(
                       clientSettings =>
                       clientSettings.ClusterConfigurator =
                           c =>
            {
                c.ConfigureCluster(s => s.With(postServerSelector: customServerSelector));
                c.Subscribe(eventCapturer);
            },
                       logger: null))
            {
                var collection = client
                                 .GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                                 .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                                 .WithReadPreference(ReadPreference.Nearest);

                customServerSelector.CustomSelectorWasCalled = false;
                eventCapturer.Clear();

                collection.CountDocuments(new BsonDocument());

                customServerSelector.CustomSelectorWasCalled.Should().BeTrue();
                eventCapturer.Next().Should().BeOfType <ClusterSelectingServerEvent>();
                eventCapturer.Next().Should().BeOfType <ClusterSelectedServerEvent>();
            }
        }
        public void AfterClusterTime_should_be_sent_after_the_first_read_operation()
        {
            RequireServer.Check().SupportsCausalConsistency();

            var events = new EventCapturer()
                         .Capture <CommandStartedEvent>(x => x.CommandName == "count")
                         .Capture <CommandSucceededEvent>(x => x.CommandName == "find");

            using (var client = GetClient(events))
                using (var session = client.StartSession())
                {
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .FindSync(session, FilterDefinition <BsonDocument> .Empty, new FindOptions <BsonDocument, BsonDocument> {
                        Limit = 1
                    });

                    var commandSucceededEvent = (CommandSucceededEvent)events.Next();
                    session.OperationTime.Should().Be(commandSucceededEvent.Reply.GetValue("operationTime"));
                    var operationTime = session.OperationTime;

                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .Count(session, FilterDefinition <BsonDocument> .Empty);

                    var commandStartedEvent = (CommandStartedEvent)events.Next();
                    commandStartedEvent.Command["readConcern"]["afterClusterTime"].AsBsonTimestamp.Should().Be(operationTime);
                }
        }
Example #3
0
        public void AfterClusterTime_should_be_sent_after_the_first_write_operation()
        {
            RequireServer.Check().SupportsCausalConsistency();

            var events = new EventCapturer()
                         .Capture <CommandStartedEvent>(x => x.CommandName == "count")
                         .Capture <CommandSucceededEvent>(x => x.CommandName == "insert");

            using (var client = GetClient(events))
                using (var session = client.StartSession())
                {
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .InsertOne(session, new BsonDocument("x", 1));

                    var commandSucceededEvent = (CommandSucceededEvent)events.Next();
                    session.OperationTime.Should().Be(commandSucceededEvent.Reply.GetValue("operationTime"));
                    var operationTime = session.OperationTime;

#pragma warning disable 618
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .Count(session, FilterDefinition <BsonDocument> .Empty);
#pragma warning restore

                    var commandStartedEvent = (CommandStartedEvent)events.Next();
                    commandStartedEvent.Command["readConcern"]["afterClusterTime"].AsBsonTimestamp.Should().Be(operationTime);
                }
        }
Example #4
0
        public void Stop_should_trigger_immidiate_maintenace_call(
            [Values(false, true)] bool checkOutConnection,
            [Values(false, true)] bool closeInUseConnection)
        {
            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolAddedConnectionEvent>()
                                .Capture <ConnectionPoolRemovedConnectionEvent>();

            int connectionId = 0;

            using (var pool = CreatePool(
                       eventCapturer,
                       minPoolSize: 1,
                       connectionFactoryConfigurator: (factory) =>
            {
                factory
                .Setup(f => f.CreateConnection(__serverId, __endPoint))
                .Returns(() => new MockConnection(new ConnectionId(__serverId, ++connectionId), new ConnectionSettings(), eventCapturer));
            }))     // use to ensure that Maintenance attempt has been called
            {
                var subject = pool._maintenanceHelper();

                var maitenanceInPlayTimeout = TimeSpan.FromMilliseconds(50);
                eventCapturer.WaitForEventOrThrowIfTimeout <ConnectionPoolAddedConnectionEvent>(maitenanceInPlayTimeout);
                eventCapturer.Next().Should().BeOfType <ConnectionPoolAddedConnectionEvent>().Which.ConnectionId.LocalValue.Should().Be(1);  // minPoolSize has been enrolled
                eventCapturer.Any().Should().BeFalse();

                SpinWait.SpinUntil(() => pool.ConnectionHolder._connections().Count > 0, TimeSpan.FromSeconds(1)).Should().BeTrue(); // wait until connection 1 has been returned to the pool after minPoolSize logic

                IConnection acquiredConnection = null;
                if (checkOutConnection)
                {
                    acquiredConnection = pool.AcquireConnection(CancellationToken.None);
                    acquiredConnection.ConnectionId.LocalValue.Should().Be(1);
                }

                IncrementGeneration(pool);
                subject.Stop(maxGenerationToReap: closeInUseConnection ? pool.Generation : null);

                var requestInPlayTimeout = TimeSpan.FromMilliseconds(100);
                if (!closeInUseConnection && checkOutConnection)
                {
                    // connection in progress should be not touched
                    Thread.Sleep(requestInPlayTimeout);
                }
                else
                {
                    eventCapturer.WaitForOrThrowIfTimeout((events) => events.OfType <ConnectionPoolRemovedConnectionEvent>().Count() >= 1, requestInPlayTimeout);
                    eventCapturer.Next().Should().BeOfType <ConnectionPoolRemovedConnectionEvent>();
                }
                eventCapturer.Any().Should().BeFalse();

                pool.AvailableCount.Should().Be(checkOutConnection ? pool.Settings.MaxConnections - 1 : pool.Settings.MaxConnections);
                pool.CreatedCount.Should().Be(checkOutConnection ? 1 : 0);
                pool.DormantCount.Should().Be(0);
                pool.PendingCount.Should().Be(0);
                pool.UsedCount.Should().Be(checkOutConnection ? 1 : 0);
            }
        }
        public void Dispose_should_dispose_the_server()
        {
            _subject.Initialize();
            _capturedEvents.Clear();

            _subject.Dispose();
            _mockConnectionPool.Verify(p => p.Dispose(), Times.Once);

            _capturedEvents.Next().Should().BeOfType <ServerClosingEvent>();
            _capturedEvents.Next().Should().BeOfType <ServerClosedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
        public void Dispose_should_dispose_the_server()
        {
            _subject.Initialize();
            _capturedEvents.Clear();

            _subject.Dispose();
            _connectionPool.Received().Dispose();
            _serverMonitor.Received().Dispose();

            _capturedEvents.Next().Should().BeOfType <ServerClosingEvent>();
            _capturedEvents.Next().Should().BeOfType <ServerClosedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
Example #7
0
        private void AssertCheckOutOnlyEvents(EventCapturer eventCapturer, int attempt, bool shouldHelloBeCalled, bool shouldNextAttemptTriggerCheckout = true)
        {
            if (attempt == 1 || shouldNextAttemptTriggerCheckout)
            {
                eventCapturer.Next().Should().BeOfType <ConnectionPoolCheckingOutConnectionEvent>();
                if (shouldHelloBeCalled) // in other cases we will reuse the first connection
                {
                    eventCapturer.Next().Should().BeOfType <CommandSucceededEvent>().Subject.CommandName.Should().Be(OppressiveLanguageConstants.LegacyHelloCommandName);
                }
                eventCapturer.Next().Should().BeOfType <ConnectionPoolCheckedOutConnectionEvent>();
            }

            eventCapturer.Any().Should().BeFalse();
        }
Example #8
0
        public void Command_should_update_the_session_and_cluster_cluster_times()
        {
            RequireServer.Check().VersionGreaterThanOrEqualTo("3.6").ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded);

            var eventCapturer = new EventCapturer().Capture <CommandSucceededEvent>(e => e.CommandName == "ping");

            using (var cluster = CoreTestConfiguration.CreateCluster(b => b.Subscribe(eventCapturer)))
                using (var session = cluster.StartSession())
                {
                    var cancellationToken = CancellationToken.None;
                    var server            = (Server)cluster.SelectServer(WritableServerSelector.Instance, cancellationToken);
                    using (var channel = server.GetChannel(cancellationToken))
                    {
                        var command = BsonDocument.Parse("{ ping : 1 }");
                        channel.Command <BsonDocument>(
                            session,
                            ReadPreference.Primary,
                            DatabaseNamespace.Admin,
                            command,
                            NoOpElementNameValidator.Instance,
                            null, // additionalOptions
                            () => CommandResponseHandling.Return,
                            BsonDocumentSerializer.Instance,
                            new MessageEncoderSettings(),
                            cancellationToken);
                    }

                    var commandSucceededEvent = eventCapturer.Next().Should().BeOfType <CommandSucceededEvent>().Subject;
                    var actualReply           = commandSucceededEvent.Reply;
                    var actualClusterTime     = actualReply["$clusterTime"].AsBsonDocument;
                    session.ClusterTime.Should().Be(actualClusterTime);
                    server.ClusterClock.ClusterTime.Should().Be(actualClusterTime);
                }
        }
        private void AssertEvents(EventCapturer actualEvents, BsonDocument test, Dictionary <string, BsonValue> sessionIdMap)
        {
            Logger.Debug("Asserting events");

            if (test.Contains("expectations"))
            {
                var expectedEvents = test["expectations"].AsBsonArray.Cast <BsonDocument>().GetEnumerator();

                while (actualEvents.Any())
                {
                    var actualEvent = actualEvents.Next();

                    if (!expectedEvents.MoveNext())
                    {
                        throw new Exception($"Unexpected event of type: {actualEvent.GetType().Name}.");
                    }
                    var expectedEvent = expectedEvents.Current;
                    RecursiveFieldSetter.SetAll(expectedEvent, "lsid", value => sessionIdMap[value.AsString]);

                    AssertEvent(actualEvent, expectedEvent);
                }

                if (expectedEvents.MoveNext())
                {
                    var expectedEvent = expectedEvents.Current;
                    throw new Exception($"Missing event: {expectedEvent}.");
                }
            }
        }
Example #10
0
        public void ReadConcern_should_include_level_when_not_using_the_server_default()
        {
            RequireServer.Check().SupportsCausalConsistency();

            var events = new EventCapturer()
                         .Capture <CommandStartedEvent>(x => x.CommandName == "count");

            using (var client = GetClient(events))
                using (var session = client.StartSession())
                {
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .InsertOne(session, new BsonDocument("x", 1));

#pragma warning disable 618
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .WithReadConcern(ReadConcern.Majority)
                    .Count(session, FilterDefinition <BsonDocument> .Empty);
#pragma warning restore

                    var commandStartedEvent = (CommandStartedEvent)events.Next();
                    commandStartedEvent.Command["readConcern"].AsBsonDocument.Contains("level").Should().BeTrue();
                    commandStartedEvent.Command["readConcern"].AsBsonDocument.Contains("afterClusterTime").Should().BeTrue();
                }
        }
        public void Connection_pool_should_work_as_expected_when_NonMaster_exception()
        {
            RequireServer.Check().Supports(Feature.FailPointsFailCommand).ClusterType(ClusterType.ReplicaSet);

            var shouldConnectionPoolBeCleared = !Feature.KeepConnectionPoolWhenNotMasterConnectionException.IsSupported(CoreTestConfiguration.ServerVersion);

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolClearedEvent>()
                                .Capture <ConnectionCreatedEvent>();

            using (var client = CreateDisposableClient(eventCapturer))
            {
                var database = client.GetDatabase(_databaseName, new MongoDatabaseSettings {
                    WriteConcern = WriteConcern.WMajority
                });
                database.DropCollection(_databaseName);
                var collection = database.GetCollection <BsonDocument>(_collectionName, new MongoCollectionSettings {
                    WriteConcern = WriteConcern.WMajority
                });
                eventCapturer.Clear();

                using (ConfigureFailPoint(client, 10107))
                {
                    var exception = Record.Exception(() => { collection.InsertOne(new BsonDocument("test", 1)); });

                    var e = exception.Should().BeOfType <MongoNotPrimaryException>().Subject;
                    e.Code.Should().Be(10107);

                    if (shouldConnectionPoolBeCleared)
                    {
                        eventCapturer.Next().Should().BeOfType <ConnectionPoolClearedEvent>();
                        eventCapturer.Events.Should().BeEmpty();
                    }
                    else
                    {
                        eventCapturer.Events.Should().BeEmpty();
                    }

                    collection.InsertOne(new BsonDocument("test", 1));
                    if (shouldConnectionPoolBeCleared)
                    {
                        eventCapturer.Next().Should().BeOfType <ConnectionCreatedEvent>();
                    }
                    eventCapturer.Events.Should().BeEmpty();
                }
            }
        }
Example #12
0
        public void RequestHeartbeat_should_force_another_heartbeat()
        {
            var capturedEvents = new EventCapturer();
            var subject        = CreateSubject(out var mockConnection, out _, out _, capturedEvents);

            SetupHeartbeatConnection(mockConnection);
            subject.Initialize();
            SpinWait.SpinUntil(() => subject.Description.State == ServerState.Connected, TimeSpan.FromSeconds(5)).Should().BeTrue();
            capturedEvents.Clear();

            subject.RequestHeartbeat();

            // the next requests down heartbeat connection will fail, so the state should
            // go back to disconnected
            SpinWait.SpinUntil(() => subject.Description.State == ServerState.Disconnected, TimeSpan.FromSeconds(5)).Should().BeTrue();

            capturedEvents.Next().Should().BeOfType <ServerHeartbeatStartedEvent>();
            capturedEvents.Next().Should().BeOfType <ServerHeartbeatFailedEvent>();
            capturedEvents.Any().Should().BeFalse();
        }
        protected virtual List <object> ExtractEventsForAsserting(EventCapturer eventCapturer)
        {
            var events = new List <object>();

            while (eventCapturer.Any())
            {
                events.Add(eventCapturer.Next());
            }

            return(events);
        }
Example #14
0
        private List <CommandStartedEvent> GetEvents(EventCapturer eventCapturer)
        {
            var events = new List <CommandStartedEvent>();

            while (eventCapturer.Any())
            {
                events.Add((CommandStartedEvent)eventCapturer.Next());
            }

            return(events);
        }
 private void AssertEvents(EventCapturer actualEvents, BsonDocument test, Dictionary <string, BsonValue> sessionIdMap)
 {
     if (test.Contains("expectations"))
     {
         foreach (var expectedEvent in test["expectations"].AsBsonArray.Cast <BsonDocument>())
         {
             RecursiveFieldSetter.SetAll(expectedEvent, "lsid", value => sessionIdMap[value.AsString]);
             var actualEvent = actualEvents.Next();
             AssertEvent(actualEvent, expectedEvent);
         }
     }
 }
        public void Session_OperationTime_should_get_updated_after_an_operation()
        {
            RequireServer.Check().SupportsCausalConsistency();

            var events = new EventCapturer()
                         .Capture <CommandStartedEvent>(x => x.CommandName == "count")
                         .Capture <CommandSucceededEvent>(x => x.CommandName == "count");

            using (var client = GetClient(events))
                using (var session = client.StartSession())
                {
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .Count(session, FilterDefinition <BsonDocument> .Empty);

                    var commandStartedEvent = (CommandStartedEvent)events.Next();
                    commandStartedEvent.Command.GetValue("readConcern", null).Should().BeNull();

                    var commandSucceededEvent = (CommandSucceededEvent)events.Next();
                    session.OperationTime.Should().Be(commandSucceededEvent.Reply.GetValue("operationTime"));
                }
        }
        public void Connection_pool_should_be_cleared_when_Shutdown_exceptions(
            [Values(
                 ServerErrorCode.ShutdownInProgress,     // 91
                 ServerErrorCode.InterruptedAtShutdown)] // 11600
            int errorCode)
        {
            RequireServer.Check().Supports(Feature.FailPointsFailCommand).ClusterType(ClusterType.ReplicaSet);

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolClearedEvent>()
                                .Capture <ConnectionCreatedEvent>();

            using (var client = CreateDisposableClient(eventCapturer))
            {
                var database = client.GetDatabase(_databaseName, new MongoDatabaseSettings {
                    WriteConcern = WriteConcern.WMajority
                });
                database.DropCollection(_databaseName);
                var collection = database.GetCollection <BsonDocument>(_collectionName, new MongoCollectionSettings {
                    WriteConcern = WriteConcern.WMajority
                });
                eventCapturer.Clear();

                using (ConfigureFailPoint(client, errorCode))
                {
                    var exception = Record.Exception(() => { collection.InsertOne(new BsonDocument("test", 1)); });

                    var e = exception.Should().BeOfType <MongoNodeIsRecoveringException>().Subject;
                    e.Code.Should().Be(errorCode);

                    eventCapturer.Next().Should().BeOfType <ConnectionPoolClearedEvent>();
                    eventCapturer.Events.Should().BeEmpty();

                    collection.InsertOne(new BsonDocument("test", 1));
                    eventCapturer.Next().Should().BeOfType <ConnectionCreatedEvent>();
                    eventCapturer.Events.Should().BeEmpty();
                }
            }
        }
Example #18
0
        public void Command_should_send_the_greater_of_the_session_and_cluster_cluster_times(long sessionTimestamp, long clusterTimestamp, long expectedTimestamp)
        {
            RequireServer.Check().VersionGreaterThanOrEqualTo("3.6").ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded);
            var sessionClusterTime  = new BsonDocument("clusterTime", new BsonTimestamp(sessionTimestamp));
            var clusterClusterTime  = new BsonDocument("clusterTime", new BsonTimestamp(clusterTimestamp));
            var expectedClusterTime = new BsonDocument("clusterTime", new BsonTimestamp(expectedTimestamp));

            var eventCapturer = new EventCapturer().Capture <CommandStartedEvent>(e => e.CommandName == "ping");

            using (var cluster = CoreTestConfiguration.CreateCluster(b => b.Subscribe(eventCapturer)))
                using (var session = cluster.StartSession())
                {
                    var cancellationToken = CancellationToken.None;
                    var server            = (Server)cluster.SelectServer(WritableServerSelector.Instance, cancellationToken);
                    using (var channel = server.GetChannel(cancellationToken))
                    {
                        session.AdvanceClusterTime(sessionClusterTime);
                        server.ClusterClock.AdvanceClusterTime(clusterClusterTime);

                        var command = BsonDocument.Parse("{ ping : 1 }");
                        try
                        {
                            channel.Command <BsonDocument>(
                                session,
                                ReadPreference.Primary,
                                DatabaseNamespace.Admin,
                                command,
                                null, // payloads
                                NoOpElementNameValidator.Instance,
                                null, // additionalOptions
                                null, // postWriteAction
                                CommandResponseHandling.Return,
                                BsonDocumentSerializer.Instance,
                                new MessageEncoderSettings(),
                                cancellationToken);
                        }
                        catch (MongoCommandException ex)
                        {
                            // we're expecting the command to fail because the $clusterTime we sent is not properly signed
                            // the point of this test is just to assert that the driver sent the higher of the session and cluster clusterTimes
                            ex.Message.Should().Contain("Missing expected field \"signature\"");
                        }
                    }
                }

            var commandStartedEvent = eventCapturer.Next().Should().BeOfType <CommandStartedEvent>().Subject;
            var actualCommand       = commandStartedEvent.Command;
            var actualClusterTime   = actualCommand["$clusterTime"].AsBsonDocument;

            actualClusterTime.Should().Be(expectedClusterTime);
        }
 // private methods
 private void AssertSessionIdWasNotSentIfUnacknowledgedWrite(EventCapturer eventCapturer, ICoreSessionHandle session, Exception ex)
 {
     if (session.IsImplicit)
     {
         var commandStartedEvent = (CommandStartedEvent)eventCapturer.Next();
         var command             = commandStartedEvent.Command;
         command.Contains("lsid").Should().BeFalse();
         session.ReferenceCount().Should().Be(2);
     }
     else
     {
         var e = ex.Should().BeOfType <InvalidOperationException>().Subject;
         e.Message.Should().Be("Explicit session must not be used with unacknowledged writes.");
     }
 }
Example #20
0
        public void DescriptionChanged_should_be_raised_when_moving_from_disconnected_to_connected()
        {
            var changes = new List <ServerDescriptionChangedEventArgs>();

            _subject.DescriptionChanged += (o, e) => changes.Add(e);

            SetupHeartbeatConnection();
            _subject.Initialize();
            SpinWait.SpinUntil(() => _subject.Description.State == ServerState.Connected, TimeSpan.FromSeconds(5)).Should().BeTrue();

            changes.Count.Should().Be(1);
            changes[0].OldServerDescription.State.Should().Be(ServerState.Disconnected);
            changes[0].NewServerDescription.State.Should().Be(ServerState.Connected);

            _capturedEvents.Next().Should().BeOfType <ServerHeartbeatStartedEvent>();
            _capturedEvents.Next().Should().BeOfType <ServerHeartbeatSucceededEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
        private void AssertSessionIdWasSentWhenSupported(EventCapturer eventCapturer, ICoreSessionHandle session, Exception exception)
        {
            exception.Should().BeNull();
            var commandStartedEvent = (CommandStartedEvent)eventCapturer.Next();
            var command             = commandStartedEvent.Command;

            if (session.Id == null)
            {
                command.Contains("lsid").Should().BeFalse();
            }
            else
            {
                command["lsid"].Should().Be(session.Id);
            }

            session.ReferenceCount().Should().Be(2);
        }
        public void TxnNumber_should_be_included_with_FindOneAndReplace()
        {
            RequireSupportForRetryableWrites();

            var events = new EventCapturer().Capture <CommandStartedEvent>(x => x.CommandName == "findAndModify");

            using (var client = GetClient(events))
                using (var session = client.StartSession())
                {
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .FindOneAndReplace("{x: 'asdfafsdf'}", new BsonDocument("x", 1));

                    var commandStartedEvent = (CommandStartedEvent)events.Next();

                    commandStartedEvent.Command.GetValue("txnNumber").Should().Be(new BsonInt64(1));
                }
        }
Example #23
0
        public void AfterClusterTime_should_be_empty_on_the_first_operation()
        {
            RequireServer.Check().SupportsCausalConsistency();

            var events = new EventCapturer().Capture <CommandStartedEvent>(x => x.CommandName == "count");

            using (var client = GetClient(events))
                using (var session = client.StartSession())
                {
#pragma warning disable 618
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .Count(session, FilterDefinition <BsonDocument> .Empty);
#pragma warning restore

                    var commandStartedEvent = (CommandStartedEvent)events.Next();
                    commandStartedEvent.Command.GetValue("readConcern", null).Should().BeNull();
                }
        }
        public void AfterClusterTime_should_not_be_sent_when_the_session_is_not_causally_consistent()
        {
            RequireServer.Check().SupportsCausalConsistency();

            var events = new EventCapturer()
                         .Capture <CommandStartedEvent>(x => x.CommandName == "count");

            using (var client = GetClient(events))
                using (var session = client.StartSession(new ClientSessionOptions {
                    CausalConsistency = false
                }))
                {
                    client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName)
                    .GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName)
                    .Count(session, FilterDefinition <BsonDocument> .Empty);

                    var commandStartedEvent = (CommandStartedEvent)events.Next();
                    commandStartedEvent.Command.Contains("readConcern").Should().BeFalse();
                }
        }
        protected void VerifySessionIdWasSentWhenSupported <TResult>(
            Func <WritableServerBinding, CancellationToken, Task <TResult> > executeAsync,
            Func <WritableServerBinding, CancellationToken, TResult> execute,
            string commandName,
            bool async)
        {
            var eventCapturer = new EventCapturer().Capture <CommandStartedEvent>(e => e.CommandName == commandName);

            using (var cluster = CoreTestConfiguration.CreateCluster(b => b.Subscribe(eventCapturer)))
            {
                using (var session = CoreTestConfiguration.StartSession(cluster))
                    using (var binding = new WritableServerBinding(cluster, session))
                    {
                        var cancellationToken = new CancellationTokenSource().Token;
                        if (async)
                        {
                            executeAsync(binding, cancellationToken).GetAwaiter().GetResult();
                        }
                        else
                        {
                            execute(binding, cancellationToken);
                        }

                        var commandStartedEvent = (CommandStartedEvent)eventCapturer.Next();
                        var command             = commandStartedEvent.Command;
                        if (session.Id == null)
                        {
                            command.Contains("lsid").Should().BeFalse();
                        }
                        else
                        {
                            command["lsid"].Should().Be(session.Id);
                        }
                        session.ReferenceCount().Should().Be(1);
                    }
            }
        }
Example #26
0
        public void Heartbeat_should_make_immediate_next_attempt_for_streaming_protocol(string exceptionType, bool?moreToCome)
        {
            var capturedEvents = new EventCapturer()
                                 .Capture <ServerHeartbeatSucceededEvent>()
                                 .Capture <ServerHeartbeatFailedEvent>()
                                 .Capture <ServerDescriptionChangedEvent>();
            var subject = CreateSubject(out var mockConnection, out _, out var mockRoundTimeTripMonitor, capturedEvents);

            subject.DescriptionChanged +=
                (o, e) =>
            {
                capturedEvents.TryGetEventHandler <ServerDescriptionChangedEvent>(out var eventHandler);
                eventHandler(new ServerDescriptionChangedEvent(e.OldServerDescription, e.NewServerDescription));
            };

            SetupHeartbeatConnection(mockConnection, isStreamable: true, autoFillStreamingResponses: false);

            Exception exception = null;

            switch (exceptionType)
            {
            case null:
                mockConnection.EnqueueCommandResponseMessage(CreateStreamableCommandResponseMessage(moreToCome.Value), null);
                break;

            case "MongoConnectionException":
                // previousDescription type is "Known" for this case
                mockConnection.EnqueueCommandResponseMessage(
                    exception = CoreExceptionHelper.CreateException(exceptionType));
                break;
            }

            // 10 seconds delay. Not expected to be processed
            mockConnection.EnqueueCommandResponseMessage(CreateStreamableCommandResponseMessage(), TimeSpan.FromSeconds(10));

            subject.Initialize();

            var expectedServerDescriptionChangedEventCount = exception != null
                ? 3 // +1 event because a connection initialized event doesn't have waiting
                : 2;

            capturedEvents.WaitForOrThrowIfTimeout(
                events =>
                events.Count(e => e is ServerDescriptionChangedEvent) >= expectedServerDescriptionChangedEventCount,      // the connection has been initialized and the first heatbeat event has been fired
                TimeSpan.FromSeconds(10));

            capturedEvents.Next().Should().BeOfType <ServerDescriptionChangedEvent>(); // connection initialized
            AssertHeartbeatAttempt();
            capturedEvents.Any().Should().BeFalse();                                   // the next attempt will be in 10 seconds because the second stremable respone has 10 seconds delay

            void AssertHeartbeatAttempt()
            {
                if (exception != null)
                {
                    mockRoundTimeTripMonitor.Verify(c => c.Reset(), Times.Once);

                    var serverHeartbeatFailedEvent = capturedEvents.Next().Should().BeOfType <ServerHeartbeatFailedEvent>().Subject; // updating the server based on the heartbeat
                    serverHeartbeatFailedEvent.Exception.Should().Be(exception);

                    var serverDescriptionChangedEvent = capturedEvents.Next().Should().BeOfType <ServerDescriptionChangedEvent>().Subject;
                    serverDescriptionChangedEvent.NewDescription.HeartbeatException.Should().Be(exception);

                    serverDescriptionChangedEvent = capturedEvents.Next().Should().BeOfType <ServerDescriptionChangedEvent>().Subject;  // when we catch exceptions, we close the current connection, so opening connection will trigger one more ServerDescriptionChangedEvent
                    serverDescriptionChangedEvent.OldDescription.HeartbeatException.Should().Be(exception);
                    serverDescriptionChangedEvent.NewDescription.HeartbeatException.Should().BeNull();
                }
                else
                {
                    mockRoundTimeTripMonitor.Verify(c => c.Reset(), Times.Never);
                    capturedEvents.Next().Should().BeOfType <ServerHeartbeatSucceededEvent>();
                    var serverDescriptionChangedEvent = capturedEvents.Next().Should().BeOfType <ServerDescriptionChangedEvent>().Subject; // updating the server based on the heartbeat
                    serverDescriptionChangedEvent.NewDescription.HeartbeatException.Should().BeNull();
                }
            }
        }
Example #27
0
        public void Command_should_use_serverApi([Values(false, true)] bool async)
        {
            RequireServer.Check().Supports(Feature.CommandMessage);

            var serverApi     = new ServerApi(ServerApiVersion.V1);
            var eventCapturer = new EventCapturer().Capture <CommandStartedEvent>(e => e.CommandName == "ping");
            var builder       = CoreTestConfiguration
                                .ConfigureCluster(new ClusterBuilder())
                                .Subscribe(eventCapturer)
                                .ConfigureCluster(x => x.With(serverApi: serverApi));

            using (var cluster = CoreTestConfiguration.CreateCluster(builder))
                using (var session = cluster.StartSession())
                {
                    var cancellationToken = CancellationToken.None;
                    var server            = (Server)cluster.SelectServer(WritableServerSelector.Instance, cancellationToken);
                    using (var channel = server.GetChannel(cancellationToken))
                    {
                        var command = BsonDocument.Parse("{ ping : 1 }");
                        if (async)
                        {
                            channel
                            .CommandAsync(
                                session,
                                ReadPreference.Primary,
                                DatabaseNamespace.Admin,
                                command,
                                null, // payloads
                                NoOpElementNameValidator.Instance,
                                null, // additionalOptions
                                null, // postWriteAction
                                CommandResponseHandling.Return,
                                BsonDocumentSerializer.Instance,
                                new MessageEncoderSettings(),
                                cancellationToken)
                            .GetAwaiter()
                            .GetResult();
                        }
                        else
                        {
                            channel.Command(
                                session,
                                ReadPreference.Primary,
                                DatabaseNamespace.Admin,
                                command,
                                null, // payloads
                                NoOpElementNameValidator.Instance,
                                null, // additionalOptions
                                null, // postWriteAction
                                CommandResponseHandling.Return,
                                BsonDocumentSerializer.Instance,
                                new MessageEncoderSettings(),
                                cancellationToken);
                        }
                    }
                }

            var commandStartedEvent = eventCapturer.Next().Should().BeOfType <CommandStartedEvent>().Subject;

            commandStartedEvent.Command["apiVersion"].AsString.Should().Be("1");
        }
Example #28
0
        public void Ensure_command_network_error_before_hadnshake_is_correctly_handled([Values(false, true)] bool async, [Values(false, true)] bool streamable)
        {
            var eventCapturer = new EventCapturer().Capture <ServerDescriptionChangedEvent>();

            // ensure that hello or legacy hello check response is finished only after network error
            var hasNetworkErrorBeenTriggered = new TaskCompletionSource <bool>();
            // ensure that there are no unexpected events between test ending and cluster disposing
            var hasClusterBeenDisposed = new TaskCompletionSource <bool>();

            EndPoint initialSelectedEndpoint = null;

            using (var cluster = CreateAndSetupCluster(hasNetworkErrorBeenTriggered, hasClusterBeenDisposed, eventCapturer, streamable))
            {
                ForceClusterId(cluster, __clusterId);

                // 0. Initial heartbeat via `connection.Open`
                // The next hello or legacy hello response will be delayed because the Task.WaitAny in the mock.Returns
                cluster.Initialize();

                var selectedServer = cluster.SelectServer(CreateWritableServerAndEndPointSelector(__endPoint1), CancellationToken.None);
                initialSelectedEndpoint = selectedServer.EndPoint;
                initialSelectedEndpoint.Should().Be(__endPoint1);

                // make sure the next hello or legacy hello check has been called
                Thread.Sleep(__heartbeatInterval + TimeSpan.FromMilliseconds(50));

                // 1. Trigger the command network error BEFORE handshake. At this time hello or legacy hello response is already delayed until `hasNetworkErrorBeenTriggered.SetResult`
                Exception exception;
                if (async)
                {
                    exception = Record.Exception(() => selectedServer.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult());
                }
                else
                {
                    exception = Record.Exception(() => selectedServer.GetChannel(CancellationToken.None));
                }

                var e = exception.Should().BeOfType <MongoConnectionException>().Subject;
                e.Message.Should().Be("DnsException");

                // 2. Waiting for the hello or legacy hello check
                hasNetworkErrorBeenTriggered.SetResult(true); // unlock the in-progress hello or legacy hello response

                Thread.Sleep(100);                            // make sure the delayed hello or legacy hello check had time to change description if there is a bug
                var knownServers = cluster.Description.Servers.Where(s => s.Type != ServerType.Unknown);
                if (knownServers.Select(s => s.EndPoint).Contains(initialSelectedEndpoint))
                {
                    throw new Exception($"The type of failed server {initialSelectedEndpoint} has not been changed to Unknown.");
                }

                // ensure that a new server can be selected
                selectedServer = cluster.SelectServer(WritableServerSelector.Instance, CancellationToken.None);

                // ensure that the selected server is not the same as the initial
                selectedServer.EndPoint.Should().Be(__endPoint2);

                // the 4th event is MongoConnectionException which will trigger the next hello or legacy hello check immediately
                eventCapturer.WaitForOrThrowIfTimeout(events => events.Count() >= 4, TimeSpan.FromSeconds(5));
            }
            hasClusterBeenDisposed.SetCanceled(); // Cut off not related events. Stop waiting in the latest mock.Returns for OpenAsync

            // Events asserting
            var initialHeartbeatEvents = new[]
            {
                // endpoints can be in random order
                eventCapturer.Next().Should().BeOfType <ServerDescriptionChangedEvent>().Subject,
                eventCapturer.Next().Should().BeOfType <ServerDescriptionChangedEvent>().Subject
            }
            .OrderBy(c => GetPort(c.NewDescription.EndPoint))
            .ToList();

            AssertEvent(initialHeartbeatEvents[0], __endPoint1, ServerType.ShardRouter, "Heartbeat");
            AssertEvent(initialHeartbeatEvents[1], __endPoint2, ServerType.ShardRouter, "Heartbeat"); // the next 27018 events will be suppressed

            AssertNextEvent(eventCapturer, initialSelectedEndpoint, ServerType.Unknown, "InvalidatedBecause:ChannelException during handshake: MongoDB.Driver.MongoConnectionException: DnsException");
            AssertNextEvent(eventCapturer, initialSelectedEndpoint, ServerType.Unknown, "Heartbeat", typeof(MongoConnectionException));
            eventCapturer.Any().Should().BeFalse();

            int GetPort(EndPoint endpoint) => ((DnsEndPoint)endpoint).Port;
        }
Example #29
0
        public void Dispose_should_raise_the_correct_events()
        {
            _subject.Dispose();

            _capturedEvents.Next().Should().BeOfType <ConnectionClosingEvent>();
            _capturedEvents.Next().Should().BeOfType <ConnectionClosedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
        public void Description_should_be_correct_after_initialization()
        {
            _settings = _settings.With(endPoints: new[] { _firstEndPoint });

            var subject = CreateSubject();

            subject.Initialize();

            var description = subject.Description;

            description.State.Should().Be(ClusterState.Disconnected);
            description.Type.Should().Be(ClusterType.Unknown);
            description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint));

            _capturedEvents.Next().Should().BeOfType <ClusterOpeningEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterAddingServerEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterAddedServerEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterOpenedEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterDescriptionChangedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }