public void Run(JsonDrivenTestCase testCase) { RequireServer.Check().Supports(Feature.Transactions).ClusterType(ClusterType.ReplicaSet); Run(testCase.Shared, testCase.Test); }
public void CreateDataKeyAndDoubleEncryptionTest( [Values("local", "aws")] string kmsProvider, [Values(false, true)] bool async) { RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var client = ConfigureClient()) using (var clientEncrypted = ConfigureClientEncrypted(BsonDocument.Parse(SchemaMap))) using (var clientEncryption = ConfigureClientEncryption(clientEncrypted.Wrapped as MongoClient)) { var dataKeyOptions = CreateDataKeyOptions(kmsProvider); Guid dataKey; if (async) { dataKey = clientEncryption .CreateDataKeyAsync(kmsProvider, dataKeyOptions, CancellationToken.None) .GetAwaiter() .GetResult(); } else { dataKey = clientEncryption.CreateDataKey(kmsProvider, dataKeyOptions, CancellationToken.None); } var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace); var keyVaultDocument = Find( keyVaultCollection, new BsonDocument("_id", new BsonBinaryData(dataKey, GuidRepresentation.Standard)), async) .Single(); keyVaultDocument["masterKey"]["provider"].Should().Be(BsonValue.Create(kmsProvider)); var encryptOptions = new EncryptOptions( EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), keyId: dataKey); var encryptedValue = ExplicitEncrypt( clientEncryption, encryptOptions, $"hello {kmsProvider}", async); encryptedValue.SubType.Should().Be(BsonBinarySubType.Encrypted); var coll = GetCollection(clientEncrypted, __collCollectionNamespace); Insert( coll, async, new BsonDocument { { "_id", kmsProvider }, { "value", encryptedValue } }); var findResult = Find(coll, new BsonDocument("_id", kmsProvider), async).Single(); findResult["value"].ToString().Should().Be($"hello {kmsProvider}"); encryptOptions = new EncryptOptions( EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), alternateKeyName: $"{kmsProvider}_altname"); var encryptedValueWithAlternateKeyName = ExplicitEncrypt( clientEncryption, encryptOptions, $"hello {kmsProvider}", async); encryptedValueWithAlternateKeyName.SubType.Should().Be(BsonBinarySubType.Encrypted); encryptedValueWithAlternateKeyName.Should().Be(encryptedValue); if (kmsProvider == "local") // the test description expects this assert only once for a local kms provider { coll = GetCollection(clientEncrypted, __collCollectionNamespace); var exception = Record.Exception(() => Insert(coll, async, new BsonDocument("encrypted_placeholder", encryptedValue))); exception.Should().BeOfType <MongoEncryptionException>(); } } }
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", "no_encryption_under_2mib" }, { "unencrypted", new string('a', 2097152 - 1000) } })); exception.Should().BeNull(); eventCapturer.Clear(); exception = Record.Exception( () => Insert( coll, async, new BsonDocument { { "_id", "no_encryption_over_2mib" }, { "unencrypted", new string('a', 2097152) } })); exception.Should().NotBeNull(); 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", "no_encryption_under_2mib_1" }, { "unencrypted", new string('a', 2097152 - 1000) } }, new BsonDocument { { "_id", "no_encryption_under_2mib_2" }, { "unencrypted", new string('a', 2097152 - 1000) } })); 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(); } }
public void Example1() { RequireServer.Check().ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded).Supports(Feature.Transactions); var connectionString = CoreTestConfiguration.ConnectionString.ToString(); DropCollections( connectionString, CollectionNamespace.FromFullName("mydb1.foo"), CollectionNamespace.FromFullName("mydb2.bar")); string result = null; // Start Transactions withTxn API Example 1 // For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g. // string uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl"; // For a sharded cluster, connect to the mongos instances; e.g. // string uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"; var client = new MongoClient(connectionString); // Prereq: Create collections. var database1 = client.GetDatabase("mydb1"); var collection1 = database1.GetCollection <BsonDocument>("foo").WithWriteConcern(WriteConcern.WMajority); collection1.InsertOne(new BsonDocument("abc", 0)); var database2 = client.GetDatabase("mydb2"); var collection2 = database2.GetCollection <BsonDocument>("bar").WithWriteConcern(WriteConcern.WMajority); collection2.InsertOne(new BsonDocument("xyz", 0)); // Step 1: Start a client session. using (var session = client.StartSession()) { // Step 2: Optional. Define options to use for the transaction. var transactionOptions = new TransactionOptions( readPreference: ReadPreference.Primary, readConcern: ReadConcern.Local, writeConcern: WriteConcern.WMajority); // Step 3: Define the sequence of operations to perform inside the transactions var cancellationToken = CancellationToken.None; // normally a real token would be used result = session.WithTransaction( (s, ct) => { collection1.InsertOne(s, new BsonDocument("abc", 1), cancellationToken: ct); collection2.InsertOne(s, new BsonDocument("xyz", 999), cancellationToken: ct); return("Inserted into collections in different databases"); }, transactionOptions, cancellationToken); } //End Transactions withTxn API Example 1 result.Should().Be("Inserted into collections in different databases"); var collection1Documents = collection1.Find(FilterDefinition <BsonDocument> .Empty).ToList(); collection1Documents.Count.Should().Be(2); collection1Documents[0]["abc"].Should().Be(0); collection1Documents[1]["abc"].Should().Be(1); var collection2Documents = collection2.Find(FilterDefinition <BsonDocument> .Empty).ToList(); collection2Documents.Count.Should().Be(2); collection2Documents[0]["xyz"].Should().Be(0); collection2Documents[1]["xyz"].Should().Be(999); }
public void CorpusTest( [Values(false, true)] bool useLocalSchema, [Values(false, true)] bool async) { RequireServer.Check().Supports(Feature.ClientSideEncryption); var corpusSchema = JsonFileReader.Instance.Documents["corpus.corpus-schema.json"]; var schemaMap = useLocalSchema ? new BsonDocument("db.coll", corpusSchema) : null; using (var client = ConfigureClient()) using (var clientEncrypted = ConfigureClientEncrypted(schemaMap)) using (var clientEncryption = ConfigureClientEncryption(clientEncrypted.Wrapped as MongoClient)) { CreateCollection(client, __collCollectionNamespace, new BsonDocument("$jsonSchema", corpusSchema)); var corpusKeyLocal = JsonFileReader.Instance.Documents["corpus.corpus-key-local.json"]; var corpusKeyAws = JsonFileReader.Instance.Documents["corpus.corpus-key-aws.json"]; var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace); Insert(keyVaultCollection, async, corpusKeyLocal, corpusKeyAws); var corpus = JsonFileReader.Instance.Documents["corpus.corpus.json"]; var corpusCopied = new BsonDocument { corpus.GetElement("_id"), corpus.GetElement("altname_aws"), corpus.GetElement("altname_local") }; foreach (var corpusElement in corpus.Elements.Where(c => c.Value.IsBsonDocument)) { var corpusValue = corpusElement.Value.DeepClone(); var kms = corpusValue["kms"].AsString; var abbreviatedAlgorithmName = corpusValue["algo"].AsString; var identifier = corpusValue["identifier"].AsString; var allowed = corpusValue["allowed"].ToBoolean(); var value = corpusValue["value"]; var method = corpusValue["method"].AsString; switch (method) { case "auto": corpusCopied.Add(corpusElement); continue; case "explicit": { var encryptionOptions = CreateEncryptOptions(abbreviatedAlgorithmName, identifier, kms); BsonBinaryData encrypted = null; var exception = Record.Exception(() => { encrypted = ExplicitEncrypt( clientEncryption, encryptionOptions, value, async); }); if (allowed) { exception.Should().BeNull(); encrypted.Should().NotBeNull(); corpusValue["value"] = encrypted; } else { exception.Should().NotBeNull(); } corpusCopied.Add(new BsonElement(corpusElement.Name, corpusValue)); } break; default: throw new ArgumentException($"Unsupported method name {method}.", nameof(method)); } } var coll = GetCollection(clientEncrypted, __collCollectionNamespace); Insert(coll, async, corpusCopied); var corpusDecrypted = Find(coll, new BsonDocument(), async).Single(); corpusDecrypted.Should().Be(corpus); var corpusEncryptedExpected = JsonFileReader.Instance.Documents["corpus.corpus-encrypted.json"]; coll = GetCollection(client, __collCollectionNamespace); var corpusEncryptedActual = Find(coll, new BsonDocument(), async).Single(); foreach (var expectedElement in corpusEncryptedExpected.Elements.Where(c => c.Value.IsBsonDocument)) { var expectedElementValue = expectedElement.Value; var expectedAlgorithm = ParseAlgorithm(expectedElementValue["algo"].AsString); var expectedAllowed = expectedElementValue["allowed"].ToBoolean(); var expectedValue = expectedElementValue["value"]; var actualValue = corpusEncryptedActual.GetValue(expectedElement.Name)["value"]; switch (expectedAlgorithm) { case EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic: actualValue.Should().Be(expectedValue); break; case EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random: if (expectedAllowed) { actualValue.Should().NotBe(expectedValue); } break; default: throw new ArgumentException($"Unsupported expected algorithm {expectedAllowed}.", nameof(expectedAlgorithm)); } if (expectedAllowed) { var actualDecryptedValue = ExplicitDecrypt(clientEncryption, actualValue.AsBsonBinaryData, async); var expectedDecryptedValue = ExplicitDecrypt(clientEncryption, expectedValue.AsBsonBinaryData, async); actualDecryptedValue.Should().Be(expectedDecryptedValue); } else { actualValue.Should().Be(expectedValue); } } } EncryptOptions CreateEncryptOptions(string algorithm, string identifier, string kms) { Guid? keyId = null; string alternateName = null; if (identifier == "id") { switch (kms) { case "local": keyId = GuidConverter.FromBytes(Convert.FromBase64String("LOCALAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard); break; case "aws": keyId = GuidConverter.FromBytes(Convert.FromBase64String("AWSAAAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard); break; default: throw new ArgumentException($"Unsupported kms type {kms}."); } } else if (identifier == "altname") { alternateName = kms; } else { throw new ArgumentException($"Unsupported identifier {identifier}.", nameof(identifier)); } return(new EncryptOptions(ParseAlgorithm(algorithm).ToString(), alternateName, keyId)); } EncryptionAlgorithm ParseAlgorithm(string algorithm) { switch (algorithm) { case "rand": return(EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random); case "det": return(EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic); default: throw new ArgumentException($"Unsupported algorithm {algorithm}."); } } }
public void Lookup_with_let_and_mismatched_pipeline_condition_should_return_the_expected_result() { RequireServer.Check().Supports(Feature.AggregateLet); string databaseName = "test"; string ordersCollectionName = "orders"; string warehousesCollectionName = "warehouses"; var client = CreateClient(); DropCollection(client, databaseName, ordersCollectionName); DropCollection(client, databaseName, warehousesCollectionName); var ordersCollection = client.GetDatabase(databaseName).GetCollection <Order>(ordersCollectionName); var warehousesCollection = client.GetDatabase(databaseName).GetCollection <Warehouse>(warehousesCollectionName); var orderDocuments = new[] { new Order { Item = "almonds", Price = 12, Ordered = 2 }, new Order { Item = "pecans", Price = 20, Ordered = 1 }, new Order { Item = "cookies", Price = 10, Ordered = 60 } }; ordersCollection.InsertMany(orderDocuments); var warehouseDocuments = new[] { new Warehouse { StockItem = "almonds", Instock = 120 }, new Warehouse { StockItem = "pecans", Instock = 80 }, new Warehouse { StockItem = "almonds", Instock = 60 }, new Warehouse { StockItem = "cookies", Instock = 40 }, new Warehouse { StockItem = "cookies", Instock = 80 }, }; warehousesCollection.InsertMany(warehouseDocuments); var lookupPipeline = new EmptyPipelineDefinition <Warehouse>() .Match(new BsonDocument("$expr", new BsonDocument("$and", new BsonArray { new BsonDocument("$eq", new BsonArray { "$stock_item", "not_exist_item" }), }))) .Project <Warehouse, Warehouse, StockData>( Builders <Warehouse> .Projection .Exclude(warehouses => warehouses.StockItem) .Exclude(warehouses => warehouses.Id)); var result = ordersCollection .Aggregate() .Lookup( warehousesCollection, new BsonDocument { { "order_item", "$item" }, { "order_qty", "$ordered" } }, lookupPipeline, new ExpressionFieldDefinition <Order, IEnumerable <StockData> >(order => order.StockData)) .ToList() .Select(item => { var document = item.ToBsonDocument(); document.Remove("_id"); return(document); }) .ToList(); result.Count.Should().Be(3); result[0].Should().Be("{ 'item' : 'almonds', 'price' : 12, 'ordered' : 2, 'stockdata' : [] }"); result[1].Should().Be("{ 'item' : 'pecans', 'price' : 20, 'ordered' : 1, 'stockdata' : [] }"); result[2].Should().Be("{ 'item' : 'cookies', 'price' : 10, 'ordered' : 60, 'stockdata' : [] }"); }
// private methods private void Run(BsonDocument shared, BsonDocument test) { JsonDrivenHelper.EnsureAllFieldsAreValid(shared, "_path", "database_name", "database2_name", "collection_name", "collection2_name", "tests"); JsonDrivenHelper.EnsureAllFieldsAreValid(test, "description", "minServerVersion", "maxServerVersion", "topology", "target", "changeStreamPipeline", "changeStreamOptions", "operations", "expectations", "result", "async", "failPoint"); RequireServer.Check().RunOn(EmulateRunOn()); _databaseName = shared["database_name"].AsString; _database2Name = shared.GetValue("database2_name", null)?.AsString; _collectionName = shared["collection_name"].AsString; _collection2Name = shared.GetValue("collection2_name", null)?.AsString; CreateCollections(); List <ChangeStreamDocument <BsonDocument> > actualResult = null; Exception actualException = null; List <CommandStartedEvent> actualEvents = null; var eventCapturer = CreateEventCapturer(); using (ConfigureFailPoint(test)) using (var client = CreateDisposableClient(eventCapturer)) { try { var async = test["async"].AsBoolean; using (var cursor = Watch(client, test, async)) { var globalClient = DriverTestConfiguration.Client; ExecuteOperations(globalClient, test["operations"].AsBsonArray); actualResult = ReadChangeStreamDocuments(cursor, test, async); actualEvents = GetEvents(eventCapturer); } } catch (Exception exception) { actualException = exception; } } if (test.Contains("expectations") && actualEvents != null) { var expectedEvents = test["expectations"].AsBsonArray.Cast <BsonDocument>().ToList(); AssertEvents(actualEvents, expectedEvents); } if (test.Contains("result")) { var expectedResult = test["result"].AsBsonDocument; AssertResult(actualResult, actualException, expectedResult); } BsonArray EmulateRunOn() { var condition = new BsonDocument(); if (test.TryGetElement("minServerVersion", out var minServerVersion)) { condition.Add(minServerVersion); } if (test.TryGetElement("maxServerVersion", out var maxServerVersion)) { condition.Add(maxServerVersion); } if (test.TryGetElement("topology", out var topology)) { condition.Add(topology); } return(new BsonArray { condition }); } }
public void Supported_single_statement_writes_should_have_transaction_id( [Values("insertOne", "updateOne", "replaceOne", "deleteOne", "findOneAndDelete", "findOneAndReplace", "findOneAndUpdate")] string operation, [Values(false, true)] bool async) { RequireServer.Check().VersionGreaterThanOrEqualTo("3.6.0").ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded); DropCollection(); var eventCapturer = CreateEventCapturer(); using (var client = CreateDisposableClient(eventCapturer)) { var database = client.GetDatabase(_databaseName); var collection = database.GetCollection <BsonDocument>(_collectionName); switch (operation) { case "deleteOne": var deleteOneFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); if (async) { collection.DeleteOneAsync(deleteOneFilter).GetAwaiter().GetResult(); } else { collection.DeleteOne(deleteOneFilter); } break; case "findOneAndDelete": var findOneAndDeleteFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); if (async) { collection.FindOneAndDeleteAsync(findOneAndDeleteFilter).GetAwaiter().GetResult(); } else { collection.FindOneAndDelete(findOneAndDeleteFilter); } break; case "findOneAndReplace": var findOneAndReplaceFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); var findOneAndReplaceReplacement = new BsonDocument("_id", 1); if (async) { collection.FindOneAndReplaceAsync(findOneAndReplaceFilter, findOneAndReplaceReplacement).GetAwaiter().GetResult(); } else { collection.FindOneAndReplace(findOneAndReplaceFilter, findOneAndReplaceReplacement); } break; case "findOneAndUpdate": var findOneAndUpdateFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); var findOneAndUpdateUpdate = Builders <BsonDocument> .Update.Set("x", 2); if (async) { collection.FindOneAndUpdateAsync(findOneAndUpdateFilter, findOneAndUpdateUpdate).GetAwaiter().GetResult(); } else { collection.FindOneAndUpdate(findOneAndUpdateFilter, findOneAndUpdateUpdate); } break; case "insertOne": var document = new BsonDocument("_id", 1); if (async) { collection.InsertOneAsync(document).GetAwaiter().GetResult(); } else { collection.InsertOne(document); } break; case "replaceOne": var replaceOneFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); var replacement = new BsonDocument("_id", 1); if (async) { collection.ReplaceOneAsync(replaceOneFilter, replacement).GetAwaiter().GetResult(); } else { collection.ReplaceOne(replaceOneFilter, replacement); } break; case "updateOne": var updateOneFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); var updateOne = Builders <BsonDocument> .Update.Set("x", 2); if (async) { collection.UpdateOneAsync(updateOneFilter, updateOne).GetAwaiter().GetResult(); } else { collection.UpdateOne(updateOneFilter, updateOne); } break; default: throw new Exception($"Unexpected operation: {operation}."); } AssertCommandHasTransactionId(eventCapturer); } }
public void Unacknowledged_writes_should_not_have_transaction_id( [Values("delete", "insert", "update")] string operation, [Values(false, true)] bool async) { RequireServer.Check().ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded); DropCollection(); var eventCapturer = CreateEventCapturer(); using (var client = CreateDisposableClient(eventCapturer)) { var database = client.GetDatabase(_databaseName); var collection = database.GetCollection <BsonDocument>(_collectionName).WithWriteConcern(WriteConcern.Unacknowledged); switch (operation) { case "delete": var deleteFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); if (async) { collection.DeleteOneAsync(deleteFilter).GetAwaiter().GetResult(); } else { collection.DeleteOne(deleteFilter); } break; case "insert": var document = new BsonDocument("_id", 1); if (async) { collection.InsertOneAsync(document).GetAwaiter().GetResult();; } else { collection.InsertOne(document); } SpinUntilCollectionIsNotEmpty(); // wait for unacknowledged insert to complete so it won't execute later while another test is running break; case "update": var updateFilter = Builders <BsonDocument> .Filter.Eq("_id", 1); var update = Builders <BsonDocument> .Update.Set("x", 1); if (async) { collection.UpdateOneAsync(updateFilter, update).GetAwaiter().GetResult(); } else { collection.UpdateOne(updateFilter, update); } break; default: throw new Exception($"Unexpected operation: {operation}."); } AssertCommandDoesNotHaveTransactionId(eventCapturer); } }
public void CustomEndpointTest([Values(false, true)] bool async) { RequireServer.Check().Supports(Feature.ClientSideEncryption); using (var client = ConfigureClient()) using (var clientEncryption = ConfigureClientEncryption(client.Wrapped as MongoClient)) { var testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" } }; TestCase(testCaseMasterKey); testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" }, { "endpoint", "kms.us-east-1.amazonaws.com" } }; TestCase(testCaseMasterKey); testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" }, { "endpoint", "kms.us-east-1.amazonaws.com:443" } }; TestCase(testCaseMasterKey); testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" }, { "endpoint", "kms.us-east-1.amazonaws.com:12345" } }; var exception = Record.Exception(() => TestCase(testCaseMasterKey)); exception.InnerException.Should().BeAssignableTo <SocketException>(); testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" }, { "endpoint", "kms.us-east-2.amazonaws.com" } }; exception = Record.Exception(() => TestCase(testCaseMasterKey)); exception.Should().NotBeNull(); exception.Message.Should().Contain("us-east-1"); testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" }, { "endpoint", "example.com" } }; exception = Record.Exception(() => TestCase(testCaseMasterKey)); exception.Should().NotBeNull(); exception.Message.Should().Contain("parse error"); // additional not spec tests testCaseMasterKey = new BsonDocument { { "region", "us-east-1" }, { "key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" }, { "endpoint", "$test$" } }; exception = Record.Exception(() => TestCase(testCaseMasterKey)); exception.Should().NotBeNull(); exception.InnerException.Should().BeAssignableTo <SocketException>(); void TestCase(BsonDocument masterKey) { var dataKeyOptions = new DataKeyOptions(masterKey: masterKey); var dataKey = CreateDataKey(clientEncryption, "aws", dataKeyOptions, async); var encryptOptions = new EncryptOptions( algorithm: EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), keyId: dataKey); var value = "test"; var encrypted = ExplicitEncrypt(clientEncryption, encryptOptions, value, async); var decrypted = ExplicitDecrypt(clientEncryption, encrypted, async); decrypted.Should().Be(BsonValue.Create(value)); } } }
// private methods private void Run(BsonDocument shared, BsonDocument test) { JsonDrivenHelper.EnsureAllFieldsAreValid(shared, "_path", "database_name", "database2_name", "collection_name", "collection2_name", "tests"); JsonDrivenHelper.EnsureAllFieldsAreValid(test, "description", "minServerVersion", "topology", "target", "changeStreamPipeline", "changeStreamOptions", "operations", "expectations", "result", "async"); if (test.Contains("minServerVersion")) { var minServerVersion = test["minServerVersion"].AsString; RequireServer.Check().VersionGreaterThanOrEqualTo(minServerVersion); } if (test.Contains("topology")) { var clusterTypes = MapTopologyToClusterTypes(test["topology"].AsBsonArray); RequireServer.Check().ClusterTypes(clusterTypes); } _databaseName = shared["database_name"].AsString; _database2Name = shared["database2_name"].AsString; _collectionName = shared["collection_name"].AsString; _collection2Name = shared["collection2_name"].AsString; CreateCollections(); List <ChangeStreamDocument <BsonDocument> > actualResult = null; Exception actualException = null; List <CommandStartedEvent> actualEvents = null; var eventCapturer = CreateEventCapturer(); using (var client = CreateDisposableClient(eventCapturer)) { try { var async = test["async"].AsBoolean; using (var cursor = Watch(client, test, async)) { var globalClient = DriverTestConfiguration.Client; ExecuteOperations(globalClient, test["operations"].AsBsonArray); actualResult = ReadChangeStreamDocuments(cursor, test, async); actualEvents = GetEvents(eventCapturer); } } catch (Exception exception) { actualException = exception; } } if (test.Contains("expectations") && actualEvents != null) { var expectedEvents = test["expectations"].AsBsonArray.Cast <BsonDocument>().ToList(); AssertEvents(actualEvents, expectedEvents); } if (test.Contains("result")) { var expectedResult = test["result"].AsBsonDocument; AssertResult(actualResult, actualException, expectedResult); } }
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(); 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 : 20, 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(); } 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); } } }
private void RequireSupportForRetryableWrites() { RequireServer.Check().ClusterTypes(ClusterType.Sharded, ClusterType.ReplicaSet); }
public void GraphLookup_untyped_based_should_return_expected_result() { RequireServer.Check().Supports(Feature.AggregateGraphLookupStage); EnsureTestData(); var subject = __employeesCollection.Aggregate(); var result = subject .GraphLookup(__employeesCollection, "reportsTo", "name", "$reportsTo", "reportingHierarchy") .ToList(); var comparer = new EmployeeWithReportingHierarchyBsonDocumentEqualityComparer(); result.WithComparer(comparer).Should().Equal( BsonDocument.Parse(@"{ _id : 1, name : 'Dev', reportingHierarchy : [ ] }"), BsonDocument.Parse(@"{ _id : 2, name : 'Eliot', reportsTo : 'Dev', reportingHierarchy : [ { _id : 1, name : 'Dev' } ] }"), BsonDocument.Parse(@"{ _id : 3, name : 'Ron', reportsTo : 'Eliot', reportingHierarchy : [ { _id : 1, name : 'Dev' }, { _id : 2, name : 'Eliot', reportsTo : 'Dev' } ] }"), BsonDocument.Parse(@"{ _id : 4, name : 'Andrew', reportsTo : 'Eliot', reportingHierarchy : [ { _id : 1, name : 'Dev' }, { _id : 2, name : 'Eliot', reportsTo : 'Dev' } ] }"), BsonDocument.Parse(@"{ _id : 5, name : 'Asya', reportsTo : 'Ron', reportingHierarchy : [ { _id : 1, name : 'Dev' }, { _id : 2, name : 'Eliot', reportsTo : 'Dev' }, { _id : 3, name : 'Ron', reportsTo : 'Eliot' } ] }"), BsonDocument.Parse(@"{ _id : 6, name : 'Dan', reportsTo : 'Andrew', reportingHierarchy : [ { _id : 1, name : 'Dev' }, { _id : 2, name : 'Eliot', reportsTo : 'Dev' }, { _id : 4, name : 'Andrew', reportsTo : 'Eliot' } ] }")); }
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; bool? observeSensitiveCommands = 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; RequireServer.Check().MultipleMongosesIfSharded(required: useMultipleShardRouters); 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 "observeSensitiveCommands": observeSensitiveCommands = element.Value.AsBoolean; 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}'."); } } // Regardless of whether events are observed, we still need to track some info about the pool in order to implement // the assertNumberConnectionsCheckedOut operation if (eventTypesToCapture.Count == 0) { eventTypesToCapture.Add( (Key: Ensure.IsNotNull(clientId, nameof(clientId)), Events: new[] { "connectionCheckedInEvent", "connectionCheckedOutEvent" }, CommandNotToCapture: commandNamesToSkipInEvents)); } var defaultCommandNamesToSkip = new List <string> { "configureFailPoint", "getLastError", OppressiveLanguageConstants.LegacyHelloCommandName, // skip handshake events, should be reconsidered in the scope of CSHARP-3823 "hello" }; if (!observeSensitiveCommands.GetValueOrDefault()) { defaultCommandNamesToSkip.AddRange(new[] { "authenticate", "getnonce", "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); } }; } }, _loggerFactory.CreateLogger <DisposableMongoClient>(), useMultipleShardRouters); return(client, clientEventCapturers); }
public void Run( string schemaVersion, BsonArray testSetRunOnRequirements, BsonArray entities, BsonArray initialData, BsonArray runOnRequirements, string skipReason, BsonArray operations, BsonArray expectedEvents, BsonArray outcome, bool async) { if (_runHasBeenCalled) { throw new InvalidOperationException("The test suite has already been run."); } _runHasBeenCalled = true; var schemaSemanticVersion = SemanticVersion.Parse(schemaVersion); if (schemaSemanticVersion < new SemanticVersion(1, 0, 0) || schemaSemanticVersion > new SemanticVersion(1, 7, 0)) { throw new FormatException($"Schema version '{schemaVersion}' is not supported."); } if (testSetRunOnRequirements != null) { RequireServer.Check().RunOn(testSetRunOnRequirements); } if (runOnRequirements != null) { RequireServer.Check().RunOn(runOnRequirements); } if (skipReason != null) { throw new SkipException($"Test skipped because '{skipReason}'."); } KillOpenTransactions(DriverTestConfiguration.Client); _entityMap = new UnifiedEntityMapBuilder(_eventFormatters, _loggerFactory).Build(entities); if (initialData != null) { AddInitialData(DriverTestConfiguration.Client, initialData); } foreach (var operation in operations) { var cancellationToken = CancellationToken.None; CreateAndRunOperation(operation.AsBsonDocument, async, cancellationToken); } if (expectedEvents != null) { AssertEvents(expectedEvents, _entityMap); } if (outcome != null) { AssertOutcome(DriverTestConfiguration.Client, outcome); } }
public void Lookup_with_let_and_bsondocuments_params_should_return_the_expected_result() { RequireServer.Check().Supports(Feature.AggregateLet); string databaseName = "test"; string ordersCollectionName = "orders"; string warehousesCollectionName = "warehouses"; var client = CreateClient(); DropCollection(client, databaseName, ordersCollectionName); DropCollection(client, databaseName, warehousesCollectionName); var ordersCollection = client.GetDatabase(databaseName).GetCollection <BsonDocument>(ordersCollectionName); var warehousesCollection = client.GetDatabase(databaseName).GetCollection <BsonDocument>(warehousesCollectionName); var orderDocuments = new[] { new BsonDocument { { "item", "almonds" }, { "price", 12 }, { "ordered", 2 } }, new BsonDocument { { "item", "pecans" }, { "price", 20 }, { "ordered", 1 } }, new BsonDocument { { "item", "cookies" }, { "price", 10 }, { "ordered", 60 } } }; ordersCollection.InsertMany(orderDocuments); var warehouseDocuments = new[] { new BsonDocument { { "stock_item", "almonds" }, { "instock", 120 } }, new BsonDocument { { "stock_item", "pecans" }, { "instock", 80 } }, new BsonDocument { { "stock_item", "almonds" }, { "instock", 60 } }, new BsonDocument { { "stock_item", "cookies" }, { "instock", 40 } }, new BsonDocument { { "stock_item", "cookies" }, { "instock", 80 } } }; warehousesCollection.InsertMany(warehouseDocuments); var lookupPipeline = new EmptyPipelineDefinition <BsonDocument>() .Match(new BsonDocument("$expr", new BsonDocument("$and", new BsonArray { new BsonDocument("$eq", new BsonArray { "$stock_item", "$$order_item" }), new BsonDocument("$gte", new BsonArray { "$instock", "$$order_qty" }) }))) .Project <BsonDocument, BsonDocument, BsonDocument>( Builders <BsonDocument> .Projection .Exclude("stock_item") .Exclude("_id")); var result = ordersCollection .Aggregate() .Lookup <BsonDocument, BsonDocument, IEnumerable <BsonDocument>, BsonDocument>( warehousesCollection, new BsonDocument { { "order_item", "$item" }, { "order_qty", "$ordered" } }, lookupPipeline, "stockdata") .ToList() .Select(item => { var document = item.ToBsonDocument(); document.Remove("_id"); return(document); }) .ToList(); result.Count.Should().Be(3); result[0].Should().Be("{ 'item' : 'almonds', 'price' : 12, 'ordered' : 2, 'stockdata' : [{ 'instock' : 120 }, { 'instock' : 60 }] }"); result[1].Should().Be("{ 'item' : 'pecans', 'price' : 20, 'ordered' : 1, 'stockdata' : [{ 'instock' : 80 }] }"); result[2].Should().Be("{ 'item' : 'cookies', 'price' : 10, 'ordered' : 60, 'stockdata' : [{ 'instock' : 80 }] }"); }
public void ClientSideEncryptionAutoEncryptionSettingsTour() { RequireServer.Check().Supports(Feature.ClientSideEncryption); var localMasterKey = Convert.FromBase64String(LocalMasterKey); var kmsProviders = new Dictionary <string, IReadOnlyDictionary <string, object> >(); var localKey = new Dictionary <string, object> { { "key", localMasterKey } }; kmsProviders.Add("local", localKey); var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault"); var keyVaultMongoClient = new MongoClient(); var clientEncryptionSettings = new ClientEncryptionOptions( keyVaultMongoClient, keyVaultNamespace, kmsProviders); var clientEncryption = new ClientEncryption(clientEncryptionSettings); var dataKeyId = clientEncryption.CreateDataKey("local", new DataKeyOptions(), CancellationToken.None); var base64DataKeyId = Convert.ToBase64String(GuidConverter.ToBytes(dataKeyId, GuidRepresentation.Standard)); clientEncryption.Dispose(); var collectionNamespace = CollectionNamespace.FromFullName("test.coll"); var schemaMap = $@"{{ properties: {{ encryptedField: {{ encrypt: {{ keyId: [{{ '$binary' : {{ 'base64' : '{base64DataKeyId}', 'subType' : '04' }} }}], bsonType: 'string', algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' }} }} }}, 'bsonType': 'object' }}"; var autoEncryptionSettings = new AutoEncryptionOptions( keyVaultNamespace, kmsProviders, schemaMap: new Dictionary <string, BsonDocument>() { { collectionNamespace.ToString(), BsonDocument.Parse(schemaMap) } }); var clientSettings = new MongoClientSettings { AutoEncryptionOptions = autoEncryptionSettings }; var client = new MongoClient(clientSettings); var database = client.GetDatabase("test"); database.DropCollection("coll"); var collection = database.GetCollection <BsonDocument>("coll"); collection.InsertOne(new BsonDocument("encryptedField", "123456789")); var result = collection.Find(FilterDefinition <BsonDocument> .Empty).First(); _output.WriteLine(result.ToJson()); }
public void Lookup_without_let_should_return_the_expected_result([Values(null, "{}")] string emptyLetValue) { RequireServer.Check().Supports(Feature.AggregateLet); string databaseName = "test"; string ordersCollectionName = "orders"; string warehousesCollectionName = "warehouses"; var client = CreateClient(); DropCollection(client, databaseName, ordersCollectionName); DropCollection(client, databaseName, warehousesCollectionName); var ordersCollection = client.GetDatabase(databaseName).GetCollection <Order>(ordersCollectionName); var warehousesCollection = client.GetDatabase(databaseName).GetCollection <Warehouse>(warehousesCollectionName); var orderDocuments = new[] { new Order { Item = "almonds", Price = 12, Ordered = 2 }, new Order { Item = "pecans", Price = 20, Ordered = 1 }, new Order { Item = "cookies", Price = 10, Ordered = 60 } }; ordersCollection.InsertMany(orderDocuments); var warehouseDocuments = new[] { new Warehouse { StockItem = "almonds", Instock = 120 }, new Warehouse { StockItem = "pecans", Instock = 80 }, new Warehouse { StockItem = "almonds", Instock = 60 }, new Warehouse { StockItem = "cookies", Instock = 40 }, new Warehouse { StockItem = "cookies", Instock = 80 }, }; warehousesCollection.InsertMany(warehouseDocuments); var lookupPipeline = new EmptyPipelineDefinition <Warehouse>() .Project <Warehouse, Warehouse, StockData>( Builders <Warehouse> .Projection .Exclude(warehouses => warehouses.StockItem) .Exclude(warehouses => warehouses.Id)); var result = ordersCollection .Aggregate() .Lookup( warehousesCollection, emptyLetValue != null ? BsonDocument.Parse(emptyLetValue) : null, lookupPipeline, new ExpressionFieldDefinition <Order, IEnumerable <StockData> >(order => order.StockData)) .ToList() .Select(item => { var document = item.ToBsonDocument(); document.Remove("_id"); return(document); }) .ToList(); result.Count.Should().Be(3); result[0].Should().Be("{ 'item' : 'almonds', 'price' : 12, 'ordered' : 2, 'stockdata' : [{ 'instock' : 120 }, { 'instock' : 80 }, { 'instock' : 60 }, { 'instock' : 40 }, { 'instock' : 80 }] }"); result[1].Should().Be("{ 'item' : 'pecans', 'price' : 20, 'ordered' : 1, 'stockdata' : [{ 'instock' : 120 }, { 'instock' : 80 }, { 'instock' : 60 }, { 'instock' : 40 }, { 'instock' : 80 }] }"); result[2].Should().Be("{ 'item' : 'cookies', 'price' : 10, 'ordered' : 60, 'stockdata' : [{ 'instock' : 120 }, { 'instock' : 80 }, { 'instock' : 60 }, { 'instock' : 40 }, { 'instock' : 80 }] }"); }
public void GetResumeToken_should_return_expected_results_when_batch_is_empty_or_fully_iterated( [Values(false, true)] bool async, [Values(false, true)] bool withResumeAfter) { RequireServer.Check().Supports(Feature.ChangeStreamStage).ClusterTypes(ClusterType.ReplicaSet); var pipeline = new BsonDocument[0]; var resultSerializer = new ChangeStreamDocumentSerializer <BsonDocument>(BsonDocumentSerializer.Instance); var messageEncoderSettings = new MessageEncoderSettings(); var subject = new ChangeStreamOperation <ChangeStreamDocument <BsonDocument> >(_collectionNamespace, pipeline, resultSerializer, messageEncoderSettings) { BatchSize = 2 }; EnsureDatabaseExists(); DropCollection(); if (withResumeAfter) { subject.ResumeAfter = GenerateResumeAfterToken(async, true); } using (var cursor = ExecuteOperation(subject, async)) using (var enumerator = new AsyncCursorEnumerator <ChangeStreamDocument <BsonDocument> >(cursor, CancellationToken.None)) { var resumeResult = cursor.GetResumeToken(); // the batch is empty if (Feature.ChangeStreamPostBatchResumeToken.IsSupported(CoreTestConfiguration.ServerVersion)) { var postBatchResumeToken = cursor._postBatchResumeToken(); postBatchResumeToken.Should().NotBeNull(); resumeResult.Should().Be(postBatchResumeToken); } else { if (withResumeAfter) { resumeResult.Should().Be(subject.ResumeAfter); } else { resumeResult.Should().BeNull(); } } // the batch has been iterated to the last document Insert("{ a : 1 }"); enumerator.MoveNext(); resumeResult = cursor.GetResumeToken(); if (Feature.ChangeStreamPostBatchResumeToken.IsSupported(CoreTestConfiguration.ServerVersion)) { var postBatchResumeToken = cursor._postBatchResumeToken(); postBatchResumeToken.Should().NotBeNull(); resumeResult.Should().Be(postBatchResumeToken); } else { var documentResumeToken = cursor._documentResumeToken(); documentResumeToken.Should().NotBeNull(); resumeResult.Should().Be(documentResumeToken); } } }
public void Lookup_with_let_should_return_the_expected_result() { RequireServer.Check().Supports(Feature.AggregateLet); var client = new MongoClient(CoreTestConfiguration.ConnectionString.ToString()); var warehousesCollection = client.GetDatabase("test").GetCollection <BsonDocument>("warehouses"); var lookupPipeline = new EmptyPipelineDefinition <BsonDocument>() .Match(new BsonDocument("$expr", new BsonDocument("$and", new BsonArray { new BsonDocument("$eq", new BsonArray { "$stock_item", "$$order_item" }), new BsonDocument("$gte", new BsonArray { "$instock", "$$order_qty" }) }))) .Project( Builders <BsonDocument> .Projection .Exclude("_id") .Exclude("stock_item")); var result = PipelineStageDefinitionBuilder.Lookup <BsonDocument, BsonDocument, BsonDocument, IEnumerable <BsonDocument>, BsonDocument>( warehousesCollection, new BsonDocument { { "order_item", "$item" }, { "order_qty", "$ordered" } }, lookupPipeline, new StringFieldDefinition <BsonDocument, IEnumerable <BsonDocument> >("stockdata") ); RenderStage(result).Document.Should().Be(@" { '$lookup' : { 'from' : 'warehouses', 'let' : { 'order_item' : '$item', 'order_qty' : '$ordered' }, 'pipeline' : [ { '$match' : { '$expr' : { '$and' : [ { '$eq' : ['$stock_item', '$$order_item'] }, { '$gte' : ['$instock', '$$order_qty'] }] } } }, { '$project' : { '_id' : 0, 'stock_item' : 0 } }], 'as' : 'stockdata' } }"); }
public void Command_should_use_serverApi([Values(false, true)] bool async) { RequireServer.Check().Supports(Feature.CommandMessage); var serverApi = new ServerApi(ServerApiVersion.V1); var eventCapturer = new EventCapturer().Capture <CommandStartedEvent>(e => e.CommandName == "ping"); var builder = CoreTestConfiguration .ConfigureCluster(new ClusterBuilder()) .Subscribe(eventCapturer) .ConfigureCluster(x => x.With(serverApi: serverApi)); using (var cluster = CoreTestConfiguration.CreateCluster(builder)) using (var session = cluster.StartSession()) { var cancellationToken = CancellationToken.None; var server = (Server)cluster.SelectServer(WritableServerSelector.Instance, cancellationToken); using (var channel = server.GetChannel(cancellationToken)) { var command = BsonDocument.Parse("{ ping : 1 }"); if (async) { channel .CommandAsync( session, ReadPreference.Primary, DatabaseNamespace.Admin, command, null, // payloads NoOpElementNameValidator.Instance, null, // additionalOptions null, // postWriteAction CommandResponseHandling.Return, BsonDocumentSerializer.Instance, new MessageEncoderSettings(), cancellationToken) .GetAwaiter() .GetResult(); } else { channel.Command( session, ReadPreference.Primary, DatabaseNamespace.Admin, command, null, // payloads NoOpElementNameValidator.Instance, null, // additionalOptions null, // postWriteAction CommandResponseHandling.Return, BsonDocumentSerializer.Instance, new MessageEncoderSettings(), cancellationToken); } } } var commandStartedEvent = eventCapturer.Next().Should().BeOfType <CommandStartedEvent>().Subject; commandStartedEvent.Command["apiVersion"].AsString.Should().Be("1"); }