1616
1717package com .mongodb .reactivestreams .client ;
1818
19- import com .mongodb .ClusterFixture ;
2019import com .mongodb .MongoClientSettings ;
2120import com .mongodb .MongoCommandException ;
2221import com .mongodb .MongoNamespace ;
2322import com .mongodb .MongoOperationTimeoutException ;
2423import com .mongodb .ReadPreference ;
2524import com .mongodb .WriteConcern ;
2625import com .mongodb .client .AbstractClientSideOperationsTimeoutProseTest ;
27- import com .mongodb .client .model .CreateCollectionOptions ;
2826import com .mongodb .client .model .changestream .FullDocument ;
2927import com .mongodb .event .CommandFailedEvent ;
3028import com .mongodb .event .CommandStartedEvent ;
4341import org .junit .jupiter .api .Test ;
4442import reactor .core .publisher .Flux ;
4543import reactor .core .publisher .Hooks ;
44+ import reactor .core .publisher .Mono ;
4645import reactor .test .StepVerifier ;
4746
4847import java .nio .ByteBuffer ;
5857
5958import static com .mongodb .ClusterFixture .TIMEOUT_DURATION ;
6059import static com .mongodb .ClusterFixture .isDiscoverableReplicaSet ;
60+ import static com .mongodb .ClusterFixture .isStandalone ;
6161import static com .mongodb .ClusterFixture .serverVersionAtLeast ;
6262import static com .mongodb .ClusterFixture .sleep ;
63+ import static com .mongodb .assertions .Assertions .assertTrue ;
6364import static java .util .Collections .singletonList ;
65+ import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
6466import static org .junit .jupiter .api .Assertions .assertEquals ;
6567import static org .junit .jupiter .api .Assertions .assertInstanceOf ;
6668import static org .junit .jupiter .api .Assertions .assertNotNull ;
69+ import static org .junit .jupiter .api .Assumptions .assumeFalse ;
6770import static org .junit .jupiter .api .Assumptions .assumeTrue ;
6871
6972
@@ -104,7 +107,6 @@ protected boolean isAsync() {
104107 @ Override
105108 public void testGridFSUploadViaOpenUploadStreamTimeout () {
106109 assumeTrue (serverVersionAtLeast (4 , 4 ));
107- long rtt = ClusterFixture .getPrimaryRTT ();
108110
109111 //given
110112 collectionHelper .runAdminCommand ("{"
@@ -113,12 +115,12 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
113115 + " data: {"
114116 + " failCommands: [\" insert\" ],"
115117 + " blockConnection: true,"
116- + " blockTimeMS: " + ( rtt + 405 )
118+ + " blockTimeMS: " + 600
117119 + " }"
118120 + "}" );
119121
120122 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
121- .timeout (rtt + 400 , TimeUnit .MILLISECONDS ))) {
123+ .timeout (600 , TimeUnit .MILLISECONDS ))) {
122124 MongoDatabase database = client .getDatabase (gridFsFileNamespace .getDatabaseName ());
123125 GridFSBucket gridFsBucket = createReaciveGridFsBucket (database , GRID_FS_BUCKET_NAME );
124126
@@ -158,7 +160,6 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
158160 @ Override
159161 public void testAbortingGridFsUploadStreamTimeout () throws ExecutionException , InterruptedException , TimeoutException {
160162 assumeTrue (serverVersionAtLeast (4 , 4 ));
161- long rtt = ClusterFixture .getPrimaryRTT ();
162163
163164 //given
164165 CompletableFuture <Throwable > droppedErrorFuture = new CompletableFuture <>();
@@ -170,12 +171,12 @@ public void testAbortingGridFsUploadStreamTimeout() throws ExecutionException, I
170171 + " data: {"
171172 + " failCommands: [\" delete\" ],"
172173 + " blockConnection: true,"
173- + " blockTimeMS: " + ( rtt + 405 )
174+ + " blockTimeMS: " + 405
174175 + " }"
175176 + "}" );
176177
177178 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
178- .timeout (rtt + 400 , TimeUnit .MILLISECONDS ))) {
179+ .timeout (400 , TimeUnit .MILLISECONDS ))) {
179180 MongoDatabase database = client .getDatabase (gridFsFileNamespace .getDatabaseName ());
180181 GridFSBucket gridFsBucket = createReaciveGridFsBucket (database , GRID_FS_BUCKET_NAME );
181182
@@ -198,12 +199,25 @@ public void testAbortingGridFsUploadStreamTimeout() throws ExecutionException, I
198199 //then
199200 Throwable droppedError = droppedErrorFuture .get (TIMEOUT_DURATION .toMillis (), TimeUnit .MILLISECONDS );
200201 Throwable commandError = droppedError .getCause ();
201- assertInstanceOf (MongoOperationTimeoutException .class , commandError );
202202
203203 CommandFailedEvent deleteFailedEvent = commandListener .getCommandFailedEvent ("delete" );
204204 assertNotNull (deleteFailedEvent );
205205
206- assertEquals (commandError , commandListener .getCommandFailedEvent ("delete" ).getThrowable ());
206+ CommandStartedEvent deleteStartedEvent = commandListener .getCommandStartedEvent ("delete" );
207+ assertTrue (deleteStartedEvent .getCommand ().containsKey ("maxTimeMS" ), "Expected delete command to have maxTimeMS" );
208+ long deleteMaxTimeMS = deleteStartedEvent
209+ .getCommand ()
210+ .get ("maxTimeMS" )
211+ .asNumber ()
212+ .longValue ();
213+
214+ assertTrue (deleteMaxTimeMS <= 420
215+ // some leeway for timing variations, when compression is used it is often less then 300.
216+ // Without it, it is more than 300.
217+ && deleteMaxTimeMS >= 150 ,
218+ "Expected maxTimeMS for delete command to be between 150s and 420ms, " + "but was: " + deleteMaxTimeMS + "ms" );
219+ assertEquals (commandError , deleteFailedEvent .getThrowable ());
220+
207221 // When subscription is cancelled, we should not receive any more events.
208222 testSubscriber .assertNoTerminalEvent ();
209223 }
@@ -219,9 +233,8 @@ public void testTimeoutMSAppliesToFullResumeAttemptInNextCall() {
219233 assumeTrue (isDiscoverableReplicaSet ());
220234
221235 //given
222- long rtt = ClusterFixture .getPrimaryRTT ();
223236 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
224- .timeout (rtt + 500 , TimeUnit .MILLISECONDS ))) {
237+ .timeout (500 , TimeUnit .MILLISECONDS ))) {
225238
226239 MongoNamespace namespace = generateNamespace ();
227240 MongoCollection <Document > collection = client .getDatabase (namespace .getDatabaseName ())
@@ -273,9 +286,8 @@ public void testTimeoutMSAppliedToInitialAggregate() {
273286 assumeTrue (isDiscoverableReplicaSet ());
274287
275288 //given
276- long rtt = ClusterFixture .getPrimaryRTT ();
277289 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
278- .timeout (rtt + 200 , TimeUnit .MILLISECONDS ))) {
290+ .timeout (200 , TimeUnit .MILLISECONDS ))) {
279291
280292 MongoNamespace namespace = generateNamespace ();
281293 MongoCollection <Document > collection = client .getDatabase (namespace .getDatabaseName ())
@@ -290,7 +302,7 @@ public void testTimeoutMSAppliedToInitialAggregate() {
290302 + " data: {"
291303 + " failCommands: [\" aggregate\" ],"
292304 + " blockConnection: true,"
293- + " blockTimeMS: " + ( rtt + 201 )
305+ + " blockTimeMS: " + 201
294306 + " }"
295307 + "}" );
296308
@@ -321,13 +333,10 @@ public void testTimeoutMsRefreshedForGetMoreWhenMaxAwaitTimeMsNotSet() {
321333
322334 //given
323335 BsonTimestamp startTime = new BsonTimestamp ((int ) Instant .now ().getEpochSecond (), 0 );
324- collectionHelper .create (namespace .getCollectionName (), new CreateCollectionOptions ());
325336 sleep (2000 );
326337
327-
328- long rtt = ClusterFixture .getPrimaryRTT ();
329338 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
330- .timeout (rtt + 300 , TimeUnit .MILLISECONDS ))) {
339+ .timeout (500 , TimeUnit .MILLISECONDS ))) {
331340
332341 MongoCollection <Document > collection = client .getDatabase (namespace .getDatabaseName ())
333342 .getCollection (namespace .getCollectionName ()).withReadPreference (ReadPreference .primary ());
@@ -338,7 +347,7 @@ public void testTimeoutMsRefreshedForGetMoreWhenMaxAwaitTimeMsNotSet() {
338347 + " data: {"
339348 + " failCommands: [\" getMore\" , \" aggregate\" ],"
340349 + " blockConnection: true,"
341- + " blockTimeMS: " + ( rtt + 200 )
350+ + " blockTimeMS: " + 200
342351 + " }"
343352 + "}" );
344353
@@ -389,12 +398,10 @@ public void testTimeoutMsRefreshedForGetMoreWhenMaxAwaitTimeMsSet() {
389398
390399 //given
391400 BsonTimestamp startTime = new BsonTimestamp ((int ) Instant .now ().getEpochSecond (), 0 );
392- collectionHelper .create (namespace .getCollectionName (), new CreateCollectionOptions ());
393401 sleep (2000 );
394402
395- long rtt = ClusterFixture .getPrimaryRTT ();
396403 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
397- .timeout (rtt + 300 , TimeUnit .MILLISECONDS ))) {
404+ .timeout (500 , TimeUnit .MILLISECONDS ))) {
398405
399406 MongoCollection <Document > collection = client .getDatabase (namespace .getDatabaseName ())
400407 .getCollection (namespace .getCollectionName ())
@@ -406,7 +413,7 @@ public void testTimeoutMsRefreshedForGetMoreWhenMaxAwaitTimeMsSet() {
406413 + " data: {"
407414 + " failCommands: [\" aggregate\" , \" getMore\" ],"
408415 + " blockConnection: true,"
409- + " blockTimeMS: " + ( rtt + 200 )
416+ + " blockTimeMS: " + 200
410417 + " }"
411418 + "}" );
412419
@@ -449,9 +456,8 @@ public void testTimeoutMsISHonoredForNnextOperationWhenSeveralGetMoreExecutedInt
449456 assumeTrue (isDiscoverableReplicaSet ());
450457
451458 //given
452- long rtt = ClusterFixture .getPrimaryRTT ();
453459 try (MongoClient client = createReactiveClient (getMongoClientSettingsBuilder ()
454- .timeout (rtt + 2500 , TimeUnit .MILLISECONDS ))) {
460+ .timeout (2500 , TimeUnit .MILLISECONDS ))) {
455461
456462 MongoCollection <Document > collection = client .getDatabase (namespace .getDatabaseName ())
457463 .getCollection (namespace .getCollectionName ()).withReadPreference (ReadPreference .primary ());
@@ -468,7 +474,78 @@ public void testTimeoutMsISHonoredForNnextOperationWhenSeveralGetMoreExecutedInt
468474 List <CommandStartedEvent > commandStartedEvents = commandListener .getCommandStartedEvents ();
469475 assertCommandStartedEventsInOder (Arrays .asList ("aggregate" , "getMore" , "getMore" , "getMore" , "killCursors" ),
470476 commandStartedEvents );
471- assertOnlyOneCommandTimeoutFailure ("getMore" );
477+
478+ }
479+ }
480+
481+ @ DisplayName ("9. End Session. The timeout specified via the MongoClient timeoutMS option" )
482+ @ Test
483+ @ Override
484+ public void test9EndSessionClientTimeout () {
485+ assumeTrue (serverVersionAtLeast (4 , 4 ));
486+ assumeFalse (isStandalone ());
487+
488+ collectionHelper .runAdminCommand ("{"
489+ + " configureFailPoint: \" failCommand\" ,"
490+ + " mode: { times: 1 },"
491+ + " data: {"
492+ + " failCommands: [\" abortTransaction\" ],"
493+ + " blockConnection: true,"
494+ + " blockTimeMS: " + 400
495+ + " }"
496+ + "}" );
497+
498+ try (MongoClient mongoClient = createReactiveClient (getMongoClientSettingsBuilder ().retryWrites (false )
499+ .timeout (300 , TimeUnit .MILLISECONDS ))) {
500+ MongoCollection <Document > collection = mongoClient .getDatabase (namespace .getDatabaseName ())
501+ .getCollection (namespace .getCollectionName ());
502+
503+ try (ClientSession session = Mono .from (mongoClient .startSession ()).block ()) {
504+ session .startTransaction ();
505+ Mono .from (collection .insertOne (session , new Document ("x" , 1 ))).block ();
506+ }
507+
508+ sleep (postSessionCloseSleep ());
509+ CommandFailedEvent abortTransactionEvent = assertDoesNotThrow (() -> commandListener .getCommandFailedEvent ("abortTransaction" ));
510+ long elapsedTime = abortTransactionEvent .getElapsedTime (TimeUnit .MILLISECONDS );
511+ assertInstanceOf (MongoOperationTimeoutException .class , abortTransactionEvent .getThrowable ());
512+ assertTrue (elapsedTime <= 400 , "Took too long to time out, elapsedMS: " + elapsedTime );
513+ }
514+ }
515+
516+ @ Test
517+ @ DisplayName ("9. End Session. The timeout specified via the ClientSession defaultTimeoutMS option" )
518+ @ Override
519+ public void test9EndSessionSessionTimeout () {
520+ assumeTrue (serverVersionAtLeast (4 , 4 ));
521+ assumeFalse (isStandalone ());
522+
523+ collectionHelper .runAdminCommand ("{"
524+ + " configureFailPoint: \" failCommand\" ,"
525+ + " mode: { times: 1 },"
526+ + " data: {"
527+ + " failCommands: [\" abortTransaction\" ],"
528+ + " blockConnection: true,"
529+ + " blockTimeMS: " + 400
530+ + " }"
531+ + "}" );
532+
533+ try (MongoClient mongoClient = createReactiveClient (getMongoClientSettingsBuilder ())) {
534+ MongoCollection <Document > collection = mongoClient .getDatabase (namespace .getDatabaseName ())
535+ .getCollection (namespace .getCollectionName ());
536+
537+ try (ClientSession session = Mono .from (mongoClient .startSession (com .mongodb .ClientSessionOptions .builder ()
538+ .defaultTimeout (300 , TimeUnit .MILLISECONDS ).build ())).block ()) {
539+
540+ session .startTransaction ();
541+ Mono .from (collection .insertOne (session , new Document ("x" , 1 ))).block ();
542+ }
543+
544+ sleep (postSessionCloseSleep ());
545+ CommandFailedEvent abortTransactionEvent = assertDoesNotThrow (() -> commandListener .getCommandFailedEvent ("abortTransaction" ));
546+ long elapsedTime = abortTransactionEvent .getElapsedTime (TimeUnit .MILLISECONDS );
547+ assertInstanceOf (MongoOperationTimeoutException .class , abortTransactionEvent .getThrowable ());
548+ assertTrue (elapsedTime <= 400 , "Took too long to time out, elapsedMS: " + elapsedTime );
472549 }
473550 }
474551
@@ -512,6 +589,6 @@ public void tearDown() throws InterruptedException {
512589
513590 @ Override
514591 protected int postSessionCloseSleep () {
515- return 256 ;
592+ return 1000 ;
516593 }
517594}
0 commit comments