From 06d944db5e10b152415a1d878d97f98e00c9416d Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Thu, 28 Dec 2023 13:30:24 -0800
Subject: [PATCH 01/19] Add CSOT to GridFS operations.
JAVA-5277
---
.../com/mongodb/internal/TimeoutContext.java | 2 +-
.../client/CommandMonitoringTestHelper.java | 4 +-
.../connection/TestCommandListener.java | 10 +-
.../client/gridfs/GridFSFindPublisher.java | 16 --
.../gridfs/GridFSFindPublisherImpl.java | 7 -
.../ClientSideOperationTimeoutProseTest.java | 29 ++-
.../client/ReadConcernTest.java | 3 +-
.../client/internal/BatchCursorFluxTest.java | 2 +-
.../client/syncadapter/SyncGridFSBucket.java | 11 ++
.../ClientSideOperationTimeoutTest.java | 1 +
.../mongodb/client/gridfs/GridFSBucket.java | 48 +++++
.../client/gridfs/GridFSBucketImpl.java | 171 +++++++++++++-----
.../gridfs/GridFSDownloadStreamImpl.java | 42 ++++-
.../client/gridfs/GridFSFindIterable.java | 24 ---
.../client/gridfs/GridFSFindIterableImpl.java | 6 -
.../client/gridfs/GridFSUploadStreamImpl.java | 40 +++-
.../mongodb/client/gridfs/TimeoutUtils.java | 44 +++++
...tractClientSideEncryptionDeadlockTest.java | 4 +-
.../AbstractClientSideEncryptionTest.java | 3 +-
...tClientSideOperationsTimeoutProseTest.java | 131 +++++++++++++-
.../com/mongodb/client/AbstractCrudTest.java | 3 +-
.../client/AbstractRetryableReadsTest.java | 3 +-
.../AbstractServerSelectionProseTest.java | 3 +-
.../mongodb/client/AbstractUnifiedTest.java | 6 +-
.../ClientSideOperationTimeoutProseTest.java | 7 +
.../ClientSideOperationTimeoutTest.java | 13 +-
.../com/mongodb/client/ReadConcernTest.java | 2 +-
.../mongodb/client/unified/ErrorMatcher.java | 1 +
.../client/unified/UnifiedCrudHelper.java | 11 +-
.../client/unified/UnifiedGridFSHelper.java | 94 +++++++++-
.../mongodb/client/unified/UnifiedTest.java | 13 +-
.../client/unified/UnifiedTestUtils.java | 34 ++++
.../GridFSDownloadStreamSpecification.groovy | 29 +--
33 files changed, 646 insertions(+), 171 deletions(-)
create mode 100644 driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
create mode 100644 driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java
diff --git a/driver-core/src/main/com/mongodb/internal/TimeoutContext.java b/driver-core/src/main/com/mongodb/internal/TimeoutContext.java
index 010bfb2b0f6..2c1a5eee246 100644
--- a/driver-core/src/main/com/mongodb/internal/TimeoutContext.java
+++ b/driver-core/src/main/com/mongodb/internal/TimeoutContext.java
@@ -212,7 +212,7 @@ public int hashCode() {
}
@Nullable
- private static Timeout calculateTimeout(@Nullable final Long timeoutMS) {
+ public static Timeout calculateTimeout(@Nullable final Long timeoutMS) {
if (timeoutMS != null) {
return timeoutMS == 0 ? Timeout.infinite() : Timeout.expiresIn(timeoutMS, MILLISECONDS);
}
diff --git a/driver-core/src/test/functional/com/mongodb/client/CommandMonitoringTestHelper.java b/driver-core/src/test/functional/com/mongodb/client/CommandMonitoringTestHelper.java
index 8ba3a5b3851..3a99277ef65 100644
--- a/driver-core/src/test/functional/com/mongodb/client/CommandMonitoringTestHelper.java
+++ b/driver-core/src/test/functional/com/mongodb/client/CommandMonitoringTestHelper.java
@@ -120,11 +120,11 @@ static boolean isWriteCommand(final String commandName) {
return asList("insert", "update", "delete").contains(commandName);
}
- public static void assertEventsEquality(final List expectedEvents, final List events) {
+ public static void assertEventsEquality(final List expectedEvents, final List extends CommandEvent> events) {
assertEventsEquality(expectedEvents, events, null);
}
- public static void assertEventsEquality(final List expectedEvents, final List events,
+ public static void assertEventsEquality(final List expectedEvents, final List extends CommandEvent> events,
@Nullable final Map lsidMap) {
assertEquals(expectedEvents.size(), events.size());
diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java b/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java
index 0a2838c2d55..6e1dda106bd 100644
--- a/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java
+++ b/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java
@@ -143,17 +143,17 @@ public CommandFailedEvent getCommandFailedEvent(final String commandName) {
.orElseThrow(() -> new IllegalArgumentException(commandName + " not found in command failed event list"));
}
- public List getCommandStartedEvents() {
+ public List getCommandStartedEvents() {
return getCommandStartedEvents(Integer.MAX_VALUE);
}
- private List getCommandStartedEvents(final int maxEvents) {
+ private List getCommandStartedEvents(final int maxEvents) {
lock.lock();
try {
- List commandStartedEvents = new ArrayList<>();
+ List commandStartedEvents = new ArrayList<>();
for (CommandEvent cur : getEvents()) {
if (cur instanceof CommandStartedEvent) {
- commandStartedEvents.add(cur);
+ commandStartedEvents.add((CommandStartedEvent) cur);
}
if (commandStartedEvents.size() == maxEvents) {
break;
@@ -165,7 +165,7 @@ private List getCommandStartedEvents(final int maxEvents) {
}
}
- public List waitForStartedEvents(final int numEvents) {
+ public List waitForStartedEvents(final int numEvents) {
lock.lock();
try {
while (!hasCompletedEvents(numEvents)) {
diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/gridfs/GridFSFindPublisher.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/gridfs/GridFSFindPublisher.java
index e7cecf230a4..75f7a7cac10 100644
--- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/gridfs/GridFSFindPublisher.java
+++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/gridfs/GridFSFindPublisher.java
@@ -16,12 +16,9 @@
package com.mongodb.reactivestreams.client.gridfs;
-import com.mongodb.client.cursor.TimeoutMode;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.model.Collation;
import com.mongodb.lang.Nullable;
-import com.mongodb.reactivestreams.client.MongoCollection;
-import com.mongodb.reactivestreams.client.MongoDatabase;
import org.bson.conversions.Bson;
import org.reactivestreams.Publisher;
@@ -127,17 +124,4 @@ public interface GridFSFindPublisher extends Publisher {
* @mongodb.driver.manual reference/method/cursor.batchSize/#cursor.batchSize Batch Size
*/
GridFSFindPublisher batchSize(int batchSize);
-
- /**
- * Sets the timeoutMode for the cursor.
- *
- *
- * Requires the {@code timeout} to be set, either in the {@link com.mongodb.MongoClientSettings},
- * via {@link MongoDatabase} or via {@link MongoCollection}
- *
- * @param timeoutMode the timeout mode
- * @return this
- * @since 4.x
- */
- GridFSFindPublisher timeoutMode(TimeoutMode timeoutMode);
}
diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSFindPublisherImpl.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSFindPublisherImpl.java
index 020b82fee20..41ee872c05e 100644
--- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSFindPublisherImpl.java
+++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSFindPublisherImpl.java
@@ -16,7 +16,6 @@
package com.mongodb.reactivestreams.client.internal.gridfs;
-import com.mongodb.client.cursor.TimeoutMode;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.model.Collation;
import com.mongodb.lang.Nullable;
@@ -93,12 +92,6 @@ public GridFSFindPublisher batchSize(final int batchSize) {
return this;
}
- @Override
- public GridFSFindPublisher timeoutMode(final TimeoutMode timeoutMode) {
- wrapped.timeoutMode(timeoutMode);
- return this;
- }
-
@Override
public void subscribe(final Subscriber super GridFSFile> s) {
wrapped.subscribe(s);
diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ClientSideOperationTimeoutProseTest.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ClientSideOperationTimeoutProseTest.java
index 3648fa29cee..878fe979fa6 100644
--- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ClientSideOperationTimeoutProseTest.java
+++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ClientSideOperationTimeoutProseTest.java
@@ -19,16 +19,43 @@
import com.mongodb.MongoClientSettings;
import com.mongodb.client.AbstractClientSideOperationsTimeoutProseTest;
import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.gridfs.GridFSBucket;
+import com.mongodb.reactivestreams.client.gridfs.GridFSBuckets;
+import com.mongodb.reactivestreams.client.syncadapter.SyncGridFSBucket;
import com.mongodb.reactivestreams.client.syncadapter.SyncMongoClient;
+import org.junit.jupiter.api.Disabled;
/**
* See https://github.com/mongodb/specifications/blob/master/source/client-side-operations-timeout/tests/README.rst#prose-tests
*/
public final class ClientSideOperationTimeoutProseTest extends AbstractClientSideOperationsTimeoutProseTest {
+ private com.mongodb.reactivestreams.client.MongoClient wrapped;
@Override
protected MongoClient createMongoClient(final MongoClientSettings mongoClientSettings) {
- return new SyncMongoClient(MongoClients.create(mongoClientSettings));
+ wrapped = MongoClients.create(mongoClientSettings);
+ return new SyncMongoClient(wrapped);
+ }
+
+ @Override
+ protected GridFSBucket createGridFsBucket(final MongoDatabase mongoDatabase, final String bucketName) {
+ return new SyncGridFSBucket(GridFSBuckets.create(wrapped.getDatabase(mongoDatabase.getName()), bucketName));
+ }
+
+ @Override
+ @Disabled("TODO (CSOT) - JAVA-4057")
+ public void testGridFSUploadViaOpenUploadStreamTimeout() {
+ }
+
+ @Disabled("TODO (CSOT) - JAVA-4057")
+ @Override
+ public void testAbortingGridFsUploadStreamTimeout() {
+ }
+
+ @Disabled("TODO (CSOT) - JAVA-4057")
+ @Override
+ public void testGridFsDownloadStreamTimeout() {
}
}
diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ReadConcernTest.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ReadConcernTest.java
index 15b1bc7f5cf..eef7cfbe9fe 100644
--- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ReadConcernTest.java
+++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/ReadConcernTest.java
@@ -17,7 +17,6 @@
package com.mongodb.reactivestreams.client;
import com.mongodb.ReadConcern;
-import com.mongodb.event.CommandEvent;
import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import org.bson.BsonDocument;
@@ -65,7 +64,7 @@ public void shouldIncludeReadConcernInCommand() throws InterruptedException {
.find())
.block(TIMEOUT_DURATION);
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
BsonDocument commandDocument = new BsonDocument("find", new BsonString("test"))
.append("readConcern", ReadConcern.LOCAL.asDocument())
diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/internal/BatchCursorFluxTest.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/internal/BatchCursorFluxTest.java
index 410dfd02fc4..ebbd2069f70 100644
--- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/internal/BatchCursorFluxTest.java
+++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/internal/BatchCursorFluxTest.java
@@ -373,7 +373,7 @@ public void testBatchCursorReportsCursorErrors() {
BsonDocument getMoreCommand = commandListener.getCommandStartedEvents().stream()
.filter(e -> e.getCommandName().equals("getMore"))
- .map(e -> ((CommandStartedEvent) e).getCommand())
+ .map(CommandStartedEvent::getCommand)
.findFirst()
.get();
diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/syncadapter/SyncGridFSBucket.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/syncadapter/SyncGridFSBucket.java
index a09b4ffbec3..5ed29caf4a0 100644
--- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/syncadapter/SyncGridFSBucket.java
+++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/syncadapter/SyncGridFSBucket.java
@@ -42,6 +42,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import static com.mongodb.ClusterFixture.TIMEOUT_DURATION;
import static com.mongodb.reactivestreams.client.syncadapter.ContextHelper.CONTEXT;
@@ -79,6 +80,11 @@ public ReadConcern getReadConcern() {
return wrapped.getReadConcern();
}
+ @Override
+ public Long getTimeout(final TimeUnit timeUnit) {
+ throw new UnsupportedOperationException("Not implemented yet!");
+ }
+
@Override
public GridFSBucket withChunkSizeBytes(final int chunkSizeBytes) {
return new SyncGridFSBucket(wrapped.withChunkSizeBytes(chunkSizeBytes));
@@ -99,6 +105,11 @@ public GridFSBucket withReadConcern(final ReadConcern readConcern) {
return new SyncGridFSBucket(wrapped.withReadConcern(readConcern));
}
+ @Override
+ public GridFSBucket withTimeout(final long timeout, final TimeUnit timeUnit) {
+ throw new UnsupportedOperationException("Not implemented yet!");
+ }
+
@Override
public GridFSUploadStream openUploadStream(final String filename) {
return openUploadStream(filename, new GridFSUploadOptions());
diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/ClientSideOperationTimeoutTest.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/ClientSideOperationTimeoutTest.java
index b3bceab35d2..91b877214cf 100644
--- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/ClientSideOperationTimeoutTest.java
+++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/ClientSideOperationTimeoutTest.java
@@ -53,6 +53,7 @@ public ClientSideOperationTimeoutTest(final String fileDescription, final String
assumeFalse(testDescription.endsWith("createChangeStream on client"));
assumeFalse(testDescription.endsWith("createChangeStream on database"));
assumeFalse(testDescription.endsWith("createChangeStream on collection"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", fileDescription.contains("GridFS"));
checkSkipCSOTTest(fileDescription, testDescription);
if (testDescription.equals("timeoutMS is refreshed for close")) {
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java
index c32f114844c..8b251199d67 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java
@@ -23,12 +23,14 @@
import com.mongodb.client.ClientSession;
import com.mongodb.client.gridfs.model.GridFSDownloadOptions;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
+import com.mongodb.lang.Nullable;
import org.bson.BsonValue;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.concurrent.TimeUnit;
/**
* Represents a GridFS Bucket
@@ -76,6 +78,36 @@ public interface GridFSBucket {
*/
ReadConcern getReadConcern();
+ /**
+ * The time limit for the full execution of an operation.
+ *
+ * If not null the following deprecated options will be ignored:
+ * {@code waitQueueTimeoutMS}, {@code socketTimeoutMS}, {@code wTimeoutMS}, {@code maxTimeMS} and {@code maxCommitTimeMS}
+ *
+ *
+ * - {@code null} means that the timeout mechanism for operations will defer to using:
+ *
+ * - {@code waitQueueTimeoutMS}: The maximum wait time in milliseconds that a thread may wait for a connection to become
+ * available
+ * - {@code socketTimeoutMS}: How long a send or receive on a socket can take before timing out.
+ * - {@code wTimeoutMS}: How long the server will wait for the write concern to be fulfilled before timing out.
+ * - {@code maxTimeMS}: The cumulative time limit for processing operations on a cursor.
+ * See: cursor.maxTimeMS.
+ * - {@code maxCommitTimeMS}: The maximum amount of time to allow a single {@code commitTransaction} command to execute.
+ * See: {@link com.mongodb.TransactionOptions#getMaxCommitTime}.
+ *
+ *
+ * - {@code 0} means infinite timeout.
+ * - {@code > 0} The time limit to use for the full execution of an operation.
+ *
+ *
+ * @param timeUnit the time unit
+ * @return the timeout in the given time unit
+ * @since 4.x
+ */
+ @Nullable
+ Long getTimeout(TimeUnit timeUnit);
+
/**
* Create a new GridFSBucket instance with a new chunk size in bytes.
*
@@ -111,6 +143,22 @@ public interface GridFSBucket {
*/
GridFSBucket withReadConcern(ReadConcern readConcern);
+ /**
+ * Create a new GridFSBucket instance with the set time limit for the full execution of an operation.
+ *
+ *
+ * - {@code 0} means infinite timeout.
+ * - {@code > 0} The time limit to use for the full execution of an operation.
+ *
+ *
+ * @param timeout the timeout, which must be greater than or equal to 0
+ * @param timeUnit the time unit
+ * @return a new GridFSBucket instance with the set time limit for the full execution of an operation
+ * @since 4.x
+ * @see #getTimeout
+ */
+ GridFSBucket withTimeout(long timeout, TimeUnit timeUnit);
+
/**
* Opens a Stream that the application can write the contents of the file to.
*
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
index f365bd2980a..c50e7dfd664 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
@@ -17,6 +17,7 @@
package com.mongodb.client.gridfs;
import com.mongodb.MongoClientSettings;
+import com.mongodb.MongoExecutionTimeoutException;
import com.mongodb.MongoGridFSException;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
@@ -26,12 +27,16 @@
import com.mongodb.client.ListIndexesIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.cursor.TimeoutMode;
import com.mongodb.client.gridfs.model.GridFSDownloadOptions;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
+import com.mongodb.internal.TimeoutContext;
+
+import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;
import org.bson.BsonObjectId;
@@ -46,19 +51,25 @@
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import static com.mongodb.ReadPreference.primary;
+import static com.mongodb.assertions.Assertions.isTrueArgument;
import static com.mongodb.assertions.Assertions.notNull;
import static java.lang.String.format;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
final class GridFSBucketImpl implements GridFSBucket {
private static final int DEFAULT_CHUNKSIZE_BYTES = 255 * 1024;
+ private static final String TIMEOUT_MESSAGE = "GridFS operation timed out";
private final String bucketName;
private final int chunkSizeBytes;
private final MongoCollection filesCollection;
private final MongoCollection chunksCollection;
private volatile boolean checkedIndexes;
+ @Nullable
+ private final Long timeoutMs;
GridFSBucketImpl(final MongoDatabase database) {
this(database, "fs");
@@ -67,15 +78,16 @@ final class GridFSBucketImpl implements GridFSBucket {
GridFSBucketImpl(final MongoDatabase database, final String bucketName) {
this(notNull("bucketName", bucketName), DEFAULT_CHUNKSIZE_BYTES,
getFilesCollection(notNull("database", database), bucketName),
- getChunksCollection(database, bucketName));
+ getChunksCollection(database, bucketName), database.getTimeout(TimeUnit.MILLISECONDS));
}
GridFSBucketImpl(final String bucketName, final int chunkSizeBytes, final MongoCollection filesCollection,
- final MongoCollection chunksCollection) {
+ final MongoCollection chunksCollection, @Nullable final Long timeoutMs) {
this.bucketName = notNull("bucketName", bucketName);
this.chunkSizeBytes = chunkSizeBytes;
this.filesCollection = notNull("filesCollection", filesCollection);
this.chunksCollection = notNull("chunksCollection", chunksCollection);
+ this.timeoutMs = timeoutMs;
}
@Override
@@ -103,27 +115,40 @@ public ReadConcern getReadConcern() {
return filesCollection.getReadConcern();
}
+ @Override
+ public Long getTimeout(final TimeUnit timeUnit) {
+ return timeoutMs == null ? null : notNull("timeUnit", timeUnit).convert(timeoutMs, MILLISECONDS);
+ }
+
@Override
public GridFSBucket withChunkSizeBytes(final int chunkSizeBytes) {
- return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection);
+ return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection, timeoutMs);
}
@Override
public GridFSBucket withReadPreference(final ReadPreference readPreference) {
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withReadPreference(readPreference),
- chunksCollection.withReadPreference(readPreference));
+ chunksCollection.withReadPreference(readPreference), timeoutMs);
}
@Override
public GridFSBucket withWriteConcern(final WriteConcern writeConcern) {
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withWriteConcern(writeConcern),
- chunksCollection.withWriteConcern(writeConcern));
+ chunksCollection.withWriteConcern(writeConcern), timeoutMs);
}
@Override
public GridFSBucket withReadConcern(final ReadConcern readConcern) {
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withReadConcern(readConcern),
- chunksCollection.withReadConcern(readConcern));
+ chunksCollection.withReadConcern(readConcern), timeoutMs);
+ }
+
+ @Override
+ public GridFSBucket withTimeout(final long timeout, final TimeUnit timeUnit) {
+ isTrueArgument("timeout >= 0", timeout >= 0);
+ notNull("timeUnit", timeUnit);
+ return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection,
+ chunksCollection, MILLISECONDS.convert(timeout, timeUnit));
}
@Override
@@ -176,12 +201,14 @@ public GridFSUploadStream openUploadStream(final ClientSession clientSession, fi
private GridFSUploadStream createGridFSUploadStream(@Nullable final ClientSession clientSession, final BsonValue id,
final String filename, final GridFSUploadOptions options) {
+ Timeout operationTimeout = startTimeout();
notNull("options", options);
Integer chunkSizeBytes = options.getChunkSizeBytes();
int chunkSize = chunkSizeBytes == null ? this.chunkSizeBytes : chunkSizeBytes;
- checkCreateIndex(clientSession);
- return new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, id, filename, chunkSize,
- options.getMetadata());
+ checkCreateIndex(clientSession, operationTimeout);
+ return new GridFSUploadStreamImpl(clientSession, filesCollection,
+ chunksCollection, id, filename, chunkSize,
+ options.getMetadata(), operationTimeout);
}
@Override
@@ -257,7 +284,10 @@ public GridFSDownloadStream openDownloadStream(final ObjectId id) {
@Override
public GridFSDownloadStream openDownloadStream(final BsonValue id) {
- return createGridFSDownloadStream(null, getFileInfoById(null, id));
+ Timeout oprationTimeout = startTimeout();
+
+ GridFSFile fileInfo = getFileInfoById(null, id, oprationTimeout);
+ return createGridFSDownloadStream(null, fileInfo, oprationTimeout);
}
@Override
@@ -267,7 +297,9 @@ public GridFSDownloadStream openDownloadStream(final String filename) {
@Override
public GridFSDownloadStream openDownloadStream(final String filename, final GridFSDownloadOptions options) {
- return createGridFSDownloadStream(null, getFileByName(null, filename, options));
+ Timeout operationTimeout = startTimeout();
+ GridFSFile file = getFileByName(null, filename, options, operationTimeout);
+ return createGridFSDownloadStream(null, file, operationTimeout);
}
@Override
@@ -278,7 +310,9 @@ public GridFSDownloadStream openDownloadStream(final ClientSession clientSession
@Override
public GridFSDownloadStream openDownloadStream(final ClientSession clientSession, final BsonValue id) {
notNull("clientSession", clientSession);
- return createGridFSDownloadStream(clientSession, getFileInfoById(clientSession, id));
+ Timeout operationTimeout = startTimeout();
+ GridFSFile fileInfoById = getFileInfoById(clientSession, id, operationTimeout);
+ return createGridFSDownloadStream(clientSession, fileInfoById, operationTimeout);
}
@Override
@@ -290,11 +324,14 @@ public GridFSDownloadStream openDownloadStream(final ClientSession clientSession
public GridFSDownloadStream openDownloadStream(final ClientSession clientSession, final String filename,
final GridFSDownloadOptions options) {
notNull("clientSession", clientSession);
- return createGridFSDownloadStream(clientSession, getFileByName(clientSession, filename, options));
+ Timeout operationTimeout = startTimeout();
+ GridFSFile file = getFileByName(clientSession, filename, options, operationTimeout);
+ return createGridFSDownloadStream(clientSession, file, operationTimeout);
}
- private GridFSDownloadStream createGridFSDownloadStream(@Nullable final ClientSession clientSession, final GridFSFile gridFSFile) {
- return new GridFSDownloadStreamImpl(clientSession, gridFSFile, chunksCollection);
+ private GridFSDownloadStream createGridFSDownloadStream(@Nullable final ClientSession clientSession, final GridFSFile gridFSFile,
+ @Nullable final Timeout operationTimeout) {
+ return new GridFSDownloadStreamImpl(clientSession, gridFSFile, chunksCollection, operationTimeout);
}
@Override
@@ -365,7 +402,12 @@ public GridFSFindIterable find(final ClientSession clientSession, final Bson fil
}
private GridFSFindIterable createGridFSFindIterable(@Nullable final ClientSession clientSession, @Nullable final Bson filter) {
- return new GridFSFindIterableImpl(createFindIterable(clientSession, filter));
+ return new GridFSFindIterableImpl(createFindIterable(clientSession, filter, startTimeout()));
+ }
+
+ private GridFSFindIterable createGridFSFindIterable(@Nullable final ClientSession clientSession, @Nullable final Bson filter,
+ @Nullable final Timeout operationTimeout) {
+ return new GridFSFindIterableImpl(createFindIterable(clientSession, filter, operationTimeout));
}
@Override
@@ -390,13 +432,18 @@ public void delete(final ClientSession clientSession, final BsonValue id) {
}
private void executeDelete(@Nullable final ClientSession clientSession, final BsonValue id) {
+ Timeout operationTimeout = startTimeout();
DeleteResult result;
if (clientSession != null) {
- result = filesCollection.deleteOne(clientSession, new BsonDocument("_id", id));
- chunksCollection.deleteMany(clientSession, new BsonDocument("files_id", id));
+ result = withNullableTimeout(filesCollection, operationTimeout)
+ .deleteOne(clientSession, new BsonDocument("_id", id));
+ withNullableTimeout(filesCollection, operationTimeout)
+ .deleteMany(clientSession, new BsonDocument("files_id", id));
} else {
- result = filesCollection.deleteOne(new BsonDocument("_id", id));
- chunksCollection.deleteMany(new BsonDocument("files_id", id));
+ result = withNullableTimeout(filesCollection, operationTimeout)
+ .deleteOne(new BsonDocument("_id", id));
+ withNullableTimeout(filesCollection, operationTimeout)
+ .deleteMany(new BsonDocument("files_id", id));
}
if (result.wasAcknowledged() && result.getDeletedCount() == 0) {
@@ -426,12 +473,13 @@ public void rename(final ClientSession clientSession, final BsonValue id, final
}
private void executeRename(@Nullable final ClientSession clientSession, final BsonValue id, final String newFilename) {
+ Timeout operationTimeout = startTimeout();
UpdateResult updateResult;
if (clientSession != null) {
- updateResult = filesCollection.updateOne(clientSession, new BsonDocument("_id", id),
+ updateResult = withNullableTimeout(filesCollection, operationTimeout).updateOne(clientSession, new BsonDocument("_id", id),
new BsonDocument("$set", new BsonDocument("filename", new BsonString(newFilename))));
} else {
- updateResult = filesCollection.updateOne(new BsonDocument("_id", id),
+ updateResult = withNullableTimeout(filesCollection, operationTimeout).updateOne(new BsonDocument("_id", id),
new BsonDocument("$set", new BsonDocument("filename", new BsonString(newFilename))));
}
@@ -442,15 +490,17 @@ private void executeRename(@Nullable final ClientSession clientSession, final Bs
@Override
public void drop() {
- filesCollection.drop();
- chunksCollection.drop();
+ Timeout oeprationTimeout = startTimeout();
+ withNullableTimeout(filesCollection, oeprationTimeout).drop();
+ withNullableTimeout(chunksCollection, oeprationTimeout).drop();
}
@Override
public void drop(final ClientSession clientSession) {
+ Timeout oeprationTimeout = startTimeout();
notNull("clientSession", clientSession);
- filesCollection.drop(clientSession);
- chunksCollection.drop(clientSession);
+ withNullableTimeout(filesCollection, oeprationTimeout).drop(clientSession);
+ withNullableTimeout(chunksCollection, oeprationTimeout).drop(clientSession);
}
private static MongoCollection getFilesCollection(final MongoDatabase database, final String bucketName) {
@@ -463,37 +513,45 @@ private static MongoCollection getChunksCollection(final MongoDatabase
return database.getCollection(bucketName + ".chunks").withCodecRegistry(MongoClientSettings.getDefaultCodecRegistry());
}
- private void checkCreateIndex(@Nullable final ClientSession clientSession) {
+ private void checkCreateIndex(@Nullable final ClientSession clientSession, @Nullable final Timeout operationTimeout) {
if (!checkedIndexes) {
- if (collectionIsEmpty(clientSession, filesCollection.withDocumentClass(Document.class).withReadPreference(primary()))) {
+ if (collectionIsEmpty(clientSession,
+ filesCollection.withDocumentClass(Document.class).withReadPreference(primary()),
+ operationTimeout)) {
+
Document filesIndex = new Document("filename", 1).append("uploadDate", 1);
- if (!hasIndex(clientSession, filesCollection.withReadPreference(primary()), filesIndex)) {
- createIndex(clientSession, filesCollection, filesIndex, new IndexOptions());
+ if (!hasIndex(clientSession, filesCollection.withReadPreference(primary()), filesIndex, operationTimeout)) {
+ createIndex(clientSession, filesCollection, filesIndex, new IndexOptions(), operationTimeout);
}
Document chunksIndex = new Document("files_id", 1).append("n", 1);
- if (!hasIndex(clientSession, chunksCollection.withReadPreference(primary()), chunksIndex)) {
- createIndex(clientSession, chunksCollection, chunksIndex, new IndexOptions().unique(true));
+ if (!hasIndex(clientSession, chunksCollection.withReadPreference(primary()), chunksIndex, operationTimeout)) {
+ createIndex(clientSession, chunksCollection, chunksIndex, new IndexOptions().unique(true), operationTimeout);
}
}
checkedIndexes = true;
}
}
- private boolean collectionIsEmpty(@Nullable final ClientSession clientSession, final MongoCollection collection) {
+ private boolean collectionIsEmpty(@Nullable final ClientSession clientSession,
+ final MongoCollection collection,
+ @Nullable final Timeout operationTimeout) {
if (clientSession != null) {
- return collection.find(clientSession).projection(new Document("_id", 1)).first() == null;
+ return withNullableTimeout(collection, operationTimeout)
+ .find(clientSession).projection(new Document("_id", 1)).first() == null;
} else {
- return collection.find().projection(new Document("_id", 1)).first() == null;
+ return withNullableTimeout(collection, operationTimeout)
+ .find().projection(new Document("_id", 1)).first() == null;
}
}
- private boolean hasIndex(@Nullable final ClientSession clientSession, final MongoCollection collection, final Document index) {
+ private boolean hasIndex(@Nullable final ClientSession clientSession, final MongoCollection collection,
+ final Document index, @Nullable final Timeout operationTimeout) {
boolean hasIndex = false;
ListIndexesIterable listIndexesIterable;
if (clientSession != null) {
- listIndexesIterable = collection.listIndexes(clientSession);
+ listIndexesIterable = withNullableTimeout(collection, operationTimeout).listIndexes(clientSession);
} else {
- listIndexesIterable = collection.listIndexes();
+ listIndexesIterable = withNullableTimeout(collection, operationTimeout).listIndexes();
}
ArrayList indexes = listIndexesIterable.into(new ArrayList<>());
@@ -513,16 +571,16 @@ private boolean hasIndex(@Nullable final ClientSession clientSession, final
}
private void createIndex(@Nullable final ClientSession clientSession, final MongoCollection collection, final Document index,
- final IndexOptions indexOptions) {
+ final IndexOptions indexOptions, final @Nullable Timeout operationTimeout) {
if (clientSession != null) {
- collection.createIndex(clientSession, index, indexOptions);
+ withNullableTimeout(collection, operationTimeout).createIndex(clientSession, index, indexOptions);
} else {
- collection.createIndex(index, indexOptions);
+ withNullableTimeout(collection, operationTimeout).createIndex(index, indexOptions);
}
}
private GridFSFile getFileByName(@Nullable final ClientSession clientSession, final String filename,
- final GridFSDownloadOptions options) {
+ final GridFSDownloadOptions options, @Nullable final Timeout operationTimeout) {
int revision = options.getRevision();
int skip;
int sort;
@@ -534,7 +592,7 @@ private GridFSFile getFileByName(@Nullable final ClientSession clientSession, fi
sort = -1;
}
- GridFSFile fileInfo = createGridFSFindIterable(clientSession, new Document("filename", filename)).skip(skip)
+ GridFSFile fileInfo = createGridFSFindIterable(clientSession, new Document("filename", filename), operationTimeout).skip(skip)
.sort(new Document("uploadDate", sort)).first();
if (fileInfo == null) {
throw new MongoGridFSException(format("No file found with the filename: %s and revision: %s", filename, revision));
@@ -542,25 +600,30 @@ private GridFSFile getFileByName(@Nullable final ClientSession clientSession, fi
return fileInfo;
}
- private GridFSFile getFileInfoById(@Nullable final ClientSession clientSession, final BsonValue id) {
+ private GridFSFile getFileInfoById(@Nullable final ClientSession clientSession, final BsonValue id,
+ @Nullable final Timeout operationTImeout) {
notNull("id", id);
- GridFSFile fileInfo = createFindIterable(clientSession, new Document("_id", id)).first();
+ GridFSFile fileInfo = createFindIterable(clientSession, new Document("_id", id), operationTImeout).first();
if (fileInfo == null) {
throw new MongoGridFSException(format("No file found with the id: %s", id));
}
return fileInfo;
}
- private FindIterable createFindIterable(@Nullable final ClientSession clientSession, @Nullable final Bson filter) {
+ private FindIterable createFindIterable(@Nullable final ClientSession clientSession, @Nullable final Bson filter,
+ @Nullable final Timeout operationTImeout) {
FindIterable findIterable;
if (clientSession != null) {
- findIterable = filesCollection.find(clientSession);
+ findIterable = withNullableTimeout(filesCollection, operationTImeout).find(clientSession);
} else {
- findIterable = filesCollection.find();
+ findIterable = withNullableTimeout(filesCollection, operationTImeout).find();
}
if (filter != null) {
findIterable = findIterable.filter(filter);
}
+ if (timeoutMs != null) {
+ findIterable.timeoutMode(TimeoutMode.CURSOR_LIFETIME);
+ }
return findIterable;
}
@@ -572,6 +635,8 @@ private void downloadToStream(final GridFSDownloadStream downloadStream, final O
while ((len = downloadStream.read(buffer)) != -1) {
destination.write(buffer, 0, len);
}
+ } catch (MongoExecutionTimeoutException e){ // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
+ throw e;
} catch (IOException e) {
savedThrowable = new MongoGridFSException("IOException when reading from the OutputStream", e);
} catch (Exception e) {
@@ -587,4 +652,14 @@ private void downloadToStream(final GridFSDownloadStream downloadStream, final O
}
}
}
+
+ private static MongoCollection withNullableTimeout(final MongoCollection chunksCollection,
+ @Nullable final Timeout timeout) {
+ return TimeoutUtils.withNullableTimeout(chunksCollection, TIMEOUT_MESSAGE, timeout);
+ }
+
+ @Nullable
+ private Timeout startTimeout() {
+ return TimeoutContext.calculateTimeout(timeoutMs);
+ }
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
index 16f0bcd7fd3..112188c303f 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
@@ -16,12 +16,15 @@
package com.mongodb.client.gridfs;
+import com.mongodb.MongoExecutionTimeoutException;
import com.mongodb.MongoGridFSException;
import com.mongodb.client.ClientSession;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
+import com.mongodb.client.cursor.TimeoutMode;
import com.mongodb.client.gridfs.model.GridFSFile;
+import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;
import org.bson.BsonValue;
import org.bson.Document;
@@ -33,12 +36,17 @@
import static com.mongodb.assertions.Assertions.notNull;
import static com.mongodb.internal.Locks.withInterruptibleLock;
import static java.lang.String.format;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
class GridFSDownloadStreamImpl extends GridFSDownloadStream {
+ private static final String TIMEOUT_MESSAGE = "The GridFS download stream has timed out";
private final ClientSession clientSession;
private final GridFSFile fileInfo;
private final MongoCollection chunksCollection;
private final BsonValue fileId;
+ /**
+ * The length, in bytes of the file to download.
+ */
private final long length;
private final int chunkSizeInBytes;
private final int numberOfChunks;
@@ -46,16 +54,20 @@ class GridFSDownloadStreamImpl extends GridFSDownloadStream {
private int batchSize;
private int chunkIndex;
private int bufferOffset;
+ /**
+ * Current byte position in the file.
+ */
private long currentPosition;
private byte[] buffer = null;
private long markPosition;
-
+ @Nullable
+ private final Timeout timeout;
private final ReentrantLock closeLock = new ReentrantLock();
private final ReentrantLock cursorLock = new ReentrantLock();
private boolean closed = false;
GridFSDownloadStreamImpl(@Nullable final ClientSession clientSession, final GridFSFile fileInfo,
- final MongoCollection chunksCollection) {
+ final MongoCollection chunksCollection, @Nullable final Timeout timeout) {
this.clientSession = clientSession;
this.fileInfo = notNull("file information", fileInfo);
this.chunksCollection = notNull("chunks collection", chunksCollection);
@@ -64,6 +76,7 @@ class GridFSDownloadStreamImpl extends GridFSDownloadStream {
length = fileInfo.getLength();
chunkSizeInBytes = fileInfo.getChunkSize();
numberOfChunks = (int) Math.ceil((double) length / chunkSizeInBytes);
+ this.timeout = timeout;
}
@Override
@@ -97,6 +110,7 @@ public int read(final byte[] b) {
@Override
public int read(final byte[] b, final int off, final int len) {
checkClosed();
+ checkTimeout();
if (currentPosition == length) {
return -1;
@@ -118,6 +132,7 @@ public int read(final byte[] b, final int off, final int len) {
@Override
public long skip(final long bytesToSkip) {
checkClosed();
+ checkTimeout();
if (bytesToSkip <= 0) {
return 0;
}
@@ -146,6 +161,7 @@ public long skip(final long bytesToSkip) {
@Override
public int available() {
checkClosed();
+ checkTimeout();
if (buffer == null) {
return 0;
} else {
@@ -166,6 +182,7 @@ public void mark(final int readlimit) {
@Override
public void reset() {
checkClosed();
+ checkTimeout();
if (currentPosition == markPosition) {
return;
}
@@ -195,6 +212,12 @@ public void close() {
});
}
+ private void checkTimeout() {
+ if (timeout != null && timeout.hasExpired()) {
+ // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
+ throw new MongoExecutionTimeoutException("The GridFS download stream has timed out");
+ }
+ }
private void checkClosed() {
withInterruptibleLock(closeLock, () -> {
if (closed) {
@@ -236,11 +259,15 @@ private MongoCursor getCursor(final int startChunkIndex) {
FindIterable findIterable;
Document filter = new Document("files_id", fileId).append("n", new Document("$gte", startChunkIndex));
if (clientSession != null) {
- findIterable = chunksCollection.find(clientSession, filter);
+ findIterable = withNullableTimeout(chunksCollection, timeout).find(clientSession, filter);
} else {
- findIterable = chunksCollection.find(filter);
+ findIterable = withNullableTimeout(chunksCollection, timeout).find(filter);
}
- return findIterable.batchSize(batchSize).sort(new Document("n", 1)).iterator();
+ if (timeout != null){
+ findIterable.timeoutMode(TimeoutMode.CURSOR_LIFETIME);
+ }
+ return findIterable.batchSize(batchSize)
+ .sort(new Document("n", 1)).iterator();
}
private byte[] getBufferFromChunk(@Nullable final Document chunk, final int expectedChunkIndex) {
@@ -279,4 +306,9 @@ private byte[] getBufferFromChunk(@Nullable final Document chunk, final int expe
private byte[] getBuffer(final int chunkIndexToFetch) {
return getBufferFromChunk(getChunk(chunkIndexToFetch), chunkIndexToFetch);
}
+
+ private MongoCollection withNullableTimeout(final MongoCollection chunksCollection,
+ @Nullable final Timeout timeout) {
+ return TimeoutUtils.withNullableTimeout(chunksCollection, TIMEOUT_MESSAGE, timeout);
+ }
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterable.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterable.java
index abd97fe499b..9b8cb8b9117 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterable.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterable.java
@@ -16,10 +16,7 @@
package com.mongodb.client.gridfs;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
-import com.mongodb.client.cursor.TimeoutMode;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.model.Collation;
import com.mongodb.lang.Nullable;
@@ -118,25 +115,4 @@ public interface GridFSFindIterable extends MongoIterable {
* @mongodb.server.release 3.4
*/
GridFSFindIterable collation(@Nullable Collation collation);
-
- /**
- * Sets the timeoutMode for the cursor.
- *
- *
- * Requires the {@code timeout} to be set, either in the {@link com.mongodb.MongoClientSettings},
- * via {@link MongoDatabase} or via {@link MongoCollection}
- *
- *
- * If the {@code timeout} is set then:
- *
- * - For non-tailable cursors, the default value of timeoutMode is {@link TimeoutMode#CURSOR_LIFETIME}
- * - For tailable cursors, the default value of timeoutMode is {@link TimeoutMode#ITERATION} and its an error
- * to configure it as: {@link TimeoutMode#CURSOR_LIFETIME}
- *
- *
- * @param timeoutMode the timeout mode
- * @return this
- * @since 4.x
- */
- GridFSFindIterable timeoutMode(TimeoutMode timeoutMode);
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java
index dbd5625f6fa..240f2ec0acc 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java
@@ -73,12 +73,6 @@ public GridFSFindIterable batchSize(final int batchSize) {
return this;
}
- @Override
- public GridFSFindIterable timeoutMode(final TimeoutMode timeoutMode) {
- underlying.timeoutMode(timeoutMode);
- return this;
- }
-
@Override
public GridFSFindIterable collation(@Nullable final Collation collation) {
underlying.collation(collation);
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
index ff359e34781..b57d2b5a76d 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
@@ -16,10 +16,12 @@
package com.mongodb.client.gridfs;
+import com.mongodb.MongoExecutionTimeoutException;
import com.mongodb.MongoGridFSException;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.gridfs.model.GridFSFile;
+import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;
import org.bson.BsonValue;
import org.bson.Document;
@@ -33,6 +35,7 @@
import static com.mongodb.internal.Locks.withInterruptibleLock;
final class GridFSUploadStreamImpl extends GridFSUploadStream {
+ public static final String TIMEOUT_MESSAGE = "The GridFS upload stream has timed out";
private final ClientSession clientSession;
private final MongoCollection filesCollection;
private final MongoCollection chunksCollection;
@@ -44,13 +47,14 @@ final class GridFSUploadStreamImpl extends GridFSUploadStream {
private long lengthInBytes;
private int bufferOffset;
private int chunkIndex;
-
+ @Nullable
+ private final Timeout timeout;
private final ReentrantLock closeLock = new ReentrantLock();
private boolean closed = false;
GridFSUploadStreamImpl(@Nullable final ClientSession clientSession, final MongoCollection filesCollection,
final MongoCollection chunksCollection, final BsonValue fileId, final String filename,
- final int chunkSizeBytes, @Nullable final Document metadata) {
+ final int chunkSizeBytes, @Nullable final Document metadata, @Nullable final Timeout timeout) {
this.clientSession = clientSession;
this.filesCollection = notNull("files collection", filesCollection);
this.chunksCollection = notNull("chunks collection", chunksCollection);
@@ -61,6 +65,7 @@ final class GridFSUploadStreamImpl extends GridFSUploadStream {
chunkIndex = 0;
bufferOffset = 0;
buffer = new byte[chunkSizeBytes];
+ this.timeout = timeout;
}
@Override
@@ -84,9 +89,11 @@ public void abort() {
});
if (clientSession != null) {
- chunksCollection.deleteMany(clientSession, new Document("files_id", fileId));
+ withNullableTimeout(chunksCollection, timeout)
+ .deleteMany(clientSession, new Document("files_id", fileId));
} else {
- chunksCollection.deleteMany(new Document("files_id", fileId));
+ withNullableTimeout(chunksCollection, timeout)
+ .deleteMany(new Document("files_id", fileId));
}
}
@@ -105,6 +112,7 @@ public void write(final byte[] b) {
@Override
public void write(final byte[] b, final int off, final int len) {
checkClosed();
+ checkTimeout();
notNull("b", b);
if ((off < 0) || (off > b.length) || (len < 0)
@@ -136,6 +144,13 @@ public void write(final byte[] b, final int off, final int len) {
}
}
+ private void checkTimeout() {
+ if (timeout != null && timeout.hasExpired()) {
+ // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
+ throw new MongoExecutionTimeoutException(TIMEOUT_MESSAGE);
+ }
+ }
+
@Override
public void close() {
boolean alreadyClosed = withInterruptibleLock(closeLock, () -> {
@@ -150,9 +165,9 @@ public void close() {
GridFSFile gridFSFile = new GridFSFile(fileId, filename, lengthInBytes, chunkSizeBytes, new Date(),
metadata);
if (clientSession != null) {
- filesCollection.insertOne(clientSession, gridFSFile);
+ withNullableTimeout(filesCollection, timeout).insertOne(clientSession, gridFSFile);
} else {
- filesCollection.insertOne(gridFSFile);
+ withNullableTimeout(filesCollection, timeout).insertOne(gridFSFile);
}
buffer = null;
}
@@ -160,10 +175,12 @@ public void close() {
private void writeChunk() {
if (bufferOffset > 0) {
if (clientSession != null) {
- chunksCollection.insertOne(clientSession, new Document("files_id", fileId).append("n", chunkIndex)
- .append("data", getData()));
+ withNullableTimeout(chunksCollection, timeout)
+ .insertOne(clientSession, new Document("files_id", fileId).append("n", chunkIndex).append("data", getData()));
} else {
- chunksCollection.insertOne(new Document("files_id", fileId).append("n", chunkIndex).append("data", getData()));
+ withNullableTimeout(chunksCollection, timeout)
+ .insertOne(new Document("files_id", fileId)
+ .append("n", chunkIndex).append("data", getData()));
}
chunkIndex++;
bufferOffset = 0;
@@ -186,4 +203,9 @@ private void checkClosed() {
}
});
}
+
+ private static MongoCollection withNullableTimeout(final MongoCollection collection,
+ @Nullable final Timeout timeout) {
+ return TimeoutUtils.withNullableTimeout(collection, TIMEOUT_MESSAGE, timeout);
+ }
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java b/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
new file mode 100644
index 00000000000..8b7349d751b
--- /dev/null
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008-present MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.mongodb.client.gridfs;
+
+import com.mongodb.MongoExecutionTimeoutException;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.internal.time.Timeout;
+import com.mongodb.lang.Nullable;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+final class TimeoutUtils {
+ private TimeoutUtils(){
+ //NOP
+ }
+
+ public static MongoCollection withNullableTimeout(final MongoCollection collection,
+ final String message,
+ @Nullable final Timeout timeout) {
+ if (timeout != null) {
+ long remainingMs = timeout.remaining(MILLISECONDS);
+ if (remainingMs <= 0) {
+ // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
+ throw new MongoExecutionTimeoutException(message);
+ }
+ return collection.withTimeout(remainingMs, MILLISECONDS);
+ }
+ return collection;
+ }
+}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionDeadlockTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionDeadlockTest.java
index ef965f0ae95..2ac985f21a6 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionDeadlockTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionDeadlockTest.java
@@ -195,11 +195,11 @@ public void shouldPassAllOutcomes(final int maxPoolSize,
}
private void assertEventEquality(final TestCommandListener commandListener, final List expectedStartEvents) {
- List actualStartedEvents = commandListener.getCommandStartedEvents();
+ List actualStartedEvents = commandListener.getCommandStartedEvents();
assertEquals(expectedStartEvents.size(), actualStartedEvents.size());
for (int i = 0; i < expectedStartEvents.size(); i++) {
ExpectedEvent expectedEvent = expectedStartEvents.get(i);
- CommandStartedEvent actualEvent = (CommandStartedEvent) actualStartedEvents.get(i);
+ CommandStartedEvent actualEvent = actualStartedEvents.get(i);
assertEquals(expectedEvent.getDatabase(), actualEvent.getDatabaseName(), "Database name");
assertEquals(expectedEvent.getCommandName(), actualEvent.getCommandName(), "Command name");
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionTest.java
index 9c14640cb4b..8d5fccaef98 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionTest.java
@@ -26,6 +26,7 @@
import com.mongodb.client.model.ValidationOptions;
import com.mongodb.client.test.CollectionHelper;
import com.mongodb.event.CommandEvent;
+import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import com.mongodb.lang.Nullable;
import org.bson.BsonArray;
@@ -325,7 +326,7 @@ public void shouldPassAllOutcomes() {
if (definition.containsKey("expectations")) {
List expectedEvents = getExpectedEvents(definition.getArray("expectations"), "default", null);
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
assertEventsEquality(expectedEvents, events);
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index fe69d0a66dd..048cab4893c 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -26,10 +26,13 @@
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
+import com.mongodb.client.gridfs.GridFSBucket;
+import com.mongodb.client.gridfs.GridFSDownloadStream;
+import com.mongodb.client.gridfs.GridFSUploadStream;
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.changestream.ChangeStreamDocument;
import com.mongodb.client.test.CollectionHelper;
-import com.mongodb.event.CommandEvent;
+import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.ServerHelper;
import com.mongodb.internal.connection.TestCommandListener;
import com.mongodb.test.FlakyTest;
@@ -38,8 +41,10 @@
import org.bson.BsonTimestamp;
import org.bson.Document;
import org.bson.codecs.BsonDocumentCodec;
+import org.bson.types.ObjectId;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.Tag;
@@ -51,6 +56,7 @@
import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet;
@@ -70,11 +76,120 @@
*/
public abstract class AbstractClientSideOperationsTimeoutProseTest {
+ private static final String GRID_FS_BUCKET_NAME = "db.fs";
+ private static final String GRID_FS_COLLECTION_NAME_CHUNKS = GRID_FS_BUCKET_NAME + ".chunks";
+ private static final String GRID_FS_COLLECTION_NAME_FILE = GRID_FS_BUCKET_NAME + ".files";
private final MongoNamespace namespace = new MongoNamespace(getDefaultDatabaseName(), this.getClass().getSimpleName());
private TestCommandListener commandListener;
private CollectionHelper collectionHelper;
-
+ private CollectionHelper filesCollectionHelper;
+ private CollectionHelper chunksCollectionHelper;
protected abstract MongoClient createMongoClient(MongoClientSettings mongoClientSettings);
+ protected abstract GridFSBucket createGridFsBucket(MongoDatabase mongoDatabase, String bucketName);
+
+ @Tag("setsFailPoint")
+ @FlakyTest(maxAttempts = 3)
+ @DisplayName("6. GridFS Upload - uploads via openUploadStream can be timed out")
+ @Disabled("TODO (CSOT) - JAVA-4057")
+ public void testGridFSUploadViaOpenUploadStreamTimeout() {
+ assumeTrue(serverVersionAtLeast(4, 4));
+ collectionHelper.runAdminCommand("{"
+ + " configureFailPoint: \"failCommand\","
+ + " mode: { times: 1 },"
+ + " data: {"
+ + " failCommands: [\"insert\"],"
+ + " blockConnection: true,"
+ + " blockTimeMS: " + 50
+ + " }"
+ + "}");
+ try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
+ .timeout(45, TimeUnit.MILLISECONDS))) {
+ MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
+ GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME);
+
+ try (GridFSUploadStream uploadStream = gridFsBucket.openUploadStream("filename")){
+ uploadStream.write(0x12);
+ assertThrows(MongoExecutionTimeoutException.class, uploadStream::close);
+ }
+ }
+ }
+
+ @Tag("setsFailPoint")
+ @FlakyTest(maxAttempts = 3)
+ @DisplayName("6. GridFS Upload - Aborting an upload stream can be timed out")
+ public void testAbortingGridFsUploadStreamTimeout() {
+ assumeTrue(serverVersionAtLeast(4, 4));
+ collectionHelper.runAdminCommand("{"
+ + " configureFailPoint: \"failCommand\","
+ + " mode: { times: 1 },"
+ + " data: {"
+ + " failCommands: [\"delete\"],"
+ + " blockConnection: true,"
+ + " blockTimeMS: " + 50
+ + " }"
+ + "}");
+ try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
+ .timeout(45, TimeUnit.MILLISECONDS))) {
+ MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
+ GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
+
+ try (GridFSUploadStream uploadStream = gridFsBucket.openUploadStream("filename")){
+ uploadStream.write(new byte[]{0x01, 0x02, 0x03, 0x04});
+ assertThrows(MongoExecutionTimeoutException.class, uploadStream::abort);
+ }
+ }
+ }
+
+ @Tag("setsFailPoint")
+ @FlakyTest(maxAttempts = 3)
+ @DisplayName("6. GridFS Download")
+ public void testGridFsDownloadStreamTimeout() {
+ assumeTrue(serverVersionAtLeast(4, 4));
+
+ try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
+ .timeout(20, TimeUnit.MILLISECONDS))) {
+ MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
+ GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
+ database.getCollection(GRID_FS_COLLECTION_NAME_FILE)
+ .insertOne(Document.parse(
+ "{"
+ + " _id: {"
+ + " $oid: \"000000000000000000000005\""
+ + " },"
+ + " length: 10,"
+ + " chunkSize: 4,"
+ + " uploadDate: {"
+ + " $date: \"1970-01-01T00:00:00.000Z\""
+ + " },"
+ + " md5: \"57d83cd477bfb1ccd975ab33d827a92b\","
+ + " filename: \"length-10\","
+ + " contentType: \"application/octet-stream\","
+ + " aliases: [],"
+ + " metadata: {}"
+ + "}"
+ ));
+
+ try (GridFSDownloadStream downloadStream = gridFsBucket.openDownloadStream(new ObjectId("000000000000000000000005"))){
+ collectionHelper.runAdminCommand("{"
+ + " configureFailPoint: \"failCommand\","
+ + " mode: { times: 1 },"
+ + " data: {"
+ + " failCommands: [\"find\"],"
+ + " blockConnection: true,"
+ + " blockTimeMS: " + 25
+ + " }"
+ + "}");
+ assertThrows(MongoExecutionTimeoutException.class, downloadStream::read);
+
+ List events = commandListener.getCommandStartedEvents();
+ List findCommands = events.stream().filter(e -> e.getCommandName().equals("find")).collect(Collectors.toList());
+
+ assertEquals(2, findCommands.size());
+ assertEquals(GRID_FS_COLLECTION_NAME_FILE, findCommands.get(0).getCommand().getString("find").getValue());
+ assertEquals(GRID_FS_COLLECTION_NAME_CHUNKS, findCommands.get(1).getCommand().getString("find").getValue());
+ }
+ }
+ }
@Tag("setsFailPoint")
@FlakyTest(maxAttempts = 3)
@@ -105,7 +220,7 @@ public void testBlockingIterationMethodsTailableCursor() {
assertThrows(MongoExecutionTimeoutException.class, cursor::next);
}
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
assertEquals(1, events.stream().filter(e -> e.getCommandName().equals("find")).count());
assertTrue(events.stream().filter(e -> e.getCommandName().equals("getMore")).count() <= 2);
}
@@ -149,7 +264,7 @@ public void testBlockingIterationMethodsChangeStream() {
assertEquals(1, document.getFullDocument().get("x"));
assertThrows(MongoExecutionTimeoutException.class, cursor::next);
}
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
assertEquals(1, events.stream().filter(e -> e.getCommandName().equals("find")).count());
assertEquals(1, events.stream().filter(e -> e.getCommandName().equals("getMore")).count());
}
@@ -203,7 +318,13 @@ private MongoClientSettings.Builder getMongoClientSettingsBuilder() {
@BeforeEach
public void setUp() {
collectionHelper = new CollectionHelper<>(new BsonDocumentCodec(), namespace);
+ filesCollectionHelper = new CollectionHelper<>(new BsonDocumentCodec(),
+ new MongoNamespace(getDefaultDatabaseName(), GRID_FS_COLLECTION_NAME_FILE));
+ chunksCollectionHelper = new CollectionHelper<>(new BsonDocumentCodec(),
+ new MongoNamespace(getDefaultDatabaseName(), GRID_FS_COLLECTION_NAME_CHUNKS));
collectionHelper.drop();
+ filesCollectionHelper.drop();
+ chunksCollectionHelper.drop();
commandListener = new TestCommandListener();
}
@@ -214,6 +335,8 @@ public void tearDown(final TestInfo info) {
}
collectionHelper.drop();
+ filesCollectionHelper.drop();
+ chunksCollectionHelper.drop();
try {
ServerHelper.checkPool(getPrimary());
} catch (InterruptedException e) {
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractCrudTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractCrudTest.java
index fe78841bec4..634f9946ea3 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractCrudTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractCrudTest.java
@@ -22,6 +22,7 @@
import com.mongodb.client.test.CollectionHelper;
import com.mongodb.event.CommandEvent;
import com.mongodb.event.CommandListener;
+import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import org.bson.BsonArray;
import org.bson.BsonBoolean;
@@ -152,7 +153,7 @@ public void shouldPassAllOutcomes() {
}
if (definition.containsKey("expectations")) {
List expectedEvents = getExpectedEvents(definition.getArray("expectations"), databaseName, null);
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
assertEventsEquality(expectedEvents, events.subList(0, expectedEvents.size()));
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsTest.java
index 1df7174e246..34620130a40 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsTest.java
@@ -28,6 +28,7 @@
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.test.CollectionHelper;
import com.mongodb.event.CommandEvent;
+import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import org.bson.BsonArray;
import org.bson.BsonBinary;
@@ -235,7 +236,7 @@ public void shouldPassAllOutcomes() {
if (definition.containsKey("expectations")) {
List expectedEvents = getExpectedEvents(definition.getArray("expectations"), databaseName, null);
- List events = commandListener.waitForStartedEvents(expectedEvents.size());
+ List events = commandListener.waitForStartedEvents(expectedEvents.size());
assertEventsEquality(expectedEvents, events);
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java
index 894d291a743..4fff4583426 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java
@@ -19,6 +19,7 @@
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.event.CommandEvent;
+import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import org.bson.BsonArray;
import org.bson.BsonBoolean;
@@ -133,7 +134,7 @@ private static Map doSelections(final MongoCollection result : results) {
result.get();
}
- List commandStartedEvents = commandListener.getCommandStartedEvents();
+ List commandStartedEvents = commandListener.getCommandStartedEvents();
assertEquals(tasks * opsPerTask, commandStartedEvents.size());
return commandStartedEvents.stream()
.collect(groupingBy(event -> event.getConnectionDescription().getServerAddress()))
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java
index cbfab4725bc..75b3ea67b70 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java
@@ -393,7 +393,7 @@ public void shouldPassAllOutcomes() {
if (definition.containsKey("expectations")) {
List expectedEvents = getExpectedEvents(definition.getArray("expectations"), databaseName, null);
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
assertTrue("Actual number of events is less than expected number of events", events.size() >= expectedEvents.size());
assertEventsEquality(expectedEvents, events.subList(0, expectedEvents.size()), lsidMap);
@@ -723,9 +723,9 @@ private boolean assertExceptionState(final Exception e, final BsonValue expected
}
private List lastTwoCommandEvents() {
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
assertTrue(events.size() >= 2);
- return events.subList(events.size() - 2, events.size());
+ return new ArrayList<>(events.subList(events.size() - 2, events.size()));
}
private TransactionOptions createTransactionOptions(final BsonDocument options) {
diff --git a/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutProseTest.java
index 2febc6f271f..9df68ddad5d 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutProseTest.java
@@ -17,6 +17,8 @@
package com.mongodb.client;
import com.mongodb.MongoClientSettings;
+import com.mongodb.client.gridfs.GridFSBucket;
+import com.mongodb.client.gridfs.GridFSBuckets;
/**
@@ -28,4 +30,9 @@ public final class ClientSideOperationTimeoutProseTest extends AbstractClientSid
protected MongoClient createMongoClient(final MongoClientSettings mongoClientSettings) {
return MongoClients.create(mongoClientSettings);
}
+
+ @Override
+ protected GridFSBucket createGridFsBucket(final MongoDatabase mongoDatabase, final String bucketName) {
+ return GridFSBuckets.create(mongoDatabase, bucketName);
+ }
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java b/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java
index 3adaec1916b..2719b85e522 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java
@@ -86,13 +86,24 @@ public static void checkSkipCSOTTest(final String fileDescription, final String
assumeFalse("TODO (CSOT) - JAVA-4052", fileDescription.startsWith("legacy timeouts behave correctly for retryable operations"));
assumeFalse("TODO (CSOT) - JAVA-4063", testDescription.contains("RTT"));
- assumeFalse("TODO (CSOT) - JAVA-4059", fileDescription.contains("GridFS"));
assumeFalse("TODO (CSOT) - JAVA-5248",
fileDescription.equals("MaxTimeMSExpired server errors are transformed into a custom timeout error"));
assumeFalse("TODO (CSOT) - JAVA-4062", testDescription.contains("wTimeoutMS is ignored"));
+ if (fileDescription.contains("GridFS")) {
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("chunk insertion"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("creation of files document"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("delete against the files collection"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("delete against the chunks collection"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("overridden for a rename"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("update during a rename"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("collection drop"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("drop as a whole"));
+ assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("entire delete"));
+ }
+
assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.equals("maxTimeMS value in the command is less than timeoutMS"));
assumeFalse("TODO (CSOT) - JAVA-4057", fileDescription.contains("bulkWrite") || testDescription.contains("bulkWrite"));
diff --git a/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java b/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java
index 6521fa67010..3ed0d975650 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java
@@ -64,7 +64,7 @@ public void shouldIncludeReadConcernInCommand() {
mongoClient.getDatabase(getDefaultDatabaseName()).getCollection("test")
.withReadConcern(ReadConcern.LOCAL).find().into(new ArrayList<>());
- List events = commandListener.getCommandStartedEvents();
+ List events = commandListener.getCommandStartedEvents();
BsonDocument commandDocument = new BsonDocument("find", new BsonString("test"))
.append("readConcern", ReadConcern.LOCAL.asDocument())
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java b/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java
index 90f358be35a..47878c4c11e 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java
@@ -65,6 +65,7 @@ void assertErrorsMatch(final BsonDocument expectedError, final Exception e) {
|| e instanceof MongoSocketException);
}
if (expectedError.containsKey("isTimeoutError")) {
+ e.printStackTrace();
assertEquals(context.getMessage("Exception must be of type MongoExecutionTimeoutException"),
expectedError.getBoolean("isTimeoutError").getValue(),
e instanceof MongoExecutionTimeoutException);
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
index 08c4acc117c..d27c2e71ce3 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
@@ -105,6 +105,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
+import static com.mongodb.client.unified.UnifiedTestUtils.getAndRemoveTimeoutMS;
import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
@@ -1737,16 +1738,6 @@ private MongoCollection getMongoCollection(final BsonDocument oper
return collection;
}
- @Nullable
- private Long getAndRemoveTimeoutMS(final BsonDocument arguments) {
- Long timeoutMS = null;
- if (arguments.containsKey("timeoutMS")) {
- timeoutMS = arguments.getNumber("timeoutMS").longValue();
- arguments.remove("timeoutMS");
- }
- return timeoutMS;
- }
-
private static void setCursorType(final FindIterable iterable, final Map.Entry cur) {
switch (cur.getValue().asString().getValue()) {
case "tailable":
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
index 179d88a4a32..f525d64da3f 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
@@ -17,6 +17,7 @@
package com.mongodb.client.unified;
import com.mongodb.client.gridfs.GridFSBucket;
+import com.mongodb.client.gridfs.GridFSFindIterable;
import com.mongodb.client.gridfs.model.GridFSDownloadOptions;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import com.mongodb.internal.HexUtils;
@@ -32,8 +33,11 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import static com.mongodb.client.unified.UnifiedTestUtils.getAndRemoveTimeoutMS;
import static java.util.Objects.requireNonNull;
final class UnifiedGridFSHelper {
@@ -43,8 +47,35 @@ final class UnifiedGridFSHelper {
this.entities = entities;
}
+ public OperationResult executeFind(final BsonDocument operation) {
+ GridFSFindIterable iterable = createGridFSFindIterable(operation);
+ try {
+ iterable.into(new ArrayList<>());
+ return OperationResult.NONE; // we don't expect results in the tests.
+ } catch (Exception e) {
+ return OperationResult.of(e);
+ }
+ }
+
+ public OperationResult executeRename(final BsonDocument operation) {
+ GridFSBucket bucket = getGirdFsBucket(operation);
+ BsonDocument arguments = operation.getDocument("arguments");
+ BsonValue id = arguments.get("id");
+ String fileName = arguments.get("newFilename").asString().getValue();
+
+ requireNonNull(id);
+ requireNonNull(fileName);
+
+ try {
+ bucket.rename(id, fileName);
+ return OperationResult.NONE;
+ } catch (Exception e) {
+ return OperationResult.of(e);
+ }
+ }
+
OperationResult executeDelete(final BsonDocument operation) {
- GridFSBucket bucket = entities.getBucket(operation.getString("object").getValue());
+ GridFSBucket bucket = getGirdFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
BsonValue id = arguments.get("id");
@@ -63,8 +94,23 @@ OperationResult executeDelete(final BsonDocument operation) {
}
}
+ public OperationResult executeDrop(final BsonDocument operation) {
+ GridFSBucket bucket = getGirdFsBucket(operation);
+ BsonDocument arguments = operation.getDocument("arguments", new BsonDocument());
+ if (arguments.size() > 0) {
+ throw new UnsupportedOperationException("Unexpected arguments " + operation.get("arguments"));
+ }
+
+ try {
+ bucket.drop();
+ return OperationResult.NONE;
+ } catch (Exception e) {
+ return OperationResult.of(e);
+ }
+ }
+
public OperationResult executeDownload(final BsonDocument operation) {
- GridFSBucket bucket = entities.getBucket(operation.getString("object").getValue());
+ GridFSBucket bucket = getGirdFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
BsonValue id = arguments.get("id");
@@ -119,7 +165,7 @@ private GridFSDownloadOptions getDownloadOptions(final BsonDocument arguments) {
}
public OperationResult executeUpload(final BsonDocument operation) {
- GridFSBucket bucket = entities.getBucket(operation.getString("object").getValue());
+ GridFSBucket bucket = getGirdFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
String filename = null;
@@ -165,4 +211,46 @@ public OperationResult executeUpload(final BsonDocument operation) {
Document asDocument(final BsonDocument bsonDocument) {
return new DocumentCodec().decode(new BsonDocumentReader(bsonDocument), DecoderContext.builder().build());
}
+
+ private GridFSBucket getGirdFsBucket(final BsonDocument operation) {
+ GridFSBucket bucket = entities.getBucket(operation.getString("object").getValue());
+ Long timeoutMS = getAndRemoveTimeoutMS(operation.getDocument("arguments", new BsonDocument()));
+ if (timeoutMS != null) {
+ bucket = bucket.withTimeout(timeoutMS, TimeUnit.MILLISECONDS);
+ }
+ return bucket;
+ }
+
+ private GridFSFindIterable createGridFSFindIterable(final BsonDocument operation) {
+ GridFSBucket bucket = getGirdFsBucket(operation);
+
+ BsonDocument arguments = operation.getDocument("arguments");
+ BsonDocument filter = arguments.getDocument("filter");
+ GridFSFindIterable iterable = bucket.find(filter);
+ for (Map.Entry cur : arguments.entrySet()) {
+ switch (cur.getKey()) {
+ case "session":
+ case "filter":
+ break;
+ case "sort":
+ iterable.sort(cur.getValue().asDocument());
+ break;
+ case "batchSize":
+ iterable.batchSize(cur.getValue().asInt32().intValue());
+ break;
+ case "maxTimeMS":
+ iterable.maxTime(cur.getValue().asInt32().longValue(), TimeUnit.MILLISECONDS);
+ break;
+ case "skip":
+ iterable.skip(cur.getValue().asInt32().intValue());
+ break;
+ case "limit":
+ iterable.limit(cur.getValue().asInt32().intValue());
+ break;
+ default:
+ throw new UnsupportedOperationException("Unsupported argument: " + cur.getKey());
+ }
+ }
+ return iterable;
+ }
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
index 8b76f426dbc..4754c319c5f 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
@@ -324,6 +324,7 @@ private void assertOperation(final UnifiedTestContext context, final BsonDocumen
private OperationResult executeOperation(final UnifiedTestContext context, final BsonDocument operation, final int operationNum) {
context.getAssertionContext().push(ContextElement.ofStartedOperation(operation, operationNum));
String name = operation.getString("name").getValue();
+ String object = operation.getString("object").getValue();
try {
switch (name) {
case "createEntities":
@@ -393,6 +394,9 @@ private OperationResult executeOperation(final UnifiedTestContext context, final
case "aggregate":
return crudHelper.executeAggregate(operation);
case "find":
+ if ("bucket".equals(object)){
+ return gridFSHelper.executeFind(operation);
+ }
return crudHelper.executeFind(operation);
case "findOne":
return crudHelper.executeFindOne(operation);
@@ -427,6 +431,9 @@ private OperationResult executeOperation(final UnifiedTestContext context, final
case "modifyCollection":
return crudHelper.executeModifyCollection(operation);
case "rename":
+ if ("bucket".equals(object)){
+ return gridFSHelper.executeRename(operation);
+ }
return crudHelper.executeRenameCollection(operation);
case "createSearchIndex":
return crudHelper.executeCreateSearchIndex(operation);
@@ -460,6 +467,8 @@ private OperationResult executeOperation(final UnifiedTestContext context, final
return crudHelper.executeIterateUntilDocumentOrError(operation);
case "delete":
return gridFSHelper.executeDelete(operation);
+ case "drop":
+ return gridFSHelper.executeDrop(operation);
case "download":
return gridFSHelper.executeDownload(operation);
case "downloadByName":
@@ -885,9 +894,9 @@ private boolean indexExists(final BsonDocument operation) {
}
private List lastTwoCommandEvents(final TestCommandListener listener) {
- List events = listener.getCommandStartedEvents();
+ List events = listener.getCommandStartedEvents();
assertTrue(events.size() >= 2);
- return events.subList(events.size() - 2, events.size());
+ return new ArrayList<>(events.subList(events.size() - 2, events.size()));
}
private void addInitialData() {
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java
new file mode 100644
index 00000000000..96fdc3ff3ea
--- /dev/null
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008-present MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.mongodb.client.unified;
+
+import org.bson.BsonDocument;
+
+public abstract class UnifiedTestUtils {
+ private UnifiedTestUtils() {
+ //NOP
+ }
+
+ static Long getAndRemoveTimeoutMS(final BsonDocument arguments) {
+ Long timeoutMS = null;
+ if (arguments.containsKey("timeoutMS")) {
+ timeoutMS = arguments.getNumber("timeoutMS").longValue();
+ arguments.remove("timeoutMS");
+ }
+ return timeoutMS;
+ }
+}
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSDownloadStreamSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSDownloadStreamSpecification.groovy
index 99e8f7a2167..90b53014ed2 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSDownloadStreamSpecification.groovy
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSDownloadStreamSpecification.groovy
@@ -33,7 +33,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def 'should return the file info'() {
when:
- def downloadStream = new GridFSDownloadStreamImpl(null, fileInfo, Stub(MongoCollection))
+ def downloadStream = new GridFSDownloadStreamImpl(null, fileInfo, Stub(MongoCollection), null)
then:
downloadStream.getGridFSFile() == fileInfo
@@ -56,7 +56,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
then:
downloadStream.available() == 0
@@ -126,7 +126,8 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection).batchSize(1)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection,
+ null).batchSize(1)
then:
downloadStream.available() == 0
@@ -205,7 +206,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
def skipResult = downloadStream.skip(15)
@@ -281,7 +282,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
def readByte = new byte[10]
@@ -346,7 +347,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
downloadStream.mark()
@@ -421,7 +422,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
def readByte = new byte[25]
@@ -478,7 +479,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def 'should not throw an exception when trying to mark post close'() {
given:
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection))
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection), null)
downloadStream.close()
when:
@@ -499,7 +500,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def 'should handle negative skip value correctly '() {
given:
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection))
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection), null)
when:
def result = downloadStream.skip(-1)
@@ -514,7 +515,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def 'should handle skip that is larger or equal to the file length'() {
given:
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
def result = downloadStream.skip(skipValue)
@@ -535,7 +536,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def 'should throw if trying to pass negative batchSize'() {
given:
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection))
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection), null)
when:
downloadStream.batchSize(0)
@@ -559,7 +560,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
downloadStream.read()
@@ -591,7 +592,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def mongoCursor = Mock(MongoCursor)
def findIterable = Mock(FindIterable)
def chunksCollection = Mock(MongoCollection)
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection)
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection, null)
when:
downloadStream.read()
@@ -617,7 +618,7 @@ class GridFSDownloadStreamSpecification extends Specification {
def 'should throw an exception when trying to action post close'() {
given:
- def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection))
+ def downloadStream = new GridFSDownloadStreamImpl(clientSession, fileInfo, Stub(MongoCollection), null)
downloadStream.close()
when:
From bae4b50e93674b431b22c389b69385072e5f0b07 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Wed, 3 Jan 2024 20:50:46 -0800
Subject: [PATCH 02/19] Increase timeouts in prose tests.
JAVA-5277
---
.../AbstractClientSideOperationsTimeoutProseTest.java | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index 048cab4893c..0ce489107c8 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -99,11 +99,11 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"insert\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + 50
+ + " blockTimeMS: " + 100
+ " }"
+ "}");
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
- .timeout(45, TimeUnit.MILLISECONDS))) {
+ .timeout(95, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME);
@@ -116,6 +116,7 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
@Tag("setsFailPoint")
@FlakyTest(maxAttempts = 3)
+ @Disabled("TODO (CSOT) - JAVA-4057")
@DisplayName("6. GridFS Upload - Aborting an upload stream can be timed out")
public void testAbortingGridFsUploadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
@@ -125,11 +126,11 @@ public void testAbortingGridFsUploadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"delete\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + 50
+ + " blockTimeMS: " + 100
+ " }"
+ "}");
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
- .timeout(45, TimeUnit.MILLISECONDS))) {
+ .timeout(95, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
From 7a397e10b8d72ee6190489453f5013ec633375fb Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Wed, 3 Jan 2024 21:51:42 -0800
Subject: [PATCH 03/19] Fix tests.
JAVA-5277
---
.../internal/gridfs/GridFSBucketImpl.java | 2 +-
.../client/gridfs/GridFSBucketImpl.java | 31 +++++++++---------
.../mongodb/client/gridfs/TimeoutUtils.java | 2 +-
.../gridfs/GridFSBucketSpecification.groovy | 32 +++++++++++--------
.../GridFSUploadStreamSpecification.groovy | 21 ++++++------
5 files changed, 46 insertions(+), 42 deletions(-)
diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSBucketImpl.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSBucketImpl.java
index d92f68154dc..87f0217289a 100644
--- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSBucketImpl.java
+++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/gridfs/GridFSBucketImpl.java
@@ -72,7 +72,7 @@ public GridFSBucketImpl(final MongoDatabase database, final String bucketName) {
getChunksCollection(database, bucketName));
}
- GridFSBucketImpl(final String bucketName, final int chunkSizeBytes, final MongoCollection filesCollection,
+ private GridFSBucketImpl(final String bucketName, final int chunkSizeBytes, final MongoCollection filesCollection,
final MongoCollection chunksCollection) {
this.bucketName = notNull("bucketName", bucketName);
this.chunkSizeBytes = chunkSizeBytes;
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
index c50e7dfd664..c8f5f49521d 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
@@ -36,6 +36,7 @@
import com.mongodb.client.result.UpdateResult;
import com.mongodb.internal.TimeoutContext;
+import com.mongodb.internal.VisibleForTesting;
import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;
@@ -68,8 +69,6 @@ final class GridFSBucketImpl implements GridFSBucket {
private final MongoCollection filesCollection;
private final MongoCollection chunksCollection;
private volatile boolean checkedIndexes;
- @Nullable
- private final Long timeoutMs;
GridFSBucketImpl(final MongoDatabase database) {
this(database, "fs");
@@ -78,16 +77,16 @@ final class GridFSBucketImpl implements GridFSBucket {
GridFSBucketImpl(final MongoDatabase database, final String bucketName) {
this(notNull("bucketName", bucketName), DEFAULT_CHUNKSIZE_BYTES,
getFilesCollection(notNull("database", database), bucketName),
- getChunksCollection(database, bucketName), database.getTimeout(TimeUnit.MILLISECONDS));
+ getChunksCollection(database, bucketName));
}
+ @VisibleForTesting(otherwise = VisibleForTesting.AccessModifier.PRIVATE)
GridFSBucketImpl(final String bucketName, final int chunkSizeBytes, final MongoCollection filesCollection,
- final MongoCollection chunksCollection, @Nullable final Long timeoutMs) {
+ final MongoCollection chunksCollection) {
this.bucketName = notNull("bucketName", bucketName);
this.chunkSizeBytes = chunkSizeBytes;
this.filesCollection = notNull("filesCollection", filesCollection);
this.chunksCollection = notNull("chunksCollection", chunksCollection);
- this.timeoutMs = timeoutMs;
}
@Override
@@ -117,38 +116,38 @@ public ReadConcern getReadConcern() {
@Override
public Long getTimeout(final TimeUnit timeUnit) {
- return timeoutMs == null ? null : notNull("timeUnit", timeUnit).convert(timeoutMs, MILLISECONDS);
+ return filesCollection.getTimeout(timeUnit);
}
@Override
public GridFSBucket withChunkSizeBytes(final int chunkSizeBytes) {
- return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection, timeoutMs);
+ return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection, chunksCollection);
}
@Override
public GridFSBucket withReadPreference(final ReadPreference readPreference) {
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withReadPreference(readPreference),
- chunksCollection.withReadPreference(readPreference), timeoutMs);
+ chunksCollection.withReadPreference(readPreference));
}
@Override
public GridFSBucket withWriteConcern(final WriteConcern writeConcern) {
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withWriteConcern(writeConcern),
- chunksCollection.withWriteConcern(writeConcern), timeoutMs);
+ chunksCollection.withWriteConcern(writeConcern));
}
@Override
public GridFSBucket withReadConcern(final ReadConcern readConcern) {
return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withReadConcern(readConcern),
- chunksCollection.withReadConcern(readConcern), timeoutMs);
+ chunksCollection.withReadConcern(readConcern));
}
@Override
public GridFSBucket withTimeout(final long timeout, final TimeUnit timeUnit) {
isTrueArgument("timeout >= 0", timeout >= 0);
notNull("timeUnit", timeUnit);
- return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection,
- chunksCollection, MILLISECONDS.convert(timeout, timeUnit));
+ return new GridFSBucketImpl(bucketName, chunkSizeBytes, filesCollection.withTimeout(timeout, timeUnit),
+ chunksCollection.withTimeout(timeout, timeUnit));
}
@Override
@@ -437,12 +436,12 @@ private void executeDelete(@Nullable final ClientSession clientSession, final Bs
if (clientSession != null) {
result = withNullableTimeout(filesCollection, operationTimeout)
.deleteOne(clientSession, new BsonDocument("_id", id));
- withNullableTimeout(filesCollection, operationTimeout)
+ withNullableTimeout(chunksCollection, operationTimeout)
.deleteMany(clientSession, new BsonDocument("files_id", id));
} else {
result = withNullableTimeout(filesCollection, operationTimeout)
.deleteOne(new BsonDocument("_id", id));
- withNullableTimeout(filesCollection, operationTimeout)
+ withNullableTimeout(chunksCollection, operationTimeout)
.deleteMany(new BsonDocument("files_id", id));
}
@@ -621,7 +620,7 @@ private FindIterable createFindIterable(@Nullable final ClientSessio
if (filter != null) {
findIterable = findIterable.filter(filter);
}
- if (timeoutMs != null) {
+ if (filesCollection.getTimeout(MILLISECONDS) != null) {
findIterable.timeoutMode(TimeoutMode.CURSOR_LIFETIME);
}
return findIterable;
@@ -660,6 +659,6 @@ private static MongoCollection withNullableTimeout(final MongoCollection<
@Nullable
private Timeout startTimeout() {
- return TimeoutContext.calculateTimeout(timeoutMs);
+ return TimeoutContext.calculateTimeout(filesCollection.getTimeout(MILLISECONDS));
}
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java b/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
index 8b7349d751b..771eb362513 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
@@ -31,7 +31,7 @@ private TimeoutUtils(){
public static MongoCollection withNullableTimeout(final MongoCollection collection,
final String message,
@Nullable final Timeout timeout) {
- if (timeout != null) {
+ if (timeout != null && !timeout.isInfinite()) {
long remainingMs = timeout.remaining(MILLISECONDS);
if (remainingMs <= 0) {
// TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
index fdae1bee894..5f557c0110c 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
@@ -16,16 +16,8 @@
package com.mongodb.client.gridfs
-import com.mongodb.MongoClientSettings
-import com.mongodb.MongoGridFSException
-import com.mongodb.MongoNamespace
-import com.mongodb.ReadConcern
-import com.mongodb.WriteConcern
-import com.mongodb.client.ClientSession
-import com.mongodb.client.FindIterable
-import com.mongodb.client.ListIndexesIterable
-import com.mongodb.client.MongoCollection
-import com.mongodb.client.MongoCursor
+import com.mongodb.*
+import com.mongodb.client.*
import com.mongodb.client.gridfs.model.GridFSDownloadOptions
import com.mongodb.client.gridfs.model.GridFSFile
import com.mongodb.client.internal.MongoDatabaseImpl
@@ -33,6 +25,7 @@ import com.mongodb.client.internal.OperationExecutor
import com.mongodb.client.internal.TestOperationExecutor
import com.mongodb.client.result.DeleteResult
import com.mongodb.client.result.UpdateResult
+import com.mongodb.internal.TimeoutSettings
import com.mongodb.internal.operation.BatchCursor
import com.mongodb.internal.operation.FindOperation
import org.bson.BsonDocument
@@ -45,6 +38,8 @@ import org.bson.types.ObjectId
import spock.lang.Specification
import spock.lang.Unroll
+import java.util.concurrent.TimeUnit
+
import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS
import static com.mongodb.CustomMatchers.isTheSameAs
import static com.mongodb.ReadPreference.primary
@@ -156,7 +151,9 @@ class GridFSBucketSpecification extends Specification {
given:
def defaultChunkSizeBytes = 255 * 1024
def database = new MongoDatabaseImpl('test', fromProviders(new DocumentCodecProvider()), secondary(), WriteConcern.ACKNOWLEDGED,
- false, false, readConcern, JAVA_LEGACY, null, null, new TestOperationExecutor([]))
+ false, false, readConcern, JAVA_LEGACY, null,
+ new TimeoutSettings(0, 0, 0, null, 0),
+ new TestOperationExecutor([]))
when:
def gridFSBucket = new GridFSBucketImpl(database)
@@ -172,6 +169,9 @@ class GridFSBucketSpecification extends Specification {
given:
def filesCollection = Stub(MongoCollection)
def chunksCollection = Stub(MongoCollection)
+ filesCollection.getTimeout(TimeUnit.MILLISECONDS) >> null
+ chunksCollection.getTimeout(TimeUnit.MILLISECONDS) >> null
+
def gridFSBucket = new GridFSBucketImpl('fs', 255, filesCollection, chunksCollection)
when:
@@ -184,7 +184,7 @@ class GridFSBucketSpecification extends Specification {
then:
expect stream, isTheSameAs(new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, stream.getId(), 'filename',
- 255, null), ['closeLock'])
+ 255, null, null), ['closeLock'])
where:
clientSession << [null, Stub(ClientSession)]
@@ -291,7 +291,9 @@ class GridFSBucketSpecification extends Specification {
def fileInfo = new GridFSFile(fileId, 'File 1', 10, 255, new Date(), new Document())
def findIterable = Mock(FindIterable)
def filesCollection = Mock(MongoCollection)
+ filesCollection.getTimeout(TimeUnit.MILLISECONDS) >> null
def chunksCollection = Stub(MongoCollection)
+ chunksCollection.getTimeout(TimeUnit.MILLISECONDS) >> null
def gridFSBucket = new GridFSBucketImpl('fs', 255, filesCollection, chunksCollection)
when:
@@ -312,7 +314,7 @@ class GridFSBucketSpecification extends Specification {
1 * findIterable.first() >> fileInfo
then:
- expect stream, isTheSameAs(new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection), ['closeLock', 'cursorLock'])
+ expect stream, isTheSameAs(new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection,null), ['closeLock', 'cursorLock'])
where:
@@ -516,7 +518,9 @@ class GridFSBucketSpecification extends Specification {
def fileInfo = new GridFSFile(bsonFileId, filename, 10, 255, new Date(), new Document())
def findIterable = Mock(FindIterable)
def filesCollection = Mock(MongoCollection)
+ filesCollection.getTimeout(TimeUnit.MILLISECONDS) >> null
def chunksCollection = Stub(MongoCollection)
+ chunksCollection.getTimeout(TimeUnit.MILLISECONDS) >> null
def gridFSBucket = new GridFSBucketImpl('fs', 255, filesCollection, chunksCollection)
when:
@@ -534,7 +538,7 @@ class GridFSBucketSpecification extends Specification {
1 * findIterable.first() >> fileInfo
then:
- expect stream, isTheSameAs(new GridFSDownloadStreamImpl(null, fileInfo, chunksCollection), ['closeLock', 'cursorLock'])
+ expect stream, isTheSameAs(new GridFSDownloadStreamImpl(null, fileInfo, chunksCollection, null), ['closeLock', 'cursorLock'])
where:
version | skip | sortOrder
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSUploadStreamSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSUploadStreamSpecification.groovy
index cff602d6f9a..04a11e85550 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSUploadStreamSpecification.groovy
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSUploadStreamSpecification.groovy
@@ -34,7 +34,7 @@ class GridFSUploadStreamSpecification extends Specification {
def 'should return the file id'() {
when:
def uploadStream = new GridFSUploadStreamImpl(null, Stub(MongoCollection), Stub(MongoCollection), fileId, filename, 255
- , metadata)
+ , metadata, null)
then:
uploadStream.getId() == fileId
}
@@ -44,7 +44,7 @@ class GridFSUploadStreamSpecification extends Specification {
def filesCollection = Mock(MongoCollection)
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 2
- , metadata)
+ , metadata, null)
when:
uploadStream.write(1)
@@ -70,7 +70,7 @@ class GridFSUploadStreamSpecification extends Specification {
def filesCollection = Mock(MongoCollection)
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 255
- , null)
+ , null, null)
when:
uploadStream.write('file content ' as byte[])
@@ -100,7 +100,8 @@ class GridFSUploadStreamSpecification extends Specification {
def chunksCollection = Mock(MongoCollection)
def content = 'file content ' as byte[]
def metadata = new Document('contentType', 'text/txt')
- def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 255, metadata)
+ def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 255,
+ metadata, null)
def filesId = fileId
when:
@@ -158,7 +159,7 @@ class GridFSUploadStreamSpecification extends Specification {
def filesCollection = Mock(MongoCollection)
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 255
- , metadata)
+ , metadata, null)
when:
uploadStream.close()
@@ -178,7 +179,7 @@ class GridFSUploadStreamSpecification extends Specification {
given:
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, Stub(MongoCollection), chunksCollection, fileId, filename, 255
- , metadata)
+ , metadata, null)
when:
uploadStream.write('file content ' as byte[])
@@ -198,7 +199,7 @@ class GridFSUploadStreamSpecification extends Specification {
def 'should close the stream on abort'() {
given:
def uploadStream = new GridFSUploadStreamImpl(clientSession, Stub(MongoCollection), Stub(MongoCollection), fileId, filename, 255
- , metadata)
+ , metadata, null)
uploadStream.write('file content ' as byte[])
uploadStream.abort()
@@ -216,7 +217,7 @@ class GridFSUploadStreamSpecification extends Specification {
given:
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, Stub(MongoCollection), chunksCollection, fileId, filename, 255
- , metadata)
+ , metadata, null)
when:
uploadStream.write('file content ' as byte[])
@@ -234,7 +235,7 @@ class GridFSUploadStreamSpecification extends Specification {
def filesCollection = Mock(MongoCollection)
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 255
- , metadata)
+ , metadata, null)
when:
uploadStream.close()
uploadStream.write(1)
@@ -252,7 +253,7 @@ class GridFSUploadStreamSpecification extends Specification {
def filesCollection = Mock(MongoCollection)
def chunksCollection = Mock(MongoCollection)
def uploadStream = new GridFSUploadStreamImpl(clientSession, filesCollection, chunksCollection, fileId, filename, 255
- , metadata)
+ , metadata, null)
when:
uploadStream.getObjectId()
From 3448d3675e5a8ad4a4a44c2d6cc84e589e5c0842 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Wed, 3 Jan 2024 22:09:27 -0800
Subject: [PATCH 04/19] Remove timeoutMode method from Scala GridFSObservable.
JAVA-5277
---
.../scala/gridfs/GridFSFindObservable.scala | 21 -------------------
.../mongodb/client/AbstractUnifiedTest.java | 4 ++--
.../mongodb/client/unified/UnifiedTest.java | 2 +-
3 files changed, 3 insertions(+), 24 deletions(-)
diff --git a/driver-scala/src/main/scala/org/mongodb/scala/gridfs/GridFSFindObservable.scala b/driver-scala/src/main/scala/org/mongodb/scala/gridfs/GridFSFindObservable.scala
index 46066c30bde..fdbea9add70 100644
--- a/driver-scala/src/main/scala/org/mongodb/scala/gridfs/GridFSFindObservable.scala
+++ b/driver-scala/src/main/scala/org/mongodb/scala/gridfs/GridFSFindObservable.scala
@@ -121,27 +121,6 @@ case class GridFSFindObservable(private val wrapped: GridFSFindPublisher) extend
this
}
- /**
- * Sets the timeoutMode for the cursor.
- *
- * Requires the `timeout` to be set, either in the `MongoClientSettings`,
- * via `MongoDatabase` or via `MongoCollection`
- *
- * If the `timeout` is set then:
- *
- * - For non-tailable cursors, the default value of timeoutMode is `TimeoutMode.CURSOR_LIFETIME`
- * - For tailable cursors, the default value of timeoutMode is `TimeoutMode.ITERATION` and its an error
- * to configure it as: `TimeoutMode.CURSOR_LIFETIME`
- *
- * @param timeoutMode the timeout mode
- * @return this
- * @since 4.x
- */
- def timeoutMode(timeoutMode: TimeoutMode): GridFSFindObservable = {
- wrapped.timeoutMode(timeoutMode)
- this
- }
-
/**
* Helper to return a single observable limited to the first result.
*
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java
index 75b3ea67b70..ac5aacd9ca2 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractUnifiedTest.java
@@ -570,7 +570,7 @@ private void executeOperations(final BsonArray operations, final boolean throwEx
} else if (operationName.equals("assertDifferentLsidOnLastTwoCommands")) {
List events = lastTwoCommandEvents();
String eventsJson = commandListener.getCommandStartedEvents().stream()
- .map(e -> ((CommandStartedEvent) e).getCommand().toJson())
+ .map(e -> e.getCommand().toJson())
.collect(Collectors.joining(", "));
assertNotEquals(eventsJson, ((CommandStartedEvent) events.get(0)).getCommand().getDocument("lsid"),
@@ -578,7 +578,7 @@ private void executeOperations(final BsonArray operations, final boolean throwEx
} else if (operationName.equals("assertSameLsidOnLastTwoCommands")) {
List events = lastTwoCommandEvents();
String eventsJson = commandListener.getCommandStartedEvents().stream()
- .map(e -> ((CommandStartedEvent) e).getCommand().toJson())
+ .map(e -> e.getCommand().toJson())
.collect(Collectors.joining(", "));
assertEquals(eventsJson, ((CommandStartedEvent) events.get(0)).getCommand().getDocument("lsid"),
((CommandStartedEvent) events.get(1)).getCommand().getDocument("lsid"));
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
index 4754c319c5f..e7682275438 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java
@@ -828,7 +828,7 @@ private OperationResult executeAssertLsidOnLastTwoCommands(final BsonDocument op
operation.getDocument("arguments").getString("client").getValue());
List events = lastTwoCommandEvents(listener);
String eventsJson = listener.getCommandStartedEvents().stream()
- .map(e -> ((CommandStartedEvent) e).getCommand().toJson())
+ .map(e -> e.getCommand().toJson())
.collect(Collectors.joining(", "));
BsonDocument expected = ((CommandStartedEvent) events.get(0)).getCommand().getDocument("lsid");
BsonDocument actual = ((CommandStartedEvent) events.get(1)).getCommand().getDocument("lsid");
From 2096bb458238a8eb4eb25928de5bde7de31cfaeb Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Wed, 3 Jan 2024 23:27:35 -0800
Subject: [PATCH 05/19] Fix formatting issues.
JAVA-5277
---
.../mongodb/client/AbstractServerSelectionProseTest.java | 1 -
.../functional/com/mongodb/client/ReadConcernTest.java | 1 -
.../com/mongodb/client/unified/ErrorMatcher.java | 1 -
.../com/mongodb/client/unified/UnifiedCrudHelper.java | 1 -
.../client/gridfs/GridFSBucketSpecification.groovy | 8 +++++---
5 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java
index 4fff4583426..0aa2ff28536 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractServerSelectionProseTest.java
@@ -18,7 +18,6 @@
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
-import com.mongodb.event.CommandEvent;
import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import org.bson.BsonArray;
diff --git a/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java b/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java
index 3ed0d975650..a40b258ea6c 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/ReadConcernTest.java
@@ -17,7 +17,6 @@
package com.mongodb.client;
import com.mongodb.ReadConcern;
-import com.mongodb.event.CommandEvent;
import com.mongodb.event.CommandStartedEvent;
import com.mongodb.internal.connection.TestCommandListener;
import org.bson.BsonDocument;
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java b/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java
index 47878c4c11e..90f358be35a 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/ErrorMatcher.java
@@ -65,7 +65,6 @@ void assertErrorsMatch(final BsonDocument expectedError, final Exception e) {
|| e instanceof MongoSocketException);
}
if (expectedError.containsKey("isTimeoutError")) {
- e.printStackTrace();
assertEquals(context.getMessage("Exception must be of type MongoExecutionTimeoutException"),
expectedError.getBoolean("isTimeoutError").getValue(),
e instanceof MongoExecutionTimeoutException);
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
index d27c2e71ce3..589f6084873 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
@@ -79,7 +79,6 @@
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.lang.NonNull;
-import com.mongodb.lang.Nullable;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonDocumentWriter;
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
index 5f557c0110c..450f67791df 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
@@ -16,8 +16,9 @@
package com.mongodb.client.gridfs
-import com.mongodb.*
-import com.mongodb.client.*
+import com.mongodb.MongoGridFSException
+import com.mongodb.MongoNamespace
+import com.mongodb.client.ClientSession
import com.mongodb.client.gridfs.model.GridFSDownloadOptions
import com.mongodb.client.gridfs.model.GridFSFile
import com.mongodb.client.internal.MongoDatabaseImpl
@@ -314,7 +315,8 @@ class GridFSBucketSpecification extends Specification {
1 * findIterable.first() >> fileInfo
then:
- expect stream, isTheSameAs(new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection,null), ['closeLock', 'cursorLock'])
+ expect stream, isTheSameAs(new GridFSDownloadStreamImpl(clientSession, fileInfo, chunksCollection,
+ null), ['closeLock', 'cursorLock'])
where:
From b84802ed620a96b0fcb4dfb6b44f659555e14a99 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Wed, 3 Jan 2024 23:31:14 -0800
Subject: [PATCH 06/19] Increase timeout in prose tests.
JAVA-5277
---
.../client/AbstractClientSideOperationsTimeoutProseTest.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index 0ce489107c8..a1cbf4df3c1 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -148,7 +148,7 @@ public void testGridFsDownloadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
- .timeout(20, TimeUnit.MILLISECONDS))) {
+ .timeout(30, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
database.getCollection(GRID_FS_COLLECTION_NAME_FILE)
@@ -177,7 +177,7 @@ public void testGridFsDownloadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"find\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + 25
+ + " blockTimeMS: " + 35
+ " }"
+ "}");
assertThrows(MongoExecutionTimeoutException.class, downloadStream::read);
From 2f27cbc5b583efcef81734c04a8dc5ea4d4f7789 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Thu, 4 Jan 2024 00:12:11 -0800
Subject: [PATCH 07/19] Fix tests.
JAVA-5277
---
.../mongodb/client/gridfs/GridFSDownloadStreamImpl.java | 1 -
.../com/mongodb/client/gridfs/GridFSFindIterableImpl.java | 1 -
.../mongodb/client/gridfs/GridFSBucketSpecification.groovy | 7 +++++++
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
index 112188c303f..5ddd0c3fce1 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
@@ -36,7 +36,6 @@
import static com.mongodb.assertions.Assertions.notNull;
import static com.mongodb.internal.Locks.withInterruptibleLock;
import static java.lang.String.format;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
class GridFSDownloadStreamImpl extends GridFSDownloadStream {
private static final String TIMEOUT_MESSAGE = "The GridFS download stream has timed out";
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java
index 240f2ec0acc..80bfb498e12 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSFindIterableImpl.java
@@ -20,7 +20,6 @@
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoIterable;
-import com.mongodb.client.cursor.TimeoutMode;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.model.Collation;
import com.mongodb.lang.Nullable;
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
index 450f67791df..ac3fb98281c 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/GridFSBucketSpecification.groovy
@@ -16,9 +16,16 @@
package com.mongodb.client.gridfs
+import com.mongodb.MongoClientSettings
import com.mongodb.MongoGridFSException
import com.mongodb.MongoNamespace
+import com.mongodb.ReadConcern
+import com.mongodb.WriteConcern
import com.mongodb.client.ClientSession
+import com.mongodb.client.FindIterable
+import com.mongodb.client.ListIndexesIterable
+import com.mongodb.client.MongoCollection
+import com.mongodb.client.MongoCursor
import com.mongodb.client.gridfs.model.GridFSDownloadOptions
import com.mongodb.client.gridfs.model.GridFSFile
import com.mongodb.client.internal.MongoDatabaseImpl
From 57452fc8603642d1acbb2e108a30f50a9b35726b Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Thu, 4 Jan 2024 16:00:31 -0800
Subject: [PATCH 08/19] Update tests.
JAVA-5277
---
.../client/AbstractClientSideOperationsTimeoutProseTest.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index a1cbf4df3c1..fee7bc85e9d 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -151,8 +151,7 @@ public void testGridFsDownloadStreamTimeout() {
.timeout(30, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
- database.getCollection(GRID_FS_COLLECTION_NAME_FILE)
- .insertOne(Document.parse(
+ filesCollectionHelper.insertDocuments(Document.parse(
"{"
+ " _id: {"
+ " $oid: \"000000000000000000000005\""
From 9e8f75ea92917604135f5aceb818b22347f4f4c4 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Fri, 5 Jan 2024 14:29:45 -0800
Subject: [PATCH 09/19] Account for RTT in tests.
JAVA-5277
---
...tClientSideOperationsTimeoutProseTest.java | 20 ++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index fee7bc85e9d..8216ee3b549 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -93,17 +93,19 @@ public abstract class AbstractClientSideOperationsTimeoutProseTest {
@Disabled("TODO (CSOT) - JAVA-4057")
public void testGridFSUploadViaOpenUploadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
+ long rtt = ClusterFixture.getPrimaryRTT();
+
collectionHelper.runAdminCommand("{"
+ " configureFailPoint: \"failCommand\","
+ " mode: { times: 1 },"
+ " data: {"
+ " failCommands: [\"insert\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + 100
+ + " blockTimeMS: " + rtt + 100
+ " }"
+ "}");
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
- .timeout(95, TimeUnit.MILLISECONDS))) {
+ .timeout(rtt + 95, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME);
@@ -120,17 +122,19 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
@DisplayName("6. GridFS Upload - Aborting an upload stream can be timed out")
public void testAbortingGridFsUploadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
+ long rtt = ClusterFixture.getPrimaryRTT();
+
collectionHelper.runAdminCommand("{"
+ " configureFailPoint: \"failCommand\","
+ " mode: { times: 1 },"
+ " data: {"
+ " failCommands: [\"delete\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + 100
+ + " blockTimeMS: " + rtt + 100
+ " }"
+ "}");
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
- .timeout(95, TimeUnit.MILLISECONDS))) {
+ .timeout(rtt + 95, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
@@ -146,9 +150,10 @@ public void testAbortingGridFsUploadStreamTimeout() {
@DisplayName("6. GridFS Download")
public void testGridFsDownloadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
+ long rtt = ClusterFixture.getPrimaryRTT();
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
- .timeout(30, TimeUnit.MILLISECONDS))) {
+ .timeout(rtt + 100, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
filesCollectionHelper.insertDocuments(Document.parse(
@@ -176,7 +181,7 @@ public void testGridFsDownloadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"find\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + 35
+ + " blockTimeMS: " + rtt + 95
+ " }"
+ "}");
assertThrows(MongoExecutionTimeoutException.class, downloadStream::read);
@@ -322,9 +327,6 @@ public void setUp() {
new MongoNamespace(getDefaultDatabaseName(), GRID_FS_COLLECTION_NAME_FILE));
chunksCollectionHelper = new CollectionHelper<>(new BsonDocumentCodec(),
new MongoNamespace(getDefaultDatabaseName(), GRID_FS_COLLECTION_NAME_CHUNKS));
- collectionHelper.drop();
- filesCollectionHelper.drop();
- chunksCollectionHelper.drop();
commandListener = new TestCommandListener();
}
From 0da8b1148261e53007507ed4e511c30302fb9fd5 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Sun, 7 Jan 2024 22:14:47 -0800
Subject: [PATCH 10/19] Fix test issues.
JAVA-5277
---
...bstractClientSideOperationsTimeoutProseTest.java | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index 8216ee3b549..06004deb6f9 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -64,6 +64,7 @@
import static com.mongodb.ClusterFixture.sleep;
import static com.mongodb.client.Fixture.getDefaultDatabaseName;
import static com.mongodb.client.Fixture.getPrimary;
+import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -101,7 +102,7 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"insert\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + rtt + 100
+ + " blockTimeMS: " + (rtt + 100)
+ " }"
+ "}");
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
@@ -130,7 +131,7 @@ public void testAbortingGridFsUploadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"delete\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + rtt + 100
+ + " blockTimeMS: " + (rtt + 100)
+ " }"
+ "}");
try (MongoClient client = createMongoClient(getMongoClientSettingsBuilder()
@@ -156,7 +157,7 @@ public void testGridFsDownloadStreamTimeout() {
.timeout(rtt + 100, TimeUnit.MILLISECONDS))) {
MongoDatabase database = client.getDatabase(namespace.getDatabaseName());
GridFSBucket gridFsBucket = createGridFsBucket(database, GRID_FS_BUCKET_NAME).withChunkSizeBytes(2);
- filesCollectionHelper.insertDocuments(Document.parse(
+ filesCollectionHelper.insertDocuments(asList(BsonDocument.parse(
"{"
+ " _id: {"
+ " $oid: \"000000000000000000000005\""
@@ -172,7 +173,7 @@ public void testGridFsDownloadStreamTimeout() {
+ " aliases: [],"
+ " metadata: {}"
+ "}"
- ));
+ )), WriteConcern.MAJORITY);
try (GridFSDownloadStream downloadStream = gridFsBucket.openDownloadStream(new ObjectId("000000000000000000000005"))){
collectionHelper.runAdminCommand("{"
@@ -181,7 +182,7 @@ public void testGridFsDownloadStreamTimeout() {
+ " data: {"
+ " failCommands: [\"find\"],"
+ " blockConnection: true,"
- + " blockTimeMS: " + rtt + 95
+ + " blockTimeMS: " + (rtt + 95)
+ " }"
+ "}");
assertThrows(MongoExecutionTimeoutException.class, downloadStream::read);
@@ -332,7 +333,7 @@ public void setUp() {
@AfterEach
public void tearDown(final TestInfo info) {
- if (info.getTags().contains("usesFailPoint")) {
+ if (info.getTags().contains("setsFailPoint")) {
collectionHelper.runAdminCommand("{configureFailPoint: \"failCommand\", mode: \"off\"}");
}
From 3d33e338350218f04fbbbe457a6e575bd2e1adc3 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Mon, 8 Jan 2024 00:56:08 -0800
Subject: [PATCH 11/19] Check for minimum server version.
JAVA-5277
---
.../client/AbstractClientSideOperationsTimeoutProseTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index 06004deb6f9..a062c323bf2 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -333,7 +333,7 @@ public void setUp() {
@AfterEach
public void tearDown(final TestInfo info) {
- if (info.getTags().contains("setsFailPoint")) {
+ if (info.getTags().contains("setsFailPoint") && serverVersionAtLeast(4, 4)) {
collectionHelper.runAdminCommand("{configureFailPoint: \"failCommand\", mode: \"off\"}");
}
From 1ba1bd2af73220c9dc9abc27636a94a7c9647ea9 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Mon, 8 Jan 2024 01:28:44 -0800
Subject: [PATCH 12/19] Merge with CSOT branch.
JAVA-5277
---
.../internal/connection/TestCommandListener.java | 10 +++++++---
.../AbstractClientSideOperationsTimeoutProseTest.java | 6 +++---
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java b/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java
index 3f8c3b34c24..c02065363f9 100644
--- a/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java
+++ b/driver-core/src/test/functional/com/mongodb/internal/connection/TestCommandListener.java
@@ -41,6 +41,7 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
import static com.mongodb.ClusterFixture.TIMEOUT;
import static com.mongodb.internal.connection.InternalStreamConnection.getSecuritySensitiveCommands;
@@ -147,14 +148,17 @@ public List getCommandStartedEvents() {
return getEvents(CommandStartedEvent.class, Integer.MAX_VALUE);
}
- public List getCommandSucceededEvents() {
+ public List getCommandSucceededEvents() {
return getEvents(CommandSucceededEvent.class, Integer.MAX_VALUE);
}
- private List getEvents(final Class extends CommandEvent> type, final int maxEvents) {
+ private List getEvents(final Class type, final int maxEvents) {
lock.lock();
try {
- return getEvents().stream().filter(e -> e.getClass() == type).limit(maxEvents).collect(Collectors.toList());
+ return getEvents().stream()
+ .filter(e -> e.getClass() == type)
+ .map(type::cast)
+ .limit(maxEvents).collect(Collectors.toList());
} finally {
lock.unlock();
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index fe65ebc3d5f..58f8ce7f3fd 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -33,8 +33,8 @@
import com.mongodb.client.model.changestream.ChangeStreamDocument;
import com.mongodb.client.model.changestream.FullDocument;
import com.mongodb.client.test.CollectionHelper;
-import com.mongodb.event.CommandEvent;
import com.mongodb.event.CommandStartedEvent;
+import com.mongodb.event.CommandSucceededEvent;
import com.mongodb.internal.connection.ServerHelper;
import com.mongodb.internal.connection.TestCommandListener;
import com.mongodb.test.FlakyTest;
@@ -233,7 +233,7 @@ public void testBlockingIterationMethodsTailableCursor() {
assertThrows(MongoExecutionTimeoutException.class, cursor::next);
}
- List events = commandListener.getCommandSucceededEvents();
+ List events = commandListener.getCommandSucceededEvents();
assertEquals(1, events.stream().filter(e -> e.getCommandName().equals("find")).count());
long getMoreCount = events.stream().filter(e -> e.getCommandName().equals("getMore")).count();
assertTrue(getMoreCount <= 2, "getMoreCount expected to less than or equal to two but was: " + getMoreCount);
@@ -281,7 +281,7 @@ public void testBlockingIterationMethodsChangeStream() {
assertEquals(1, fullDocument.get("x"));
assertThrows(MongoExecutionTimeoutException.class, cursor::next);
}
- List events = commandListener.getCommandSucceededEvents();
+ List events = commandListener.getCommandSucceededEvents();
assertEquals(1, events.stream().filter(e -> e.getCommandName().equals("aggregate")).count());
long getMoreCount = events.stream().filter(e -> e.getCommandName().equals("getMore")).count();
assertTrue(getMoreCount <= 2, "getMoreCount expected to less than or equal to two but was: " + getMoreCount);
From d1a94497ff7e545a2ecf172a6d3c4d14aa72a2d7 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Mon, 8 Jan 2024 14:41:08 -0800
Subject: [PATCH 13/19] Rename classes. Add tests.
JAVA-5277
---
...tils.java => CollectionTimeoutHelper.java} | 12 +--
.../client/gridfs/GridFSBucketImpl.java | 20 ++--
.../gridfs/GridFSDownloadStreamImpl.java | 2 +-
.../client/gridfs/GridFSUploadStreamImpl.java | 2 +-
...tClientSideOperationsTimeoutProseTest.java | 10 +-
.../client/unified/UnifiedCrudHelper.java | 3 +-
.../client/unified/UnifiedGridFSHelper.java | 3 +-
...ifiedTestUtils.java => UnifiedHelper.java} | 5 +-
.../client/gridfs/TimeoutUtilsTest.java | 96 +++++++++++++++++++
9 files changed, 122 insertions(+), 31 deletions(-)
rename driver-sync/src/main/com/mongodb/client/gridfs/{TimeoutUtils.java => CollectionTimeoutHelper.java} (76%)
rename driver-sync/src/test/functional/com/mongodb/client/unified/{UnifiedTestUtils.java => UnifiedHelper.java} (91%)
create mode 100644 driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java b/driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java
similarity index 76%
rename from driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
rename to driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java
index 771eb362513..696c8d75df7 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/TimeoutUtils.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java
@@ -23,17 +23,17 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-final class TimeoutUtils {
- private TimeoutUtils(){
+final class CollectionTimeoutHelper {
+ private CollectionTimeoutHelper(){
//NOP
}
- public static MongoCollection withNullableTimeout(final MongoCollection collection,
- final String message,
- @Nullable final Timeout timeout) {
+ public static MongoCollection collectionWithTimeout(final MongoCollection collection,
+ final String message,
+ @Nullable final Timeout timeout) {
if (timeout != null && !timeout.isInfinite()) {
long remainingMs = timeout.remaining(MILLISECONDS);
- if (remainingMs <= 0) {
+ if (timeout.hasExpired()) {
// TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
throw new MongoExecutionTimeoutException(message);
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
index c8f5f49521d..326cf6ae2a9 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
@@ -283,10 +283,10 @@ public GridFSDownloadStream openDownloadStream(final ObjectId id) {
@Override
public GridFSDownloadStream openDownloadStream(final BsonValue id) {
- Timeout oprationTimeout = startTimeout();
+ Timeout operationTimeout = startTimeout();
- GridFSFile fileInfo = getFileInfoById(null, id, oprationTimeout);
- return createGridFSDownloadStream(null, fileInfo, oprationTimeout);
+ GridFSFile fileInfo = getFileInfoById(null, id, operationTimeout);
+ return createGridFSDownloadStream(null, fileInfo, operationTimeout);
}
@Override
@@ -489,17 +489,17 @@ private void executeRename(@Nullable final ClientSession clientSession, final Bs
@Override
public void drop() {
- Timeout oeprationTimeout = startTimeout();
- withNullableTimeout(filesCollection, oeprationTimeout).drop();
- withNullableTimeout(chunksCollection, oeprationTimeout).drop();
+ Timeout operationTimeout = startTimeout();
+ withNullableTimeout(filesCollection, operationTimeout).drop();
+ withNullableTimeout(chunksCollection, operationTimeout).drop();
}
@Override
public void drop(final ClientSession clientSession) {
- Timeout oeprationTimeout = startTimeout();
+ Timeout operationTimeout = startTimeout();
notNull("clientSession", clientSession);
- withNullableTimeout(filesCollection, oeprationTimeout).drop(clientSession);
- withNullableTimeout(chunksCollection, oeprationTimeout).drop(clientSession);
+ withNullableTimeout(filesCollection, operationTimeout).drop(clientSession);
+ withNullableTimeout(chunksCollection, operationTimeout).drop(clientSession);
}
private static MongoCollection getFilesCollection(final MongoDatabase database, final String bucketName) {
@@ -654,7 +654,7 @@ private void downloadToStream(final GridFSDownloadStream downloadStream, final O
private static MongoCollection withNullableTimeout(final MongoCollection chunksCollection,
@Nullable final Timeout timeout) {
- return TimeoutUtils.withNullableTimeout(chunksCollection, TIMEOUT_MESSAGE, timeout);
+ return CollectionTimeoutHelper.collectionWithTimeout(chunksCollection, TIMEOUT_MESSAGE, timeout);
}
@Nullable
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
index 5ddd0c3fce1..d3f36643cb5 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
@@ -308,6 +308,6 @@ private byte[] getBuffer(final int chunkIndexToFetch) {
private MongoCollection withNullableTimeout(final MongoCollection chunksCollection,
@Nullable final Timeout timeout) {
- return TimeoutUtils.withNullableTimeout(chunksCollection, TIMEOUT_MESSAGE, timeout);
+ return CollectionTimeoutHelper.collectionWithTimeout(chunksCollection, TIMEOUT_MESSAGE, timeout);
}
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
index b57d2b5a76d..3355459e5b0 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
@@ -206,6 +206,6 @@ private void checkClosed() {
private static MongoCollection withNullableTimeout(final MongoCollection collection,
@Nullable final Timeout timeout) {
- return TimeoutUtils.withNullableTimeout(collection, TIMEOUT_MESSAGE, timeout);
+ return CollectionTimeoutHelper.collectionWithTimeout(collection, TIMEOUT_MESSAGE, timeout);
}
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index cc60299ce72..529afad6b47 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -43,14 +43,15 @@
import org.bson.BsonTimestamp;
import org.bson.Document;
import org.bson.codecs.BsonDocumentCodec;
-import org.jetbrains.annotations.Nullable;
import org.bson.types.ObjectId;
+import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -61,7 +62,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet;
@@ -99,9 +99,9 @@ public abstract class AbstractClientSideOperationsTimeoutProseTest {
protected abstract GridFSBucket createGridFsBucket(MongoDatabase mongoDatabase, String bucketName);
@Tag("setsFailPoint")
- @FlakyTest(maxAttempts = 3)
@DisplayName("6. GridFS Upload - uploads via openUploadStream can be timed out")
@Disabled("TODO (CSOT) - JAVA-4057")
+ @Test
public void testGridFSUploadViaOpenUploadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
long rtt = ClusterFixture.getPrimaryRTT();
@@ -128,9 +128,9 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
}
@Tag("setsFailPoint")
- @FlakyTest(maxAttempts = 3)
@Disabled("TODO (CSOT) - JAVA-4057")
@DisplayName("6. GridFS Upload - Aborting an upload stream can be timed out")
+ @Test
public void testAbortingGridFsUploadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
long rtt = ClusterFixture.getPrimaryRTT();
@@ -157,8 +157,8 @@ public void testAbortingGridFsUploadStreamTimeout() {
}
@Tag("setsFailPoint")
- @FlakyTest(maxAttempts = 3)
@DisplayName("6. GridFS Download")
+ @Test
public void testGridFsDownloadStreamTimeout() {
assumeTrue(serverVersionAtLeast(4, 4));
long rtt = ClusterFixture.getPrimaryRTT();
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
index 82567dcae60..1cd5dff6512 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java
@@ -104,12 +104,11 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
-import static com.mongodb.client.unified.UnifiedTestUtils.getAndRemoveTimeoutMS;
import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
-final class UnifiedCrudHelper {
+final class UnifiedCrudHelper extends UnifiedHelper {
private final Entities entities;
private final String testDescription;
private final AtomicInteger uniqueIdGenerator = new AtomicInteger();
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
index f525d64da3f..31f61f50d13 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
@@ -37,10 +37,9 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import static com.mongodb.client.unified.UnifiedTestUtils.getAndRemoveTimeoutMS;
import static java.util.Objects.requireNonNull;
-final class UnifiedGridFSHelper {
+final class UnifiedGridFSHelper extends UnifiedHelper{
private final Entities entities;
UnifiedGridFSHelper(final Entities entities) {
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedHelper.java
similarity index 91%
rename from driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java
rename to driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedHelper.java
index 96fdc3ff3ea..027ccf92fb5 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestUtils.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedHelper.java
@@ -18,10 +18,7 @@
import org.bson.BsonDocument;
-public abstract class UnifiedTestUtils {
- private UnifiedTestUtils() {
- //NOP
- }
+abstract class UnifiedHelper {
static Long getAndRemoveTimeoutMS(final BsonDocument arguments) {
Long timeoutMS = null;
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java b/driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java
new file mode 100644
index 00000000000..62fe496234b
--- /dev/null
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java
@@ -0,0 +1,96 @@
+package com.mongodb.client.gridfs;
+
+import com.mongodb.MongoExecutionTimeoutException;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.internal.time.Timeout;
+import org.bson.Document;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.TimeUnit;
+
+import static com.mongodb.client.gridfs.CollectionTimeoutHelper.collectionWithTimeout;
+import static com.mongodb.internal.mockito.MongoMockito.mock;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.longThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+class TimeoutUtilsTest {
+
+ private static final String TIMEOUT_ERROR_MESSAGE = "message";
+
+ @Test
+ void shouldNotSetRemainingTimeoutWhenTimeoutIsNull() {
+ //given
+ MongoCollection collection = mock(MongoCollection.class);
+
+ //when
+ MongoCollection result = collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, null);
+
+ //then
+ assertEquals(collection, result);
+ }
+
+ @Test
+ void shouldNotSetRemainingTimeoutWhenTimeoutIsInfinite() {
+ //given
+ MongoCollection collection = mock(MongoCollection.class);
+
+ //when
+ MongoCollection result = collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, Timeout.infinite());
+
+ //then
+ assertEquals(collection, result);
+ }
+
+ @Test
+ void shouldSetRemainingTimeoutWhenTimeout() {
+ //given
+ MongoCollection collection = mock(MongoCollection.class);
+ MongoCollection collectionWithTimeout = mock(MongoCollection.class);
+ when(collection.withTimeout(anyLong(), eq(TimeUnit.MILLISECONDS))).thenReturn(collectionWithTimeout);
+ Timeout timeout = Timeout.expiresIn(1, TimeUnit.DAYS);
+
+ //when
+ MongoCollection result = collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout);
+
+ //then
+ verify(collection).withTimeout(longThat(remaining -> remaining > 0), eq(TimeUnit.MILLISECONDS));
+ assertNotEquals(collectionWithTimeout, result);
+ }
+
+ @Test
+ void shouldThrowErrorWhenTimeoutHasExpired() {
+ //given
+ MongoCollection collection = mock(MongoCollection.class);
+ Timeout timeout = Timeout.expiresIn(1, TimeUnit.MICROSECONDS);
+
+ //when
+ assertThrows(MongoExecutionTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
+
+ //then
+ verifyNoInteractions(collection);
+ }
+
+ @Test
+ void shouldThrowErrorWhenTimeoutHasExpiredWithZeroRemaining() {
+ //given
+ MongoCollection collection = mock(MongoCollection.class);
+ Timeout timeout = mock(Timeout.class, timeout1 -> {
+ when(timeout1.hasExpired()).thenReturn(true);
+ when(timeout1.isInfinite()).thenReturn(false);
+ when(timeout1.remaining(TimeUnit.MILLISECONDS)).thenReturn(0L);
+ });
+
+ //when
+ assertThrows(MongoExecutionTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
+
+ //then
+ verifyNoInteractions(collection);
+ }
+}
\ No newline at end of file
From f351d04bb0bb5c19394709193cf304355a8d53b6 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Mon, 8 Jan 2024 14:49:03 -0800
Subject: [PATCH 14/19] Add TODO comments for dependencies.
JAVA-5277
---
.../com/mongodb/client/ClientSideOperationTimeoutTest.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java b/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java
index 2719b85e522..22812b30d18 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/ClientSideOperationTimeoutTest.java
@@ -92,7 +92,8 @@ public static void checkSkipCSOTTest(final String fileDescription, final String
assumeFalse("TODO (CSOT) - JAVA-4062", testDescription.contains("wTimeoutMS is ignored"));
- if (fileDescription.contains("GridFS")) {
+
+ if (fileDescription.contains("GridFS")) { //TODO (CSOT) - JAVA-4057
assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("chunk insertion"));
assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("creation of files document"));
assumeFalse("TODO (CSOT) - JAVA-4057", testDescription.contains("delete against the files collection"));
From a5061d581821676750213ad17c7ed0b789da0b07 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Mon, 8 Jan 2024 16:10:49 -0800
Subject: [PATCH 15/19] Add copyrights.
JAVA-5277
---
....java => CollectionTimeoutHelperTest.java} | 29 +++++++++++++++----
1 file changed, 24 insertions(+), 5 deletions(-)
rename driver-sync/src/test/unit/com/mongodb/client/gridfs/{TimeoutUtilsTest.java => CollectionTimeoutHelperTest.java} (74%)
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java b/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
similarity index 74%
rename from driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java
rename to driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
index 62fe496234b..a4dd876693c 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/TimeoutUtilsTest.java
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2008-present MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.mongodb.client.gridfs;
import com.mongodb.MongoExecutionTimeoutException;
@@ -20,7 +36,7 @@
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
-class TimeoutUtilsTest {
+class CollectionTimeoutHelperTest {
private static final String TIMEOUT_ERROR_MESSAGE = "message";
@@ -51,9 +67,10 @@ void shouldNotSetRemainingTimeoutWhenTimeoutIsInfinite() {
@Test
void shouldSetRemainingTimeoutWhenTimeout() {
//given
- MongoCollection collection = mock(MongoCollection.class);
MongoCollection collectionWithTimeout = mock(MongoCollection.class);
- when(collection.withTimeout(anyLong(), eq(TimeUnit.MILLISECONDS))).thenReturn(collectionWithTimeout);
+ MongoCollection collection = mock(MongoCollection.class, mongoCollection -> {
+ when(mongoCollection.withTimeout(anyLong(), eq(TimeUnit.MILLISECONDS))).thenReturn(mongoCollection);
+ });
Timeout timeout = Timeout.expiresIn(1, TimeUnit.DAYS);
//when
@@ -71,9 +88,11 @@ void shouldThrowErrorWhenTimeoutHasExpired() {
Timeout timeout = Timeout.expiresIn(1, TimeUnit.MICROSECONDS);
//when
- assertThrows(MongoExecutionTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
+ MongoExecutionTimeoutException mongoExecutionTimeoutException =
+ assertThrows(MongoExecutionTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
//then
+ assertEquals(TIMEOUT_ERROR_MESSAGE, mongoExecutionTimeoutException.getMessage());
verifyNoInteractions(collection);
}
@@ -93,4 +112,4 @@ void shouldThrowErrorWhenTimeoutHasExpiredWithZeroRemaining() {
//then
verifyNoInteractions(collection);
}
-}
\ No newline at end of file
+}
From a05cf56fa81e58eed4e1c56c51400bc3c4e749c5 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Tue, 9 Jan 2024 23:31:50 -0800
Subject: [PATCH 16/19] Reduce bock time for download test.
JAVA-5277
---
.../client-side-operation-timeout/gridfs-download.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/gridfs-download.json b/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/gridfs-download.json
index 8542f69e898..3cf4a285fa6 100644
--- a/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/gridfs-download.json
+++ b/driver-core/src/test/resources/unified-test-format/client-side-operation-timeout/gridfs-download.json
@@ -299,7 +299,7 @@
"find"
],
"blockConnection": true,
- "blockTimeMS": 50
+ "blockTimeMS": 40
}
}
}
From 3025b3c2083810fcc2de40b2442cdc4b7985c77b Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Fri, 12 Jan 2024 17:34:39 -0800
Subject: [PATCH 17/19] Fix merge conflicts with CSOT branch.
JAVA-5277
---
.../gridfs/CollectionTimeoutHelper.java | 4 +--
.../mongodb/client/gridfs/GridFSBucket.java | 25 +++++++++++++++++++
.../client/gridfs/GridFSBucketImpl.java | 4 +--
.../gridfs/GridFSDownloadStreamImpl.java | 4 +--
.../client/gridfs/GridFSUploadStreamImpl.java | 5 ++--
...tClientSideOperationsTimeoutProseTest.java | 6 ++---
.../client/unified/UnifiedGridFSHelper.java | 25 ++++++++++++-------
.../gridfs/CollectionTimeoutHelperTest.java | 1 +
8 files changed, 53 insertions(+), 21 deletions(-)
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java b/driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java
index 696c8d75df7..9df56290b11 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/CollectionTimeoutHelper.java
@@ -16,7 +16,7 @@
package com.mongodb.client.gridfs;
-import com.mongodb.MongoExecutionTimeoutException;
+import com.mongodb.MongoOperationTimeoutException;
import com.mongodb.client.MongoCollection;
import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;
@@ -35,7 +35,7 @@ public static MongoCollection collectionWithTimeout(final MongoCollection
long remainingMs = timeout.remaining(MILLISECONDS);
if (timeout.hasExpired()) {
// TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
- throw new MongoExecutionTimeoutException(message);
+ throw new MongoOperationTimeoutException(message);
}
return collection.withTimeout(remainingMs, MILLISECONDS);
}
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java
index 8b251199d67..d79ae468db7 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucket.java
@@ -21,6 +21,7 @@
import com.mongodb.WriteConcern;
import com.mongodb.annotations.ThreadSafe;
import com.mongodb.client.ClientSession;
+import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.model.GridFSDownloadOptions;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import com.mongodb.lang.Nullable;
@@ -344,6 +345,10 @@ public interface GridFSBucket {
* chunks have been uploaded, it creates a files collection document for {@code filename} in the files collection.
*
*
+ Note: When this {@link GridFSBucket} is set with a operation timeout (via timeout inherited from {@link MongoDatabase}
+ * settings or {@link #withTimeout(long, TimeUnit)}), timeout breaches may occur due to the {@link InputStream}
+ * lacking inherent read timeout support, which might extend the operation beyond the specified timeout limit.
+ *
* @param id the custom id value of the file
* @param filename the filename for the stream
* @param source the Stream providing the file data
@@ -358,6 +363,10 @@ public interface GridFSBucket {
* chunks have been uploaded, it creates a files collection document for {@code filename} in the files collection.
*
*
+ Note: When this {@link GridFSBucket} is set with a operation timeout (via timeout inherited from {@link MongoDatabase}
+ * settings or {@link #withTimeout(long, TimeUnit)}), timeout breaches may occur due to the {@link InputStream}
+ * lacking inherent read timeout support, which might extend the operation beyond the specified timeout limit.
+ *
* @param id the custom id value of the file
* @param filename the filename for the stream
* @param source the Stream providing the file data
@@ -373,6 +382,10 @@ public interface GridFSBucket {
* chunks have been uploaded, it creates a files collection document for {@code filename} in the files collection.
*
*
+ Note: When this {@link GridFSBucket} is set with a operation timeout (via timeout inherited from {@link MongoDatabase}
+ * settings or {@link #withTimeout(long, TimeUnit)}), timeout breaches may occur due to the {@link InputStream}
+ * lacking inherent read timeout support, which might extend the operation beyond the specified timeout limit.
+ *
* @param clientSession the client session with which to associate this operation
* @param filename the filename for the stream
* @param source the Stream providing the file data
@@ -389,6 +402,10 @@ public interface GridFSBucket {
* chunks have been uploaded, it creates a files collection document for {@code filename} in the files collection.
*
*
+ Note: When this {@link GridFSBucket} is set with a operation timeout (via timeout inherited from {@link MongoDatabase}
+ * settings or {@link #withTimeout(long, TimeUnit)}), timeout breaches may occur due to the {@link InputStream}
+ * lacking inherent read timeout support, which might extend the operation beyond the specified timeout limit.
+ *
* @param clientSession the client session with which to associate this operation
* @param filename the filename for the stream
* @param source the Stream providing the file data
@@ -406,6 +423,10 @@ public interface GridFSBucket {
* chunks have been uploaded, it creates a files collection document for {@code filename} in the files collection.
*
*
+ Note: When this {@link GridFSBucket} is set with a operation timeout (via timeout inherited from {@link MongoDatabase}
+ * settings or {@link #withTimeout(long, TimeUnit)}), timeout breaches may occur due to the {@link InputStream}
+ * lacking inherent read timeout support, which might extend the operation beyond the specified timeout limit.
+ *
* @param clientSession the client session with which to associate this operation
* @param id the custom id value of the file
* @param filename the filename for the stream
@@ -422,6 +443,10 @@ public interface GridFSBucket {
* chunks have been uploaded, it creates a files collection document for {@code filename} in the files collection.
*
*
+ Note: When this {@link GridFSBucket} is set with a operation timeout (via timeout inherited from {@link MongoDatabase}
+ * settings or {@link #withTimeout(long, TimeUnit)}), timeout breaches may occur due to the {@link InputStream}
+ * lacking inherent read timeout support, which might extend the operation beyond the specified timeout limit.
+ *
* @param clientSession the client session with which to associate this operation
* @param id the custom id value of the file
* @param filename the filename for the stream
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
index 326cf6ae2a9..ca6ca3d30c5 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSBucketImpl.java
@@ -17,7 +17,7 @@
package com.mongodb.client.gridfs;
import com.mongodb.MongoClientSettings;
-import com.mongodb.MongoExecutionTimeoutException;
+import com.mongodb.MongoOperationTimeoutException;
import com.mongodb.MongoGridFSException;
import com.mongodb.ReadConcern;
import com.mongodb.ReadPreference;
@@ -634,7 +634,7 @@ private void downloadToStream(final GridFSDownloadStream downloadStream, final O
while ((len = downloadStream.read(buffer)) != -1) {
destination.write(buffer, 0, len);
}
- } catch (MongoExecutionTimeoutException e){ // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
+ } catch (MongoOperationTimeoutException e){ // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
throw e;
} catch (IOException e) {
savedThrowable = new MongoGridFSException("IOException when reading from the OutputStream", e);
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
index d3f36643cb5..e744607a0ad 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java
@@ -16,7 +16,7 @@
package com.mongodb.client.gridfs;
-import com.mongodb.MongoExecutionTimeoutException;
+import com.mongodb.MongoOperationTimeoutException;
import com.mongodb.MongoGridFSException;
import com.mongodb.client.ClientSession;
import com.mongodb.client.FindIterable;
@@ -214,7 +214,7 @@ public void close() {
private void checkTimeout() {
if (timeout != null && timeout.hasExpired()) {
// TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
- throw new MongoExecutionTimeoutException("The GridFS download stream has timed out");
+ throw new MongoOperationTimeoutException("The GridFS download stream has timed out");
}
}
private void checkClosed() {
diff --git a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
index 3355459e5b0..e722f3a4c0a 100644
--- a/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
+++ b/driver-sync/src/main/com/mongodb/client/gridfs/GridFSUploadStreamImpl.java
@@ -16,11 +16,11 @@
package com.mongodb.client.gridfs;
-import com.mongodb.MongoExecutionTimeoutException;
import com.mongodb.MongoGridFSException;
import com.mongodb.client.ClientSession;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.gridfs.model.GridFSFile;
+import com.mongodb.internal.TimeoutContext;
import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;
import org.bson.BsonValue;
@@ -146,8 +146,7 @@ public void write(final byte[] b, final int off, final int len) {
private void checkTimeout() {
if (timeout != null && timeout.hasExpired()) {
- // TODO (CSOT) - JAVA-5248 Update to MongoOperationTimeoutException
- throw new MongoExecutionTimeoutException(TIMEOUT_MESSAGE);
+ throw TimeoutContext.createMongoTimeoutException(TIMEOUT_MESSAGE);
}
}
diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
index 5a934d41aca..392cd1e81bf 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideOperationsTimeoutProseTest.java
@@ -123,7 +123,7 @@ public void testGridFSUploadViaOpenUploadStreamTimeout() {
try (GridFSUploadStream uploadStream = gridFsBucket.openUploadStream("filename")){
uploadStream.write(0x12);
- assertThrows(MongoExecutionTimeoutException.class, uploadStream::close);
+ assertThrows(MongoOperationTimeoutException.class, uploadStream::close);
}
}
}
@@ -152,7 +152,7 @@ public void testAbortingGridFsUploadStreamTimeout() {
try (GridFSUploadStream uploadStream = gridFsBucket.openUploadStream("filename")){
uploadStream.write(new byte[]{0x01, 0x02, 0x03, 0x04});
- assertThrows(MongoExecutionTimeoutException.class, uploadStream::abort);
+ assertThrows(MongoOperationTimeoutException.class, uploadStream::abort);
}
}
}
@@ -196,7 +196,7 @@ public void testGridFsDownloadStreamTimeout() {
+ " blockTimeMS: " + (rtt + 95)
+ " }"
+ "}");
- assertThrows(MongoExecutionTimeoutException.class, downloadStream::read);
+ assertThrows(MongoOperationTimeoutException.class, downloadStream::read);
List events = commandListener.getCommandStartedEvents();
List findCommands = events.stream().filter(e -> e.getCommandName().equals("find")).collect(Collectors.toList());
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
index 31f61f50d13..915465836d4 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
@@ -19,6 +19,7 @@
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSFindIterable;
import com.mongodb.client.gridfs.model.GridFSDownloadOptions;
+import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import com.mongodb.internal.HexUtils;
import org.bson.BsonDocument;
@@ -49,15 +50,21 @@ final class UnifiedGridFSHelper extends UnifiedHelper{
public OperationResult executeFind(final BsonDocument operation) {
GridFSFindIterable iterable = createGridFSFindIterable(operation);
try {
- iterable.into(new ArrayList<>());
- return OperationResult.NONE; // we don't expect results in the tests.
+ ArrayList target = new ArrayList<>();
+ iterable.into(target);
+
+ if (target.isEmpty()) {
+ return OperationResult.NONE;
+ }
+
+ throw new UnsupportedOperationException("expectResult is not implemented for Unified GridFS tests.");
} catch (Exception e) {
return OperationResult.of(e);
}
}
public OperationResult executeRename(final BsonDocument operation) {
- GridFSBucket bucket = getGirdFsBucket(operation);
+ GridFSBucket bucket = getGridFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
BsonValue id = arguments.get("id");
String fileName = arguments.get("newFilename").asString().getValue();
@@ -74,7 +81,7 @@ public OperationResult executeRename(final BsonDocument operation) {
}
OperationResult executeDelete(final BsonDocument operation) {
- GridFSBucket bucket = getGirdFsBucket(operation);
+ GridFSBucket bucket = getGridFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
BsonValue id = arguments.get("id");
@@ -94,7 +101,7 @@ OperationResult executeDelete(final BsonDocument operation) {
}
public OperationResult executeDrop(final BsonDocument operation) {
- GridFSBucket bucket = getGirdFsBucket(operation);
+ GridFSBucket bucket = getGridFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments", new BsonDocument());
if (arguments.size() > 0) {
throw new UnsupportedOperationException("Unexpected arguments " + operation.get("arguments"));
@@ -109,7 +116,7 @@ public OperationResult executeDrop(final BsonDocument operation) {
}
public OperationResult executeDownload(final BsonDocument operation) {
- GridFSBucket bucket = getGirdFsBucket(operation);
+ GridFSBucket bucket = getGridFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
BsonValue id = arguments.get("id");
@@ -164,7 +171,7 @@ private GridFSDownloadOptions getDownloadOptions(final BsonDocument arguments) {
}
public OperationResult executeUpload(final BsonDocument operation) {
- GridFSBucket bucket = getGirdFsBucket(operation);
+ GridFSBucket bucket = getGridFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
String filename = null;
@@ -211,7 +218,7 @@ Document asDocument(final BsonDocument bsonDocument) {
return new DocumentCodec().decode(new BsonDocumentReader(bsonDocument), DecoderContext.builder().build());
}
- private GridFSBucket getGirdFsBucket(final BsonDocument operation) {
+ private GridFSBucket getGridFsBucket(final BsonDocument operation) {
GridFSBucket bucket = entities.getBucket(operation.getString("object").getValue());
Long timeoutMS = getAndRemoveTimeoutMS(operation.getDocument("arguments", new BsonDocument()));
if (timeoutMS != null) {
@@ -221,7 +228,7 @@ private GridFSBucket getGirdFsBucket(final BsonDocument operation) {
}
private GridFSFindIterable createGridFSFindIterable(final BsonDocument operation) {
- GridFSBucket bucket = getGirdFsBucket(operation);
+ GridFSBucket bucket = getGridFsBucket(operation);
BsonDocument arguments = operation.getDocument("arguments");
BsonDocument filter = arguments.getDocument("filter");
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java b/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
index a4dd876693c..25402c92c4f 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
@@ -36,6 +36,7 @@
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
+@SuppressWarnings("unchecked")
class CollectionTimeoutHelperTest {
private static final String TIMEOUT_ERROR_MESSAGE = "message";
From 0d15fffb686e21b2d7e7b545149adec61c2d7c36 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Fri, 12 Jan 2024 18:04:31 -0800
Subject: [PATCH 18/19] Add detailed message for unsupported GridFS test
execution.
JAVA-5277
---
.../com/mongodb/client/unified/UnifiedGridFSHelper.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
index 915465836d4..13e95a58463 100644
--- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
+++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedGridFSHelper.java
@@ -57,7 +57,8 @@ public OperationResult executeFind(final BsonDocument operation) {
return OperationResult.NONE;
}
- throw new UnsupportedOperationException("expectResult is not implemented for Unified GridFS tests.");
+ throw new UnsupportedOperationException("expectResult is not implemented for Unified GridFS tests. "
+ + "Unexpected result: " + target);
} catch (Exception e) {
return OperationResult.of(e);
}
From 66bee9bd9c509e5013de1c9723f2dff3f2c14857 Mon Sep 17 00:00:00 2001
From: "slav.babanin"
Date: Fri, 12 Jan 2024 18:18:55 -0800
Subject: [PATCH 19/19] Fix tests.
JAVA-5277
---
.../client/gridfs/CollectionTimeoutHelperTest.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java b/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
index 25402c92c4f..e7e851b270b 100644
--- a/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
+++ b/driver-sync/src/test/unit/com/mongodb/client/gridfs/CollectionTimeoutHelperTest.java
@@ -16,7 +16,7 @@
package com.mongodb.client.gridfs;
-import com.mongodb.MongoExecutionTimeoutException;
+import com.mongodb.MongoOperationTimeoutException;
import com.mongodb.client.MongoCollection;
import com.mongodb.internal.time.Timeout;
import org.bson.Document;
@@ -89,8 +89,8 @@ void shouldThrowErrorWhenTimeoutHasExpired() {
Timeout timeout = Timeout.expiresIn(1, TimeUnit.MICROSECONDS);
//when
- MongoExecutionTimeoutException mongoExecutionTimeoutException =
- assertThrows(MongoExecutionTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
+ MongoOperationTimeoutException mongoExecutionTimeoutException =
+ assertThrows(MongoOperationTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
//then
assertEquals(TIMEOUT_ERROR_MESSAGE, mongoExecutionTimeoutException.getMessage());
@@ -108,7 +108,7 @@ void shouldThrowErrorWhenTimeoutHasExpiredWithZeroRemaining() {
});
//when
- assertThrows(MongoExecutionTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
+ assertThrows(MongoOperationTimeoutException.class, () -> collectionWithTimeout(collection, TIMEOUT_ERROR_MESSAGE, timeout));
//then
verifyNoInteractions(collection);