Skip to content

Commit 06a2ad3

Browse files
CSHARP-2258: Spec tests should use the same format for bulk writes
1 parent adef3c9 commit 06a2ad3

File tree

13 files changed

+267
-227
lines changed

13 files changed

+267
-227
lines changed

tests/MongoDB.Driver.Tests/Specifications/command-monitoring/BulkWriteTest.cs

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515

1616
using System;
1717
using System.Collections.Generic;
18-
using System.Linq;
19-
using System.Threading.Tasks;
20-
using FluentAssertions;
2118
using MongoDB.Bson;
2219

2320
namespace MongoDB.Driver.Tests.Specifications.command_monitoring
@@ -26,18 +23,21 @@ public class BulkWriteTest : CrudOperationTestBase
2623
{
2724
private List<WriteModel<BsonDocument>> _requests;
2825
private BulkWriteOptions _options = new BulkWriteOptions();
29-
private WriteConcern _writeConcern = WriteConcern.Acknowledged;
3026

3127
protected override void Execute(IMongoCollection<BsonDocument> collection, bool async)
3228
{
33-
var collectionWithWriteConcern = collection.WithWriteConcern(_writeConcern);
29+
if (collection.Settings.WriteConcern == null)
30+
{
31+
collection = collection.WithWriteConcern(WriteConcern.Acknowledged);
32+
}
33+
3434
if (async)
3535
{
36-
collectionWithWriteConcern.BulkWriteAsync(_requests, _options).GetAwaiter().GetResult();
36+
collection.BulkWriteAsync(_requests, _options).GetAwaiter().GetResult();
3737
}
3838
else
3939
{
40-
collectionWithWriteConcern.BulkWrite(_requests, _options);
40+
collection.BulkWrite(_requests, _options);
4141
}
4242
}
4343

@@ -46,37 +46,58 @@ protected override bool TrySetArgument(string name, BsonValue value)
4646
switch (name)
4747
{
4848
case "requests":
49-
_requests = ParseRequests((BsonArray)value).ToList();
50-
return true;
51-
case "ordered":
52-
_options.IsOrdered = value.ToBoolean();
49+
_requests = ParseRequests(value.AsBsonArray);
5350
return true;
54-
case "writeConcern":
55-
_writeConcern = WriteConcern.FromBsonDocument((BsonDocument)value);
51+
case "options":
52+
_options = ParseOptions(value.AsBsonDocument);
5653
return true;
5754
}
5855

5956
return false;
6057
}
58+
59+
// private methods
60+
private BulkWriteOptions ParseOptions(BsonDocument value)
61+
{
62+
var options = new BulkWriteOptions();
63+
64+
foreach (var option in value.Elements)
65+
{
66+
switch (option.Name)
67+
{
68+
case "ordered":
69+
options.IsOrdered = option.Value.ToBoolean();
70+
break;
71+
default:
72+
throw new FormatException($"Unexpected option: ${option.Name}.");
73+
}
74+
}
75+
76+
return options;
77+
}
6178

62-
private IEnumerable<WriteModel<BsonDocument>> ParseRequests(BsonArray requests)
79+
private List<WriteModel<BsonDocument>> ParseRequests(BsonArray requests)
6380
{
81+
var result = new List<WriteModel<BsonDocument>>();
6482
foreach (BsonDocument request in requests)
6583
{
66-
var element = request.GetElement(0);
67-
switch (element.Name)
84+
var name = request["name"].AsString;
85+
var arguments = request["arguments"].AsBsonDocument;
86+
switch (name)
6887
{
6988
case "deleteOne":
70-
yield return ParseDeleteOne((BsonDocument)element.Value);
89+
result.Add(ParseDeleteOne(arguments));
7190
break;
7291
case "insertOne":
73-
yield return ParseInsertOne((BsonDocument)element.Value);
92+
result.Add(ParseInsertOne(arguments));
7493
break;
7594
case "updateOne":
76-
yield return ParseUpdateOne((BsonDocument)element.Value);
95+
result.Add(ParseUpdateOne(arguments));
7796
break;
7897
}
7998
}
99+
100+
return result;
80101
}
81102

