Skip to content

Commit 6157640

Browse files
committed
CSHARP-1438, CSHARP-1436: implemented read and write concern specification.
1 parent 592b4ff commit 6157640

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1948
-93
lines changed

Diff for: src/MongoDB.Driver.Core.Tests/Core/Configuration/ConnectionStringTests.cs

+13
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ public void When_nothing_is_specified(string connectionString)
156156
subject.MaxPoolSize.Should().Be(null);
157157
subject.MinPoolSize.Should().Be(null);
158158
subject.Password.Should().BeNull();
159+
subject.ReadConcernLevel.Should().BeNull();
159160
subject.ReadPreference.Should().BeNull();
160161
subject.ReadPreferenceTags.Should().BeNull();
161162
subject.ReplicaSet.Should().BeNull();
@@ -188,6 +189,7 @@ public void When_everything_is_specified()
188189
"maxLifeTime=5ms;" +
189190
"maxPoolSize=20;" +
190191
"minPoolSize=15;" +
192+
"readConcernLevel=majority;" +
191193
"readPreference=primary;" +
192194
"readPreferenceTags=dc:1;" +
193195
"replicaSet=funny;" +
@@ -219,6 +221,7 @@ public void When_everything_is_specified()
219221
subject.MaxPoolSize.Should().Be(20);
220222
subject.MinPoolSize.Should().Be(15);
221223
subject.Password.Should().Be("pass");
224+
subject.ReadConcernLevel.Should().Be(ReadConcernLevel.Majority);
222225
subject.ReadPreference.Should().Be(ReadPreferenceMode.Primary);
223226
subject.ReadPreferenceTags.Single().Should().Be(new TagSet(new[] { new Tag("dc", "1") }));
224227
subject.ReplicaSet.Should().Be("funny");
@@ -410,6 +413,16 @@ public void When_password_is_specified(string connectionString, string password)
410413
subject.Password.Should().Be(password);
411414
}
412415

416+
[Test]
417+
[TestCase("mongodb://localhost?readConcernLevel=local", ReadConcernLevel.Local)]
418+
[TestCase("mongodb://localhost?readConcernLevel=majority", ReadConcernLevel.Majority)]
419+
public void When_readConcernLevel_is_specified(string connectionString, ReadConcernLevel readConcernLevel)
420+
{
421+
var subject = new ConnectionString(connectionString);
422+
423+
subject.ReadConcernLevel.Should().Be(readConcernLevel);
424+
}
425+
413426
[Test]
414427
[TestCase("mongodb://localhost?readPreference=primary", ReadPreferenceMode.Primary)]
415428
[TestCase("mongodb://localhost?readPreference=primaryPreferred", ReadPreferenceMode.PrimaryPreferred)]

Diff for: src/MongoDB.Driver.Core.Tests/Core/Operations/AggregateOperationTests.cs

+18-4
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,11 @@ public void UseCursor_should_have_the_correct_value()
120120

121121
[Test]
122122
public void CreateCommand_should_create_the_correct_command(
123-
[Values("2.4.0", "2.6.0", "2.8.0")] string serverVersion,
123+
[Values("2.4.0", "2.6.0", "2.8.0", "3.0.0", "3.2.0")] string serverVersion,
124124
[Values(null, false, true)] bool? allowDiskUse,
125125
[Values(null, 10, 20)] int? batchSize,
126126
[Values(null, 2000)] int? maxTime,
127+
[Values(null, ReadConcernLevel.Local, ReadConcernLevel.Majority)] ReadConcernLevel? readConcernLevel,
127128
[Values(null, false, true)] bool? useCursor)
128129
{
129130
var semanticServerVersion = SemanticVersion.Parse(serverVersion);
@@ -132,6 +133,7 @@ public void CreateCommand_should_create_the_correct_command(
132133
AllowDiskUse = allowDiskUse,
133134
BatchSize = batchSize,
134135
MaxTime = maxTime.HasValue ? TimeSpan.FromMilliseconds(maxTime.Value) : (TimeSpan?)null,
136+
ReadConcern = new ReadConcern(readConcernLevel),
135137
UseCursor = useCursor
136138
};
137139

@@ -143,6 +145,11 @@ public void CreateCommand_should_create_the_correct_command(
143145
{ "maxTimeMS", () => maxTime.Value, maxTime.HasValue }
144146
};
145147

148+
if (subject.ReadConcern.ShouldBeSent(semanticServerVersion))
149+
{
150+
expectedResult["readConcern"] = subject.ReadConcern.ToBsonDocument();
151+
}
152+
146153
if (semanticServerVersion >= new SemanticVersion(2, 6, 0) && useCursor.GetValueOrDefault(true))
147154
{
148155
expectedResult["cursor"] = new BsonDocument
@@ -151,9 +158,16 @@ public void CreateCommand_should_create_the_correct_command(
151158
};
152159
}
153160

154-
var result = subject.CreateCommand(semanticServerVersion);
155-
156-
result.Should().Be(expectedResult);
161+
if (semanticServerVersion < new SemanticVersion(3, 2, 0) && subject.ReadConcern.Level.GetValueOrDefault(ReadConcernLevel.Local) != ReadConcernLevel.Local)
162+
{
163+
Action act = () => subject.CreateCommand(semanticServerVersion);
164+
act.ShouldThrow<MongoClientException>();
165+
}
166+
else
167+
{
168+
var result = subject.CreateCommand(semanticServerVersion);
169+
result.Should().Be(expectedResult);
170+
}
157171
}
158172

