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();
        }
Ejemplo n.º 2
0
        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();
        }
        public void Description_should_not_contain_any_servers_if_the_provided_server_is_not_of_the_required_type(ClusterConnectionMode connectionMode, ServerType serverType)
        {
            _settings = _settings.With(connectionMode: connectionMode);

            var subject = CreateSubject();

            subject.Initialize();
            _capturedEvents.Clear();

            PublishDescription(_endPoint, serverType);

            subject.Description.Servers.Should().BeEmpty();
            _capturedEvents.Next().Should().BeOfType <ClusterDescriptionChangedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
Ejemplo n.º 4
0
        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 <ConnectionPoolRemovedConnectionEvent>();

            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.Events.Count.Should().Be(1);
            }
        }
Ejemplo n.º 5
0
        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 <ConnectionPoolRemovedConnectionEvent>();

            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 document  = new BsonDocument("test", 1);
                    var exception = Record.Exception(() => { collection.InsertOne(document); });

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

                    if (!shouldConnectionPoolBeCleared)
                    {
                        collection.InsertOne(document);
                    }
                }
                eventCapturer.Events.Count.Should().Be(shouldConnectionPoolBeCleared ? 1 : 0);
            }
        }
Ejemplo n.º 6
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 Setup()
        {
            _capturedEvents = new EventCapturer()
                .Capture<CommandStartedEvent>()
                .Capture<CommandSucceededEvent>()
                .Capture<CommandFailedEvent>();

            _streamFactory = Substitute.For<IStreamFactory>();

            _endPoint = new DnsEndPoint("localhost", 27017);
            var serverId = new ServerId(new ClusterId(), _endPoint);

            _connectionInitializer = Substitute.For<IConnectionInitializer>();
            _connectionInitializer.InitializeConnectionAsync(null, CancellationToken.None)
                .ReturnsForAnyArgs(Task.FromResult(new ConnectionDescription(
                    new ConnectionId(serverId),
                    new IsMasterResult(new BsonDocument()),
                    new BuildInfoResult(new BsonDocument("version", "2.6.3")))));

            _subject = new BinaryConnection(
                serverId: serverId,
                endPoint: _endPoint,
                settings: new ConnectionSettings(),
                streamFactory: _streamFactory,
                connectionInitializer: _connectionInitializer,
                eventSubscriber: _capturedEvents);

            _stream = new BlockingMemoryStream();
            _streamFactory.CreateStreamAsync(null, CancellationToken.None)
                .ReturnsForAnyArgs(Task.FromResult<Stream>(_stream));
            _subject.OpenAsync(CancellationToken.None).Wait();
            _capturedEvents.Clear();

            _operationIdDisposer = EventContext.BeginOperation();
        }
        public BinaryConnection_CommandEventTests()
        {
            _capturedEvents = new EventCapturer()
                .Capture<CommandStartedEvent>()
                .Capture<CommandSucceededEvent>()
                .Capture<CommandFailedEvent>();

            _mockStreamFactory = new Mock<IStreamFactory>();

            _endPoint = new DnsEndPoint("localhost", 27017);
            var serverId = new ServerId(new ClusterId(), _endPoint);

            _mockConnectionInitializer = new Mock<IConnectionInitializer>();
            _mockConnectionInitializer.Setup(i => i.InitializeConnectionAsync(It.IsAny<IConnection>(), CancellationToken.None))
                .Returns(() => Task.FromResult(new ConnectionDescription(
                    new ConnectionId(serverId),
                    new IsMasterResult(new BsonDocument()),
                    new BuildInfoResult(new BsonDocument("version", "2.6.3")))));

            _subject = new BinaryConnection(
                serverId: serverId,
                endPoint: _endPoint,
                settings: new ConnectionSettings(),
                streamFactory: _mockStreamFactory.Object,
                connectionInitializer: _mockConnectionInitializer.Object,
                eventSubscriber: _capturedEvents);

            _stream = new BlockingMemoryStream();
            _mockStreamFactory.Setup(f => f.CreateStreamAsync(_endPoint, CancellationToken.None))
                .Returns(Task.FromResult<Stream>(_stream));
            _subject.OpenAsync(CancellationToken.None).Wait();
            _capturedEvents.Clear();

            _operationIdDisposer = EventContext.BeginOperation();
        }
        public BinaryConnection_CommandEventTests()
        {
            _capturedEvents = new EventCapturer()
                              .Capture <CommandStartedEvent>()
                              .Capture <CommandSucceededEvent>()
                              .Capture <CommandFailedEvent>();

            _mockStreamFactory = new Mock <IStreamFactory>();

            _endPoint = new DnsEndPoint("localhost", 27017);
            var serverId = new ServerId(new ClusterId(), _endPoint);

            _mockConnectionInitializer = new Mock <IConnectionInitializer>();
            _mockConnectionInitializer.Setup(i => i.InitializeConnectionAsync(It.IsAny <IConnection>(), CancellationToken.None))
            .Returns(() => Task.FromResult(new ConnectionDescription(
                                               new ConnectionId(serverId),
                                               new IsMasterResult(new BsonDocument()),
                                               new BuildInfoResult(new BsonDocument("version", "2.6.3")))));

            _subject = new BinaryConnection(
                serverId: serverId,
                endPoint: _endPoint,
                settings: new ConnectionSettings(),
                streamFactory: _mockStreamFactory.Object,
                connectionInitializer: _mockConnectionInitializer.Object,
                eventSubscriber: _capturedEvents);

            _stream = new BlockingMemoryStream();
            _mockStreamFactory.Setup(f => f.CreateStreamAsync(_endPoint, CancellationToken.None))
            .Returns(Task.FromResult <Stream>(_stream));
            _subject.OpenAsync(CancellationToken.None).Wait();
            _capturedEvents.Clear();

            _operationIdDisposer = EventContext.BeginOperation();
        }
        public void Setup()
        {
            _capturedEvents = new EventCapturer()
                              .Capture <CommandStartedEvent>()
                              .Capture <CommandSucceededEvent>()
                              .Capture <CommandFailedEvent>();

            _streamFactory = Substitute.For <IStreamFactory>();

            _endPoint = new DnsEndPoint("localhost", 27017);
            var serverId = new ServerId(new ClusterId(), _endPoint);

            _connectionInitializer = Substitute.For <IConnectionInitializer>();
            _connectionInitializer.InitializeConnectionAsync(null, CancellationToken.None)
            .ReturnsForAnyArgs(Task.FromResult(new ConnectionDescription(
                                                   new ConnectionId(serverId),
                                                   new IsMasterResult(new BsonDocument()),
                                                   new BuildInfoResult(new BsonDocument("version", "2.6.3")))));

            _subject = new BinaryConnection(
                serverId: serverId,
                endPoint: _endPoint,
                settings: new ConnectionSettings(),
                streamFactory: _streamFactory,
                connectionInitializer: _connectionInitializer,
                eventSubscriber: _capturedEvents);

            _stream = new BlockingMemoryStream();
            _streamFactory.CreateStreamAsync(null, CancellationToken.None)
            .ReturnsForAnyArgs(Task.FromResult <Stream>(_stream));
            _subject.OpenAsync(CancellationToken.None).Wait();
            _capturedEvents.Clear();

            _operationIdDisposer = EventContext.BeginOperation();
        }