82103
private DeleteOneModel<BsonDocument> ParseDeleteOne(BsonDocument request)
@@ -98,7 +119,5 @@ private UpdateOneModel<BsonDocument> ParseUpdateOne(BsonDocument request)
98119
model.IsUpsert = request.GetValue("upsert", false).ToBoolean();
99120
return model;
100121
}
101-
102-
103122
}
104123
}

tests/MongoDB.Driver.Tests/Specifications/command-monitoring/TestRunner.cs renamed to tests/MongoDB.Driver.Tests/Specifications/command-monitoring/CommandMonitoringTestRunner.cs

Lines changed: 71 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@
1414
*/
1515

1616
using System;
17-
using System.Collections;
1817
using System.Collections.Generic;
19-
using System.IO;
2018
using System.Linq;
21-
using System.Reflection;
2219
using System.Threading;
2320
using FluentAssertions;
2421
using MongoDB.Bson;
22+
using MongoDB.Bson.TestHelpers.JsonDrivenTests;
2523
using MongoDB.Driver.Core;
2624
using MongoDB.Driver.Core.Clusters.ServerSelectors;
2725
using MongoDB.Driver.Core.Events;
@@ -30,7 +28,7 @@
3028

3129
namespace MongoDB.Driver.Tests.Specifications.command_monitoring
3230
{
33-
public class TestRunner
31+
public class CommandMonitoringTestRunner
3432
{
3533
private static MongoClient __client;
3634
private static EventCapturer __capturedEvents;
@@ -39,7 +37,7 @@ public class TestRunner
3937
private static bool __oneTimeSetupHasRun = false;
4038
private static object __oneTimeSetupLock = new object();
4139

42-
static TestRunner()
40+
static CommandMonitoringTestRunner()
4341
{
4442
__commandsToCapture = new string[]
4543
{
@@ -66,7 +64,7 @@ static TestRunner()
6664
};
6765
}
6866

69-
public TestRunner()
67+
public CommandMonitoringTestRunner()
7068
{
7169
lock (__oneTimeSetupLock)
7270
{
@@ -101,9 +99,9 @@ public bool OneTimeSetup()
10199

102100
[SkippableTheory]
103101
[ClassData(typeof(TestCaseFactory))]
104-
public void RunTestDefinition(IEnumerable<BsonDocument> data, string databaseName, string collectionName, BsonDocument definition, bool async)
102+
public void RunTestDefinition(JsonDrivenTestCase testCase)
105103
{
106-
definition = (BsonDocument)DeepCopy(definition); // protect against side effects when the same definition is run twice (async=false/true)
104+
var definition = testCase.Test;
107105

108106
BsonValue bsonValue;
109107
if (definition.TryGetValue("ignore_if_server_version_greater_than", out bsonValue))
@@ -136,18 +134,21 @@ public void RunTestDefinition(IEnumerable<BsonDocument> data, string databaseNam
136134
}
137135
}
138136

139-
var database = __client
140-
.GetDatabase(databaseName);
141-
var collection = database
142-
.GetCollection<BsonDocument>(collectionName);
137+
var data = testCase.Shared["data"].AsBsonArray.Cast<BsonDocument>().ToList();
138+
var databaseName = testCase.Shared["database_name"].AsString;
139+
var collectionName = testCase.Shared["collection_name"].AsString;
140+
141+
var operation = (BsonDocument)definition["operation"];
142+
var database = __client.GetDatabase(databaseName);
143+
var collection = database.GetCollection<BsonDocument>(collectionName);
143144

144145
database.DropCollection(collection.CollectionNamespace.CollectionName);
145146
collection.InsertMany(data);
146147

147148
__capturedEvents.Clear();
148149
try
149150
{
150-
ExecuteOperation(database, collection, (BsonDocument)definition["operation"], async);
151+
ExecuteOperation(database, collectionName, operation, definition["async"].AsBoolean);
151152
}
152153
catch (NotImplementedException)
153154
{
@@ -196,13 +197,24 @@ public void RunTestDefinition(IEnumerable<BsonDocument> data, string databaseNam
196197
}
197198
}
198199

200+
private IMongoCollection<BsonDocument> GetCollection(IMongoDatabase database, string collectionName, BsonDocument operation)
201+
{
202+
var collectionSettings = ParseOperationCollectionSettings(operation);
203+
204+
var collection = database.GetCollection<BsonDocument>(
205+
collectionName,
206+
collectionSettings);
207+
208+
return collection;
209+
}
210+
199211
private SemanticVersion GetServerVersion()
200212
{
201213
var server = __client.Cluster.SelectServer(WritableServerSelector.Instance, CancellationToken.None);
202214
return server.Description.Version;
203215
}
204216

205-
private void ExecuteOperation(IMongoDatabase database, IMongoCollection<BsonDocument> collection, BsonDocument operation, bool async)
217+
private void ExecuteOperation(IMongoDatabase database, string collectionName, BsonDocument operation, bool async)
206218
{
207219
var name = (string)operation["name"];
208220
Func<ICrudOperationTest> factory;
@@ -219,9 +231,40 @@ private void ExecuteOperation(IMongoDatabase database, IMongoCollection<BsonDocu
219231
throw new SkipException(reason);
220232
}
221233

234+
var collection = GetCollection(database, collectionName, operation);
222235
test.Execute(__client.Cluster.Description, database, collection, arguments, async);
223236
}
224237

238+
private MongoCollectionSettings ParseCollectionSettings(BsonDocument collectionOptions)
239+
{
240+
var settings = new MongoCollectionSettings();
241+
foreach (var collectionOption in collectionOptions.Elements)
242+
{
243+
switch (collectionOption.Name)
244+
{
245+
case "writeConcern":
246+
settings.WriteConcern = WriteConcern.FromBsonDocument(collectionOption.Value.AsBsonDocument);
247+
break;
248+
default:
249+
throw new FormatException($"Unexpected collection option: {collectionOption.Name}.");
250+
}
251+
}
252+
253+
return settings;
254+
}
255+
256+
private MongoCollectionSettings ParseOperationCollectionSettings(BsonDocument operation)
257+
{
258+
if (operation.TryGetValue("collectionOptions", out var collectionOptions))
259+
{
260+
return ParseCollectionSettings(collectionOptions.AsBsonDocument);
261+
}
262+
else
263+
{
264+
return null;
265+
}
266+
}
267+
225268
private void VerifyCommandStartedEvent(CommandStartedEvent actual, BsonDocument expected, string databaseName, string collectionName)
226269
{
227270
actual.CommandName.Should().Be(expected["command_name"].ToString());
@@ -250,7 +293,7 @@ private void VerifyCommandFailedEvent(CommandFailedEvent actual, BsonDocument ex
250293

251294
private BsonDocument MassageCommand(string commandName, BsonDocument command)
252295
{
253-
var massagedCommand = (BsonDocument)DeepCopy(command);
296+
var massagedCommand = (BsonDocument)command.DeepClone();
254297
switch (commandName)
255298
{
256299
case "delete":
@@ -267,12 +310,6 @@ private BsonDocument MassageCommand(string commandName, BsonDocument command)
267310
break;
268311
case "update":
269312
massagedCommand["ordered"] = massagedCommand.GetValue("ordered", true);
270-
foreach (BsonDocument update in (BsonArray)massagedCommand["updates"])
271-
{
272-
update["multi"] = update.GetValue("multi", false);
273-
update["upsert"] = update.GetValue("upsert", false);
274-
}
275-
276313
break;
277314
}
278315

@@ -284,7 +321,7 @@ private BsonDocument MassageCommand(string commandName, BsonDocument command)
284321

285322
private BsonDocument MassageReply(string commandName, BsonDocument reply, BsonDocument expectedReply)
286323
{
287-
var massagedReply = (BsonDocument)DeepCopy(reply);
324+
var massagedReply = (BsonDocument)reply.DeepClone();
288325
switch (commandName)
289326
{
290327
case "find":
@@ -318,78 +355,25 @@ private BsonDocument MassageReply(string commandName, BsonDocument reply, BsonDo
318355
return massagedReply;
319356
}
320357

321-
private BsonValue DeepCopy(BsonValue value)
358+
// nested types
359+
private class TestCaseFactory : JsonDrivenTestCaseFactory
322360
{
323-
if (value.BsonType == BsonType.Document)
324-
{
325-
var document = new BsonDocument();
326-
foreach (var element in (BsonDocument)value)
327-
{
328-
document.Add(element.Name, DeepCopy(element.Value));
329-
}
330-
331-
return document;
332-
}
333-
else if (value.BsonType == BsonType.Array)
334-
{
335-
var array = new BsonArray();
336-
foreach (var element in (BsonArray)value)
337-
{
338-
array.Add(DeepCopy(element));
339-
}
340-
return array;
341-
}
361+
// protected properties
362+
protected override string PathPrefix => "MongoDB.Driver.Tests.Specifications.command_monitoring.tests.";
342363

343-
return value;
344-
}
345-
346-
private class TestCaseFactory : IEnumerable<object[]>
347-
{
348-
public IEnumerator<object[]> GetEnumerator()
364+
// protected methods
365+
protected override IEnumerable<JsonDrivenTestCase> CreateTestCases(BsonDocument document)
349366
{
350-
const string prefix = "MongoDB.Driver.Tests.Specifications.command_monitoring.tests.";
351-
var testDocuments = typeof(TestCaseFactory).GetTypeInfo().Assembly
352-
.GetManifestResourceNames()
353-
.Where(path => path.StartsWith(prefix) && path.EndsWith(".json"))
354-
.Select(path => ReadDocument(path));
355-
356-
var testCases = new List<object[]>();
357-
foreach (var testDocument in testDocuments)
367+
var testCases = base.CreateTestCases(document);
368+
foreach (var testCase in testCases)
358369
{
359-
var data = testDocument["data"].AsBsonArray.Cast<BsonDocument>().ToList();
360-
var databaseName = testDocument["database_name"].ToString();
361-
var collectionName = testDocument["collection_name"].ToString();
362-
363-
foreach (BsonDocument definition in testDocument["tests"].AsBsonArray)
370+
foreach (var async in new[] { false, true })
364371
{
365-
foreach (var async in new[] { false, true })
366-
{
367-
//var testCase = new TestCaseData(data, databaseName, collectionName, definition, async);
368-
//testCase.SetCategory("Specifications");
369-
//testCase.SetCategory("command-monitoring");
370-
//testCase.SetName($"{definition["description"]}({async})");
371-
var testCase = new object[] { data, databaseName, collectionName, definition, async };
372-
testCases.Add(testCase);
373-
}
372+
var name = $"{testCase.Name}:async={async}";
373+
var test = testCase.Test.DeepClone().AsBsonDocument.Add("async", async);
374+
yield return new JsonDrivenTestCase(name, testCase.Shared, test);
374375
}
375376
}
376-
377-
return testCases.GetEnumerator();
378-
}
379-
380-
IEnumerator IEnumerable.GetEnumerator()
381-
{
382-
return GetEnumerator();
383-
}
384-
385-
private static BsonDocument ReadDocument(string path)
386-
{
387-
using (var definitionStream = typeof(TestCaseFactory).GetTypeInfo().Assembly.GetManifestResourceStream(path))
388-
using (var definitionStringReader = new StreamReader(definitionStream))
389-
{
390-
var definitionString = definitionStringReader.ReadToEnd();
391-
return BsonDocument.Parse(definitionString);
392-
}
393377
}
394378
}
395379
}

0 commit comments

Comments
 (0)