Skip to content

Commit

Permalink
CSHARP-2258: Spec tests should use the same format for bulk writes
Browse files Browse the repository at this point in the history
  • Loading branch information
MikalaiMazurenka committed Dec 9, 2019
1 parent adef3c9 commit 06a2ad3
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 227 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using MongoDB.Bson;

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

protected override void Execute(IMongoCollection<BsonDocument> collection, bool async)
{
var collectionWithWriteConcern = collection.WithWriteConcern(_writeConcern);
if (collection.Settings.WriteConcern == null)
{
collection = collection.WithWriteConcern(WriteConcern.Acknowledged);
}

if (async)
{
collectionWithWriteConcern.BulkWriteAsync(_requests, _options).GetAwaiter().GetResult();
collection.BulkWriteAsync(_requests, _options).GetAwaiter().GetResult();
}
else
{
collectionWithWriteConcern.BulkWrite(_requests, _options);
collection.BulkWrite(_requests, _options);
}
}

Expand All @@ -46,37 +46,58 @@ protected override bool TrySetArgument(string name, BsonValue value)
switch (name)
{
case "requests":
_requests = ParseRequests((BsonArray)value).ToList();
return true;
case "ordered":
_options.IsOrdered = value.ToBoolean();
_requests = ParseRequests(value.AsBsonArray);
return true;
case "writeConcern":
_writeConcern = WriteConcern.FromBsonDocument((BsonDocument)value);
case "options":
_options = ParseOptions(value.AsBsonDocument);
return true;
}

return false;
}

// private methods
private BulkWriteOptions ParseOptions(BsonDocument value)
{
var options = new BulkWriteOptions();

foreach (var option in value.Elements)
{
switch (option.Name)
{
case "ordered":
options.IsOrdered = option.Value.ToBoolean();
break;
default:
throw new FormatException($"Unexpected option: ${option.Name}.");
}
}

return options;
}

private IEnumerable<WriteModel<BsonDocument>> ParseRequests(BsonArray requests)
private List<WriteModel<BsonDocument>> ParseRequests(BsonArray requests)
{
var result = new List<WriteModel<BsonDocument>>();
foreach (BsonDocument request in requests)
{
var element = request.GetElement(0);
switch (element.Name)
var name = request["name"].AsString;
var arguments = request["arguments"].AsBsonDocument;
switch (name)
{
case "deleteOne":
yield return ParseDeleteOne((BsonDocument)element.Value);
result.Add(ParseDeleteOne(arguments));
break;
case "insertOne":
yield return ParseInsertOne((BsonDocument)element.Value);
result.Add(ParseInsertOne(arguments));
break;
case "updateOne":
yield return ParseUpdateOne((BsonDocument)element.Value);
result.Add(ParseUpdateOne(arguments));
break;
}
}

return result;
}

private DeleteOneModel<BsonDocument> ParseDeleteOne(BsonDocument request)
Expand All @@ -98,7 +119,5 @@ private UpdateOneModel<BsonDocument> ParseUpdateOne(BsonDocument request)
model.IsUpsert = request.GetValue("upsert", false).ToBoolean();
return model;
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using FluentAssertions;
using MongoDB.Bson;
using MongoDB.Bson.TestHelpers.JsonDrivenTests;
using MongoDB.Driver.Core;
using MongoDB.Driver.Core.Clusters.ServerSelectors;
using MongoDB.Driver.Core.Events;
Expand All @@ -30,7 +28,7 @@

