Skip to content

Commit 8210b5a

Browse files
committed
CSHARP-2221: Update JSON driven transaction tests.
1 parent 19eefd9 commit 8210b5a

File tree

106 files changed

+3859
-3383
lines changed

Some content is hidden

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

106 files changed

+3859
-3383
lines changed

src/MongoDB.Driver.Core/Core/Operations/EndTransactionOperation.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,33 @@ public MessageEncoderSettings MessageEncoderSettings
7777
/// <inheritdoc />
7878
public BsonDocument Execute(IReadBinding binding, CancellationToken cancellationToken)
7979
{
80-
var operation = CreateOperation();
81-
return operation.Execute(binding, cancellationToken);
80+
Ensure.IsNotNull(binding, nameof(binding));
81+
82+
using (var channelSource = binding.GetReadChannelSource(cancellationToken))
83+
using (var channel = channelSource.GetChannel(cancellationToken))
84+
using (var channelBinding = new ChannelReadWriteBinding(channelSource.Server, channel, binding.Session.Fork()))
85+
{
86+
var operation = CreateOperation();
87+
var result = operation.Execute(channelBinding, cancellationToken);
88+
WriteConcernErrorHelper.ThrowIfHasWriteConcernError(channel.ConnectionDescription.ConnectionId, result);
89+
return result;
90+
}
8291
}
8392

8493
/// <inheritdoc />
85-
public Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
94+
public async Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
8695
{
87-
var operation = CreateOperation();
88-
return operation.ExecuteAsync(binding, cancellationToken);
96+
Ensure.IsNotNull(binding, nameof(binding));
97+
98+
using (var channelSource = await binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false))
99+
using (var channel = await channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false))
100+
using (var channelBinding = new ChannelReadWriteBinding(channelSource.Server, channel, binding.Session.Fork()))
101+
{
102+
var operation = CreateOperation();
103+
var result = await operation.ExecuteAsync(channelBinding, cancellationToken).ConfigureAwait(false);
104+
WriteConcernErrorHelper.ThrowIfHasWriteConcernError(channel.ConnectionDescription.ConnectionId, result);
105+
return result;
106+
}
89107
}
90108

91109
// private methods

src/MongoDB.Driver.Core/MongoCommandException.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public int Code
100100
/// </value>
101101
public string CodeName
102102
{
103-
get { return _result.GetValue("codeName", null).AsString; }
103+
get { return _result.GetValue("codeName", null)?.AsString; }
104104
}
105105

106106
/// <summary>