Ejemplo n.º 11
0
        public void Description_should_contain_expected_server_description()
        {
            var subject = CreateSubject();

            subject.Description.Servers.Should().BeEmpty();
            subject.Initialize();
            _capturedEvents.Clear();

            PublishDescription(_endPoint);

            var description = subject.Description;

            description.Servers.Should().ContainSingle(s => EndPointHelper.Equals(s.EndPoint, _endPoint) && s.State == ServerState.Connected);

            _capturedEvents.Next().Should().BeOfType <ClusterDescriptionChangedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
Ejemplo n.º 12
0
        public void ReceiveMessageAsync_should_complete_when_reply_is_already_on_the_stream()
        {
            using (var stream = new BlockingMemoryStream())
            {
                _streamFactory.CreateStreamAsync(null, CancellationToken.None)
                .ReturnsForAnyArgs(Task.FromResult <Stream>(stream));

                _subject.OpenAsync(CancellationToken.None).Wait();
                _capturedEvents.Clear();

                var messageToReceive = MessageHelper.BuildSuccessReply <BsonDocument>(new BsonDocument(), BsonDocumentSerializer.Instance, responseTo: 10);
                MessageHelper.WriteResponsesToStream(stream, new[] { messageToReceive });

                var encoderSelector = new ReplyMessageEncoderSelector <BsonDocument>(BsonDocumentSerializer.Instance);
                var received        = _subject.ReceiveMessageAsync(10, encoderSelector, _messageEncoderSettings, CancellationToken.None).Result;

                var expected = MessageHelper.TranslateMessagesToBsonDocuments(new[] { messageToReceive });
                var actual   = MessageHelper.TranslateMessagesToBsonDocuments(new[] { received });

                actual.Should().BeEquivalentTo(expected);

                _capturedEvents.Next().Should().BeOfType <ConnectionReceivingMessageEvent>();
                _capturedEvents.Next().Should().BeOfType <ConnectionReceivedMessageEvent>();
                _capturedEvents.Any().Should().BeFalse();
            }
        }
Ejemplo n.º 13
0
        public void RequestHeartbeat_should_force_another_heartbeat()
        {
            SetupHeartbeatConnection();
            _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();

            // when heart fails, we immediately attempt a second, hence the multiple events...
            _capturedEvents.Next().Should().BeOfType <ServerHeartbeatStartedEvent>();
            _capturedEvents.Next().Should().BeOfType <ServerHeartbeatFailedEvent>();
            _capturedEvents.Next().Should().BeOfType <ServerHeartbeatStartedEvent>();
            _capturedEvents.Next().Should().BeOfType <ServerHeartbeatFailedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
Ejemplo n.º 14
0
        public void ReceiveMessage_should_complete_when_reply_is_already_on_the_stream(
            [Values(false, true)]
            bool async)
        {
            using (var stream = new BlockingMemoryStream())
            {
                var messageToReceive = MessageHelper.BuildReply <BsonDocument>(new BsonDocument(), BsonDocumentSerializer.Instance, responseTo: 10);
                MessageHelper.WriteResponsesToStream(stream, new[] { messageToReceive });

                var encoderSelector = new ReplyMessageEncoderSelector <BsonDocument>(BsonDocumentSerializer.Instance);

                ResponseMessage received;
                if (async)
                {
                    _mockStreamFactory.Setup(f => f.CreateStreamAsync(_endPoint, CancellationToken.None))
                    .Returns(Task.FromResult <Stream>(stream));
                    _subject.OpenAsync(CancellationToken.None).GetAwaiter().GetResult();
                    _capturedEvents.Clear();

                    received = _subject.ReceiveMessageAsync(10, encoderSelector, _messageEncoderSettings, CancellationToken.None).GetAwaiter().GetResult();
                }
                else
                {
                    _mockStreamFactory.Setup(f => f.CreateStream(_endPoint, CancellationToken.None))
                    .Returns(stream);
                    _subject.Open(CancellationToken.None);
                    _capturedEvents.Clear();

                    received = _subject.ReceiveMessage(10, encoderSelector, _messageEncoderSettings, CancellationToken.None);
                }

                var expected = MessageHelper.TranslateMessagesToBsonDocuments(new[] { messageToReceive });
                var actual   = MessageHelper.TranslateMessagesToBsonDocuments(new[] { received });

                actual.Should().BeEquivalentTo(expected);

                _capturedEvents.Next().Should().BeOfType <ConnectionReceivingMessageEvent>();
                _capturedEvents.Next().Should().BeOfType <ConnectionReceivedMessageEvent>();
                _capturedEvents.Any().Should().BeFalse();
            }
        }
        public void AcquireConnection_should_return_a_connection(
            [Values(false, true)]
            bool async)
        {
            InitializeAndWait();
            _capturedEvents.Clear();

            IConnectionHandle connection;

            if (async)
            {
                connection = _subject.AcquireConnectionAsync(CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                connection = _subject.AcquireConnection(CancellationToken.None);
            }

            connection.Should().NotBeNull();
            _subject.AvailableCount.Should().Be(_settings.MaxConnections - 1);
            _subject.CreatedCount.Should().Be(_settings.MinConnections);
            _subject.DormantCount.Should().Be(_settings.MinConnections - 1);
            _subject.UsedCount.Should().Be(1);

            _capturedEvents.Next().Should().BeOfType <ConnectionPoolCheckingOutConnectionEvent>();
            _capturedEvents.Next().Should().BeOfType <ConnectionPoolCheckedOutConnectionEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
Ejemplo n.º 16
0
        public async Task Ensure_server_session_are_allocated_only_on_connection_checkout()
        {
            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <CommandStartedEvent>();

            using var client = DriverTestConfiguration.CreateDisposableClient(
                      (MongoClientSettings settings) =>
            {
                settings.MaxConnectionPoolSize = 1;
                settings.ClusterConfigurator   = c => c.Subscribe(eventCapturer);
            },
                      logger: null);

            var database = client.GetDatabase("test");

            var collection = database.GetCollection <BsonDocument>("inventory");

            database.DropCollection("inventory");

            collection.InsertOne(new BsonDocument("x", 0));

            var serverSessionPool  = (CoreServerSessionPool)Reflector.GetFieldValue(client.Cluster, "_serverSessionPool");
            var serverSessionsList = (List <ICoreServerSession>)Reflector.GetFieldValue(serverSessionPool, "_pool");

            var serverSession = serverSessionsList.Single();

            eventCapturer.Clear();

            var eventsTask = eventCapturer.NotifyWhen(events =>
            {
                var connectionCheckedOutEvent = events.OfType <ConnectionPoolCheckedOutConnectionEvent>().FirstOrDefault();
                var commandStartedEvent       = events.OfType <CommandStartedEvent>().FirstOrDefault();

                if (commandStartedEvent.ConnectionId != null)
                {
                    serverSessionsList.Count.Should().Be(0);
                    commandStartedEvent.Command["lsid"].Should().Be(serverSession.Id);

                    return(true);
                }
                else if (connectionCheckedOutEvent.ConnectionId != null)
                {
                    serverSessionsList.Single().Should().Be(serverSession);
                }

                return(false);
            });

            collection.InsertOne(new BsonDocument("x", 1));
            await TasksUtils.WithTimeout(eventsTask, 1000);
        }
Ejemplo n.º 17
0
        public void Connection_pool_should_not_be_cleared_when_replSetStepDown_and_GetMore([Values(false, true)] bool async)
        {
            RequireServer.Check().Supports(Feature.KeepConnectionPoolWhenReplSetStepDown).ClusterType(ClusterType.ReplicaSet);

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

            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
                });
                var adminDatabase = client.GetDatabase("admin").WithWriteConcern(WriteConcern.W1);

                collection.InsertMany(
                    new[]
                {
                    new BsonDocument("x", 1),
                    new BsonDocument("x", 2),
                    new BsonDocument("x", 3),
                    new BsonDocument("x", 4),
                    new BsonDocument("x", 5),
                });
                eventCapturer.Clear();

                var cursor = collection.FindSync(FilterDefinition <BsonDocument> .Empty, new FindOptions <BsonDocument> {
                    BatchSize = 2
                });
                cursor.MoveNext();

                BsonDocument replSetStepDownResult;
                if (async)
                {
                    replSetStepDownResult = adminDatabase.RunCommandAsync <BsonDocument>("{ replSetStepDown : 5, force : true }").GetAwaiter().GetResult();
                }
                else
                {
                    replSetStepDownResult = adminDatabase.RunCommand <BsonDocument>("{ replSetStepDown : 5, force : true }");
                }

                replSetStepDownResult.GetValue("ok", false).ToBoolean().Should().BeTrue();

                cursor.MoveNext();

                eventCapturer.Events.Should().BeEmpty();
            }
        }
        public void BulkWrite_should_pin_connection_as_expected(
            [Values(1, 3)] int attempts,
            [Values(false, true)] bool async)
        {
            SkipIfNotLoadBalancingMode();

            KillOpenTransactions();

            SetupData();

            ServiceIdHelper.IsServiceIdEmulationEnabled = true; // TODO: temporary solution to enable emulating serviceId in a server response

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckingOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckedInConnectionEvent>()
                                .Capture <ConnectionPoolCheckingInConnectionEvent>()
                                .Capture <CommandSucceededEvent>();

            using (var cluster = CreateLoadBalancedCluster(eventCapturer))
            {
                eventCapturer.Clear();

                for (int i = 1; i <= attempts; i++)
                {
                    ICoreSessionHandle session;
                    DisposableBindingBundle <IReadWriteBindingHandle, RetryableWriteContext> writeBindingsBundle;

                    using (session = CreateSession(cluster, isImplicit: false, withTransaction: true))
                    {
                        eventCapturer.Any().Should().BeFalse();
                        using (writeBindingsBundle = CreateReadWriteBindingsAndRetryableWriteContext(cluster, session.Fork(), async))
                        {
                            AssertCheckOutOnlyEvents(eventCapturer, i);

                            _ = CreateAndRunBulkOperation(writeBindingsBundle.RetryableContext, async);

                            AssertCommand(eventCapturer, "insert", noMoreEvents: true);
                        }
                    }
                    AssertCommand(eventCapturer, "abortTransaction", noMoreEvents: false);
                    AssertCheckInOnlyEvents(eventCapturer);
                    AssertSessionReferenceCount(session, 0);
                    AssertChannelReferenceCount(writeBindingsBundle.RetryableContext.Channel, 0);
                }
            }
        }
Ejemplo n.º 19
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();
        }
        public void Heartbeat_should_work_as_expected()
        {
            var heartbeatSuceededTimestamps = new ConcurrentQueue <DateTime>();
            var eventCapturer = new EventCapturer()
                                .Capture <ServerHeartbeatSucceededEvent>(
                (@event) =>
            {
                heartbeatSuceededTimestamps.Enqueue(DateTime.UtcNow);
                return(true);
            }
                );

            var heartbeatInterval = TimeSpan.FromMilliseconds(500);

            eventCapturer.Clear();
            using (var client = CreateClient(eventCapturer, heartbeatInterval))
            {
                eventCapturer.WaitForOrThrowIfTimeout(
                    events => events.Count() > 3, // wait for at least 3 events
                    TimeSpan.FromSeconds(10),
                    (timeout) =>
                {
                    return($"Waiting for the expected events exceeded the timeout {timeout}. The number of triggered events is {eventCapturer.Events.ToList().Count}.");
                });
            }

            var heartbeatSuceededTimestampsList = heartbeatSuceededTimestamps.ToList();

            // we have at least 3 items here
            // Skip the first event because we have nothing to compare it to
            for (int i = 1; i < heartbeatSuceededTimestampsList.Count; i++)
            {
                var attemptDuration = heartbeatSuceededTimestampsList[i] - heartbeatSuceededTimestampsList[i - 1];
                attemptDuration
                .Should()
                .BeLessThan(TimeSpan.FromSeconds(2));
                // Assert the client processes isMaster replies more frequently than 10 secs (approximately every 500ms)
            }
        }
