You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1045 lines
40 KiB

/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using System.Threading;
using FluentAssertions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Bson.TestHelpers.XunitExtensions;
using MongoDB.Driver.Core.Bindings;
using MongoDB.Driver.Core.Clusters;
using MongoDB.Driver.Core.Operations;
using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
using MongoDB.Driver.Tests;
using Moq;
using Xunit;
namespace MongoDB.Driver
{
public class MongoDatabaseImplTests
{
private MockOperationExecutor _operationExecutor;
private MongoDatabaseImpl _subject;
public MongoDatabaseImplTests()
{
_operationExecutor = new MockOperationExecutor();
_subject = CreateSubject(_operationExecutor);
_operationExecutor.Client = _subject.Client;
}
[Fact]
public void Client_should_be_set()
{
_subject.Client.Should().NotBeNull();
}
[Fact]
public void DatabaseName_should_be_set()
{
_subject.DatabaseNamespace.DatabaseName.Should().Be("foo");
}
[Fact]
public void Settings_should_be_set()
{
_subject.Settings.Should().NotBeNull();
}
[Theory]
[ParameterAttributeData]
public void CreateCollection_should_execute_a_CreateCollectionOperation_when_options_is_generic(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var writeConcern = new WriteConcern(1);
var subject = _subject.WithWriteConcern(writeConcern);
var session = CreateSession(usingSession);
var name = "bar";
var storageEngine = new BsonDocument("awesome", true);
var validatorDocument = BsonDocument.Parse("{ x : 1 }");
var validatorDefinition = (FilterDefinition<BsonDocument>)validatorDocument;
#pragma warning disable 618
var options = new CreateCollectionOptions<BsonDocument>
{
AutoIndexId = false,
Capped = true,
Collation = new Collation("en_US"),
IndexOptionDefaults = new IndexOptionDefaults { StorageEngine = new BsonDocument("x", 1) },
MaxDocuments = 10,
MaxSize = 11,
NoPadding = true,
StorageEngine = storageEngine,
UsePowerOf2Sizes = true,
ValidationAction = DocumentValidationAction.Warn,
ValidationLevel = DocumentValidationLevel.Off,
Validator = validatorDefinition
};
#pragma warning restore
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
subject.CreateCollectionAsync(session, name, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateCollection(session, name, options, cancellationToken);
}
}
else
{
if (async)
{
subject.CreateCollectionAsync(name, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateCollection(name, options, cancellationToken);
}
}
var call = _operationExecutor.GetWriteCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<CreateCollectionOperation>().Subject;
op.CollectionNamespace.Should().Be(new CollectionNamespace(_subject.DatabaseNamespace, name));
#pragma warning disable 618
op.AutoIndexId.Should().Be(options.AutoIndexId);
#pragma warning restore
op.Capped.Should().Be(options.Capped);
op.Collation.Should().BeSameAs(options.Collation);
op.IndexOptionDefaults.ToBsonDocument().Should().Be(options.IndexOptionDefaults.ToBsonDocument());
op.MaxDocuments.Should().Be(options.MaxDocuments);
op.MaxSize.Should().Be(options.MaxSize);
op.NoPadding.Should().Be(options.NoPadding);
op.StorageEngine.Should().Be(storageEngine);
op.UsePowerOf2Sizes.Should().Be(options.UsePowerOf2Sizes);
op.ValidationAction.Should().Be(options.ValidationAction);
op.ValidationLevel.Should().Be(options.ValidationLevel);
op.Validator.Should().Be(validatorDocument);
op.WriteConcern.Should().BeSameAs(writeConcern);
}
[Theory]
[ParameterAttributeData]
public void CreateCollection_should_execute_a_CreateCollectionOperation_when_options_is_not_generic(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var writeConcern = new WriteConcern(1);
var subject = _subject.WithWriteConcern(writeConcern);
var session = CreateSession(usingSession);
var name = "bar";
var storageEngine = new BsonDocument("awesome", true);
#pragma warning disable 618
var options = new CreateCollectionOptions
{
AutoIndexId = false,
Capped = true,
Collation = new Collation("en_US"),
IndexOptionDefaults = new IndexOptionDefaults { StorageEngine = new BsonDocument("x", 1) },
MaxDocuments = 10,
MaxSize = 11,
NoPadding = true,
StorageEngine = storageEngine,
UsePowerOf2Sizes = true,
ValidationAction = DocumentValidationAction.Warn,
ValidationLevel = DocumentValidationLevel.Off
};
#pragma warning restore
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
subject.CreateCollectionAsync(session, name, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateCollection(session, name, options, cancellationToken);
}
}
else
{
if (async)
{
subject.CreateCollectionAsync(name, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateCollection(name, options, cancellationToken);
}
}
var call = _operationExecutor.GetWriteCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<CreateCollectionOperation>().Subject;
op.CollectionNamespace.Should().Be(new CollectionNamespace(_subject.DatabaseNamespace, name));
#pragma warning disable 618
op.AutoIndexId.Should().Be(options.AutoIndexId);
#pragma warning restore
op.Capped.Should().Be(options.Capped);
op.Collation.Should().BeSameAs(options.Collation);
op.IndexOptionDefaults.ToBsonDocument().Should().Be(options.IndexOptionDefaults.ToBsonDocument());
op.MaxDocuments.Should().Be(options.MaxDocuments);
op.MaxSize.Should().Be(options.MaxSize);
op.NoPadding.Should().Be(options.NoPadding);
op.StorageEngine.Should().Be(storageEngine);
op.UsePowerOf2Sizes.Should().Be(options.UsePowerOf2Sizes);
op.ValidationAction.Should().Be(options.ValidationAction);
op.ValidationLevel.Should().Be(options.ValidationLevel);
op.Validator.Should().BeNull();
}
[Theory]
[ParameterAttributeData]
public void CreateCollection_should_execute_a_CreateCollectionOperation_when_options_is_null(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var writeConcern = new WriteConcern(1);
var subject = _subject.WithWriteConcern(writeConcern);
var session = CreateSession(usingSession);
var name = "bar";
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
subject.CreateCollectionAsync(session, name, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateCollection(session, name, null, cancellationToken);
}
}
else
{
if (async)
{
subject.CreateCollectionAsync(name, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateCollection(name, null, cancellationToken);
}
}
var call = _operationExecutor.GetWriteCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<CreateCollectionOperation>().Subject;
op.CollectionNamespace.Should().Be(new CollectionNamespace(_subject.DatabaseNamespace, name));
#pragma warning disable 618
op.AutoIndexId.Should().NotHaveValue();
#pragma warning restore
op.Capped.Should().NotHaveValue();
op.IndexOptionDefaults.Should().BeNull();
op.MaxDocuments.Should().NotHaveValue();
op.MaxSize.Should().NotHaveValue();
op.NoPadding.Should().NotHaveValue();
op.StorageEngine.Should().BeNull();
op.UsePowerOf2Sizes.Should().NotHaveValue();
op.ValidationAction.Should().BeNull();
op.ValidationLevel.Should().BeNull();
op.Validator.Should().BeNull();
op.WriteConcern.Should().BeSameAs(writeConcern);
}
[Theory]
[ParameterAttributeData]
public void CreateView_should_execute_a_CreateViewOperation(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var writeConcern = new WriteConcern(1);
var subject = _subject.WithWriteConcern(writeConcern);
var session = CreateSession(usingSession);
var viewName = "view";
var viewOn = "on";
var pipelineDocuments = new[] { BsonDocument.Parse("{ a : 1 }") };
var pipelineDefinition = (PipelineDefinition<BsonDocument, BsonDocument>)pipelineDocuments;
var collation = new Collation("en-us");
var options = new CreateViewOptions<BsonDocument>
{
Collation = collation,
DocumentSerializer = BsonDocumentSerializer.Instance,
SerializerRegistry = BsonSerializer.SerializerRegistry
};
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
subject.CreateViewAsync(session, viewName, viewOn, pipelineDefinition, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateView(session, viewName, viewOn, pipelineDefinition, options, cancellationToken);
}
}
else
{
if (async)
{
subject.CreateViewAsync(viewName, viewOn, pipelineDefinition, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.CreateView(viewName, viewOn, pipelineDefinition, options, cancellationToken);
}
}
var call = _operationExecutor.GetWriteCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var operation = call.Operation.Should().BeOfType<CreateViewOperation>().Subject;
operation.Collation.Should().Be(collation);
operation.DatabaseNamespace.Should().Be(subject.DatabaseNamespace);
operation.Pipeline.Should().Equal(pipelineDocuments);
operation.ViewName.Should().Be(viewName);
operation.ViewOn.Should().Be(viewOn);
operation.WriteConcern.Should().Be(writeConcern);
}
[Theory]
[ParameterAttributeData]
public void CreateView_should_throw_when_viewName_is_null(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var pipeline = new EmptyPipelineDefinition<BsonDocument>();
var exception = Record.Exception(() =>
{
if(usingSession)
{
if (async)
{
_subject.CreateViewAsync(session, null, "viewOn", pipeline).GetAwaiter().GetResult();
}
else
{
_subject.CreateView(session, null, "viewOn", pipeline);
}
}
else
{
if (async)
{
_subject.CreateViewAsync(null, "viewOn", pipeline).GetAwaiter().GetResult();
}
else
{
_subject.CreateView(null, "viewOn", pipeline);
}
}
});
var argumentNullException = exception.Should().BeOfType<ArgumentNullException>().Subject;
argumentNullException.ParamName.Should().Be("viewName");
}
[Theory]
[ParameterAttributeData]
public void CreateView_should_throw_when_viewOn_is_null(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var pipeline = new EmptyPipelineDefinition<BsonDocument>();
var exception = Record.Exception(() =>
{
if (usingSession)
{
if (async)
{
_subject.CreateViewAsync(session, "viewName", null, pipeline).GetAwaiter().GetResult();
}
else
{
_subject.CreateView(session, "viewName", null, pipeline);
}
}
else
{
if (async)
{
_subject.CreateViewAsync("viewName", null, pipeline).GetAwaiter().GetResult();
}
else
{
_subject.CreateView("viewName", null, pipeline);
}
}
});
var argumentNullException = exception.Should().BeOfType<ArgumentNullException>().Subject;
argumentNullException.ParamName.Should().Be("viewOn");
}
[Theory]
[ParameterAttributeData]
public void CreateView_should_throw_when_pipeline_is_null(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var exception = Record.Exception(() =>
{
if (usingSession)
{
if (async)
{
_subject.CreateViewAsync<BsonDocument, BsonDocument>(session, "viewName", "viewOn", null).GetAwaiter().GetResult();
}
else
{
_subject.CreateView<BsonDocument, BsonDocument>(session, "viewName", "viewOn", null);
}
}
else
{
if (async)
{
_subject.CreateViewAsync<BsonDocument, BsonDocument>("viewName", "viewOn", null).GetAwaiter().GetResult();
}
else
{
_subject.CreateView<BsonDocument, BsonDocument>("viewName", "viewOn", null);
}
}
});
var argumentNullException = exception.Should().BeOfType<ArgumentNullException>().Subject;
argumentNullException.ParamName.Should().Be("pipeline");
}
[Theory]
[ParameterAttributeData]
public void DropCollection_should_execute_a_DropCollectionOperation(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var writeConcern = new WriteConcern(1);
var subject = _subject.WithWriteConcern(writeConcern);
var session = CreateSession(usingSession);
var name = "bar";
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
subject.DropCollectionAsync(session, name, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.DropCollection(session, name, cancellationToken);
}
}
else
{
if (async)
{
subject.DropCollectionAsync(name, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.DropCollection(name, cancellationToken);
}
}
var call = _operationExecutor.GetWriteCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<DropCollectionOperation>().Subject;
op.CollectionNamespace.Should().Be(new CollectionNamespace(subject.DatabaseNamespace, name));
op.WriteConcern.Should().BeSameAs(writeConcern);
}
[Theory]
[ParameterAttributeData]
public void ListCollectionNames_should_execute_a_ListCollectionsOperation(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool usingOptions,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var filterDocument = BsonDocument.Parse("{ name : \"awesome\" }");
var filterDefinition = (FilterDefinition<BsonDocument>)filterDocument;
ListCollectionNamesOptions options = null;
if (usingOptions)
{
options = new ListCollectionNamesOptions
{
Filter = filterDefinition
};
}
var cancellationToken = new CancellationTokenSource().Token;
var mockCursor = new Mock<IAsyncCursor<BsonDocument>>();
_operationExecutor.EnqueueResult<IAsyncCursor<BsonDocument>>(mockCursor.Object);
if (usingSession)
{
if (async)
{
_subject.ListCollectionNamesAsync(session, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.ListCollectionNames(session, options, cancellationToken);
}
}
else
{
if (async)
{
_subject.ListCollectionNamesAsync(options, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.ListCollectionNames(options, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<IAsyncCursor<BsonDocument>>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<ListCollectionsOperation>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.NameOnly.Should().BeTrue();
if (usingOptions)
{
op.Filter.Should().Be(filterDocument);
}
else
{
op.Filter.Should().BeNull();
}
}
[SkippableTheory]
[ParameterAttributeData]
public void ListCollectionNames_should_return_expected_result(
[Values(0, 1, 2, 10)] int numberOfCollections,
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
RequireServer.Check();
var collectionNames = Enumerable.Range(1, numberOfCollections).Select(n => $"c{n}").ToArray();
var client = DriverTestConfiguration.Client;
var database = client.GetDatabase("ListCollectionNames-test");
client.DropDatabase(database.DatabaseNamespace.DatabaseName);
foreach (var collectionName in collectionNames)
{
database.CreateCollection(collectionName);
}
using (var session = usingSession ? client.StartSession() : null)
{
IAsyncCursor<string> cursor;
if (usingSession)
{
if (async)
{
cursor = database.ListCollectionNamesAsync(session).GetAwaiter().GetResult();
}
else
{
cursor = database.ListCollectionNames(session);
}
}
else
{
if (async)
{
cursor = database.ListCollectionNamesAsync().GetAwaiter().GetResult();
}
else
{
cursor = database.ListCollectionNames();
}
}
var actualCollectionNames = cursor.ToList();
actualCollectionNames.Should().BeEquivalentTo(collectionNames);
}
}
[Theory]
[ParameterAttributeData]
public void ListCollections_should_execute_a_ListCollectionsOperation(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool usingOptions,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var filterDocument = BsonDocument.Parse("{ name : \"awesome\" }");
var filterDefinition = (FilterDefinition<BsonDocument>)filterDocument;
ListCollectionsOptions options = null;
if (usingOptions)
{
options = new ListCollectionsOptions
{
Filter = filterDefinition
};
}
var cancellationToken = new CancellationTokenSource().Token;
var mockCursor = new Mock<IAsyncCursor<BsonDocument>>();
_operationExecutor.EnqueueResult<IAsyncCursor<BsonDocument>>(mockCursor.Object);
if (usingSession)
{
if (async)
{
_subject.ListCollectionsAsync(session, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.ListCollections(session, options, cancellationToken);
}
}
else
{
if (async)
{
_subject.ListCollectionsAsync(options, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.ListCollections(options, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<IAsyncCursor<BsonDocument>>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<ListCollectionsOperation>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.NameOnly.Should().NotHaveValue();
if (usingOptions)
{
op.Filter.Should().Be(filterDocument);
}
else
{
op.Filter.Should().BeNull();
}
}
[Theory]
[ParameterAttributeData]
public void RenameCollection_should_execute_a_RenameCollectionOperation(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var writeConcern = new WriteConcern(1);
var subject = _subject.WithWriteConcern(writeConcern);
var session = CreateSession(usingSession);
var oldName = "bar";
var newName = "baz";
var options = new RenameCollectionOptions
{
DropTarget = true,
};
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
subject.RenameCollectionAsync(session, oldName, newName, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.RenameCollection(session, oldName, newName, options, cancellationToken);
}
}
else
{
if (async)
{
subject.RenameCollectionAsync(oldName, newName, options, cancellationToken).GetAwaiter().GetResult();
}
else
{
subject.RenameCollection(oldName, newName, options, cancellationToken);
}
}
var call = _operationExecutor.GetWriteCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var op = call.Operation.Should().BeOfType<RenameCollectionOperation>().Subject;
op.CollectionNamespace.Should().Be(new CollectionNamespace(_subject.DatabaseNamespace, oldName));
op.NewCollectionNamespace.Should().Be(new CollectionNamespace(_subject.DatabaseNamespace, newName));
op.DropTarget.Should().Be(options.DropTarget);
op.WriteConcern.Should().BeSameAs(writeConcern);
}
[Theory]
[ParameterAttributeData]
public void RunCommand_should_default_to_ReadPreference_primary(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var commandDocument = BsonDocument.Parse("{ count : \"foo\" }");
var command = (Command<BsonDocument>)commandDocument;
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
_subject.RunCommandAsync(session, command, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(session, command, null, cancellationToken);
}
}
else
{
if (async)
{
_subject.RunCommandAsync(command, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(command, null, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var binding = call.Binding.Should().BeOfType<ReadBindingHandle>().Subject;
binding.ReadPreference.Should().Be(ReadPreference.Primary);
var op = call.Operation.Should().BeOfType<ReadCommandOperation<BsonDocument>>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.Command.Should().Be(commandDocument);
}
[Theory]
[ParameterAttributeData]
public void RunCommand_should_use_the_provided_ReadPreference(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var commandDocument = new BsonDocument("count", "foo");
var command = (Command<BsonDocument>)commandDocument;
var readPreference = ReadPreference.Secondary;
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
_subject.RunCommandAsync(session, command, readPreference, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(session, command, readPreference, cancellationToken);
}
}
else
{
if (async)
{
_subject.RunCommandAsync(command, readPreference, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(command, readPreference, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var binding = call.Binding.Should().BeOfType<ReadBindingHandle>().Subject;
binding.ReadPreference.Should().Be(readPreference);
var op = call.Operation.Should().BeOfType<ReadCommandOperation<BsonDocument>>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.Command.Should().Be(commandDocument);
}
[Theory]
[ParameterAttributeData]
public void RunCommand_should_run_a_non_read_command(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var commandDocument = new BsonDocument("shutdown", 1);
var command = (Command<BsonDocument>)commandDocument;
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
_subject.RunCommandAsync(session, command, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(session, command, null, cancellationToken);
}
}
else
{
if (async)
{
_subject.RunCommandAsync(command, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(command, null, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var binding = call.Binding.Should().BeOfType<ReadBindingHandle>().Subject;
binding.ReadPreference.Should().Be(ReadPreference.Primary);
var op = call.Operation.Should().BeOfType<ReadCommandOperation<BsonDocument>>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.Command.Should().Be(commandDocument);
}
[Theory]
[ParameterAttributeData]
public void RunCommand_should_run_a_json_command(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var commandJson = "{ count : \"foo\" }";
var commandDocument = BsonDocument.Parse(commandJson);
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
_subject.RunCommandAsync<BsonDocument>(session, commandJson, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand<BsonDocument>(session, commandJson, null, cancellationToken);
}
}
else
{
if (async)
{
_subject.RunCommandAsync<BsonDocument>(commandJson, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand<BsonDocument>(commandJson, null, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var binding = call.Binding.Should().BeOfType<ReadBindingHandle>().Subject;
binding.ReadPreference.Should().Be(ReadPreference.Primary);
var op = call.Operation.Should().BeOfType<ReadCommandOperation<BsonDocument>>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.Command.Should().Be(commandDocument);
}
[Theory]
[ParameterAttributeData]
public void RunCommand_should_run_a_serialized_command(
[Values(false, true)] bool usingSession,
[Values(false, true)] bool async)
{
var session = CreateSession(usingSession);
var commandObject = new CountCommand { Collection = "foo" };
var command = new ObjectCommand<BsonDocument>(commandObject);
var cancellationToken = new CancellationTokenSource().Token;
if (usingSession)
{
if (async)
{
_subject.RunCommandAsync(session, command, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(session, command, null, cancellationToken);
}
}
else
{
if (async)
{
_subject.RunCommandAsync(command, null, cancellationToken).GetAwaiter().GetResult();
}
else
{
_subject.RunCommand(command, null, cancellationToken);
}
}
var call = _operationExecutor.GetReadCall<BsonDocument>();
VerifySessionAndCancellationToken(call, session, cancellationToken);
var binding = call.Binding.Should().BeOfType<ReadBindingHandle>().Subject;
binding.ReadPreference.Should().Be(ReadPreference.Primary);
var op = call.Operation.Should().BeOfType<ReadCommandOperation<BsonDocument>>().Subject;
op.DatabaseNamespace.Should().Be(_subject.DatabaseNamespace);
op.Command.Should().Be("{ count : \"foo\" }");
}
[Fact]
public void WithReadConcern_should_return_expected_result()
{
var originalReadConcern = new ReadConcern(ReadConcernLevel.Linearizable);
var subject = CreateSubject(_operationExecutor).WithReadConcern(originalReadConcern);
var newReadConcern = new ReadConcern(ReadConcernLevel.Majority);
var result = subject.WithReadConcern(newReadConcern);
subject.Settings.ReadConcern.Should().BeSameAs(originalReadConcern);
result.Settings.ReadConcern.Should().BeSameAs(newReadConcern);
result.WithReadConcern(originalReadConcern).Settings.Should().Be(subject.Settings);
}
[Fact]
public void WithReadPreference_should_return_expected_result()
{
var originalReadPreference = new ReadPreference(ReadPreferenceMode.Secondary);
var subject = CreateSubject(_operationExecutor).WithReadPreference(originalReadPreference);
var newReadPreference = new ReadPreference(ReadPreferenceMode.SecondaryPreferred);
var result = subject.WithReadPreference(newReadPreference);
subject.Settings.ReadPreference.Should().BeSameAs(originalReadPreference);
result.Settings.ReadPreference.Should().BeSameAs(newReadPreference);
result.WithReadPreference(originalReadPreference).Settings.Should().Be(subject.Settings);
}
[Fact]
public void WithWriteConcern_should_return_expected_result()
{
var originalWriteConcern = new WriteConcern(2);
var subject = CreateSubject(_operationExecutor).WithWriteConcern(originalWriteConcern);
var newWriteConcern = new WriteConcern(3);
var result = subject.WithWriteConcern(newWriteConcern);
subject.Settings.WriteConcern.Should().BeSameAs(originalWriteConcern);
result.Settings.WriteConcern.Should().BeSameAs(newWriteConcern);
result.WithWriteConcern(originalWriteConcern).Settings.Should().Be(subject.Settings);
}
// private methods
private IClientSessionHandle CreateSession(bool usingSession)
{
if (usingSession)
{
var client = new Mock<IMongoClient>().Object;
var cluster = Mock.Of<ICluster>();
var options = new ClientSessionOptions();
var coreServerSession = new CoreServerSession();
var coreSession = new CoreSession(cluster, coreServerSession, options.ToCore());
var coreSessionHandle = new CoreSessionHandle(coreSession);
return new ClientSessionHandle(client, options, coreSessionHandle);
}
else
{
return null;
}
}
private MongoDatabaseImpl CreateSubject(IOperationExecutor operationExecutor)
{
var mockClient = new Mock<IMongoClient>();
var mockCluster = new Mock<ICluster>();
mockClient.SetupGet(m => m.Cluster).Returns(mockCluster.Object);
var settings = new MongoDatabaseSettings();
settings.ApplyDefaultValues(new MongoClientSettings());
return new MongoDatabaseImpl(
mockClient.Object,
new DatabaseNamespace("foo"),
settings,
new Mock<ICluster>().Object,
_operationExecutor);
}
private static void VerifySessionAndCancellationToken<TDocument>(MockOperationExecutor.ReadCall<TDocument> call, IClientSessionHandle session, CancellationToken cancellationToken)
{
call.CancellationToken.Should().Be(cancellationToken);
if (session == null)
{
call.UsedImplicitSession.Should().BeTrue();
}
else
{
call.SessionId.Should().Be(session.ServerSession.Id);
}
}
private static void VerifySessionAndCancellationToken<TDocument>(MockOperationExecutor.WriteCall<TDocument> call, IClientSessionHandle session, CancellationToken cancellationToken)
{
call.CancellationToken.Should().Be(cancellationToken);
if (session == null)
{
call.UsedImplicitSession.Should().BeTrue();
}
else
{
call.SessionId.Should().Be(session.ServerSession.Id);
}
}
private class CountCommand
{
[BsonElement("count")]
public string Collection;
}
}
}