159173
[Test]

Diff for: src/MongoDB.Driver.Core.Tests/Core/Operations/CountOperationTests.cs

+18-3
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ public void Constructor_should_throw_when_message_encoder_settings_is_null()
4444
}
4545

4646
[Test]
47-
public void CreateCommand_should_create_the_correct_command()
47+
public void CreateCommand_should_create_the_correct_command(
48+
[Values("3.0.0", "3.2.0")] string serverVersion,
49+
[Values(null, ReadConcernLevel.Local, ReadConcernLevel.Majority)] ReadConcernLevel? readConcernLevel)
4850
{
51+
var semanticServerVersion = SemanticVersion.Parse(serverVersion);
4952
var filter = new BsonDocument("x", 1);
5053
var hint = "funny";
5154
var limit = 10;
@@ -69,9 +72,21 @@ public void CreateCommand_should_create_the_correct_command()
6972
{ "maxTimeMS", maxTime.TotalMilliseconds }
7073
};
7174

72-
var result = subject.CreateCommand();
75+
if (subject.ReadConcern.ShouldBeSent(semanticServerVersion))
76+
{
77+
expectedResult["readConcern"] = subject.ReadConcern.ToBsonDocument();
78+
}
7379

74-
result.Should().Be(expectedResult);
80+
if (semanticServerVersion < new SemanticVersion(3, 2, 0) && subject.ReadConcern.Level.GetValueOrDefault(ReadConcernLevel.Local) != ReadConcernLevel.Local)
81+
{
82+
Action act = () => subject.CreateCommand(semanticServerVersion);
83+
act.ShouldThrow<MongoClientException>();
84+
}
85+
else
86+
{
87+
var result = subject.CreateCommand(semanticServerVersion);
88+
result.Should().Be(expectedResult);
89+
}
7590
}
7691

7792
[Test]

Diff for: src/MongoDB.Driver.Core.Tests/Core/Operations/DistinctOperationTests.cs

+21-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using MongoDB.Bson;
2020
using MongoDB.Bson.Serialization;
2121
using MongoDB.Bson.Serialization.Serializers;
22+
using MongoDB.Driver.Core.Misc;
2223
using NUnit.Framework;
2324

2425
namespace MongoDB.Driver.Core.Operations
@@ -70,12 +71,16 @@ public void Constructor_should_throw_when_message_encoder_settings_is_null()
7071
}
7172

7273
[Test]
73-
public void CreateCommand_should_create_the_correct_command()
74+
public void CreateCommand_should_create_the_correct_command(
75+
[Values("3.0.0", "3.2.0")] string serverVersion,
76+
[Values(null, ReadConcernLevel.Local, ReadConcernLevel.Majority)] ReadConcernLevel? readConcernLevel)
7477
{
78+
var semanticServerVersion = SemanticVersion.Parse(serverVersion);
7579
var subject = new DistinctOperation<int>(_collectionNamespace, _valueSerializer, _fieldName, _messageEncoderSettings)
7680
{
7781
Filter = new BsonDocument("x", 1),
7882
MaxTime = TimeSpan.FromSeconds(20),
83+
ReadConcern = new ReadConcern(readConcernLevel)
7984
};
8085

8186
var expectedResult = new BsonDocument
@@ -85,9 +90,22 @@ public void CreateCommand_should_create_the_correct_command()
8590
{ "query", BsonDocument.Parse("{ x: 1 }") },
8691
{ "maxTimeMS", 20000 }
8792
};
88-
var result = subject.CreateCommand();
8993