Ejemplo n.º 21
0
        public void AcquireConnectionAsync_should_return_a_connection()
        {
            InitializeAndWait();
            _capturedEvents.Clear();

            var connection = _subject.AcquireConnectionAsync(CancellationToken.None).Result;

            connection.Should().NotBeNull();
            _subject.AvailableCount.Should().Be(_settings.MaxConnections - 1);
            _subject.CreatedCount.Should().Be(_settings.MinConnections);
            _subject.DormantCount.Should().Be(_settings.MinConnections - 1);
            _subject.UsedCount.Should().Be(1);

            _capturedEvents.Next().Should().BeOfType <ConnectionPoolCheckingOutConnectionEvent>();
            _capturedEvents.Next().Should().BeOfType <ConnectionPoolCheckedOutConnectionEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
        public void AcquireConnection_should_throw_an_InvalidOperationException_if_not_initialized(
            [Values(false, true)]
            bool async)
        {
            _capturedEvents.Clear();
            Action act;

            if (async)
            {
                act = () => _subject.AcquireConnectionAsync(CancellationToken.None).GetAwaiter().GetResult();
            }
            else
            {
                act = () => _subject.AcquireConnection(CancellationToken.None);
            }

            act.ShouldThrow <InvalidOperationException>();
            _capturedEvents.Next().Should().BeOfType <ConnectionPoolCheckingOutConnectionEvent>();
            var connectionPoolCheckingOutConnectionFailedEvent = _capturedEvents.Next();
            var e = connectionPoolCheckingOutConnectionFailedEvent.Should().BeOfType <ConnectionPoolCheckingOutConnectionFailedEvent>().Subject;

            e.Reason.Should().Be(ConnectionCheckOutFailedReason.ConnectionError);
            _capturedEvents.Any().Should().BeFalse();
        }
        public void Connection_pool_should_not_be_cleared_when_replSetStepDown_and_GetMore([Values(false, true)] bool async)
        {
            RequireServer.Check().Supports(Feature.KeepConnectionPoolWhenReplSetStepDown).ClusterType(ClusterType.ReplicaSet);

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

            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
                });
                var adminDatabase = client.GetDatabase("admin").WithWriteConcern(WriteConcern.W1);

                collection.InsertMany(
                    new[]
                {
                    new BsonDocument("x", 1),
                    new BsonDocument("x", 2),
                    new BsonDocument("x", 3),
                    new BsonDocument("x", 4),
                    new BsonDocument("x", 5),
                });
                eventCapturer.Clear();

                var cursor = collection.FindSync(FilterDefinition <BsonDocument> .Empty, new FindOptions <BsonDocument> {
                    BatchSize = 2
                });
                cursor.MoveNext();

                foreach (var secondary in client.Cluster.Description.Servers.Where(c => c.Type == ServerType.ReplicaSetSecondary))
                {
                    RunOnSecondary(client, secondary.EndPoint, BsonDocument.Parse("{ replSetFreeze : 0 }"));
                }

                var          replSetStepDownCommand = BsonDocument.Parse("{ replSetStepDown : 30, force : true }");
                BsonDocument replSetStepDownResult;
                if (async)
                {
                    replSetStepDownResult = adminDatabase.RunCommandAsync <BsonDocument>(replSetStepDownCommand).GetAwaiter().GetResult();
                }
                else
                {
                    replSetStepDownResult = adminDatabase.RunCommand <BsonDocument>(replSetStepDownCommand);
                }

                replSetStepDownResult.Should().NotBeNull();
                replSetStepDownResult.GetValue("ok", false).ToBoolean().Should().BeTrue();

                cursor.MoveNext();

                eventCapturer.Events.Should().BeEmpty(); // it also means that no new PoolClearedEvent
            }

            void RunOnSecondary(IMongoClient primaryClient, EndPoint secondaryEndpoint, BsonDocument command)
            {
                var secondarySettings = primaryClient.Settings.Clone();

                secondarySettings.ClusterConfigurator = null;
#pragma warning disable CS0618 // Type or member is obsolete
                secondarySettings.ConnectionMode = ConnectionMode.Direct;
#pragma warning restore CS0618 // Type or member is obsolete
                var secondaryDnsEndpoint = (DnsEndPoint)secondaryEndpoint;
                secondarySettings.Server = new MongoServerAddress(secondaryDnsEndpoint.Host, secondaryDnsEndpoint.Port);
                using (var secondaryClient = DriverTestConfiguration.CreateDisposableClient(secondarySettings))
                {
                    var adminDatabase = secondaryClient.GetDatabase(DatabaseNamespace.Admin.DatabaseName);
                    adminDatabase.RunCommand <BsonDocument>(command);
                }
            }
        }
        public async Task PoolClearedError_write_retryablity_test([Values(false, true)] bool async)
        {
            RequireServer.Check()
            .Supports(Feature.FailPointsBlockConnection)
            .ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded);

            var heartbeatInterval = TimeSpan.FromMilliseconds(50);
            var eventsWaitTimeout = TimeSpan.FromMilliseconds(5000);

            var failPointCommand = BsonDocument.Parse(
                $@"{{
                    configureFailPoint : 'failCommand',
                    mode : {{ 'times' : 1 }},
                    data :
                    {{
                        failCommands : [ 'insert' ],
                        errorCode : 91,
                        blockConnection: true,
                        blockTimeMS: 1000,
                        errorLabels: [""RetryableWriteError""]
                    }}
                }}");

            IServerSelector failPointSelector = WritableServerSelector.Instance;
            var             settings          = DriverTestConfiguration.GetClientSettings();

            if (CoreTestConfiguration.Cluster.Description.Type == ClusterType.Sharded)
            {
                var serverAddress = settings.Servers.First();
                settings.Servers = new[] { serverAddress };

                // set settings.DirectConnection = true after removing obsolete ConnectionMode
#pragma warning disable CS0618 // Type or member is obsolete
                settings.ConnectionMode = ConnectionMode.Direct;
#pragma warning restore CS0618 // Type or member is obsolete

                failPointSelector = new EndPointServerSelector(new DnsEndPoint(serverAddress.Host, serverAddress.Port));
            }

            settings.MaxConnectionPoolSize = 1;
            settings.RetryWrites           = true;

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolClearedEvent>()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckingOutConnectionFailedEvent>()
                                .CaptureCommandEvents("insert");

            var failpointServer = DriverTestConfiguration.Client.Cluster.SelectServer(failPointSelector, default);
            using var failPoint = FailPoint.Configure(failpointServer, NoCoreSession.NewHandle(), failPointCommand);

            using var client = CreateClient(settings, eventCapturer, heartbeatInterval);
            var database   = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName);
            var collection = database.GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName);

            eventCapturer.Clear();

            if (async)
            {
                await ThreadingUtilities.ExecuteTasksOnNewThreads(2, async _ =>
                {
                    await collection.InsertOneAsync(new BsonDocument("x", 1));
                });
            }
            else
            {
                ThreadingUtilities.ExecuteOnNewThreads(2, _ =>
                {
                    collection.InsertOne(new BsonDocument("x", 1));
                });
            }

            // wait for 2 CommandSucceededEvent events, meaning that all other events should be received
            eventCapturer.WaitForOrThrowIfTimeout(
                events => events.OfType <CommandSucceededEvent>().Count() == 2,
                eventsWaitTimeout);

            eventCapturer.Events.OfType <CommandStartedEvent>().Count().Should().Be(3);
            eventCapturer.Events.OfType <CommandFailedEvent>().Count().Should().Be(1);
            eventCapturer.Events.OfType <CommandSucceededEvent>().Count().Should().Be(2);
            eventCapturer.Events.OfType <ConnectionPoolClearedEvent>().Count().Should().Be(1);
            eventCapturer.Events.OfType <ConnectionPoolCheckedOutConnectionEvent>().Count().Should().Be(3);
            eventCapturer.Events.OfType <ConnectionPoolCheckingOutConnectionFailedEvent>().Count().Should().Be(1);
        }
        public void Should_discover_all_servers_in_the_cluster_reported_by_the_primary()
        {
            _settings = _settings.With(endPoints: new[] { _firstEndPoint });

            var subject = CreateSubject();

            subject.Initialize();
            _capturedEvents.Clear();

            PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary);

            var description = subject.Description;

            description.State.Should().Be(ClusterState.Connected);
            description.Type.Should().Be(ClusterType.ReplicaSet);
            description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint, _thirdEndPoint));

            _capturedEvents.Next().Should().BeOfType <ClusterAddingServerEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterAddedServerEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterAddingServerEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterAddedServerEvent>();
            _capturedEvents.Next().Should().BeOfType <ClusterDescriptionChangedEvent>();
            _capturedEvents.Any().Should().BeFalse();
        }
        public void BsonSizeLimitAndBatchSizeSplittingTest(
            [Values(false, true)] bool async)
        {
            RequireServer.Check().Supports(Feature.ClientSideEncryption);

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

            using (var client = ConfigureClient())
                using (var clientEncrypted = ConfigureClientEncrypted(kmsProviderFilter: "local", eventCapturer: eventCapturer))
                {
                    var collLimitSchema = JsonFileReader.Instance.Documents["limits.limits-schema.json"];
                    CreateCollection(client, __collCollectionNamespace, new BsonDocument("$jsonSchema", collLimitSchema));
                    var datakeysLimitsKey  = JsonFileReader.Instance.Documents["limits.limits-key.json"];
                    var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace);
                    Insert(keyVaultCollection, async, datakeysLimitsKey);

                    var coll = GetCollection(clientEncrypted, __collCollectionNamespace);

                    var exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            new BsonDocument
                    {
                        { "_id", "over_2mib_under_16mib" },
                        { "unencrypted", new string('a', 2097152) }
                    }));
                    exception.Should().BeNull();
                    eventCapturer.Clear();

                    var limitsDoc = JsonFileReader.Instance.Documents["limits.limits-doc.json"];
                    limitsDoc.AddRange(
                        new BsonDocument
                    {
                        { "_id", "encryption_exceeds_2mib" },
                        { "unencrypted", new string('a', 2097152 - 2000) }
                    });
                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            limitsDoc));
                    exception.Should().BeNull();
                    eventCapturer.Clear();

                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            new BsonDocument
                    {
                        { "_id", "over_2mib_1" },
                        { "unencrypted", new string('a', 2097152) }
                    },
                            new BsonDocument
                    {
                        { "_id", "over_2mib_2" },
                        { "unencrypted", new string('a', 2097152) }
                    }));
                    exception.Should().BeNull();
                    eventCapturer.Count.Should().Be(2);
                    eventCapturer.Clear();

                    var limitsDoc1 = JsonFileReader.Instance.Documents["limits.limits-doc.json"];
                    limitsDoc1.AddRange(
                        new BsonDocument
                    {
                        { "_id", "encryption_exceeds_2mib_1" },
                        { "unencrypted", new string('a', 2097152 - 2000) }
                    });
                    var limitsDoc2 = JsonFileReader.Instance.Documents["limits.limits-doc.json"];
                    limitsDoc2.AddRange(
                        new BsonDocument
                    {
                        { "_id", "encryption_exceeds_2mib_2" },
                        { "unencrypted", new string('a', 2097152 - 2000) }
                    });

                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            limitsDoc1,
                            limitsDoc2));
                    exception.Should().BeNull();
                    eventCapturer.Count.Should().Be(2);
                    eventCapturer.Clear();

                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            new BsonDocument
                    {
                        { "_id", "under_16mib" },
                        { "unencrypted", new string('a', 16777216 - 2000) }
                    }));
                    exception.Should().BeNull();
                    eventCapturer.Clear();

                    limitsDoc = JsonFileReader.Instance.Documents["limits.limits-doc.json"];
                    limitsDoc.AddRange(
                        new BsonDocument
                    {
                        { "_id", "encryption_exceeds_16mib" },
                        { "unencrypted", new string('a', 16777216 - 2000) }
                    });
                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            limitsDoc));
                    exception.Should().NotBeNull();
                    eventCapturer.Clear();

                    // additional not spec tests
                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            new BsonDocument
                    {
                        { "_id", "advanced_over_2mib_1" },
                        { "unencrypted", new string('a', 2097152) }
                    },
                            new BsonDocument
                    {
                        { "_id", "advanced_over_2mib_2" },
                        { "unencrypted", new string('a', 2097152) }
                    },
                            new BsonDocument
                    {
                        { "_id", "advanced_over_2mib_3" },
                        { "unencrypted", new string('a', 2097152) }
                    }));
                    exception.Should().BeNull();
                    eventCapturer.Count.Should().Be(3);
                    eventCapturer.Clear();

                    exception = Record.Exception(
                        () => Insert(
                            coll,
                            async,
                            new BsonDocument
                    {
                        { "_id", "small_1" },
                        { "unencrypted", "a" }
                    },
                            new BsonDocument
                    {
                        { "_id", "small_2" },
                        { "unencrypted", "a" }
                    },
                            new BsonDocument
                    {
                        { "_id", "small_3" },
                        { "unencrypted", "a" }
                    }));
                    exception.Should().BeNull();
                    eventCapturer.Count.Should().Be(1);
                    eventCapturer.Clear();
                }
        }
        public async Task Ensure_server_session_are_allocated_only_on_connection_checkout([Values(true, false)] bool async)
        {
            var eventCapturer = new EventCapturer()
                                .Capture <CommandStartedEvent>();

            using var client = DriverTestConfiguration.CreateDisposableClient(
                      (MongoClientSettings settings) =>
            {
                settings.RetryWrites           = true;
                settings.MaxConnectionPoolSize = 1;
                settings.ClusterConfigurator   = c => c.Subscribe(eventCapturer);
            },
                      logger: null);

            var database = client.GetDatabase("test");

            database.DropCollection("inventory");
            var collection = database.GetCollection <BsonDocument>("inventory");

            const int operationsCount   = 8;
            var       singleSessionUsed = false;

            for (int i = 0; i < 5; i++)
            {
                eventCapturer.Clear();
                await ThreadingUtilities.ExecuteTasksOnNewThreads(operationsCount, async i =>
                {
                    switch (i)
                    {
                    case 0:
                        if (async)
                        {
                            await collection.InsertOneAsync(new BsonDocument("x", 0));
                        }
                        else
                        {
                            collection.InsertOne(new BsonDocument("x", 0));
                        }
                        break;

                    case 1:
                        if (async)
                        {
                            await collection.DeleteOneAsync(Builders <BsonDocument> .Filter.Eq("_id", 1));
                        }
                        else
                        {
                            collection.DeleteOne(Builders <BsonDocument> .Filter.Eq("_id", 1));
                        }
                        break;

                    case 2:
                        if (async)
                        {
                            await collection.UpdateOneAsync(Builders <BsonDocument> .Filter.Empty, Builders <BsonDocument> .Update.Set("a", 1));
                        }
                        else
                        {
                            collection.UpdateOne(Builders <BsonDocument> .Filter.Empty, Builders <BsonDocument> .Update.Set("a", 1));
                        }
                        break;

                    case 3:
                        var bulkWriteRequests = new WriteModel <BsonDocument>[]
                        {
                            new UpdateOneModel <BsonDocument>(Builders <BsonDocument> .Filter.Empty, new BsonDocument("$set", new BsonDocument("1", 1)))
                        };

                        if (async)
                        {
                            await collection.BulkWriteAsync(bulkWriteRequests);
                        }
                        else
                        {
                            collection.BulkWrite(bulkWriteRequests);
                        }
                        break;

                    case 4:
                        if (async)
                        {
                            await collection.FindOneAndDeleteAsync(Builders <BsonDocument> .Filter.Empty);
                        }
                        else
                        {
                            collection.FindOneAndDelete(Builders <BsonDocument> .Filter.Empty);
                        }
                        break;

                    case 5:
                        if (async)
                        {
                            await collection.FindOneAndUpdateAsync(Builders <BsonDocument> .Filter.Empty, Builders <BsonDocument> .Update.Set("a", 1));
                        }
                        else
                        {
                            collection.FindOneAndUpdate(Builders <BsonDocument> .Filter.Empty, Builders <BsonDocument> .Update.Set("a", 1));
                        }

                        break;

                    case 6:
                        if (async)
                        {
                            await collection.FindOneAndReplaceAsync(Builders <BsonDocument> .Filter.Empty, new BsonDocument("x", 0));
                        }
                        else
                        {
                            collection.FindOneAndReplace(Builders <BsonDocument> .Filter.Empty, new BsonDocument("x", 0));
                        }
                        break;

                    case 7:
                        if (async)
                        {
                            var cursor = await collection.FindAsync(Builders <BsonDocument> .Filter.Empty);
                            _          = await cursor.ToListAsync();
                        }
                        else
                        {
                            _ = collection.Find(Builders <BsonDocument> .Filter.Empty).ToList();
                        }
                        break;
                    }
                });

                eventCapturer.WaitForOrThrowIfTimeout(e => e.OfType <CommandStartedEvent>().Count() >= operationsCount, TimeSpan.FromSeconds(10));
                var lsids = eventCapturer.Events.OfType <CommandStartedEvent>().Select(c => c.Command["lsid"]).ToArray();
                var distinctLsidsCount = lsids.Distinct().Count();

                distinctLsidsCount.Should().BeLessThan(operationsCount);
                if (distinctLsidsCount == 1)
                {
                    singleSessionUsed = true;
                    break;
                }
            }

            singleSessionUsed.Should().BeTrue("At least one iteration should use single session");
        }
        private (IConnectionPool, FailPoint, ICluster, Func <object, bool>) SetupConnectionData(BsonDocument test, EventCapturer eventCapturer, bool isUnit)
        {
            ParseSettings(test, out var connectionPoolSettings, out var connectionSettings);

            IConnectionPool     connectionPool;
            ICluster            cluster      = null;
            FailPoint           failPoint    = null;
            Func <object, bool> eventsFilter = _ => true;

            if (isUnit)
            {
                var endPoint = new DnsEndPoint("localhost", 27017);
                var serverId = new ServerId(new ClusterId(), endPoint);

                var connectionFactory          = new Mock <IConnectionFactory>();
                var connectionExceptionHandler = new Mock <IConnectionExceptionHandler>();

                connectionFactory
                .Setup(c => c.CreateConnection(serverId, endPoint))
                .Returns(() =>
                {
                    var connection = new MockConnection(serverId, connectionSettings, eventCapturer);
                    return(connection);
                });

                connectionPool = new ExclusiveConnectionPool(
                    serverId,
                    endPoint,
                    connectionPoolSettings,
                    connectionFactory.Object,
                    eventCapturer,
                    connectionExceptionHandler.Object);

                connectionPool.Initialize();
            }
            else
            {
                var async = test.GetValue(Schema.async).ToBoolean();
                cluster = CoreTestConfiguration.CreateCluster(b => b
                                                              .ConfigureServer(s => s.With(
                                                                                   heartbeatInterval: TimeSpan.FromMinutes(10)))
                                                              .ConfigureConnectionPool(c => c.With(
                                                                                           maxConnecting: connectionPoolSettings.MaxConnecting,
                                                                                           maxConnections: connectionPoolSettings.MaxConnections,
                                                                                           minConnections: connectionPoolSettings.MinConnections,
                                                                                           maintenanceInterval: connectionPoolSettings.MaintenanceInterval,
                                                                                           waitQueueTimeout: connectionPoolSettings.WaitQueueTimeout))
                                                              .ConfigureConnection(s => s.With(applicationName: $"{connectionSettings.ApplicationName}_async_{async}"))
                                                              .Subscribe(eventCapturer));

                var server = cluster.SelectServer(WritableServerSelector.Instance, CancellationToken.None);
                connectionPool = server._connectionPool();

                if (test.TryGetValue(Schema.Intergration.failPoint, out var failPointDocument))
                {
                    if (failPointDocument.AsBsonDocument.Contains("data"))
                    {
                        var data = failPointDocument["data"].AsBsonDocument;
                        if (data.TryGetValue("appName", out var appNameValue))
                        {
                            data["appName"] = $"{appNameValue}_async_{async}";
                        }
                    }

                    var resetPool = connectionPoolSettings.MinConnections > 0;

                    if (resetPool)
                    {
                        eventCapturer.WaitForOrThrowIfTimeout(events => events.Any(e => e is ConnectionCreatedEvent), TimeSpan.FromMilliseconds(500));

                        var connectionIdsToIgnore = new HashSet <int>(eventCapturer.Events
                                                                      .OfType <ConnectionCreatedEvent>()
                                                                      .Select(c => c.ConnectionId.LocalValue)
                                                                      .ToList());

                        eventsFilter = o =>
                        {
                            if (o is ConnectionOpenedEvent
                                or ConnectionClosedEvent
                                or ConnectionCreatedEvent
                                or ConnectionFailedEvent)
                            {
                                var connectionId = o.ConnectionId();
                                return(!connectionIdsToIgnore.Contains(connectionId.LocalValue) &&
                                       EndPointHelper.Equals(connectionId.ServerId.EndPoint, server.EndPoint));
                            }

                            if (o is ConnectionPoolReadyEvent
                                or ConnectionPoolClearedEvent)
                            {
                                var serverId = o.ServerId();
                                return(EndPointHelper.Equals(serverId.EndPoint, server.EndPoint));
                            }

                            return(true);
                        };

                        connectionPool.Clear(closeInUseConnections: false);
                        eventCapturer.WaitForOrThrowIfTimeout(events => events.Any(e => e is ConnectionPoolClearedEvent), TimeSpan.FromMilliseconds(500));
                    }

                    var failPointServer = CoreTestConfiguration.Cluster.SelectServer(new EndPointServerSelector(server.EndPoint), default);
                    failPoint = FailPoint.Configure(failPointServer, NoCoreSession.NewHandle(), failPointDocument.AsBsonDocument);

                    if (resetPool)
                    {
                        eventCapturer.Clear();
                        connectionPool.SetReady();
                    }
                }
            }

            return(connectionPool, failPoint, cluster, eventsFilter);
        }
