16
16
17
17
package com .mongodb .client ;
18
18
19
+ import com .mongodb .ClusterFixture ;
19
20
import com .mongodb .MongoClientException ;
20
21
import com .mongodb .MongoClientSettings ;
21
22
import com .mongodb .MongoCommandException ;
25
26
import com .mongodb .client .model .Updates ;
26
27
import com .mongodb .event .CommandListener ;
27
28
import com .mongodb .event .CommandStartedEvent ;
29
+ import com .mongodb .event .ServerHeartbeatStartedEvent ;
30
+ import com .mongodb .event .ServerHeartbeatSucceededEvent ;
31
+ import com .mongodb .event .TestServerMonitorListener ;
32
+ import com .mongodb .internal .connection .TestCommandListener ;
28
33
import org .bson .BsonDocument ;
29
34
import org .bson .Document ;
30
35
import org .junit .jupiter .api .AfterAll ;
33
38
34
39
import java .io .File ;
35
40
import java .io .IOException ;
41
+ import java .time .Duration ;
36
42
import java .util .List ;
37
43
import java .util .Set ;
38
44
import java .util .concurrent .ConcurrentHashMap ;
39
45
import java .util .concurrent .ExecutorService ;
40
46
import java .util .concurrent .Executors ;
41
47
import java .util .concurrent .TimeUnit ;
48
+ import java .util .concurrent .TimeoutException ;
42
49
import java .util .concurrent .atomic .AtomicBoolean ;
43
50
44
51
import static com .mongodb .ClusterFixture .getDefaultDatabaseName ;
52
+ import static com .mongodb .ClusterFixture .isStandalone ;
45
53
import static com .mongodb .client .Fixture .getMongoClientSettingsBuilder ;
46
54
import static java .util .Arrays .asList ;
47
55
import static java .util .Collections .singletonList ;
56
+ import static java .util .concurrent .TimeUnit .MILLISECONDS ;
48
57
import static org .bson .assertions .Assertions .fail ;
49
58
import static org .junit .jupiter .api .Assertions .assertEquals ;
50
59
import static org .junit .jupiter .api .Assertions .assertFalse ;
51
60
import static org .junit .jupiter .api .Assertions .assertTrue ;
61
+ import static org .junit .jupiter .api .Assumptions .assumeTrue ;
52
62
53
63
// Prose tests for Sessions specification: https://github.com/mongodb/specifications/tree/master/source/sessions
54
64
// Prose test README: https://github.com/mongodb/specifications/tree/master/source/sessions/tests/README.md
@@ -194,6 +204,61 @@ public void shouldThrowOnExplicitSessionIfConnectionDoesNotSupportSessions() thr
194
204
}
195
205
}
196
206
207
+ /* Test 20 from #20-drivers-do-not-gossip-clustertime-on-sdam-commands
208
+ In this test, we check that the cluster time has not been advanced on client1 through the server monitors, after client2 advanced
209
+ the cluster time on the deployment/cluster.
210
+ */
211
+ @ Test
212
+ public void shouldNotGossipClusterTimeInServerMonitors () throws InterruptedException , TimeoutException {
213
+ assumeTrue (!isStandalone ());
214
+
215
+ //given
216
+ TestServerMonitorListener serverMonitorListener =
217
+ new TestServerMonitorListener (asList ("serverHeartbeatStartedEvent" , "serverHeartbeatSucceededEvent" ,
218
+ "serverHeartbeatFailedEvent" ));
219
+ TestCommandListener commandListener = new TestCommandListener ();
220
+ try (MongoClient client1 = getMongoClient (
221
+ getDirectPrimaryMongoClientSettingsBuilder ()
222
+ .addCommandListener (commandListener )
223
+ .applyToServerSettings (builder -> builder
224
+ .heartbeatFrequency (10 , MILLISECONDS )
225
+ .addServerMonitorListener (serverMonitorListener ))
226
+ .build ());
227
+ MongoClient client2 = getMongoClient (getDirectPrimaryMongoClientSettingsBuilder ()
228
+ .build ())) {
229
+
230
+ Document clusterTime = executePing (client1 )
231
+ .get ("$clusterTime" , Document .class );
232
+
233
+ //when
234
+ client2 .getDatabase ("test" )
235
+ .getCollection ("test" )
236
+ .insertOne (new Document ("advance" , "$clusterTime" ));
237
+
238
+ // wait until the client1 processes the next pair of SDAM heartbeat started + succeeded events.
239
+ serverMonitorListener .reset ();
240
+ serverMonitorListener .waitForEvents (ServerHeartbeatStartedEvent .class , serverHeartbeatStartedEvent -> true ,
241
+ 1 , Duration .ofMillis (20 + ClusterFixture .getPrimaryRTT ()));
242
+ serverMonitorListener .waitForEvents (ServerHeartbeatSucceededEvent .class , serverHeartbeatSucceededEvent -> true ,
243
+ 1 , Duration .ofMillis (20 + ClusterFixture .getPrimaryRTT ()));
244
+
245
+ commandListener .reset ();
246
+ executePing (client1 );
247
+
248
+ //then
249
+ List <CommandStartedEvent > pingStartedEvents = commandListener .getCommandStartedEvents ("ping" );
250
+ assertEquals (1 , pingStartedEvents .size ());
251
+ BsonDocument sentClusterTime = pingStartedEvents .get (0 ).getCommand ().getDocument ("$clusterTime" );
252
+
253
+ assertEquals (clusterTime .toBsonDocument (), sentClusterTime , "Cluster time should not have advanced after the first ping" );
254
+ }
255
+ }
256
+
257
+ private static MongoClientSettings .Builder getDirectPrimaryMongoClientSettingsBuilder () {
258
+ return getMongoClientSettingsBuilder ()
259
+ .applyToClusterSettings (ClusterFixture ::setDirectConnection );
260
+ }
261
+
197
262
private static MongoClientSettings .Builder getMongocryptdMongoClientSettingsBuilder () {
198
263
return MongoClientSettings .builder ()
199
264
.applyToClusterSettings (builder ->
@@ -209,5 +274,10 @@ private static Process startMongocryptdProcess() throws IOException {
209
274
processBuilder .redirectOutput (new File ("/tmp/mongocryptd.log" ));
210
275
return processBuilder .start ();
211
276
}
277
+
278
+ private static Document executePing (final MongoClient client1 ) {
279
+ return client1 .getDatabase ("admin" )
280
+ .runCommand (new Document ("ping" , 1 ));
281
+ }
212
282
}
213
283
0 commit comments