90-
result.Should().Be(expectedResult);
94+
if (subject.ReadConcern.ShouldBeSent(semanticServerVersion))
95+
{
96+
expectedResult["readConcern"] = subject.ReadConcern.ToBsonDocument();
97+
}
98+
99+
if (semanticServerVersion < new SemanticVersion(3, 2, 0) && subject.ReadConcern.Level.GetValueOrDefault(ReadConcernLevel.Local) != ReadConcernLevel.Local)
100+
{
101+
Action act = () => subject.CreateCommand(semanticServerVersion);
102+
act.ShouldThrow<MongoClientException>();
103+
}
104+
else
105+
{
106+
var result = subject.CreateCommand(semanticServerVersion);
107+
result.Should().Be(expectedResult);
108+
}
91109
}
92110

93111
[Test]

Diff for: src/MongoDB.Driver.Core.Tests/Core/Operations/FindCommandOperationTests.cs

+10-11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using MongoDB.Bson;
2323
using MongoDB.Bson.Serialization.Serializers;
2424
using MongoDB.Driver.Core.Clusters;
25+
using MongoDB.Driver.Core.Misc;
2526
using MongoDB.Driver.Core.Servers;
2627
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
2728
using NUnit.Framework;
@@ -122,7 +123,7 @@ public void constructor_should_initialize_instance()
122123
subject.NoCursorTimeout.Should().NotHaveValue();
123124
subject.OplogReplay.Should().NotHaveValue();
124125
subject.Projection.Should().BeNull();
125-
subject.ReadConcern.Should().NotHaveValue();
126+
subject.ReadConcern.Should().Be(ReadConcern.Default);
126127
subject.ResultSerializer.Should().Be(BsonDocumentSerializer.Instance);
127128
subject.ReturnKey.Should().NotHaveValue();
128129
subject.ShowRecordId.Should().NotHaveValue();
@@ -380,17 +381,17 @@ public void CreateCommand_should_return_expected_result_when_projection_is_provi
380381

381382
[Test]
382383
public void CreateCommand_should_return_expected_result_when_readConcern_is_provided(
383-
[Values(0, 1)]
384-
int value)
384+
[Values("{level: 'local'}", "{level: 'majority'}")]
385+
string readConcernJson)
385386
{
386387
var subject = new FindCommandOperation<BsonDocument>(_collectionNamespace, BsonDocumentSerializer.Instance, _messageEncoderSettings);
387-
subject.ReadConcern = value;
388+
subject.ReadConcern = ReadConcern.FromBsonDocument(BsonDocument.Parse(readConcernJson));
388389
var reflector = new Reflector(subject);
389390
var serverDescription = CreateServerDescription();
390391

391392
var result = reflector.CreateCommand(serverDescription, null);
392393

393-
result.Should().Be($"{{ find : '{_collectionNamespace.CollectionName}', readConcern : {value} }}");
394+
result.Should().Be($"{{ find : '{_collectionNamespace.CollectionName}', readConcern : {readConcernJson} }}");
394395
}
395396

396397
[Test]
@@ -746,16 +747,14 @@ public void Projection_get_and_set_should_work(
746747
}
747748

748749
[Test]
749-
public void ReadConcern_get_and_set_should_work(
750-
[Values(null, 0, 1)]
751-
int? value)
750+
public void ReadConcern_get_and_set_should_work()
752751
{
753752
var subject = new FindCommandOperation<BsonDocument>(_collectionNamespace, BsonDocumentSerializer.Instance, _messageEncoderSettings);
754753

755-
subject.ReadConcern = value;
754+
subject.ReadConcern = ReadConcern.Majority;
756755
var result = subject.ReadConcern;
757756

758-
result.Should().Be(value);
757+
result.Should().Be(ReadConcern.Majority);
759758
}
760759

