Skip to content

Commit 8fdbd8e

Browse files
authored
Add prose test to verify server monitors do not gossip cluster time. (#1766)
JAVA-5546
1 parent 5f2c539 commit 8fdbd8e

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

driver-core/src/test/unit/com/mongodb/event/TestServerMonitorListener.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ public TestServerMonitorListener(final Iterable<String> listenableEventTypes) {
5353
events = new ArrayList<>();
5454
}
5555

56+
public void reset() {
57+
lock.lock();
58+
try {
59+
events.clear();
60+
condition.signalAll();
61+
} finally {
62+
lock.unlock();
63+
}
64+
}
65+
5666
public void serverHearbeatStarted(final ServerHeartbeatStartedEvent event) {
5767
register(event);
5868
}
@@ -65,7 +75,7 @@ public void serverHeartbeatFailed(final ServerHeartbeatFailedEvent event) {
6575
register(event);
6676
}
6777

68-
public <T> void waitForEvents(final Class<T> type, final Predicate<? super T> matcher, final int count, final Duration duration)
78+
public <T> void waitForEvents(final Class<T> type, final Predicate<? super T> matcher, final long count, final Duration duration)
6979
throws InterruptedException, TimeoutException {
7080
assertTrue(listenable(type));
7181
long remainingNanos = duration.toNanos();

driver-sync/src/test/functional/com/mongodb/client/AbstractSessionsProseTest.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.mongodb.client;
1818

19+
import com.mongodb.ClusterFixture;
1920
import com.mongodb.MongoClientException;
2021
import com.mongodb.MongoClientSettings;
2122
import com.mongodb.MongoCommandException;
@@ -25,6 +26,10 @@
2526
import com.mongodb.client.model.Updates;
2627
import com.mongodb.event.CommandListener;
2728
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;
2833
import org.bson.BsonDocument;
2934
import org.bson.Document;
3035
import org.junit.jupiter.api.AfterAll;
@@ -33,22 +38,27 @@
3338

3439
import java.io.File;
3540
import java.io.IOException;
41+
import java.time.Duration;
3642
import java.util.List;
3743
import java.util.Set;
3844
import java.util.concurrent.ConcurrentHashMap;
3945
import java.util.concurrent.ExecutorService;
4046
import java.util.concurrent.Executors;
4147
import java.util.concurrent.TimeUnit;
48+
import java.util.concurrent.TimeoutException;
4249
import java.util.concurrent.atomic.AtomicBoolean;
4350

4451
import static com.mongodb.ClusterFixture.getDefaultDatabaseName;
52+
import static com.mongodb.ClusterFixture.isStandalone;
4553
import static com.mongodb.client.Fixture.getMongoClientSettingsBuilder;
4654
import static java.util.Arrays.asList;
4755
import static java.util.Collections.singletonList;
56+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
4857
import static org.bson.assertions.Assertions.fail;
4958
import static org.junit.jupiter.api.Assertions.assertEquals;
5059
import static org.junit.jupiter.api.Assertions.assertFalse;
5160
import static org.junit.jupiter.api.Assertions.assertTrue;
61+
import static org.junit.jupiter.api.Assumptions.assumeTrue;
5262

5363
// Prose tests for Sessions specification: https://github.com/mongodb/specifications/tree/master/source/sessions
5464
// Prose test README: https://github.com/mongodb/specifications/tree/master/source/sessions/tests/README.md
@@ -194,6 +204,61 @@ public void shouldThrowOnExplicitSessionIfConnectionDoesNotSupportSessions() thr
194204
}
195205
}
196206

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+
197262
private static MongoClientSettings.Builder getMongocryptdMongoClientSettingsBuilder() {
198263
return MongoClientSettings.builder()
199264
.applyToClusterSettings(builder ->
@@ -209,5 +274,10 @@ private static Process startMongocryptdProcess() throws IOException {
209274
processBuilder.redirectOutput(new File("/tmp/mongocryptd.log"));
210275
return processBuilder.start();
211276
}
277+
278+
private static Document executePing(final MongoClient client1) {
279+
return client1.getDatabase("admin")
280+
.runCommand(new Document("ping", 1));
281+
}
212282
}
213283

0 commit comments

Comments
 (0)