Skip to content

Commit d3fb9a4

Browse files
committed
Support explicit and implicit sessions on standalone servers
JAVA-3745
1 parent 3413d85 commit d3fb9a4

File tree

9 files changed

+302
-315
lines changed

9 files changed

+302
-315
lines changed

driver-core/src/main/com/mongodb/internal/async/client/ClientSessionHelper.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
import com.mongodb.TransactionOptions;
2121
import com.mongodb.connection.ClusterConnectionMode;
2222
import com.mongodb.connection.ClusterDescription;
23-
import com.mongodb.connection.ClusterType;
2423
import com.mongodb.connection.ServerDescription;
25-
import com.mongodb.connection.ServerType;
2624
import com.mongodb.internal.async.SingleResultCallback;
2725
import com.mongodb.internal.connection.Server;
2826
import com.mongodb.internal.session.ServerSessionPool;
@@ -58,8 +56,7 @@ void createClientSession(final ClientSessionOptions options, final OperationExec
5856
final SingleResultCallback<AsyncClientSession> callback) {
5957
ClusterDescription clusterDescription = mongoClient.getCluster().getCurrentDescription();
6058
if (!getServerDescriptionListToConsiderForSessionSupport(clusterDescription).isEmpty()
61-
&& clusterDescription.getLogicalSessionTimeoutMinutes() != null
62-
&& clusterDescription.getType() != ClusterType.STANDALONE) {
59+
&& clusterDescription.getLogicalSessionTimeoutMinutes() != null) {
6360
callback.onResult(createClientSession(options, executor), null);
6461
} else {
6562
mongoClient.getCluster().selectServerAsync(new ServerSelector() {
@@ -72,8 +69,7 @@ public List<ServerDescription> select(final ClusterDescription clusterDescriptio
7269
public void onResult(final Server server, final Throwable t) {
7370
if (t != null) {
7471
callback.onResult(null, null);
75-
} else if (server.getDescription().getLogicalSessionTimeoutMinutes() == null
76-
|| server.getDescription().getType() == ServerType.STANDALONE) {
72+
} else if (server.getDescription().getLogicalSessionTimeoutMinutes() == null) {
7773
callback.onResult(null, null);
7874
} else {
7975
callback.onResult(createClientSession(options, executor), null);

driver-core/src/test/functional/com/mongodb/internal/async/client/MongoClientSessionSpecification.groovy

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,27 @@ import java.util.concurrent.TimeUnit
4141
import static Fixture.getMongoClient
4242
import static TestHelper.run
4343
import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet
44-
import static com.mongodb.ClusterFixture.isStandalone
4544
import static com.mongodb.ClusterFixture.serverVersionAtLeast
4645

4746
class MongoClientSessionSpecification extends FunctionalSpecification {
4847

4948
def 'should throw IllegalArgumentException if options are null'() {
5049
when:
51-
Fixture.getMongoClient().startSession(null, Stub(SingleResultCallback))
50+
getMongoClient().startSession(null, Stub(SingleResultCallback))
5251

5352
then:
5453
thrown(IllegalArgumentException)
5554
}
5655

57-
@IgnoreIf({ serverVersionAtLeast(3, 6) && !isStandalone() })
58-
def 'should throw MongoClientException starting a session when sessions are not supported'() {
59-
when:
60-
startSession(ClientSessionOptions.builder().build())
61-
62-
then:
63-
thrown(MongoClientException)
64-
}
65-
66-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
56+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
6757
def 'should create session with correct defaults'() {
6858
when:
6959
def options = ClientSessionOptions.builder().build()
7060
def clientSession = startSession(options)
7161

7262
then:
7363
clientSession != null
74-
clientSession.getOriginator() == Fixture.getMongoClient()
64+
clientSession.getOriginator() == getMongoClient()
7565
clientSession.isCausallyConsistent()
7666
clientSession.getOptions() == ClientSessionOptions.builder()
7767
.defaultTransactionOptions(TransactionOptions.builder()
@@ -88,7 +78,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
8878
clientSession.close()
8979
}
9080

91-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
81+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
9282
def 'cluster time should advance'() {
9383
given:
9484
def firstOperationTime = new BsonTimestamp(42, 1)
@@ -132,7 +122,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
132122
clientSession.close()
133123
}
134124

135-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
125+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
136126
def 'operation time should advance'() {
137127
given:
138128
def firstOperationTime = new BsonTimestamp(42, 1)
@@ -173,7 +163,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
173163
clientSession.close()
174164
}
175165

176-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
166+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
177167
def 'methods that use the session should throw if the session is closed'() {
178168
given:
179169
def options = ClientSessionOptions.builder().build()
@@ -202,7 +192,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
202192
clientSession.close()
203193
}
204194

205-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
195+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
206196
def 'informational methods should not throw if the session is closed'() {
207197
given:
208198
def options = ClientSessionOptions.builder().build()
@@ -219,7 +209,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
219209
true
220210
}
221211

222-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
212+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
223213
def 'should apply causally consistent session option to client session'() {
224214
when:
225215
def clientSession = startSession(ClientSessionOptions.builder().causallyConsistent(causallyConsistent).build())
@@ -235,7 +225,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
235225
causallyConsistent << [true, false]
236226
}
237227

238-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
228+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
239229
def 'client session should have server session with valid identifier'() {
240230
given:
241231
def clientSession = startSession(ClientSessionOptions.builder().build())
@@ -254,7 +244,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
254244
clientSession.close()
255245
}
256246

257-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
247+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
258248
def 'should use a default session'() {
259249
given:
260250
def commandListener = new TestCommandListener()
@@ -273,25 +263,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
273263
client?.close()
274264
}
275265

276-
@IgnoreIf({ serverVersionAtLeast(3, 6) && !isStandalone() })
277-
def 'should not use a default session when sessions are not supported'() {
278-
given:
279-
def commandListener = new TestCommandListener()
280-
def options = Fixture.getMongoClientBuilderFromConnectionString().addCommandListener(commandListener).build()
281-
def client = AsyncMongoClients.create(options)
282-
283-
when:
284-
run(client.getDatabase('admin').&runCommand, new BsonDocument('ping', new BsonInt32(1)))
285-
286-
then:
287-
def pingCommandStartedEvent = commandListener.events.get(0)
288-
!(pingCommandStartedEvent as CommandStartedEvent).command.containsKey('lsid')
289-
290-
cleanup:
291-
client?.close()
292-
}
293-
294-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
266+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
295267
def 'should throw exception if unacknowledged write used with explicit session'() {
296268
given:
297269
def session = run(getMongoClient().&startSession)
@@ -334,7 +306,7 @@ class MongoClientSessionSpecification extends FunctionalSpecification {
334306
// This test is inherently racy as it's possible that the server _does_ replicate fast enough and therefore the test passes anyway
335307
// even if causal consistency was not actually in effect. For that reason the test iterates a number of times in order to increase
336308
// confidence that it's really causal consistency that is causing the test to succeed
337-
@IgnoreIf({ !serverVersionAtLeast(3, 6) || isStandalone() })
309+
@IgnoreIf({ !serverVersionAtLeast(3, 6) })
338310
@Category(Slow)
339311
def 'should find inserted document on a secondary when causal consistency is enabled'() {
340312
given:
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
====================
2+
Driver Session Tests
3+
====================
4+
5+
.. contents::
6+
7+
----
8+
9+
Introduction
10+
============
11+
12+
The YAML and JSON files in this directory are platform-independent tests that
13+
drivers can use to prove their conformance to the Driver Sessions Spec. They are
14+
designed with the intention of sharing most test-runner code with the
15+
Transactions spec tests.
16+
17+
Several prose tests, which are not easily expressed in YAML, are also presented
18+
in the Driver Sessions Spec. Those tests will need to be manually implemented
19+
by each driver.
20+
21+
Test Format
22+
===========
23+
24+
The same as the `Transactions Spec Test format
25+
<../../transactions/tests/README.rst#test-format>`_.
26+
27+
Special Test Operations
28+
```````````````````````
29+
30+
Certain operations that appear in the "operations" array do not correspond to
31+
API methods but instead represent special test operations. Such operations are
32+
defined on the "testRunner" object and are documented in the
33+
`Transactions Spec Test
34+
<../../transactions/tests/README.rst#special-test-operations>`_.
35+
Additional, session test specific operations are documented here:
36+
37+
assertDifferentLsidOnLastTwoCommands
38+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39+
40+
The "assertDifferentLsidOnLastTwoCommands" operation instructs the test runner
41+
to assert that the last two command started events from the test's MongoClient
42+
have different "lsid" fields. This assertion is used to ensure that dirty
43+
server sessions are discarded from the pool::
44+
45+
- name: assertDifferentLsidOnLastTwoCommands
46+
object: testRunner
47+
48+
assertSameLsidOnLastTwoCommands
49+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50+
51+
The "assertSameLsidOnLastTwoCommands" operation instructs the test runner
52+
to assert that the last two command started events from the test's MongoClient
53+
have the same "lsid" field. This assertion is used to ensure that non-dirty
54+
server sessions are not discarded from the pool::
55+
56+
- name: assertSameLsidOnLastTwoCommands
57+
object: testRunner
58+
59+
assertSessionDirty
60+
~~~~~~~~~~~~~~~~~~
61+
62+
The "assertSessionDirty" operation instructs the test runner to assert that
63+
the given session is marked dirty::
64+
65+
- name: assertSessionDirty
66+
object: testRunner
67+
arguments:
68+
session: session0
69+
70+
assertSessionNotDirty
71+
~~~~~~~~~~~~~~~~~~~~~
72+
73+
The "assertSessionNotDirty" operation instructs the test runner to assert that
74+
the given session is *not* marked dirty::
75+
76+
- name: assertSessionNotDirty
77+
object: testRunner
78+
arguments:
79+
session: session0
80+
81+
Changelog
82+
=========
83+
84+
:2019-05-15: Initial version.

0 commit comments

Comments
 (0)