761760
[Test]
@@ -866,7 +865,7 @@ private ServerDescription CreateServerDescription(ServerType type = ServerType.S
866865
var clusterId = new ClusterId(1);
867866
var endPoint = new DnsEndPoint("localhost", 27017);
868867
var serverId = new ServerId(clusterId, endPoint);
869-
return new ServerDescription(serverId, endPoint, type: type);
868+
return new ServerDescription(serverId, endPoint, type: type, version: new SemanticVersion(3, 2, 0));
870869
}
871870

872871
private void EnsureTestData()

Diff for: src/MongoDB.Driver.Core.Tests/Core/Operations/FindOperationTests.cs

+26-9
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public void constructor_should_initialize_instance()
118118
subject.NoCursorTimeout.Should().NotHaveValue();
119119
subject.OplogReplay.Should().NotHaveValue();
120120
subject.Projection.Should().BeNull();
121-
subject.ReadConcern.Should().NotHaveValue();
121+
subject.ReadConcern.Should().Be(ReadConcern.Default);
122122
subject.ResultSerializer.Should().Be(BsonDocumentSerializer.Instance);
123123
subject.ReturnKey.Should().NotHaveValue();
124124
subject.ShowRecordId.Should().NotHaveValue();
@@ -171,7 +171,7 @@ public void CreateFindCommandOperation_should_return_expected_result()
171171
subject.NoCursorTimeout = true;
172172
subject.OplogReplay = true;
173173
subject.Projection = new BsonDocument("projection", 1);
174-
subject.ReadConcern = 5;
174+
subject.ReadConcern = ReadConcern.Local;
175175
subject.ReturnKey = true;
176176
subject.ShowRecordId = true;
177177
subject.SingleBatch = true;
@@ -211,7 +211,10 @@ public void CreateFindCommandOperation_should_return_expected_result()
211211
[Test]
212212
public void CreateFindCommandOperation_should_return_expected_result_when_modifiers_are_provided()
213213
{
214-
var subject = new FindOperation<BsonDocument>(_collectionNamespace, BsonDocumentSerializer.Instance, _messageEncoderSettings);
214+
var subject = new FindOperation<BsonDocument>(_collectionNamespace, BsonDocumentSerializer.Instance, _messageEncoderSettings)
215+
{
216+
ReadConcern = ReadConcern.Majority
217+
};
215218
subject.Modifiers = new BsonDocument
216219
{
217220
{ "$hint", "x_1" },
@@ -231,6 +234,7 @@ public void CreateFindCommandOperation_should_return_expected_result_when_modifi
231234
result.MaxScan.Should().Be(subject.Modifiers["$maxScan"].AsInt32);
232235
result.MaxTime.Should().Be(TimeSpan.FromMilliseconds(subject.Modifiers["$maxTimeMS"].AsInt32));
233236
result.Min.Should().Be(subject.Modifiers["$min"].AsBsonDocument);
237+
result.ReadConcern.Should().Be(subject.ReadConcern);
234238
result.ShowRecordId.Should().Be(subject.Modifiers["$showDiskLoc"].AsBoolean);
235239
result.Snapshot.Should().Be(subject.Modifiers["$snapshot"].AsBoolean);
236240
result.Sort.Should().Be(subject.Modifiers["$orderby"].AsBsonDocument);
@@ -254,7 +258,7 @@ public void CreateFindOpcodeOperation_should_return_expected_result()
254258
subject.NoCursorTimeout = true;
255259
subject.OplogReplay = true;
256260
subject.Projection = new BsonDocument("projection", 1);
257-
subject.ReadConcern = 5;
261+
subject.ReadConcern = ReadConcern.Local;
258262
subject.ReturnKey = true;
259263
subject.ShowRecordId = true;
260264
subject.SingleBatch = false;
@@ -367,6 +371,21 @@ public void Execute_should_find_documents_matching_options(
367371
result.Should().HaveCount(1);
368372
}
369373

374+
[Test]
375+
[RequiresServer("EnsureTestData", VersionLessThan = "3.1.0")]
376+
public void Execute_should_raise_an_error_when_an_unsupported_read_concern_is_specified(
377+
[Values(false, true)]
378+
bool async)
379+
{
380+
var subject = new FindOperation<BsonDocument>(_collectionNamespace, BsonDocumentSerializer.Instance, _messageEncoderSettings)
381+
{
382+
ReadConcern = ReadConcern.Majority
383+
};
384+
385+
Action act = () => ExecuteOperation(subject, async);
386+
act.ShouldThrow<MongoClientException>();
387+
}
388+
370389
[Test]
371390
public void ExecuteAsync_should_throw_when_binding_is_null()
372391
{
@@ -566,16 +585,14 @@ public void Projection_get_and_set_should_work(
566585
}
567586

568587
[Test]
569-
public void ReadConcern_get_and_set_should_work(
570-
[Values(null, 0, 1)]
571-
int? value)
588+
public void ReadConcern_get_and_set_should_work()
572589
{
573590
var subject = new FindOperation<BsonDocument>(_collectionNamespace, BsonDocumentSerializer.Instance, _messageEncoderSettings);
574591

575-
subject.ReadConcern = value;
592+
subject.ReadConcern = ReadConcern.Local;
576593
var result = subject.ReadConcern;
577594

578-
result.Should().Be(value);
595+
result.Should().Be(ReadConcern.Local);
579596
}
580597

581598
[Test]

Diff for: src/MongoDB.Driver.Core.Tests/MongoDB.Driver.Core.Tests.csproj

+13
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@
159159
<Compile Include="Core\Clusters\SingleServerClusterTests.cs" />
160160
<Compile Include="SetUpFixture.cs" />
161161
<Compile Include="Specifications\connection-string\TestRunner.cs" />
162+
<Compile Include="Specifications\read-write-concern\DocumentTestRunner.cs" />
163+
<Compile Include="Specifications\read-write-concern\ConnectionStringTestRunner.cs" />
162164
<Compile Include="Specifications\server-discovery-and-monitoring\TestRunner.cs" />
163165
<Compile Include="Specifications\server-selection\ServerSelectionTestRunner.cs" />
164166
<Compile Include="Specifications\server-selection\RttTestRunner.cs" />
@@ -192,6 +194,7 @@
192194
<Compile Include="Core\Misc\SemanticVersionTests.cs" />
193195
<Compile Include="Core\Misc\InterlockedInt32Tests.cs" />
194196
<Compile Include="Core\Misc\TimeSpanParserTests.cs" />
197+
<Compile Include="ReadConcernTests.cs" />
195198
<Compile Include="WriteConcernTests.cs" />
196199
<Compile Include="Properties\AssemblyInfo.cs" />
197200
<Compile Include="Core\Servers\ServerDescriptionTests.cs" />
@@ -259,6 +262,16 @@
259262
<EmbeddedResource Include="Specifications\connection-string\tests\valid-unix_socket-relative.yml" />
260263
<EmbeddedResource Include="Specifications\connection-string\tests\valid-warnings.json" />
261264
<EmbeddedResource Include="Specifications\connection-string\tests\valid-warnings.yml" />
265+
<EmbeddedResource Include="Specifications\read-write-concern\tests\connection-string\read-concern.json" />
266+
<EmbeddedResource Include="Specifications\read-write-concern\tests\connection-string\read-concern.yml" />
267+
<EmbeddedResource Include="Specifications\read-write-concern\tests\connection-string\write-concern.json" />
268+
<EmbeddedResource Include="Specifications\read-write-concern\tests\connection-string\write-concern.yml" />
269+
<EmbeddedResource Include="Specifications\read-write-concern\tests\document\read-concern.json" />
270+
<EmbeddedResource Include="Specifications\read-write-concern\tests\document\read-concern.yml" />
271+
<EmbeddedResource Include="Specifications\read-write-concern\tests\document\write-concern.json" />
272+
<EmbeddedResource Include="Specifications\read-write-concern\tests\document\write-concern.yml" />
273+
<None Include="Specifications\read-write-concern\tests\Makefile" />
274+
<None Include="Specifications\read-write-concern\tests\README.rst" />
262275
<None Include="Specifications\server-discovery-and-monitoring\tests\Makefile" />
263276
<None Include="Specifications\server-discovery-and-monitoring\tests\README.rst" />
264277
<EmbeddedResource Include="Specifications\server-discovery-and-monitoring\tests\rs\discovery.json" />

0 commit comments

Comments
 (0)