Ejemplo n.º 29
0
        public void Cursor_should_pin_connection_in_transaction_with_new_sessions_as_expected(
            [Values(1, 3)] int attempts,
            [Values(false, true)] bool forceCursorClose,
            [Values(false)] bool async)
        {
            SkipIfNotLoadBalancingMode();

            KillOpenTransactions();

            SetupData();

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckingOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckedInConnectionEvent>()
                                .Capture <ConnectionPoolCheckingInConnectionEvent>()
                                .Capture <CommandSucceededEvent>();

            using (var cluster = CreateLoadBalancedCluster(eventCapturer))
            {
                eventCapturer.Clear();

                for (int i = 1; i <= attempts; i++)
                {
                    ICoreSessionHandle session;
                    DisposableBindingBundle <IReadBindingHandle, RetryableReadContext> readBindingsBundle;
                    IAsyncCursor <BsonDocument> asyncCursor;

                    using (session = CreateSession(cluster, isImplicit: false, withTransaction: true))
                    {
                        AssertSessionReferenceCount(session, 1);

                        eventCapturer.Any().Should().BeFalse();
                        using (readBindingsBundle = CreateReadBindingsAndRetryableReadContext(cluster, session.Fork(), async))
                        {
                            AssertCheckOutOnlyEvents(eventCapturer, i);

                            asyncCursor = CreateAndRunFindOperation(readBindingsBundle.RetryableContext, async);

                            AssertCommand(eventCapturer, "find", noMoreEvents: true);
                        }

                        MoveNext(asyncCursor, async).Should().BeTrue(); // no op
                        MoveNext(asyncCursor, async).Should().BeTrue();

                        AssertSessionReferenceCount(session, 2);
                        AssertChannelReferenceCount(readBindingsBundle.RetryableContext.Channel, 2);
                        AssertChannelReferenceCount(asyncCursor, 2);
                        AssertCommand(eventCapturer, "getMore", noMoreEvents: true);

                        if (forceCursorClose)
                        {
                            asyncCursor.Dispose();

                            AssertCommand(eventCapturer, "killCursors", noMoreEvents: true);
                        }
                        else
                        {
                            MoveNext(asyncCursor, async).Should().BeTrue(); // cursorId = 0
                            MoveNext(asyncCursor, async).Should().BeFalse();

                            AssertCommand(eventCapturer, "getMore", noMoreEvents: true);
                        }
                    }
                    AssertCommand(eventCapturer, "abortTransaction", noMoreEvents: false);
                    AssertCheckInOnlyEvents(eventCapturer);
                    AssertSessionReferenceCount(session, 0);
                    AssertChannelReferenceCount(readBindingsBundle.RetryableContext.Channel, 0);
                }
            }
        }