tests/MongoDB.Bson.TestHelpers/JsonDrivenTests/JsonDrivenHelper.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,18 @@ public static void EnsureAllFieldsAreValid(BsonDocument document, params string[
3131
}
3232
}
3333
}
34+
35+
public static void EnsureFieldEquals(BsonDocument document, string name, BsonValue value)
36+
{
37+
if (!document.Contains(name))
38+
{
39+
throw new FormatException($"Missing field: \"{name}\".");
40+
}
41+
42+
if (!document[name].Equals(value))
43+
{
44+
throw new FormatException($"Field \"{name}\" has an invalid value: {value.ToJson()}.");
45+
}
46+
}
3447
}
3548
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/* Copyright 2018-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Collections.Generic;
18+
using System.Threading;
19+
using System.Threading.Tasks;
20+
21+
namespace MongoDB.Bson.TestHelpers.JsonDrivenTests
22+
{
23+
public abstract class JsonDrivenTest
24+
{
25+
// protected fields
26+
protected Exception _actualException;
27+
protected BsonDocument _expectedException;
28+
protected BsonValue _expectedResult;
29+
protected Dictionary<string, object> _objectMap;
30+
31+
// constructors
32+
protected JsonDrivenTest(Dictionary<string, object> objectMap = null)
33+
{
34+
_objectMap = objectMap;
35+
}
36+
37+
// public methods
38+
public virtual void Act(CancellationToken cancellationToken)
39+
{
40+
try
41+
{
42+
CallMethod(cancellationToken);
43+
}
44+
catch (Exception exception)
45+
{
46+
_actualException = exception;
47+
}
48+
}
49+
50+
public virtual async Task ActAsync(CancellationToken cancellationToken)
51+
{
52+
try
53+
{
54+
await CallMethodAsync(cancellationToken).ConfigureAwait(false);
55+
}
56+
catch (Exception exception)
57+
{
58+
_actualException = exception;
59+
}
60+
}
61+
62+
public virtual void Arrange(BsonDocument document)
63+
{
64+
if (document.Contains("arguments"))
65+
{
66+
SetArguments(document["arguments"].AsBsonDocument);
67+
}
68+
69+
if (document.Contains("result"))
70+
{
71+
ParseExpectedResult(document["result"]);
72+
}
73+
}
74+
75+
public virtual void Assert()
76+
{
77+
if (_expectedException == null)
78+
{
79+
if (_actualException != null)
80+
{
81+
throw new Exception("Unexpected exception was thrown.", _actualException);
82+
}
83+
AssertResult();
84+
}
85+
else
86+
{
87+
if (_actualException == null)
88+
{
89+
throw new Exception("Expected an exception but none was thrown.");
90+
}
91+
AssertException();
92+
}
93+
}
94+
95+
// protected methods
96+
protected virtual void AssertException()
97+
{
98+
throw new NotImplementedException();
99+
}
100+
101+
protected virtual void AssertResult()
102+
{
103+
throw new NotImplementedException();
104+
}
105+
106+
protected virtual void CallMethod(CancellationToken cancellationToken)
107+
{
108+
throw new NotImplementedException();
109+
}
110+
111+
protected virtual Task CallMethodAsync(CancellationToken cancellationToken)
112+
{
113+
throw new NotImplementedException();
114+
}
115+
116+
protected virtual void ParseExpectedResult(BsonValue value)
117+
{
118+
_expectedResult = value;
119+
}
120+
121+
protected virtual void SetArgument(string name, BsonValue value)
122+
{
123+
throw new FormatException($"{GetType().Name} unexpected argument: \"{name}\".");
124+
}
125+
126+
protected virtual void SetArguments(BsonDocument arguments)
127+
{
128+
foreach (var argument in arguments)
129+
{
130+
SetArgument(argument.Name, argument.Value);
131+
}
132+
}
133+
}
134+
}

tests/MongoDB.Bson.TestHelpers/MongoDB.Bson.TestHelpers.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<Compile Include="JsonDrivenTests\AspectAsserter.cs" />
9090
<Compile Include="JsonDrivenTests\BsonDocumentAspectAsserter.cs" />
9191
<Compile Include="JsonDrivenTests\JsonDrivenHelper.cs" />
92+
<Compile Include="JsonDrivenTests\JsonDrivenTest.cs" />
9293
<Compile Include="JsonDrivenTests\JsonDrivenTestCase.cs" />
9394
<Compile Include="JsonDrivenTests\JsonDrivenTestCaseFactory.cs" />
9495
<Compile Include="Properties\AssemblyInfo.cs" />

tests/MongoDB.Driver.Tests.Dotnet/Specifications/transactions/tests/README.rst

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,19 @@ Each YAML file has the following keys:
4141
- ``operations``: Array of documents, each describing an operation to be
4242
executed. Each document has the following fields:
4343

44-
- ``name``: The name of the operation.
44+
- ``name``: The name of the operation on ``object``.
4545

46-
- ``arguments``: The names and values of arguments.
46+
- ``object``: The name of the object to perform the operation on. Can be
47+
"database", collection", "session0", or "session1".
48+
49+
- ``collectionOptions``: Optional, parameters to pass to the Collection()
50+
used for this operation.
51+
52+
- ``command_name``: Present only when ``name`` is "runCommand". The name
53+
of the command to run. Required for languages that are unable preserve
54+
the order keys in the "command" argument when parsing JSON/YAML.
55+
56+
- ``arguments``: Optional, the names and values of arguments.
4757

4858
- ``result``: The return value from the operation, if any. If the
4959
operation is expected to return an error, the ``result`` has one field,
@@ -64,12 +74,14 @@ Each YAML file has the following keys:
6474
Use as integration tests
6575
========================
6676

67-
Run a MongoDB replica set with a primary, two secondaries, and an arbiter,
68-
server version 4.0 or later. (Including two secondaries ensures that transaction
69-
pinning works properly. Include an arbiter to ensure no new bugs have been
70-
introduced related to arbiters.)
77+
Run a MongoDB replica set with a primary, a secondary, and an arbiter,
78+
server version 4.0 or later. (Including a secondary ensures that server
79+
selection in a transaction works properly. Including an arbiter helps ensure
80+
that no new bugs have been introduced related to arbiters.)
81+
82+
Load each YAML (or JSON) file using a Canonical Extended JSON parser.
7183

72-
For each YAML file, for each element in ``tests``:
84+
Then for each element in ``tests``:
7385

7486
#. Create a MongoClient and call
7587
``client.admin.runCommand({killAllSessions: []})`` to clean up any open
@@ -96,34 +108,31 @@ For each YAML file, for each element in ``tests``:
96108
#. For each element in ``operations``:
97109

98110
- Enter a "try" block or your programming language's closest equivalent.
99-
- If ``name`` is "startTransaction", "commitTransaction", or
100-
"abortTransaction", call the named method on ``session0`` or
101-
``session1``, depending on the "session" argument.
102-
- If ``name`` is "runCommand", call the runCommand method on the database
103-
specified in the test. Pass the argument named "command" to the runCommand
104-
method. Pass ``session0`` or ``session1`` to the runCommand method, depending
105-
on which session's name is in the arguments list. If ``arguments``
106-
contains no "session", pass no explicit session to the method. If ``arguments``
107-
includes "readPreference", also pass the read preference to the runCommand
108-
method.
109-
- Otherwise, ``name`` refers to a CRUD method, such as ``insertOne``.
110-
Execute the named method on the "transactions-tests" database on the "test"
111-
collection, passing the arguments listed. Pass ``session0`` or ``session1``
112-
to the method, depending on which session's name is in the arguments list.
111+
- Create a Database object from the MongoClient, using the ``database_name``
112+
field at the top level of the test file.
113+
- Create a Collection object from the Database, using the
114+
``collection_name`` field at the top level of the test file.
115+
If ``collectionOptions`` is present create the Collection object with the
116+
provided options. Otherwise create the object with the default options.
117+
- Execute the named method on the provided ``object``, passing the
118+
arguments listed. Pass ``session0`` or ``session1`` to the method,
119+
depending on which session's name is in the arguments list.
113120
If ``arguments`` contains no "session", pass no explicit session to the
114-
method. If ``arguments`` includes "readPreference", configure the specified
115-
read preference in whatever manner the driver supports.
121+
method.
116122
- If the driver throws an exception / returns an error while executing this
117123
series of operations, store the error message and server error code.
118124
- If the result document has an "errorContains" field, verify that the
119125
method threw an exception or returned an error, and that the value of the
120-
"errorContains" field matches the error string. If the result document has
121-
an "errorCodeName" field, verify that the method threw a command failed
122-
exception or returned an error, and that the value of the "errorCodeName"
123-
field matches the "codeName" in the server error response.
126+
"errorContains" field matches the error string. "errorContains" is a
127+
substring (case-insensitive) of the actual error message.
128+
If the result document has an "errorCodeName" field, verify that the
129+
method threw a command failed exception or returned an error, and that
130+
the value of the "errorCodeName" field matches the "codeName" in the
131+
server error response.
132+
If the operation returns a raw command response, eg from ``runCommand``,
133+
then compare only the fields present in the expected result document.
124134
Otherwise, compare the method's return value to ``result`` using the same
125-
logic as the CRUD Spec Tests runner. key is a substring (case-insensitive)
126-
of the actual error message.
135+
logic as the CRUD Spec Tests runner.
127136

128137
#. Call ``session0.endSession()`` and ``session1.endSession``.
129138
#. If the test includes a list of command-started events in ``expectations``,

0 commit comments

Comments
 (0)