namespace MongoDB.Driver.Tests.Specifications.command_monitoring
{
public class TestRunner
public class CommandMonitoringTestRunner
{
private static MongoClient __client;
private static EventCapturer __capturedEvents;
Expand All @@ -39,7 +37,7 @@ public class TestRunner
private static bool __oneTimeSetupHasRun = false;
private static object __oneTimeSetupLock = new object();

static TestRunner()
static CommandMonitoringTestRunner()
{
__commandsToCapture = new string[]
{
Expand All @@ -66,7 +64,7 @@ static TestRunner()
};
}

public TestRunner()
public CommandMonitoringTestRunner()
{
lock (__oneTimeSetupLock)
{
Expand Down Expand Up @@ -101,9 +99,9 @@ public bool OneTimeSetup()

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

BsonValue bsonValue;
if (definition.TryGetValue("ignore_if_server_version_greater_than", out bsonValue))
Expand Down Expand Up @@ -136,18 +134,21 @@ public void RunTestDefinition(IEnumerable<BsonDocument> data, string databaseNam
}
}

var database = __client
.GetDatabase(databaseName);
var collection = database
.GetCollection<BsonDocument>(collectionName);
var data = testCase.Shared["data"].AsBsonArray.Cast<BsonDocument>().ToList();
var databaseName = testCase.Shared["database_name"].AsString;
var collectionName = testCase.Shared["collection_name"].AsString;

var operation = (BsonDocument)definition["operation"];
var database = __client.GetDatabase(databaseName);
var collection = database.GetCollection<BsonDocument>(collectionName);

database.DropCollection(collection.CollectionNamespace.CollectionName);
collection.InsertMany(data);

__capturedEvents.Clear();
try
{
ExecuteOperation(database, collection, (BsonDocument)definition["operation"], async);
ExecuteOperation(database, collectionName, operation, definition["async"].AsBoolean);
}
catch (NotImplementedException)
{
Expand Down Expand Up @@ -196,13 +197,24 @@ public void RunTestDefinition(IEnumerable<BsonDocument> data, string databaseNam
}
}

private IMongoCollection<BsonDocument> GetCollection(IMongoDatabase database, string collectionName, BsonDocument operation)
{
var collectionSettings = ParseOperationCollectionSettings(operation);

var collection = database.GetCollection<BsonDocument>(
collectionName,
collectionSettings);

return collection;
}

private SemanticVersion GetServerVersion()
{
var server = __client.Cluster.SelectServer(WritableServerSelector.Instance, CancellationToken.None);
return server.Description.Version;
}

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

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

private MongoCollectionSettings ParseCollectionSettings(BsonDocument collectionOptions)
{
var settings = new MongoCollectionSettings();
foreach (var collectionOption in collectionOptions.Elements)
{
switch (collectionOption.Name)
{
case "writeConcern":
settings.WriteConcern = WriteConcern.FromBsonDocument(collectionOption.Value.AsBsonDocument);
break;
default:
throw new FormatException($"Unexpected collection option: {collectionOption.Name}.");
}
}

return settings;
}

private MongoCollectionSettings ParseOperationCollectionSettings(BsonDocument operation)
{
if (operation.TryGetValue("collectionOptions", out var collectionOptions))
{
return ParseCollectionSettings(collectionOptions.AsBsonDocument);
}
else
{
return null;
}
}

private void VerifyCommandStartedEvent(CommandStartedEvent actual, BsonDocument expected, string databaseName, string collectionName)
{
actual.CommandName.Should().Be(expected["command_name"].ToString());
Expand Down Expand Up @@ -250,7 +293,7 @@ private void VerifyCommandFailedEvent(CommandFailedEvent actual, BsonDocument ex

private BsonDocument MassageCommand(string commandName, BsonDocument command)
{
var massagedCommand = (BsonDocument)DeepCopy(command);
var massagedCommand = (BsonDocument)command.DeepClone();
switch (commandName)
{
case "delete":
Expand All @@ -267,12 +310,6 @@ private BsonDocument MassageCommand(string commandName, BsonDocument command)
break;
case "update":
massagedCommand["ordered"] = massagedCommand.GetValue("ordered", true);
foreach (BsonDocument update in (BsonArray)massagedCommand["updates"])
{
update["multi"] = update.GetValue("multi", false);
update["upsert"] = update.GetValue("upsert", false);
}

break;
}

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

private BsonDocument MassageReply(string commandName, BsonDocument reply, BsonDocument expectedReply)
{
var massagedReply = (BsonDocument)DeepCopy(reply);
var massagedReply = (BsonDocument)reply.DeepClone();
switch (commandName)
{
case "find":
Expand Down Expand Up @@ -318,78 +355,25 @@ private BsonDocument MassageReply(string commandName, BsonDocument reply, BsonDo
return massagedReply;
}

private BsonValue DeepCopy(BsonValue value)
// nested types
private class TestCaseFactory : JsonDrivenTestCaseFactory
{
if (value.BsonType == BsonType.Document)
{
var document = new BsonDocument();
foreach (var element in (BsonDocument)value)
{
document.Add(element.Name, DeepCopy(element.Value));
}

return document;
}
else if (value.BsonType == BsonType.Array)
{
var array = new BsonArray();
foreach (var element in (BsonArray)value)
{
array.Add(DeepCopy(element));
}
return array;
}
// protected properties
protected override string PathPrefix => "MongoDB.Driver.Tests.Specifications.command_monitoring.tests.";

return value;
}

private class TestCaseFactory : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
// protected methods
protected override IEnumerable<JsonDrivenTestCase> CreateTestCases(BsonDocument document)
{
const string prefix = "MongoDB.Driver.Tests.Specifications.command_monitoring.tests.";
var testDocuments = typeof(TestCaseFactory).GetTypeInfo().Assembly
.GetManifestResourceNames()
.Where(path => path.StartsWith(prefix) && path.EndsWith(".json"))
.Select(path => ReadDocument(path));

var testCases = new List<object[]>();
foreach (var testDocument in testDocuments)
var testCases = base.CreateTestCases(document);
foreach (var testCase in testCases)
{
var data = testDocument["data"].AsBsonArray.Cast<BsonDocument>().ToList();
var databaseName = testDocument["database_name"].ToString();
var collectionName = testDocument["collection_name"].ToString();

foreach (BsonDocument definition in testDocument["tests"].AsBsonArray)
foreach (var async in new[] { false, true })
{
foreach (var async in new[] { false, true })
{
//var testCase = new TestCaseData(data, databaseName, collectionName, definition, async);
//testCase.SetCategory("Specifications");
//testCase.SetCategory("command-monitoring");
//testCase.SetName($"{definition["description"]}({async})");
var testCase = new object[] { data, databaseName, collectionName, definition, async };
testCases.Add(testCase);
}
var name = $"{testCase.Name}:async={async}";
var test = testCase.Test.DeepClone().AsBsonDocument.Add("async", async);
yield return new JsonDrivenTestCase(name, testCase.Shared, test);
}
}

return testCases.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

private static BsonDocument ReadDocument(string path)
{
using (var definitionStream = typeof(TestCaseFactory).GetTypeInfo().Assembly.GetManifestResourceStream(path))
using (var definitionStringReader = new StreamReader(definitionStream))
{
var definitionString = definitionStringReader.ReadToEnd();
return BsonDocument.Parse(definitionString);
}
}
}
}
Expand Down
Loading

0 comments on commit 06a2ad3

Please sign in to comment.