Ejemplo n.º 30
0
        public void Cursor_should_pin_connection_in_transaction_with_the_same_session_as_expected(
            [Values(1, 4)] int attempts,
            [Values(false, true)] bool forceCursorClose,
            [Values(false)] bool async)
        {
            SkipIfNotLoadBalancingMode();

            KillOpenTransactions();

            SetupData();

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckingOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckedInConnectionEvent>()
                                .Capture <ConnectionPoolCheckingInConnectionEvent>()
                                .Capture <CommandSucceededEvent>();

            List <IAsyncCursor <BsonDocument> > cursors = new();

            using (var cluster = CreateLoadBalancedCluster(eventCapturer))
            {
                eventCapturer.Clear();

                ICoreSessionHandle session;
                DisposableBindingBundle <IReadBindingHandle, RetryableReadContext> readBindingsBundle = null;

                using (session = CreateSession(cluster, isImplicit: false, withTransaction: true))
                {
                    for (int i = 1; i <= attempts; i++)
                    {
                        AssertSessionReferenceCount(session, i); // dynamic value because we don't close cursors in the loop

                        IAsyncCursor <BsonDocument> asyncCursor;
                        eventCapturer.Any().Should().BeFalse();
                        using (readBindingsBundle = CreateReadBindingsAndRetryableReadContext(cluster, session.Fork(), async))
                        {
                            AssertCheckOutOnlyEvents(eventCapturer, i, shouldNextAttemptTriggerCheckout: false);

                            asyncCursor = CreateAndRunFindOperation(readBindingsBundle.RetryableContext, async);

                            AssertCommand(eventCapturer, "find", noMoreEvents: true);
                        }
                        MoveNext(asyncCursor, async).Should().BeTrue(); // no op
                        MoveNext(asyncCursor, async).Should().BeTrue();

                        AssertCommand(eventCapturer, "getMore", noMoreEvents: true);

                        cursors.Add(asyncCursor);
                    }
                }

                for (int i = 0; i < cursors.Count; i++)
                {
                    IAsyncCursor <BsonDocument> cursor = cursors[i];
                    if (forceCursorClose)
                    {
                        cursor.Dispose();

                        AssertCommand(eventCapturer, "killCursors", noMoreEvents: i < cursors.Count - 1);
                    }
                    else
                    {
                        MoveNext(cursor, async).Should().BeTrue(); // returns cursorId = 0
                        MoveNext(cursor, async).Should().BeFalse();

                        AssertCommand(eventCapturer, "getMore", noMoreEvents: i < cursors.Count - 1);
                    }
                }
                AssertCommand(eventCapturer, "abortTransaction", noMoreEvents: false);
                AssertCheckInOnlyEvents(eventCapturer);
                AssertSessionReferenceCount(session, 0);
                AssertChannelReferenceCount(readBindingsBundle.RetryableContext.Channel, 0);
            }
        }
