public async Task Misbehaved_async_method_should_not_deadlock_server_selection() { RequireServer.Check().ClusterType(ClusterType.ReplicaSet); // note: the code below deadlocks because await StartSessionAsync continues when UpdateClusterDescription in Cluster called TrySetResult after finding the secondary // but then the sync call to RunCommand blocks waiting for a primary and the call to TrySetResult never returns // which in turn prevents SDAM from unwinding back to process the next queued heartbeat event so the primary is never found var primary = CoreTestConfiguration.Cluster.Description.Servers.Where(s => s.Type == ServerType.ReplicaSetPrimary).Single(); void clusterConfigurator(ClusterBuilder builder) { builder.Subscribe((ServerHeartbeatSucceededEvent heartbeatEvent) => { // ensure that the primary heartbeat is the last to be processed by introducing a small artificial delay if (EndPointHelper.Equals(heartbeatEvent.ConnectionId.ServerId.EndPoint, primary.EndPoint)) { Thread.Sleep(TimeSpan.FromSeconds(1)); } }); } using (var client = DriverTestConfiguration.CreateDisposableClient(clusterConfigurator)) { using (var session = await client.StartSessionAsync().ConfigureAwait(false)) { var adminDatabase = client.GetDatabase("admin"); adminDatabase.RunCommand <BsonDocument>(session, "{ ping : 1 }"); // this async method is misbehaving by calling a blocking sync method } } }
public void Aggregate_out_to_collection_should_work() { var client = DriverTestConfiguration.Client; var database = client.GetDatabase("test"); var collection = database.GetCollection <BsonDocument>("test"); var outCollection = database.GetCollection <AggregateCountResult>("out"); var writeConcern = WriteConcern.WMajority; if (DriverTestConfiguration.IsReplicaSet(client)) { var n = DriverTestConfiguration.GetReplicaSetNumberOfDataBearingMembers(client); writeConcern = new WriteConcern(n); } database.DropCollection("test"); database.DropCollection("out"); collection .WithWriteConcern(writeConcern) .InsertOne(new BsonDocument("_id", 1)); var pipeline = new EmptyPipelineDefinition <BsonDocument>() .Count() .Out(outCollection) .As <BsonDocument, AggregateCountResult, AggregateCountResultWithId>(); var results = collection.WithReadPreference(ReadPreference.SecondaryPreferred).Aggregate(pipeline).ToList(); results.Single().Count.Should().Be(1); }
private DisposableMongoClient CreateDisposableClient(EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient((MongoClientSettings settings) => { settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); })); }
protected override MongoClient CreateClientForTestSetup() { var clientSettings = DriverTestConfiguration.GetClientSettings().Clone(); clientSettings.GuidRepresentation = GuidRepresentation.Unspecified; return(new MongoClient(clientSettings)); }
private DisposableMongoClient CreateDisposableClient(BsonDocument test, EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient((MongoClientSettings settings) => { ConfigureClientSettings(settings, test); settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); })); }
private DisposableMongoClient CreateDisposableClient(EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient((MongoClientSettings settings) => { settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); // the default value for spec tests settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); })); }
private DisposableMongoClient CreateDisposableClient(EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient((MongoClientSettings settings) => { settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); settings.RetryWrites = true; }, logger: LoggerFactory.CreateLogger <DisposableMongoClient>())); }
private DisposableMongoClient CreateDisposableClient(EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient((MongoClientSettings settings) => { settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); }, logger: CreateLogger <DisposableMongoClient>())); }
public void Driver_should_connect_to_AtlasDataLake_without_authentication() { RequireEnvironment.Check().EnvironmentVariable("ATLAS_DATA_LAKE_TESTS_ENABLED"); using (var client = DriverTestConfiguration.CreateDisposableClient()) { client.GetDatabase("admin").RunCommand <BsonDocument>(new BsonDocument("ping", 1)); } }
// private methods private DisposableMongoClient CreateClient(MongoClientSettings mongoClientSettings, EventCapturer eventCapturer, TimeSpan heartbeatInterval, string applicationName = null) { var clonedClientSettings = mongoClientSettings ?? DriverTestConfiguration.Client.Settings.Clone(); clonedClientSettings.ApplicationName = applicationName; clonedClientSettings.HeartbeatInterval = heartbeatInterval; clonedClientSettings.ClusterConfigurator = builder => builder.Subscribe(eventCapturer); return(DriverTestConfiguration.CreateDisposableClient(clonedClientSettings)); }
private DisposableMongoClient CreateMongoClient( CollectionNamespace keyVaultNamespace = null, BsonDocument schemaMapDocument = null, IReadOnlyDictionary <string, IReadOnlyDictionary <string, object> > kmsProviders = null, bool withExternalKeyVault = false, Action <ClusterBuilder> clusterConfigurator = null, Dictionary <string, object> extraOptions = null, bool bypassAutoEncryption = false) { var mongoClientSettings = DriverTestConfiguration.GetClientSettings().Clone(); #pragma warning disable 618 if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2) { mongoClientSettings.GuidRepresentation = GuidRepresentation.Unspecified; } #pragma warning restore 618 mongoClientSettings.ClusterConfigurator = clusterConfigurator; if (keyVaultNamespace != null || schemaMapDocument != null || kmsProviders != null || withExternalKeyVault) { if (extraOptions == null) { extraOptions = new Dictionary <string, object>() { { "mongocryptdSpawnPath", Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? string.Empty } }; } var schemaMap = GetSchemaMapIfNotNull(schemaMapDocument); if (kmsProviders == null) { kmsProviders = new ReadOnlyDictionary <string, IReadOnlyDictionary <string, object> >(new Dictionary <string, IReadOnlyDictionary <string, object> >()); } var autoEncryptionOptions = new AutoEncryptionOptions( keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, schemaMap: schemaMap, extraOptions: extraOptions, bypassAutoEncryption: bypassAutoEncryption); if (withExternalKeyVault) { var externalKeyVaultClientSettings = DriverTestConfiguration.GetClientSettings().Clone(); externalKeyVaultClientSettings.Credential = MongoCredential.FromComponents(null, null, "fake-user", "fake-pwd"); var externalKeyVaultClient = new MongoClient(externalKeyVaultClientSettings); autoEncryptionOptions = autoEncryptionOptions.With(keyVaultClient: externalKeyVaultClient); } mongoClientSettings.AutoEncryptionOptions = autoEncryptionOptions; } return(new DisposableMongoClient(new MongoClient(mongoClientSettings))); }
protected DisposableMongoClient CreateDisposableClient(BsonDocument test, EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient(settings => { ConfigureClientSettings(settings, test); if (eventCapturer != null) { settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); } })); }
private DisposableMongoClient CreateDisposableClient(BsonDocument test, EventCapturer eventCapturer, bool useMultipleShardRouters) { return(DriverTestConfiguration.CreateDisposableClient( (MongoClientSettings settings) => { settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); // the default value for spec tests ConfigureClientSettings(settings, test); settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); }, useMultipleShardRouters)); }
protected override MongoClient CreateClientForTestSetup() { var clientSettings = DriverTestConfiguration.GetClientSettings().Clone(); #pragma warning disable 618 if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2) { clientSettings.GuidRepresentation = GuidRepresentation.Unspecified; } #pragma warning restore 618 return(new MongoClient(clientSettings)); }
private DisposableMongoClient CreateDisposableClient(BsonDocument test) { var useMultipleShardRouters = test.GetValue("useMultipleMongoses", false).AsBoolean; var clientOptions = (BsonDocument)test.GetValue("clientOptions", null); return(DriverTestConfiguration.CreateDisposableClient( settings => { ParseClientOptions(settings, clientOptions); }, useMultipleShardRouters)); }
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); }
private DisposableMongoClient CreateDisposableClient(EventCapturer eventCapturer) { return(DriverTestConfiguration.CreateDisposableClient( (MongoClientSettings settings) => { settings.ClusterConfigurator = c => { c = CoreTestConfiguration.ConfigureCluster(c); c.Subscribe(eventCapturer); c.ConfigureServer(ss => ss.With(heartbeatInterval: Timeout.InfiniteTimeSpan)); }; })); }
private DisposableMongoClient CreateDisposableClient(BsonDocument test, bool useMultipleShardRouters) { var clientOptions = (BsonDocument)test.GetValue("clientOptions", null); return(DriverTestConfiguration.CreateDisposableClient( settings => { settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); // the default value for spec tests ParseClientOptions(settings, clientOptions); }, CreateLogger <DisposableMongoClient>(), useMultipleShardRouters)); }
protected override async Task CallMethodAsync(CancellationToken cancellationToken) { using (var client = DriverTestConfiguration.CreateDisposableClient(_mongoClientSettings)) { if (_session == null) { _result = await GetAdminDatabase(client).RunCommandAsync <BsonDocument>(_command, _readPreference, cancellationToken).ConfigureAwait(false); } else { _result = await GetAdminDatabase(client).RunCommandAsync <BsonDocument>(_session, _command, _readPreference, cancellationToken).ConfigureAwait(false); } } }
protected DisposableMongoClient CreateDisposableClient(BsonDocument test, EventCapturer eventCapturer) { var useMultipleShardRouters = test.GetValue("useMultipleMongoses", false).AsBoolean; return(DriverTestConfiguration.CreateDisposableClient( settings => { ConfigureClientSettings(settings, test); if (eventCapturer != null) { settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); } }, useMultipleShardRouters)); }
protected DisposableMongoClient CreateDisposableClient(BsonDocument test, EventCapturer eventCapturer) { var useMultipleShardRouters = test.GetValue("useMultipleMongoses", false).AsBoolean; return(DriverTestConfiguration.CreateDisposableClient( settings => { settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); // the default value for spec tests ConfigureClientSettings(settings, test); if (eventCapturer != null) { settings.ClusterConfigurator = c => c.Subscribe(eventCapturer); } }, useMultipleShardRouters)); }
public void Aws_authentication_should_should_have_expected_result() { RequireEnvironment.Check().EnvironmentVariable("AWS_TESTS_ENABLED"); using (var client = DriverTestConfiguration.CreateDisposableClient()) { // test that a command that doesn't require auth completes normally var adminDatabase = client.GetDatabase("admin"); var isMasterCommand = new BsonDocument("ismaster", 1); var isMasterResult = adminDatabase.RunCommand <BsonDocument>(isMasterCommand); // test that a command that does require auth completes normally var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); var collection = database.GetCollection <BsonDocument>(DriverTestConfiguration.CollectionNamespace.CollectionName); var count = collection.CountDocuments(FilterDefinition <BsonDocument> .Empty); } }
public void Monitor_sleep_at_least_minHeartbeatFreqencyMS_between_checks() { var minVersion = new SemanticVersion(4, 9, 0, ""); RequireServer.Check().VersionGreaterThanOrEqualTo(minVersion); const string appName = "SDAMMinHeartbeatFrequencyTest"; var failPointCommand = BsonDocument.Parse( $@"{{ configureFailPoint : 'failCommand', mode : {{ 'times' : 5 }}, data : {{ failCommands : [ 'isMaster' ], errorCode : 1234, appName : '{appName}' }} }}"); var settings = DriverTestConfiguration.GetClientSettings(); 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 settings.ApplicationName = appName; settings.ServerSelectionTimeout = TimeSpan.FromSeconds(5); var server = DriverTestConfiguration.Client.Cluster.SelectServer(new EndPointServerSelector(new DnsEndPoint(serverAddress.Host, serverAddress.Port)), default); using var failPoint = FailPoint.Configure(server, NoCoreSession.NewHandle(), failPointCommand); using var client = DriverTestConfiguration.CreateDisposableClient(settings); var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); var sw = Stopwatch.StartNew(); _ = database.RunCommand <BsonDocument>("{ ping : 1 }"); sw.Stop(); sw.ElapsedMilliseconds.Should().BeInRange(2000, 3500); }
public void Driver_should_connect_to_AtlasDataLake_with_SCRAM_SHA_256() { RequireEnvironment.Check().EnvironmentVariable("ATLAS_DATA_LAKE_TESTS_ENABLED"); RequireServer.Check().Supports(Feature.ScramSha256Authentication); var connectionString = CoreTestConfiguration.ConnectionString; var username = connectionString.Username; var password = connectionString.Password; var source = connectionString.AuthSource; var settings = DriverTestConfiguration.Client.Settings.Clone(); settings.Credential = MongoCredential.FromComponents(mechanism: "SCRAM-SHA-256", source, username, password); using (var client = DriverTestConfiguration.CreateDisposableClient(settings)) { client.GetDatabase("admin").RunCommand <BsonDocument>(new BsonDocument("ping", 1)); } }
public void KillCursors_should_return_expected_result() { RequireEnvironment.Check().EnvironmentVariable("ATLAS_DATA_LAKE_TESTS_ENABLED"); RequireServer.Check(); var databaseName = "test"; var collectionName = "driverdata"; var eventCapturer = new EventCapturer() .Capture <CommandStartedEvent>(x => "killCursors" == x.CommandName) .Capture <CommandSucceededEvent>(x => new[] { "killCursors", "find" }.Contains(x.CommandName)); using (var client = DriverTestConfiguration.CreateDisposableClient(eventCapturer)) { var cursor = client .GetDatabase(databaseName) .GetCollection <BsonDocument>(collectionName) .Find(new BsonDocument(), new FindOptions { BatchSize = 2 }) .ToCursor(); var findCommandSucceededEvent = eventCapturer.Events.OfType <CommandSucceededEvent>().First(x => x.CommandName == "find"); var findCommandResult = findCommandSucceededEvent.Reply; var cursorId = findCommandResult["cursor"]["id"].AsInt64; var cursorNamespace = CollectionNamespace.FromFullName(findCommandResult["cursor"]["ns"].AsString); cursor.Dispose(); var killCursorsCommandStartedEvent = eventCapturer.Events.OfType <CommandStartedEvent>().First(x => x.CommandName == "killCursors"); var killCursorsCommandSucceededEvent = eventCapturer.Events.OfType <CommandSucceededEvent>().First(x => x.CommandName == "killCursors"); var killCursorsStartedCommand = killCursorsCommandStartedEvent.Command; cursorNamespace.DatabaseNamespace.DatabaseName.Should().Be(killCursorsCommandStartedEvent.DatabaseNamespace.DatabaseName); cursorNamespace.CollectionName.Should().Be(killCursorsStartedCommand["killCursors"].AsString); cursorId.Should().Be(killCursorsStartedCommand["cursors"][0].AsInt64); cursorId.Should().Be(killCursorsCommandSucceededEvent.Reply["cursorsKilled"][0].AsInt64); } }
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); }
private (DisposableMongoClient Client, Dictionary <string, EventCapturer> ClientEventCapturers) CreateClient(BsonDocument entity) { string appName = null; var clientEventCapturers = new Dictionary <string, EventCapturer>(); string clientId = null; var commandNamesToSkipInEvents = new List <string>(); List <(string Key, IEnumerable <string> Events, List <string> CommandNotToCapture)> eventTypesToCapture = new (); bool? loadBalanced = null; int? maxPoolSize = null; var readConcern = ReadConcern.Default; var retryReads = true; var retryWrites = true; var useMultipleShardRouters = false; TimeSpan?waitQueueTimeout = null; var writeConcern = WriteConcern.Acknowledged; var serverApi = CoreTestConfiguration.ServerApi; foreach (var element in entity) { switch (element.Name) { case "id": clientId = element.Value.AsString; break; case "uriOptions": foreach (var option in element.Value.AsBsonDocument) { switch (option.Name) { case "appname": appName = option.Value.ToString(); break; case "loadBalanced": loadBalanced = option.Value.ToBoolean(); break; case "maxPoolSize": maxPoolSize = option.Value.ToInt32(); break; case "retryWrites": retryWrites = option.Value.AsBoolean; break; case "retryReads": retryReads = option.Value.AsBoolean; break; case "readConcernLevel": var levelValue = option.Value.AsString; var level = (ReadConcernLevel)Enum.Parse(typeof(ReadConcernLevel), levelValue, true); readConcern = new ReadConcern(level); break; case "w": writeConcern = new WriteConcern(option.Value.AsInt32); break; case "waitQueueTimeoutMS": waitQueueTimeout = TimeSpan.FromMilliseconds(option.Value.ToInt32()); break; default: throw new FormatException($"Invalid client uriOption argument name: '{option.Name}'."); } } break; case "useMultipleMongoses": useMultipleShardRouters = element.Value.AsBoolean; break; case "observeEvents": var observeEvents = element.Value.AsBsonArray.Select(x => x.AsString); eventTypesToCapture.Add( (Key: Ensure.IsNotNull(clientId, nameof(clientId)), Events: observeEvents, CommandNotToCapture: commandNamesToSkipInEvents)); break; case "ignoreCommandMonitoringEvents": commandNamesToSkipInEvents.AddRange(element.Value.AsBsonArray.Select(x => x.AsString)); break; case "serverApi": ServerApiVersion serverApiVersion = null; bool? serverApiStrict = null; bool? serverApiDeprecationErrors = null; foreach (var option in element.Value.AsBsonDocument) { switch (option.Name) { case "version": var serverApiVersionString = option.Value.AsString; switch (serverApiVersionString) { case "1": serverApiVersion = ServerApiVersion.V1; break; default: throw new FormatException($"Invalid serverApi version: '{serverApiVersionString}'."); } break; case "strict": serverApiStrict = option.Value.AsBoolean; break; case "deprecationErrors": serverApiDeprecationErrors = option.Value.AsBoolean; break; default: throw new FormatException($"Invalid client serverApi argument name: '{option.Name}'."); } } if (serverApiVersion != null) { serverApi = new ServerApi(serverApiVersion, serverApiStrict, serverApiDeprecationErrors); } break; case "storeEventsAsEntities": var eventsBatches = element.Value.AsBsonArray; foreach (var batch in eventsBatches.Cast <BsonDocument>()) { var id = batch["id"].AsString; var events = batch["events"].AsBsonArray.Select(e => e.AsString); eventTypesToCapture.Add((id, events, CommandNotToCapture: null)); } break; default: throw new FormatException($"Invalid client argument name: '{element.Name}'."); } } if (eventTypesToCapture.Count > 0) { var defaultCommandNamesToSkip = new List <string> { "authenticate", "buildInfo", "configureFailPoint", "getLastError", "getnonce", "hello", OppressiveLanguageConstants.LegacyHelloCommandName, "saslContinue", "saslStart" }; foreach (var eventsDetails in eventTypesToCapture) { var commandNamesNotToCapture = Enumerable.Concat(eventsDetails.CommandNotToCapture ?? Enumerable.Empty <string>(), defaultCommandNamesToSkip); var formatter = _eventFormatters.ContainsKey(eventsDetails.Key) ? _eventFormatters[eventsDetails.Key] : null; var eventCapturer = CreateEventCapturer(eventsDetails.Events, commandNamesNotToCapture, formatter); clientEventCapturers.Add(eventsDetails.Key, eventCapturer); } } var eventCapturers = clientEventCapturers.Select(c => c.Value).ToArray(); var client = DriverTestConfiguration.CreateDisposableClient( settings => { settings.ApplicationName = appName; settings.LoadBalanced = loadBalanced.GetValueOrDefault(defaultValue: settings.LoadBalanced); settings.MaxConnectionPoolSize = maxPoolSize.GetValueOrDefault(defaultValue: settings.MaxConnectionPoolSize); settings.RetryReads = retryReads; settings.RetryWrites = retryWrites; settings.ReadConcern = readConcern; settings.WaitQueueTimeout = waitQueueTimeout.GetValueOrDefault(defaultValue: settings.WaitQueueTimeout); settings.WriteConcern = writeConcern; settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); // the default value for spec tests settings.ServerApi = serverApi; if (eventCapturers.Length > 0) { settings.ClusterConfigurator = c => { foreach (var eventCapturer in eventCapturers) { c.Subscribe(eventCapturer); } }; } }, useMultipleShardRouters); return(client, clientEventCapturers); }
private void CreateClient(BsonDocument entity, out DisposableMongoClient client, out EventCapturer eventCapturer) { var eventTypesToCapture = new List <string>(); var commandNamesToSkip = new List <string> { "authenticate", "buildInfo", "configureFailPoint", "getLastError", "getnonce", "isMaster", "saslContinue", "saslStart" }; var readConcern = ReadConcern.Default; var retryReads = true; var retryWrites = true; var useMultipleShardRouters = false; var writeConcern = WriteConcern.Acknowledged; ServerApi serverApi = null; foreach (var element in entity) { switch (element.Name) { case "id": // handled on higher level break; case "uriOptions": foreach (var option in element.Value.AsBsonDocument) { switch (option.Name) { case "retryWrites": retryWrites = option.Value.AsBoolean; break; case "retryReads": retryReads = option.Value.AsBoolean; break; case "readConcernLevel": var levelValue = option.Value.AsString; var level = (ReadConcernLevel)Enum.Parse(typeof(ReadConcernLevel), levelValue, true); readConcern = new ReadConcern(level); break; case "w": writeConcern = new WriteConcern(option.Value.AsInt32); break; default: throw new FormatException($"Unrecognized client uriOption name: '{option.Name}'."); } } break; case "useMultipleMongoses": useMultipleShardRouters = element.Value.AsBoolean; break; case "observeEvents": eventTypesToCapture.AddRange(element.Value.AsBsonArray.Select(x => x.AsString)); break; case "ignoreCommandMonitoringEvents": commandNamesToSkip.AddRange(element.Value.AsBsonArray.Select(x => x.AsString)); break; case "serverApi": ServerApiVersion serverApiVersion = null; bool? serverApiStrict = null; bool? serverApiDeprecationErrors = null; foreach (var option in element.Value.AsBsonDocument) { switch (option.Name) { case "version": var serverApiVersionString = option.Value.AsString; switch (serverApiVersionString) { case "1": serverApiVersion = ServerApiVersion.V1; break; default: throw new FormatException($"Unrecognized serverApi version: '{serverApiVersionString}'."); } break; case "strict": serverApiStrict = option.Value.AsBoolean; break; case "deprecationErrors": serverApiDeprecationErrors = option.Value.AsBoolean; break; default: throw new FormatException($"Unrecognized client serverApi option name: '{option.Name}'."); } } if (serverApiVersion != null) { serverApi = new ServerApi(serverApiVersion, serverApiStrict, serverApiDeprecationErrors); } break; default: throw new FormatException($"Unrecognized client entity field: '{element.Name}'."); } } eventCapturer = null; if (eventTypesToCapture.Count > 0) { eventCapturer = new EventCapturer(); foreach (var eventTypeToCapture in eventTypesToCapture) { switch (eventTypeToCapture) { case "commandStartedEvent": eventCapturer = eventCapturer.Capture <CommandStartedEvent>(x => !commandNamesToSkip.Contains(x.CommandName)); break; case "commandSucceededEvent": eventCapturer = eventCapturer.Capture <CommandSucceededEvent>(x => !commandNamesToSkip.Contains(x.CommandName)); break; case "commandFailedEvent": eventCapturer = eventCapturer.Capture <CommandFailedEvent>(x => !commandNamesToSkip.Contains(x.CommandName)); break; default: throw new FormatException($"Invalid event name: {eventTypeToCapture}."); } } } var localEventCapturer = eventCapturer; // copy value of eventCapturer ref variable to a local variable (to avoid error CS1628) client = DriverTestConfiguration.CreateDisposableClient( settings => { settings.RetryReads = retryReads; settings.RetryWrites = retryWrites; settings.ReadConcern = readConcern; settings.WriteConcern = writeConcern; settings.HeartbeatInterval = TimeSpan.FromMilliseconds(5); // the default value for spec tests if (localEventCapturer != null) { settings.ClusterConfigurator = c => c.Subscribe(localEventCapturer); } settings.ServerApi = serverApi; }, useMultipleShardRouters); }
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 methods private DisposableMongoClient CreateDisposableClient() { var mongoClientSettings = MongoClientSettings.FromConnectionString("mongodb://hostnotneeded"); return(DriverTestConfiguration.CreateDisposableClient(mongoClientSettings)); }