Ejemplo n.º 31
0
        public void BulkWrite_and_cursor_should_share_pinned_connection_under_the_same_transaction_2(
            [Values(false, true)] bool async)
        {
            SkipIfNotLoadBalancingMode();

            KillOpenTransactions();

            SetupData();

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckingOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckedInConnectionEvent>()
                                .Capture <ConnectionPoolCheckingInConnectionEvent>()
                                .Capture <CommandSucceededEvent>();

            using (var cluster = CreateLoadBalancedCluster(eventCapturer))
            {
                eventCapturer.Clear();

                ICoreSessionHandle session;
                DisposableBindingBundle <IReadWriteBindingHandle, RetryableWriteContext> writeBindingsBundle;
                DisposableBindingBundle <IReadBindingHandle, RetryableReadContext>       readBindingsBundle;
                IAsyncCursor <BsonDocument> asyncCursor;

                using (session = CreateSession(cluster, isImplicit: false, withTransaction: true))
                {
                    AssertSessionReferenceCount(session, 1);

                    eventCapturer.Any().Should().BeFalse();

                    // bulk operation
                    using (writeBindingsBundle = CreateReadWriteBindingsAndRetryableWriteContext(cluster, session.Fork(), async))
                    {
                        AssertCheckOutOnlyEvents(eventCapturer, 1);

                        _ = CreateAndRunBulkOperation(writeBindingsBundle.RetryableContext, async);

                        AssertCommand(eventCapturer, "insert", noMoreEvents: true);
                    }
                    AssertSessionReferenceCount(session, 1);

                    // find operation
                    using (readBindingsBundle = CreateReadBindingsAndRetryableReadContext(cluster, session.Fork(), async))
                    {
                        eventCapturer.Any().Should().BeFalse();

                        asyncCursor = CreateAndRunFindOperation(readBindingsBundle.RetryableContext, async);

                        AssertCommand(eventCapturer, "find", noMoreEvents: true);
                    }
                }

                MoveNext(asyncCursor, async).Should().BeTrue(); // no op
                MoveNext(asyncCursor, async).Should().BeTrue(); // getMore
                AssertCommand(eventCapturer, "getMore", noMoreEvents: true);
                MoveNext(asyncCursor, async).Should().BeTrue(); // getMore
                AssertCommand(eventCapturer, "getMore", noMoreEvents: true);
                MoveNext(asyncCursor, async).Should().BeTrue(); // cursorId = 0
                AssertCommand(eventCapturer, "getMore", noMoreEvents: false);
                AssertCommand(eventCapturer, "abortTransaction", noMoreEvents: false);
                AssertCheckInOnlyEvents(eventCapturer);
                MoveNext(asyncCursor, async).Should().BeFalse();

                AssertChannelReferenceCount(readBindingsBundle.RetryableContext.Channel, 0);
                AssertChannelReferenceCount(writeBindingsBundle.RetryableContext.Channel, 0);
                AssertSessionReferenceCount(session, 0);
            }
        }
Ejemplo n.º 32
0
        public void Cursor_should_unpin_connection_for_operations_under_the_same_transaction_after_abortTransaction_and_cursor_dispose(
            [Values(1, 3)] int attempts,
            [Values(false, true)] bool forceCursorClose,
            [Values(false, true)] bool async)
        {
            SkipIfNotLoadBalancingMode();

            KillOpenTransactions();

            SetupData();

            var eventCapturer = new EventCapturer()
                                .Capture <ConnectionPoolCheckedOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckingOutConnectionEvent>()
                                .Capture <ConnectionPoolCheckedInConnectionEvent>()
                                .Capture <ConnectionPoolCheckingInConnectionEvent>()
                                .Capture <CommandSucceededEvent>();

            List <IAsyncCursor <BsonDocument> > cursors = new();

            using (var cluster = CreateLoadBalancedCluster(eventCapturer))
            {
                eventCapturer.Clear();

                ICoreSessionHandle session;
                DisposableBindingBundle <IReadBindingHandle, RetryableReadContext> readBindingsBundle = null;

                using (session = CreateSession(cluster, isImplicit: false, withTransaction: true))
                {
                    for (int i = 1; i <= attempts; i++)
                    {
                        AssertSessionReferenceCount(session, i); // dynamic value because we don't close cursors in the loop

                        IAsyncCursor <BsonDocument> asyncCursor;
                        eventCapturer.Any().Should().BeFalse();
                        using (readBindingsBundle = CreateReadBindingsAndRetryableReadContext(cluster, session.Fork(), async))
                        {
                            AssertCheckOutOnlyEvents(eventCapturer, i, shouldNextAttemptTriggerCheckout: false);

                            asyncCursor = CreateAndRunFindOperation(readBindingsBundle.RetryableContext, async);

                            AssertCommand(eventCapturer, "find", noMoreEvents: true);
                        }
                        MoveNext(asyncCursor, async).Should().BeTrue(); // no op
                        MoveNext(asyncCursor, async).Should().BeTrue();

                        AssertCommand(eventCapturer, "getMore", noMoreEvents: true);

                        cursors.Add(asyncCursor);
                    }

                    AbortTransaction(session, async);
                    AssertCommand(eventCapturer, "abortTransaction", noMoreEvents: true);
                }

                for (int i = 0; i < cursors.Count; i++)
                {
                    IAsyncCursor <BsonDocument> cursor = cursors[i];
                    if (forceCursorClose)
                    {
                        cursor.Dispose();
                    }
                    else
                    {
                        var exception = Record.Exception(() => cursor.MoveNext());
                        exception
                        .Should()
                        .BeOfType <MongoCommandException>()
                        .Subject
                        .Message
                        .Should()
                        .StartWith("Command getMore failed: Cannot run getMore on cursor")
                        .And
                        .EndWith("without a txnNumber.");
                        cursor.Dispose();
                    }

                    AssertCommand(eventCapturer, "killCursors", noMoreEvents: i < cursors.Count - 1);
                }
                AssertCheckInOnlyEvents(eventCapturer);
                AssertSessionReferenceCount(session, 0);
                AssertChannelReferenceCount(readBindingsBundle.RetryableContext.Channel, 0);
            }
        }