diff --git a/driver-core/src/main/com/mongodb/ConnectionString.java b/driver-core/src/main/com/mongodb/ConnectionString.java index 659e8fd02aa..8d5e53af25d 100644 --- a/driver-core/src/main/com/mongodb/ConnectionString.java +++ b/driver-core/src/main/com/mongodb/ConnectionString.java @@ -19,6 +19,7 @@ import com.mongodb.annotations.Alpha; import com.mongodb.annotations.Reason; import com.mongodb.connection.ClusterSettings; +import com.mongodb.connection.ClusterType; import com.mongodb.connection.ConnectionPoolSettings; import com.mongodb.connection.ServerMonitoringMode; import com.mongodb.connection.ServerSettings; @@ -272,6 +273,9 @@ * Defaults to true. *
  • {@code retryReads=true|false}. If true the driver will retry supported read operations if they fail due to a network error. * Defaults to true.
  • + *
  • {@code enableOverloadRetargeting=true|false}. If true the driver may route a request to a different server on a subsequent + * retry attempt if the previously used server is overloaded. Does not take effect for {@linkplain ClusterType#SHARDED sharded clusters}. + * Defaults to false.
  • *
  • {@code uuidRepresentation=unspecified|standard|javaLegacy|csharpLegacy|pythonLegacy}. See * {@link MongoClientSettings#getUuidRepresentation()} for documentation of semantics of this parameter. Defaults to "javaLegacy", but * will change to "unspecified" in the next major release.
  • @@ -308,6 +312,7 @@ public class ConnectionString { private WriteConcern writeConcern; private Boolean retryWrites; private Boolean retryReads; + private Boolean enableOverloadRetargeting; private ReadConcern readConcern; private Integer minConnectionPoolSize; @@ -558,6 +563,7 @@ public ConnectionString(final String connectionString, @Nullable final DnsClient GENERAL_OPTIONS_KEYS.add("servermonitoringmode"); GENERAL_OPTIONS_KEYS.add("retrywrites"); GENERAL_OPTIONS_KEYS.add("retryreads"); + GENERAL_OPTIONS_KEYS.add("enableoverloadretargeting"); GENERAL_OPTIONS_KEYS.add("appname"); @@ -706,6 +712,9 @@ private void translateOptions(final Map> optionsMap) { case "retryreads": retryReads = parseBoolean(value, "retryreads"); break; + case "enableoverloadretargeting": + enableOverloadRetargeting = parseBoolean(value, "enableoverloadretargeting"); + break; case "uuidrepresentation": uuidRepresentation = createUuidRepresentation(value); break; @@ -1473,7 +1482,7 @@ public Boolean getRetryWritesValue() { /** *

    Gets whether reads should be retried if they fail due to a network error

    * - * @return the retryWrites value + * @return the retryReads value * @since 3.11 * @mongodb.server.release 3.6 */ @@ -1482,6 +1491,29 @@ public Boolean getRetryReads() { return retryReads; } + /** + * Gets whether overload retargeting is enabled. + * + *

    When enabled, the previously selected servers on which attempts failed with an error + * {@linkplain MongoException#hasErrorLabel(String) having} + * the {@value MongoException#SYSTEM_OVERLOADED_ERROR_LABEL} label may be deprioritized during + * server selection on subsequent retry attempts. This applies to reads when retryReads is enabled, + * and to writes when retryWrites is enabled.

    + * + *

    This setting does not take effect for + * {@linkplain com.mongodb.connection.ClusterType#SHARDED sharded clusters}.

    + * + *

    Defaults to {@code false}.

    + * + * @return the enableOverloadRetargeting value, or null if not set + * @see MongoClientSettings.Builder#enableOverloadRetargeting(boolean) + * @since 5.7 + */ + @Nullable + public Boolean getEnableOverloadRetargeting() { + return enableOverloadRetargeting; + } + /** * Gets the minimum connection pool size specified in the connection string. * @return the minimum connection pool size @@ -1795,6 +1827,7 @@ public boolean equals(final Object o) { && Objects.equals(writeConcern, that.writeConcern) && Objects.equals(retryWrites, that.retryWrites) && Objects.equals(retryReads, that.retryReads) + && Objects.equals(enableOverloadRetargeting, that.enableOverloadRetargeting) && Objects.equals(readConcern, that.readConcern) && Objects.equals(minConnectionPoolSize, that.minConnectionPoolSize) && Objects.equals(maxConnectionPoolSize, that.maxConnectionPoolSize) @@ -1826,8 +1859,8 @@ public boolean equals(final Object o) { @Override public int hashCode() { return Objects.hash(credential, isSrvProtocol, hosts, database, collection, directConnection, readPreference, - writeConcern, retryWrites, retryReads, readConcern, minConnectionPoolSize, maxConnectionPoolSize, maxWaitTime, - maxConnectionIdleTime, maxConnectionLifeTime, maxConnecting, connectTimeout, timeout, socketTimeout, sslEnabled, + writeConcern, retryWrites, retryReads, enableOverloadRetargeting, readConcern, minConnectionPoolSize, maxConnectionPoolSize, + maxWaitTime, maxConnectionIdleTime, maxConnectionLifeTime, maxConnecting, connectTimeout, timeout, socketTimeout, sslEnabled, sslInvalidHostnameAllowed, requiredReplicaSetName, serverSelectionTimeout, localThreshold, heartbeatFrequency, serverMonitoringMode, applicationName, compressorList, uuidRepresentation, srvServiceName, srvMaxHosts, proxyHost, proxyPort, proxyUsername, proxyPassword); diff --git a/driver-core/src/main/com/mongodb/MongoClientSettings.java b/driver-core/src/main/com/mongodb/MongoClientSettings.java index 41c5f73a1d7..bf6ef0430b2 100644 --- a/driver-core/src/main/com/mongodb/MongoClientSettings.java +++ b/driver-core/src/main/com/mongodb/MongoClientSettings.java @@ -24,6 +24,7 @@ import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; import com.mongodb.client.model.mql.ExpressionCodecProvider; import com.mongodb.connection.ClusterSettings; +import com.mongodb.connection.ClusterType; import com.mongodb.connection.ConnectionPoolSettings; import com.mongodb.connection.ServerSettings; import com.mongodb.connection.SocketSettings; @@ -93,6 +94,7 @@ public final class MongoClientSettings { private final WriteConcern writeConcern; private final boolean retryWrites; private final boolean retryReads; + private final boolean enableOverloadRetargeting; private final ReadConcern readConcern; private final MongoCredential credential; private final TransportSettings transportSettings; @@ -214,6 +216,7 @@ public static final class Builder { private WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED; private boolean retryWrites = true; private boolean retryReads = true; + private boolean enableOverloadRetargeting = false; private ReadConcern readConcern = ReadConcern.DEFAULT; private CodecRegistry codecRegistry = MongoClientSettings.getDefaultCodecRegistry(); private TransportSettings transportSettings; @@ -255,6 +258,7 @@ private Builder(final MongoClientSettings settings) { writeConcern = settings.getWriteConcern(); retryWrites = settings.getRetryWrites(); retryReads = settings.getRetryReads(); + enableOverloadRetargeting = settings.getEnableOverloadRetargeting(); readConcern = settings.getReadConcern(); credential = settings.getCredential(); uuidRepresentation = settings.getUuidRepresentation(); @@ -314,6 +318,10 @@ public Builder applyConnectionString(final ConnectionString connectionString) { if (retryReadsValue != null) { retryReads = retryReadsValue; } + Boolean enableOverloadRetargetingValue = connectionString.getEnableOverloadRetargeting(); + if (enableOverloadRetargetingValue != null) { + enableOverloadRetargeting = enableOverloadRetargetingValue; + } if (connectionString.getUuidRepresentation() != null) { uuidRepresentation = connectionString.getUuidRepresentation(); } @@ -456,6 +464,30 @@ public Builder retryReads(final boolean retryReads) { return this; } + /** + * Sets whether to enable overload retargeting. + * + *

    When enabled, the previously selected servers on which attempts failed with an error + * {@linkplain MongoException#hasErrorLabel(String) having} + * the {@value MongoException#SYSTEM_OVERLOADED_ERROR_LABEL} label may be deprioritized during + * server selection on subsequent retry attempts. This applies to reads when + * {@linkplain #retryReads(boolean) retryReads} is enabled, and to writes when + * {@linkplain #retryWrites(boolean) retryWrites} is enabled.

    + * + *

    This setting does not take effect for {@linkplain ClusterType#SHARDED sharded clusters}.

    + * + *

    Defaults to {@code false}.

    + * + * @param enableOverloadRetargeting whether to enable overload retargeting. + * @return this + * @see #getEnableOverloadRetargeting() + * @since 5.7 + */ + public Builder enableOverloadRetargeting(final boolean enableOverloadRetargeting) { + this.enableOverloadRetargeting = enableOverloadRetargeting; + return this; + } + /** * Sets the read concern. * @@ -807,6 +839,18 @@ public boolean getRetryReads() { return retryReads; } + /** + * Returns whether overload retargeting is enabled. + * See {@link Builder#enableOverloadRetargeting(boolean)} for more information. + * + * @return the enableOverloadRetargeting value + * @see Builder#enableOverloadRetargeting(boolean) + * @since 5.7 + */ + public boolean getEnableOverloadRetargeting() { + return enableOverloadRetargeting; + } + /** * The read concern to use. * @@ -1080,6 +1124,7 @@ public boolean equals(final Object o) { MongoClientSettings that = (MongoClientSettings) o; return retryWrites == that.retryWrites && retryReads == that.retryReads + && enableOverloadRetargeting == that.enableOverloadRetargeting && heartbeatSocketTimeoutSetExplicitly == that.heartbeatSocketTimeoutSetExplicitly && heartbeatConnectTimeoutSetExplicitly == that.heartbeatConnectTimeoutSetExplicitly && Objects.equals(readPreference, that.readPreference) @@ -1109,8 +1154,8 @@ public boolean equals(final Object o) { @Override public int hashCode() { - return Objects.hash(readPreference, writeConcern, retryWrites, retryReads, readConcern, credential, transportSettings, - commandListeners, codecRegistry, loggerSettings, clusterSettings, socketSettings, + return Objects.hash(readPreference, writeConcern, retryWrites, retryReads, enableOverloadRetargeting, readConcern, credential, + transportSettings, commandListeners, codecRegistry, loggerSettings, clusterSettings, socketSettings, heartbeatSocketSettings, connectionPoolSettings, serverSettings, sslSettings, applicationName, compressorList, uuidRepresentation, serverApi, autoEncryptionSettings, heartbeatSocketTimeoutSetExplicitly, heartbeatConnectTimeoutSetExplicitly, dnsClient, inetAddressResolver, contextProvider, timeoutMS); @@ -1124,6 +1169,7 @@ public String toString() { + ", writeConcern=" + writeConcern + ", retryWrites=" + retryWrites + ", retryReads=" + retryReads + + ", enableOverloadRetargeting=" + enableOverloadRetargeting + ", readConcern=" + readConcern + ", credential=" + credential + ", transportSettings=" + transportSettings @@ -1154,6 +1200,7 @@ private MongoClientSettings(final Builder builder) { writeConcern = builder.writeConcern; retryWrites = builder.retryWrites; retryReads = builder.retryReads; + enableOverloadRetargeting = builder.enableOverloadRetargeting; readConcern = builder.readConcern; credential = builder.credential; transportSettings = builder.transportSettings; diff --git a/driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java b/driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java index 4146d06c22e..2f0fcaa6379 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java +++ b/driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java @@ -113,9 +113,9 @@ abstract class BaseCluster implements Cluster { private volatile ClusterDescription description; BaseCluster(final ClusterId clusterId, - final ClusterSettings settings, - final ClusterableServerFactory serverFactory, - final ClientMetadata clientMetadata) { + final ClusterSettings settings, + final ClusterableServerFactory serverFactory, + final ClientMetadata clientMetadata) { this.clusterId = notNull("clusterId", clusterId); this.settings = notNull("settings", settings); this.serverFactory = notNull("serverFactory", serverFactory); @@ -159,7 +159,7 @@ public ServerTuple selectServer(final ServerSelector serverSelector, final Opera if (serverTuple != null) { ServerAddress serverAddress = serverTuple.getServerDescription().getAddress(); logServerSelectionSucceeded(operationContext, clusterId, serverAddress, serverSelector, currentDescription); - serverDeprioritization.updateCandidate(serverAddress); + serverDeprioritization.updateCandidate(serverAddress, currentDescription.getType()); return serverTuple; } computedServerSelectionTimeout.onExpired(() -> @@ -302,7 +302,7 @@ private boolean handleServerSelectionRequest( if (serverTuple != null) { ServerAddress serverAddress = serverTuple.getServerDescription().getAddress(); logServerSelectionSucceeded(operationContext, clusterId, serverAddress, request.originalSelector, description); - serverDeprioritization.updateCandidate(serverAddress); + serverDeprioritization.updateCandidate(serverAddress, description.getType()); request.onResult(serverTuple, null); return true; } @@ -361,8 +361,7 @@ private static ServerSelector getCompleteServerSelector( final ClusterSettings settings) { List selectors = Stream.of( getRaceConditionPreFilteringSelector(serversSnapshot), - serverSelector, - serverDeprioritization.getServerSelector(), + serverDeprioritization.apply(serverSelector), settings.getServerSelector(), // may be null new LatencyMinimizingServerSelector(settings.getLocalThreshold(MILLISECONDS), MILLISECONDS), AtMostTwoRandomServerSelector.instance(), diff --git a/driver-core/src/main/com/mongodb/internal/connection/OperationContext.java b/driver-core/src/main/com/mongodb/internal/connection/OperationContext.java index f23d5e5226b..3779cefeaba 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/OperationContext.java +++ b/driver-core/src/main/com/mongodb/internal/connection/OperationContext.java @@ -17,6 +17,7 @@ import com.mongodb.Function; import com.mongodb.MongoConnectionPoolClearedException; +import com.mongodb.MongoException; import com.mongodb.ReadConcern; import com.mongodb.RequestContext; import com.mongodb.ServerAddress; @@ -27,7 +28,6 @@ import com.mongodb.internal.IgnorableRequestContext; import com.mongodb.internal.TimeoutContext; import com.mongodb.internal.TimeoutSettings; -import com.mongodb.internal.VisibleForTesting; import com.mongodb.internal.observability.micrometer.Span; import com.mongodb.internal.observability.micrometer.TracingManager; import com.mongodb.internal.session.SessionContext; @@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import static com.mongodb.MongoException.SYSTEM_OVERLOADED_ERROR_LABEL; import static java.util.stream.Collectors.toList; /** @@ -61,14 +62,14 @@ public class OperationContext { private Span tracingSpan; public OperationContext(final RequestContext requestContext, final SessionContext sessionContext, final TimeoutContext timeoutContext, - @Nullable final ServerApi serverApi) { + @Nullable final ServerApi serverApi) { this(requestContext, sessionContext, timeoutContext, TracingManager.NO_OP, serverApi, null); } public OperationContext(final RequestContext requestContext, final SessionContext sessionContext, final TimeoutContext timeoutContext, - final TracingManager tracingManager, - @Nullable final ServerApi serverApi, - @Nullable final String operationName) { + final TracingManager tracingManager, + @Nullable final ServerApi serverApi, + @Nullable final String operationName) { this(NEXT_ID.incrementAndGet(), requestContext, sessionContext, timeoutContext, new ServerDeprioritization(), tracingManager, serverApi, @@ -76,7 +77,19 @@ public OperationContext(final RequestContext requestContext, final SessionContex null); } - public static OperationContext simpleOperationContext( + public OperationContext(final RequestContext requestContext, final SessionContext sessionContext, final TimeoutContext timeoutContext, + final TracingManager tracingManager, + @Nullable final ServerApi serverApi, + @Nullable final String operationName, + final ServerDeprioritization serverDeprioritization) { + this(NEXT_ID.incrementAndGet(), requestContext, sessionContext, timeoutContext, serverDeprioritization, + tracingManager, + serverApi, + operationName, + null); + } + + static OperationContext simpleOperationContext( final TimeoutSettings timeoutSettings, @Nullable final ServerApi serverApi) { return new OperationContext( IgnorableRequestContext.INSTANCE, @@ -85,7 +98,7 @@ public static OperationContext simpleOperationContext( TracingManager.NO_OP, serverApi, null - ); + ); } public static OperationContext simpleOperationContext(final TimeoutContext timeoutContext) { @@ -113,6 +126,16 @@ public OperationContext withOperationName(final String operationName) { operationName, tracingSpan); } + /** + * TODO-JAVA-6058: This method enables overriding the ServerDeprioritization state. + * It is a temporary solution to handle cases where deprioritization state persists across operations. + */ + public OperationContext withNewServerDeprioritization() { + return new OperationContext(id, requestContext, sessionContext, timeoutContext, + new ServerDeprioritization(serverDeprioritization.enableOverloadRetargeting), tracingManager, serverApi, + operationName, tracingSpan); + } + public long getId() { return id; } @@ -152,16 +175,15 @@ public void setTracingSpan(final Span tracingSpan) { this.tracingSpan = tracingSpan; } - @VisibleForTesting(otherwise = VisibleForTesting.AccessModifier.PRIVATE) - public OperationContext(final long id, - final RequestContext requestContext, - final SessionContext sessionContext, - final TimeoutContext timeoutContext, - final ServerDeprioritization serverDeprioritization, - final TracingManager tracingManager, - @Nullable final ServerApi serverApi, - @Nullable final String operationName, - @Nullable final Span tracingSpan) { + private OperationContext(final long id, + final RequestContext requestContext, + final SessionContext sessionContext, + final TimeoutContext timeoutContext, + final ServerDeprioritization serverDeprioritization, + final TracingManager tracingManager, + @Nullable final ServerApi serverApi, + @Nullable final String operationName, + @Nullable final Span tracingSpan) { this.id = id; this.serverDeprioritization = serverDeprioritization; @@ -174,26 +196,6 @@ public OperationContext(final long id, this.tracingSpan = tracingSpan; } - @VisibleForTesting(otherwise = VisibleForTesting.AccessModifier.PRIVATE) - public OperationContext(final long id, - final RequestContext requestContext, - final SessionContext sessionContext, - final TimeoutContext timeoutContext, - final TracingManager tracingManager, - @Nullable final ServerApi serverApi, - @Nullable final String operationName) { - this.id = id; - this.serverDeprioritization = new ServerDeprioritization(); - this.requestContext = requestContext; - this.sessionContext = sessionContext; - this.timeoutContext = timeoutContext; - this.tracingManager = tracingManager; - this.serverApi = serverApi; - this.operationName = operationName; - this.tracingSpan = null; - } - - /** * @return The same {@link ServerDeprioritization} if called on the same {@link OperationContext}. */ @@ -217,7 +219,8 @@ public OperationContext withConnectionEstablishmentSessionContext() { } public OperationContext withMinRoundTripTime(final ServerDescription serverDescription) { - return withTimeoutContext(timeoutContext.withMinRoundTripTime(TimeUnit.NANOSECONDS.toMillis(serverDescription.getMinRoundTripTimeNanos()))); + return withTimeoutContext( + timeoutContext.withMinRoundTripTime(TimeUnit.NANOSECONDS.toMillis(serverDescription.getMinRoundTripTimeNanos()))); } public OperationContext withOverride(final TimeoutContextOverride timeoutContextOverrideFunction) { @@ -227,26 +230,38 @@ public OperationContext withOverride(final TimeoutContextOverride timeoutContext public static final class ServerDeprioritization { @Nullable private ServerAddress candidate; + @Nullable + private ClusterType clusterType; private final Set deprioritized; - private final DeprioritizingSelector selector; + private final boolean enableOverloadRetargeting; - private ServerDeprioritization() { - candidate = null; - deprioritized = new HashSet<>(); - selector = new DeprioritizingSelector(); + public ServerDeprioritization() { + this(false); + } + + public ServerDeprioritization(final boolean enableOverloadRetargeting) { + this.enableOverloadRetargeting = enableOverloadRetargeting; + this.candidate = null; + this.deprioritized = new HashSet<>(); + this.clusterType = null; } /** - * The returned {@link ServerSelector} tries to {@linkplain ServerSelector#select(ClusterDescription) select} - * only the {@link ServerDescription}s that do not have deprioritized {@link ServerAddress}es. - * If no such {@link ServerDescription} can be selected, then it selects {@link ClusterDescription#getServerDescriptions()}. + * The returned {@link ServerSelector} wraps the provided selector and attempts + * {@linkplain ServerSelector#select(ClusterDescription) server selection} in two passes: + *
      + *
    1. First pass: selects using the wrapped selector with only non-deprioritized {@link ServerDescription}s.
    2. + *
    3. Second pass: if the first pass selects no {@link ServerDescription}s, + * selects using the wrapped selector again with all {@link ServerDescription}s, including deprioritized ones.
    4. + *
    */ - ServerSelector getServerSelector() { - return selector; + ServerSelector apply(final ServerSelector wrappedSelector) { + return new DeprioritizingSelector(wrappedSelector); } - void updateCandidate(final ServerAddress serverAddress) { - candidate = serverAddress; + void updateCandidate(final ServerAddress serverAddress, final ClusterType clusterType) { + this.candidate = serverAddress; + this.clusterType = clusterType; } public void onAttemptFailure(final Throwable failure) { @@ -254,7 +269,13 @@ public void onAttemptFailure(final Throwable failure) { candidate = null; return; } - deprioritized.add(candidate); + + boolean isSystemOverloadedError = failure instanceof MongoException + && ((MongoException) failure).hasErrorLabel(SYSTEM_OVERLOADED_ERROR_LABEL); + + if (clusterType == ClusterType.SHARDED || (isSystemOverloadedError && enableOverloadRetargeting)) { + deprioritized.add(candidate); + } } /** @@ -263,28 +284,46 @@ public void onAttemptFailure(final Throwable failure) { * which indeed may be used concurrently. {@link DeprioritizingSelector} does not need to be thread-safe. */ private final class DeprioritizingSelector implements ServerSelector { - private DeprioritizingSelector() { + private final ServerSelector wrappedSelector; + + private DeprioritizingSelector(final ServerSelector wrappedSelector) { + this.wrappedSelector = wrappedSelector; } @Override public List select(final ClusterDescription clusterDescription) { List serverDescriptions = clusterDescription.getServerDescriptions(); - if (!isEnabled(clusterDescription.getType())) { - return serverDescriptions; + + // TODO-JAVA-5908: Evaluate whether using the early-return optimization has a meaningful performance impact on server selection. + if (serverDescriptions.size() == 1 || deprioritized.isEmpty()) { + return wrappedSelector.select(clusterDescription); } + + // TODO-JAVA-5908: Evaluate whether using a loop instead of Stream has a meaningful performance impact on server selection. List nonDeprioritizedServerDescriptions = serverDescriptions .stream() .filter(serverDescription -> !deprioritized.contains(serverDescription.getAddress())) .collect(toList()); - return nonDeprioritizedServerDescriptions.isEmpty() ? serverDescriptions : nonDeprioritizedServerDescriptions; - } - private boolean isEnabled(final ClusterType clusterType) { - return clusterType == ClusterType.SHARDED; + // TODO-JAVA-5908: Evaluate whether using the early-return optimization has a meaningful performance impact on server selection. + if (nonDeprioritizedServerDescriptions.isEmpty()) { + return wrappedSelector.select(clusterDescription); + } + + List selected = wrappedSelector.select( + new ClusterDescription( + clusterDescription.getConnectionMode(), + clusterDescription.getType(), + clusterDescription.getSrvResolutionException(), + nonDeprioritizedServerDescriptions, + clusterDescription.getClusterSettings(), + clusterDescription.getServerSettings())); + return selected.isEmpty() ? wrappedSelector.select(clusterDescription) : selected; } } } - public interface TimeoutContextOverride extends Function {} + public interface TimeoutContextOverride extends Function { + } } diff --git a/driver-core/src/main/com/mongodb/internal/operation/AsyncChangeStreamBatchCursor.java b/driver-core/src/main/com/mongodb/internal/operation/AsyncChangeStreamBatchCursor.java index ce7127e0dc3..7c32dc41404 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/AsyncChangeStreamBatchCursor.java +++ b/driver-core/src/main/com/mongodb/internal/operation/AsyncChangeStreamBatchCursor.java @@ -73,7 +73,9 @@ final class AsyncChangeStreamBatchCursor implements AsyncAggregateResponseBat this.wrapped = new AtomicReference<>(assertNotNull(wrapped)); this.binding = binding; binding.retain(); - this.initialOperationContext = operationContext.withOverride(TimeoutContext::withMaxTimeAsMaxAwaitTimeOverride); + this.initialOperationContext = operationContext + .withOverride(TimeoutContext::withMaxTimeAsMaxAwaitTimeOverride) + .withNewServerDeprioritization(); this.resumeToken = resumeToken; this.maxWireVersion = maxWireVersion; isClosed = new AtomicBoolean(); diff --git a/driver-core/src/main/com/mongodb/internal/operation/ChangeStreamBatchCursor.java b/driver-core/src/main/com/mongodb/internal/operation/ChangeStreamBatchCursor.java index cf9f1dcf6c4..226deafa9fa 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/ChangeStreamBatchCursor.java +++ b/driver-core/src/main/com/mongodb/internal/operation/ChangeStreamBatchCursor.java @@ -85,7 +85,9 @@ final class ChangeStreamBatchCursor implements AggregateResponseBatchCursor("admin", new BsonDocument("buildInfo", new BsonInt32(1)), new BsonDocumentCodec()) - .execute(new ClusterBinding(getCluster(), ReadPreference.nearest()), OPERATION_CONTEXT)); + .execute(new ClusterBinding(getCluster(), ReadPreference.nearest()), createOperationContext())); } return serverVersion; } - public static final OperationContext OPERATION_CONTEXT = new OperationContext( - IgnorableRequestContext.INSTANCE, - new ReadConcernAwareNoOpSessionContext(ReadConcern.DEFAULT), - new TimeoutContext(TIMEOUT_SETTINGS), - getServerApi()); + public static OperationContext createOperationContext() { + return new OperationContext( + IgnorableRequestContext.INSTANCE, + new ReadConcernAwareNoOpSessionContext(ReadConcern.DEFAULT), + new TimeoutContext(TIMEOUT_SETTINGS), + getServerApi()); + } public static final InternalOperationContextFactory OPERATION_CONTEXT_FACTORY = new InternalOperationContextFactory(TIMEOUT_SETTINGS, getServerApi()); @@ -255,7 +257,7 @@ public static boolean hasEncryptionTestsEnabled() { public static Document getServerStatus() { return new CommandReadOperation<>("admin", new BsonDocument("serverStatus", new BsonInt32(1)), new DocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), createOperationContext()); } public static boolean supportsFsync() { @@ -270,7 +272,7 @@ static class ShutdownHook extends Thread { public void run() { if (cluster != null) { try { - new DropDatabaseOperation(getDefaultDatabaseName(), WriteConcern.ACKNOWLEDGED).execute(getBinding(), OPERATION_CONTEXT); + new DropDatabaseOperation(getDefaultDatabaseName(), WriteConcern.ACKNOWLEDGED).execute(getBinding(), createOperationContext()); } catch (MongoCommandException e) { // if we do not have permission to drop the database, assume it is cleaned up in some other way if (!e.getMessage().contains("Command dropDatabase requires authentication")) { @@ -322,7 +324,7 @@ public static synchronized ConnectionString getConnectionString() { try { BsonDocument helloResult = new CommandReadOperation<>("admin", new BsonDocument(LEGACY_HELLO, new BsonInt32(1)), new BsonDocumentCodec()) - .execute(new ClusterBinding(cluster, ReadPreference.nearest()), OPERATION_CONTEXT); + .execute(new ClusterBinding(cluster, ReadPreference.nearest()), createOperationContext()); if (helloResult.containsKey("setName")) { connectionString = new ConnectionString(DEFAULT_URI + "/?replicaSet=" + helloResult.getString("setName").getValue()); @@ -374,7 +376,9 @@ public static ReadWriteBinding getBinding(final Cluster cluster) { } public static ReadWriteBinding getBinding(final TimeoutSettings timeoutSettings) { - return getBinding(getCluster(), ReadPreference.primary(), createNewOperationContext(timeoutSettings)); + return getBinding(getCluster(), + ReadPreference.primary(), + createOperationContext().withTimeoutContext(new TimeoutContext(timeoutSettings))); } public static ReadWriteBinding getBinding(final OperationContext operationContext) { @@ -382,11 +386,7 @@ public static ReadWriteBinding getBinding(final OperationContext operationContex } public static ReadWriteBinding getBinding(final ReadPreference readPreference) { - return getBinding(getCluster(), readPreference, OPERATION_CONTEXT); - } - - public static OperationContext createNewOperationContext(final TimeoutSettings timeoutSettings) { - return OPERATION_CONTEXT.withTimeoutContext(new TimeoutContext(timeoutSettings)); + return getBinding(getCluster(), readPreference, createOperationContext()); } private static ReadWriteBinding getBinding(final Cluster cluster, @@ -403,7 +403,7 @@ private static ReadWriteBinding getBinding(final Cluster cluster, } public static SingleConnectionBinding getSingleConnectionBinding() { - return new SingleConnectionBinding(getCluster(), ReadPreference.primary(), OPERATION_CONTEXT); + return new SingleConnectionBinding(getCluster(), ReadPreference.primary(), createOperationContext()); } public static AsyncSingleConnectionBinding getAsyncSingleConnectionBinding() { @@ -411,7 +411,7 @@ public static AsyncSingleConnectionBinding getAsyncSingleConnectionBinding() { } public static AsyncSingleConnectionBinding getAsyncSingleConnectionBinding(final Cluster cluster) { - return new AsyncSingleConnectionBinding(cluster, ReadPreference.primary(), OPERATION_CONTEXT); + return new AsyncSingleConnectionBinding(cluster, ReadPreference.primary(), createOperationContext()); } public static AsyncReadWriteBinding getAsyncBinding(final Cluster cluster) { @@ -419,11 +419,11 @@ public static AsyncReadWriteBinding getAsyncBinding(final Cluster cluster) { } public static AsyncReadWriteBinding getAsyncBinding() { - return getAsyncBinding(getAsyncCluster(), ReadPreference.primary(), OPERATION_CONTEXT); + return getAsyncBinding(getAsyncCluster(), ReadPreference.primary(), createOperationContext()); } public static AsyncReadWriteBinding getAsyncBinding(final TimeoutSettings timeoutSettings) { - return getAsyncBinding(createNewOperationContext(timeoutSettings)); + return getAsyncBinding(createOperationContext().withTimeoutContext(new TimeoutContext(timeoutSettings))); } public static AsyncReadWriteBinding getAsyncBinding(final OperationContext operationContext) { @@ -431,7 +431,7 @@ public static AsyncReadWriteBinding getAsyncBinding(final OperationContext opera } public static AsyncReadWriteBinding getAsyncBinding(final ReadPreference readPreference) { - return getAsyncBinding(getAsyncCluster(), readPreference, OPERATION_CONTEXT); + return getAsyncBinding(getAsyncCluster(), readPreference, createOperationContext()); } public static AsyncReadWriteBinding getAsyncBinding( @@ -605,7 +605,7 @@ public static BsonDocument getServerParameters() { if (serverParameters == null) { serverParameters = new CommandReadOperation<>("admin", new BsonDocument("getParameter", new BsonString("*")), new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), createOperationContext()); } return serverParameters; } @@ -673,7 +673,7 @@ public static void configureFailPoint(final BsonDocument failPointDocument) { if (!isSharded()) { try { new CommandReadOperation<>("admin", failPointDocument, new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), createOperationContext()); } catch (MongoCommandException e) { if (e.getErrorCode() == COMMAND_NOT_FOUND_ERROR_CODE) { failsPointsSupported = false; @@ -689,7 +689,7 @@ public static void disableFailPoint(final String failPoint) { .append("mode", new BsonString("off")); try { new CommandReadOperation<>("admin", failPointDocument, new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), createOperationContext()); } catch (MongoCommandException e) { // ignore } @@ -703,7 +703,7 @@ public static T executeSync(final WriteOperation op) { @SuppressWarnings("overloads") public static T executeSync(final WriteOperation op, final ReadWriteBinding binding) { - return op.execute(binding, applySessionContext(OPERATION_CONTEXT, binding.getReadPreference())); + return op.execute(binding, applySessionContext(createOperationContext(), binding.getReadPreference())); } @SuppressWarnings("overloads") @@ -713,7 +713,7 @@ public static T executeSync(final ReadOperation op) { @SuppressWarnings("overloads") public static T executeSync(final ReadOperation op, final ReadWriteBinding binding) { - return op.execute(binding, OPERATION_CONTEXT); + return op.execute(binding, createOperationContext()); } @SuppressWarnings("overloads") @@ -729,7 +729,7 @@ public static T executeAsync(final WriteOperation op) throws Throwable { @SuppressWarnings("overloads") public static T executeAsync(final WriteOperation op, final AsyncReadWriteBinding binding) throws Throwable { FutureResultCallback futureResultCallback = new FutureResultCallback<>(); - op.executeAsync(binding, applySessionContext(OPERATION_CONTEXT, binding.getReadPreference()), futureResultCallback); + op.executeAsync(binding, applySessionContext(createOperationContext(), binding.getReadPreference()), futureResultCallback); return futureResultCallback.get(TIMEOUT, SECONDS); } @@ -741,7 +741,7 @@ public static T executeAsync(final ReadOperation op) throws Throwable @SuppressWarnings("overloads") public static T executeAsync(final ReadOperation op, final AsyncReadBinding binding) throws Throwable { FutureResultCallback futureResultCallback = new FutureResultCallback<>(); - op.executeAsync(binding, OPERATION_CONTEXT, futureResultCallback); + op.executeAsync(binding, createOperationContext(), futureResultCallback); return futureResultCallback.get(TIMEOUT, SECONDS); } @@ -811,19 +811,19 @@ public static List collectCursorResults(final BatchCursor batchCursor) public static AsyncConnectionSource getWriteConnectionSource(final AsyncReadWriteBinding binding) throws Throwable { FutureResultCallback futureResultCallback = new FutureResultCallback<>(); - binding.getWriteConnectionSource(OPERATION_CONTEXT, futureResultCallback); + binding.getWriteConnectionSource(createOperationContext(), futureResultCallback); return futureResultCallback.get(TIMEOUT, SECONDS); } public static AsyncConnectionSource getReadConnectionSource(final AsyncReadWriteBinding binding) throws Throwable { FutureResultCallback futureResultCallback = new FutureResultCallback<>(); - binding.getReadConnectionSource(OPERATION_CONTEXT, futureResultCallback); + binding.getReadConnectionSource(createOperationContext(), futureResultCallback); return futureResultCallback.get(TIMEOUT, SECONDS); } public static AsyncConnection getConnection(final AsyncConnectionSource source) throws Throwable { FutureResultCallback futureResultCallback = new FutureResultCallback<>(); - source.getConnection(OPERATION_CONTEXT, futureResultCallback); + source.getConnection(createOperationContext(), futureResultCallback); return futureResultCallback.get(TIMEOUT, SECONDS); } @@ -866,7 +866,7 @@ private static OperationContext applySessionContext(final OperationContext opera return operationContext.withSessionContext(simpleSessionContext); } - public static OperationContext getOperationContext(final ReadPreference readPreference) { - return applySessionContext(OPERATION_CONTEXT, readPreference); + public static OperationContext createOperationContext(final ReadPreference readPreference) { + return applySessionContext(createOperationContext(), readPreference); } } diff --git a/driver-core/src/test/functional/com/mongodb/OperationFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/OperationFunctionalSpecification.groovy index 6648edc50c7..a0dd685d4b3 100644 --- a/driver-core/src/test/functional/com/mongodb/OperationFunctionalSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/OperationFunctionalSpecification.groovy @@ -61,7 +61,7 @@ import spock.lang.Specification import java.util.concurrent.TimeUnit -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.TIMEOUT import static com.mongodb.ClusterFixture.checkReferenceCountReachesTarget import static com.mongodb.ClusterFixture.executeAsync @@ -108,7 +108,7 @@ class OperationFunctionalSpecification extends Specification { void acknowledgeWrite(final SingleConnectionBinding binding) { new MixedBulkWriteOperation(getNamespace(), [new InsertRequest(new BsonDocument())], true, - ACKNOWLEDGED, false).execute(binding, OPERATION_CONTEXT) + ACKNOWLEDGED, false).execute(binding, createOperationContext()) binding.release() } @@ -279,7 +279,7 @@ class OperationFunctionalSpecification extends Specification { BsonDocument expectedCommand=null, Boolean checkSecondaryOk=false, ReadPreference readPreference=ReadPreference.primary(), Boolean retryable = false, ServerType serverType = ServerType.STANDALONE, Boolean activeTransaction = false) { - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() .withSessionContext(Stub(SessionContext) { hasActiveTransaction() >> activeTransaction getReadConcern() >> readConcern @@ -353,7 +353,7 @@ class OperationFunctionalSpecification extends Specification { Boolean checkCommand = true, BsonDocument expectedCommand = null, Boolean checkSecondaryOk = false, ReadPreference readPreference = ReadPreference.primary(), Boolean retryable = false, ServerType serverType = ServerType.STANDALONE, Boolean activeTransaction = false) { - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() .withSessionContext(Stub(SessionContext) { hasActiveTransaction() >> activeTransaction getReadConcern() >> readConcern @@ -447,7 +447,7 @@ class OperationFunctionalSpecification extends Specification { } } - def operationContext = OPERATION_CONTEXT.withSessionContext( + def operationContext = createOperationContext().withSessionContext( Stub(SessionContext) { hasSession() >> true hasActiveTransaction() >> false @@ -488,7 +488,7 @@ class OperationFunctionalSpecification extends Specification { } } - def operationContext = OPERATION_CONTEXT.withSessionContext( + def operationContext = createOperationContext().withSessionContext( Stub(SessionContext) { hasSession() >> true hasActiveTransaction() >> false diff --git a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java index 935c2979fc4..e6c28d9d5bc 100644 --- a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java +++ b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java @@ -16,6 +16,7 @@ package com.mongodb.client.test; +import com.mongodb.ClusterFixture; import com.mongodb.MongoClientSettings; import com.mongodb.MongoCommandException; import com.mongodb.MongoNamespace; @@ -72,7 +73,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.executeAsync; import static com.mongodb.ClusterFixture.getBinding; import static java.lang.String.format; @@ -93,7 +93,7 @@ public CollectionHelper(final Codec codec, final MongoNamespace namespace) { public T hello() { return new CommandReadOperation<>("admin", BsonDocument.parse("{isMaster: 1}"), codec) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public static void drop(final MongoNamespace namespace) { @@ -106,7 +106,7 @@ public static void drop(final MongoNamespace namespace, final WriteConcern write boolean success = false; while (!success) { try { - new DropCollectionOperation(namespace, writeConcern).execute(getBinding(), OPERATION_CONTEXT); + new DropCollectionOperation(namespace, writeConcern).execute(getBinding(), ClusterFixture.createOperationContext()); success = true; } catch (MongoWriteConcernException e) { LOGGER.info("Retrying drop collection after a write concern error: " + e); @@ -131,7 +131,7 @@ public static void dropDatabase(final String name, final WriteConcern writeConce return; } try { - new DropDatabaseOperation(name, writeConcern).execute(getBinding(), OPERATION_CONTEXT); + new DropDatabaseOperation(name, writeConcern).execute(getBinding(), ClusterFixture.createOperationContext()); } catch (MongoCommandException e) { if (!e.getErrorMessage().contains("ns not found")) { throw e; @@ -141,7 +141,7 @@ public static void dropDatabase(final String name, final WriteConcern writeConce public static BsonDocument getCurrentClusterTime() { return new CommandReadOperation("admin", new BsonDocument("ping", new BsonInt32(1)), new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT).getDocument("$clusterTime", null); + .execute(getBinding(), ClusterFixture.createOperationContext()).getDocument("$clusterTime", null); } public MongoNamespace getNamespace() { @@ -235,7 +235,7 @@ public void create(final String collectionName, final CreateCollectionOptions op boolean success = false; while (!success) { try { - operation.execute(getBinding(), OPERATION_CONTEXT); + operation.execute(getBinding(), ClusterFixture.createOperationContext()); success = true; } catch (MongoCommandException e) { if ("Interrupted".equals(e.getErrorCodeName())) { @@ -254,7 +254,7 @@ public void killCursor(final MongoNamespace namespace, final ServerCursor server .append("cursors", new BsonArray(singletonList(new BsonInt64(serverCursor.getId())))); try { new CommandReadOperation<>(namespace.getDatabaseName(), command, new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } catch (Exception e) { // Ignore any exceptions killing old cursors } @@ -286,7 +286,7 @@ public void insertDocuments(final List documents, final WriteConce for (BsonDocument document : documents) { insertRequests.add(new InsertRequest(document)); } - new MixedBulkWriteOperation(namespace, insertRequests, true, writeConcern, false).execute(binding, OPERATION_CONTEXT); + new MixedBulkWriteOperation(namespace, insertRequests, true, writeConcern, false).execute(binding, ClusterFixture.createOperationContext()); } public void insertDocuments(final Document... documents) { @@ -329,7 +329,7 @@ public List find() { public Optional listSearchIndex(final String indexName) { ListSearchIndexesOperation listSearchIndexesOperation = new ListSearchIndexesOperation<>(namespace, codec, indexName, null, null, null, null, true); - BatchCursor cursor = listSearchIndexesOperation.execute(getBinding(), OPERATION_CONTEXT); + BatchCursor cursor = listSearchIndexesOperation.execute(getBinding(), ClusterFixture.createOperationContext()); List results = new ArrayList<>(); while (cursor.hasNext()) { @@ -342,13 +342,13 @@ public Optional listSearchIndex(final String indexName) { public void createSearchIndex(final SearchIndexRequest searchIndexModel) { CreateSearchIndexesOperation searchIndexesOperation = new CreateSearchIndexesOperation(namespace, singletonList(searchIndexModel)); - searchIndexesOperation.execute(getBinding(), OPERATION_CONTEXT); + searchIndexesOperation.execute(getBinding(), ClusterFixture.createOperationContext()); } public List find(final Codec codec) { BatchCursor cursor = new FindOperation<>(namespace, codec) .sort(new BsonDocument("_id", new BsonInt32(1))) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); List results = new ArrayList<>(); while (cursor.hasNext()) { results.addAll(cursor.next()); @@ -367,7 +367,7 @@ public void updateOne(final Bson filter, final Bson update, final boolean isUpse WriteRequest.Type.UPDATE) .upsert(isUpsert)), true, WriteConcern.ACKNOWLEDGED, false) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public void replaceOne(final Bson filter, final Bson update, final boolean isUpsert) { @@ -377,7 +377,7 @@ public void replaceOne(final Bson filter, final Bson update, final boolean isUps WriteRequest.Type.REPLACE) .upsert(isUpsert)), true, WriteConcern.ACKNOWLEDGED, false) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public void deleteOne(final Bson filter) { @@ -392,7 +392,7 @@ private void delete(final Bson filter, final boolean multi) { new MixedBulkWriteOperation(namespace, singletonList(new DeleteRequest(filter.toBsonDocument(Document.class, registry)).multi(multi)), true, WriteConcern.ACKNOWLEDGED, false) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public List find(final Bson filter) { @@ -417,7 +417,7 @@ private List aggregate(final List pipeline, final Decoder decode bsonDocumentPipeline.add(cur.toBsonDocument(Document.class, registry)); } BatchCursor cursor = new AggregateOperation<>(namespace, bsonDocumentPipeline, decoder, level) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); List results = new ArrayList<>(); while (cursor.hasNext()) { results.addAll(cursor.next()); @@ -452,7 +452,7 @@ public List find(final BsonDocument filter, final BsonDocument sort, fina public List find(final BsonDocument filter, final BsonDocument sort, final BsonDocument projection, final Decoder decoder) { BatchCursor cursor = new FindOperation<>(namespace, decoder).filter(filter).sort(sort) - .projection(projection).execute(getBinding(), OPERATION_CONTEXT); + .projection(projection).execute(getBinding(), ClusterFixture.createOperationContext()); List results = new ArrayList<>(); while (cursor.hasNext()) { results.addAll(cursor.next()); @@ -465,7 +465,7 @@ public long count() { } public long count(final ReadBinding binding) { - return new CountDocumentsOperation(namespace).execute(binding, OPERATION_CONTEXT); + return new CountDocumentsOperation(namespace).execute(binding, ClusterFixture.createOperationContext()); } public long count(final AsyncReadWriteBinding binding) throws Throwable { @@ -474,7 +474,7 @@ public long count(final AsyncReadWriteBinding binding) throws Throwable { public long count(final Bson filter) { return new CountDocumentsOperation(namespace) - .filter(toBsonDocument(filter)).execute(getBinding(), OPERATION_CONTEXT); + .filter(toBsonDocument(filter)).execute(getBinding(), ClusterFixture.createOperationContext()); } public BsonDocument wrap(final Document document) { @@ -487,36 +487,36 @@ public BsonDocument toBsonDocument(final Bson document) { public void createIndex(final BsonDocument key) { new CreateIndexesOperation(namespace, singletonList(new IndexRequest(key)), WriteConcern.ACKNOWLEDGED) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public void createIndex(final Document key) { new CreateIndexesOperation(namespace, singletonList(new IndexRequest(wrap(key))), WriteConcern.ACKNOWLEDGED) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public void createUniqueIndex(final Document key) { new CreateIndexesOperation(namespace, singletonList(new IndexRequest(wrap(key)).unique(true)), WriteConcern.ACKNOWLEDGED) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public void createIndex(final Document key, final String defaultLanguage) { new CreateIndexesOperation(namespace, singletonList(new IndexRequest(wrap(key)).defaultLanguage(defaultLanguage)), WriteConcern.ACKNOWLEDGED).execute( - getBinding(), OPERATION_CONTEXT); + getBinding(), ClusterFixture.createOperationContext()); } public void createIndex(final Bson key) { new CreateIndexesOperation(namespace, singletonList(new IndexRequest(key.toBsonDocument(Document.class, registry))), WriteConcern.ACKNOWLEDGED).execute( - getBinding(), OPERATION_CONTEXT); + getBinding(), ClusterFixture.createOperationContext()); } public List listIndexes(){ List indexes = new ArrayList<>(); BatchCursor cursor = new ListIndexesOperation<>(namespace, new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); while (cursor.hasNext()) { indexes.addAll(cursor.next()); } @@ -526,7 +526,7 @@ public List listIndexes(){ public static void killAllSessions() { try { new CommandReadOperation<>("admin", - new BsonDocument("killAllSessions", new BsonArray()), new BsonDocumentCodec()).execute(getBinding(), OPERATION_CONTEXT); + new BsonDocument("killAllSessions", new BsonArray()), new BsonDocumentCodec()).execute(getBinding(), ClusterFixture.createOperationContext()); } catch (MongoCommandException e) { // ignore exception caused by killing the implicit session that the killAllSessions command itself is running in } @@ -537,7 +537,7 @@ public void renameCollection(final MongoNamespace newNamespace) { new CommandReadOperation<>("admin", new BsonDocument("renameCollection", new BsonString(getNamespace().getFullName())) .append("to", new BsonString(newNamespace.getFullName())), new BsonDocumentCodec()).execute( - getBinding(), OPERATION_CONTEXT); + getBinding(), ClusterFixture.createOperationContext()); } catch (MongoCommandException e) { // do nothing } @@ -549,11 +549,11 @@ public void runAdminCommand(final String command) { public void runAdminCommand(final BsonDocument command) { new CommandReadOperation<>("admin", command, new BsonDocumentCodec()) - .execute(getBinding(), OPERATION_CONTEXT); + .execute(getBinding(), ClusterFixture.createOperationContext()); } public void runAdminCommand(final BsonDocument command, final ReadPreference readPreference) { new CommandReadOperation<>("admin", command, new BsonDocumentCodec()) - .execute(getBinding(readPreference), OPERATION_CONTEXT); + .execute(getBinding(readPreference), ClusterFixture.createOperationContext()); } } diff --git a/driver-core/src/test/functional/com/mongodb/connection/ConnectionSpecification.groovy b/driver-core/src/test/functional/com/mongodb/connection/ConnectionSpecification.groovy index 5658ec5ea43..5dd6145f063 100644 --- a/driver-core/src/test/functional/com/mongodb/connection/ConnectionSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/connection/ConnectionSpecification.groovy @@ -17,13 +17,14 @@ package com.mongodb.connection import com.mongodb.OperationFunctionalSpecification +import com.mongodb.internal.connection.OperationContext import com.mongodb.internal.operation.CommandReadOperation import org.bson.BsonDocument import org.bson.BsonInt32 import org.bson.codecs.BsonDocumentCodec import static com.mongodb.ClusterFixture.LEGACY_HELLO -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getBinding import static com.mongodb.connection.ConnectionDescription.getDefaultMaxMessageSize import static com.mongodb.connection.ConnectionDescription.getDefaultMaxWriteBatchSize @@ -32,8 +33,9 @@ class ConnectionSpecification extends OperationFunctionalSpecification { def 'should have id'() { when: - def source = getBinding().getReadConnectionSource(OPERATION_CONTEXT) - def connection = source.getConnection(OPERATION_CONTEXT) + def operationContext = createOperationContext() + def source = getBinding().getReadConnectionSource(operationContext) + def connection = source.getConnection(operationContext) then: connection.getDescription().getConnectionId() != null @@ -45,13 +47,14 @@ class ConnectionSpecification extends OperationFunctionalSpecification { def 'should have description'() { when: - def commandResult = getHelloResult() + def operationContext = createOperationContext() + def commandResult = getHelloResult(operationContext) def expectedMaxMessageSize = commandResult.getNumber('maxMessageSizeBytes', new BsonInt32(getDefaultMaxMessageSize())).intValue() def expectedMaxBatchCount = commandResult.getNumber('maxWriteBatchSize', new BsonInt32(getDefaultMaxWriteBatchSize())).intValue() - def source = getBinding().getReadConnectionSource(OPERATION_CONTEXT) - def connection = source.getConnection(OPERATION_CONTEXT) + def source = getBinding().getReadConnectionSource(operationContext) + def connection = source.getConnection(operationContext) then: connection.description.serverAddress == source.getServerDescription().getAddress() @@ -64,8 +67,8 @@ class ConnectionSpecification extends OperationFunctionalSpecification { connection?.release() source?.release() } - private static BsonDocument getHelloResult() { + private static BsonDocument getHelloResult(OperationContext operationContext) { new CommandReadOperation('admin', new BsonDocument(LEGACY_HELLO, new BsonInt32(1)), - new BsonDocumentCodec()).execute(getBinding(), OPERATION_CONTEXT) + new BsonDocumentCodec()).execute(getBinding(), operationContext) } } diff --git a/driver-core/src/test/functional/com/mongodb/connection/netty/NettyStreamSpecification.groovy b/driver-core/src/test/functional/com/mongodb/connection/netty/NettyStreamSpecification.groovy index e582e0fc398..8747b8c75b9 100644 --- a/driver-core/src/test/functional/com/mongodb/connection/netty/NettyStreamSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/connection/netty/NettyStreamSpecification.groovy @@ -18,7 +18,7 @@ import com.mongodb.spock.Slow import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getSslSettings class NettyStreamSpecification extends Specification { @@ -43,7 +43,7 @@ class NettyStreamSpecification extends Specification { def stream = factory.create(new ServerAddress()) when: - stream.open(OPERATION_CONTEXT) + stream.open(createOperationContext()) then: !stream.isClosed() @@ -69,7 +69,7 @@ class NettyStreamSpecification extends Specification { def stream = factory.create(new ServerAddress()) when: - stream.open(OPERATION_CONTEXT) + stream.open(createOperationContext()) then: thrown(MongoSocketOpenException) @@ -96,7 +96,7 @@ class NettyStreamSpecification extends Specification { def callback = new CallbackErrorHolder() when: - stream.openAsync(OPERATION_CONTEXT, callback) + stream.openAsync(createOperationContext(), callback) then: callback.getError().is(exception) diff --git a/driver-core/src/test/functional/com/mongodb/internal/binding/AsyncSessionBindingSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/binding/AsyncSessionBindingSpecification.groovy index 173cd9f0935..81ab2ead1e2 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/binding/AsyncSessionBindingSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/binding/AsyncSessionBindingSpecification.groovy @@ -16,17 +16,17 @@ package com.mongodb.internal.binding +import com.mongodb.ClusterFixture import com.mongodb.internal.async.SingleResultCallback import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT - class AsyncSessionBindingSpecification extends Specification { def 'should wrap the passed in async binding'() { given: def wrapped = Mock(AsyncReadWriteBinding) def binding = new AsyncSessionBinding(wrapped) + def operationContext = ClusterFixture.createOperationContext() when: binding.getCount() @@ -52,17 +52,18 @@ class AsyncSessionBindingSpecification extends Specification { then: 1 * wrapped.release() + when: - binding.getReadConnectionSource(OPERATION_CONTEXT, Stub(SingleResultCallback)) + binding.getReadConnectionSource(operationContext, Stub(SingleResultCallback)) then: - 1 * wrapped.getReadConnectionSource(OPERATION_CONTEXT, _) + 1 * wrapped.getReadConnectionSource(operationContext, _) when: - binding.getWriteConnectionSource(OPERATION_CONTEXT, Stub(SingleResultCallback)) + binding.getWriteConnectionSource(operationContext, Stub(SingleResultCallback)) then: - 1 * wrapped.getWriteConnectionSource(OPERATION_CONTEXT, _) + 1 * wrapped.getWriteConnectionSource(operationContext, _) } } diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncSocketChannelStreamSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncSocketChannelStreamSpecification.groovy index 85f23350984..2660693eccf 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncSocketChannelStreamSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncSocketChannelStreamSpecification.groovy @@ -13,7 +13,7 @@ import com.mongodb.spock.Slow import java.util.concurrent.CountDownLatch -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getSslSettings import static java.util.concurrent.TimeUnit.MILLISECONDS @@ -40,7 +40,7 @@ class AsyncSocketChannelStreamSpecification extends Specification { def stream = factory.create(new ServerAddress('host1')) when: - stream.open(OPERATION_CONTEXT) + stream.open(createOperationContext()) then: !stream.isClosed() @@ -66,7 +66,7 @@ class AsyncSocketChannelStreamSpecification extends Specification { def stream = factory.create(new ServerAddress()) when: - stream.open(OPERATION_CONTEXT) + stream.open(createOperationContext()) then: thrown(MongoSocketOpenException) @@ -90,7 +90,7 @@ class AsyncSocketChannelStreamSpecification extends Specification { def callback = new CallbackErrorHolder() when: - stream.openAsync(OPERATION_CONTEXT, callback) + stream.openAsync(createOperationContext(), callback) then: callback.getError().is(exception) diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncStreamTimeoutsSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncStreamTimeoutsSpecification.groovy index 3589362b8ac..fc4cd8be576 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncStreamTimeoutsSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/AsyncStreamTimeoutsSpecification.groovy @@ -30,7 +30,7 @@ import com.mongodb.spock.Slow import java.util.concurrent.TimeUnit -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getCredentialWithCache import static com.mongodb.ClusterFixture.getServerApi import static com.mongodb.ClusterFixture.getSslSettings @@ -49,7 +49,7 @@ class AsyncStreamTimeoutsSpecification extends OperationFunctionalSpecification .create(new ServerId(new ClusterId(), new ServerAddress(new InetSocketAddress('192.168.255.255', 27017)))) when: - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) then: thrown(MongoSocketOpenException) @@ -63,7 +63,7 @@ class AsyncStreamTimeoutsSpecification extends OperationFunctionalSpecification new ServerAddress(new InetSocketAddress('192.168.255.255', 27017)))) when: - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) then: thrown(MongoSocketOpenException) diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/AwsAuthenticationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/AwsAuthenticationSpecification.groovy index 8dd53bc1c03..501be77d6d9 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/AwsAuthenticationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/AwsAuthenticationSpecification.groovy @@ -19,7 +19,7 @@ import spock.lang.Specification import java.util.function.Supplier import static com.mongodb.AuthenticationMechanism.MONGODB_AWS -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getClusterConnectionMode import static com.mongodb.ClusterFixture.getConnectionString import static com.mongodb.ClusterFixture.getCredential @@ -52,7 +52,7 @@ class AwsAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: thrown(MongoCommandException) @@ -71,7 +71,7 @@ class AwsAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: true @@ -101,7 +101,7 @@ class AwsAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: true @@ -160,10 +160,10 @@ class AwsAuthenticationSpecification extends Specification { private static void openConnection(final InternalConnection connection, final boolean async) { if (async) { FutureResultCallback futureResultCallback = new FutureResultCallback() - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get(ClusterFixture.TIMEOUT, SECONDS) } else { - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) } } } diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy index f1585f82595..ec5f3644549 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy @@ -31,7 +31,7 @@ import java.util.concurrent.CountDownLatch import static com.mongodb.ClusterFixture.CLIENT_METADATA import static com.mongodb.ClusterFixture.LEGACY_HELLO -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getClusterConnectionMode import static com.mongodb.ClusterFixture.getCredentialWithCache import static com.mongodb.ClusterFixture.getPrimary @@ -48,7 +48,7 @@ class CommandHelperSpecification extends Specification { new NettyStreamFactory(SocketSettings.builder().build(), getSslSettings()), getCredentialWithCache(), CLIENT_METADATA, [], LoggerSettings.builder().build(), null, getServerApi()) .create(new ServerId(new ClusterId(), getPrimary())) - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) } def cleanup() { @@ -62,7 +62,7 @@ class CommandHelperSpecification extends Specification { Throwable receivedException = null def latch1 = new CountDownLatch(1) executeCommandAsync('admin', new BsonDocument(LEGACY_HELLO, new BsonInt32(1)), getClusterConnectionMode(), - getServerApi(), connection, OPERATION_CONTEXT) + getServerApi(), connection, createOperationContext()) { document, exception -> receivedDocument = document; receivedException = exception; latch1.countDown() } latch1.await() @@ -74,7 +74,7 @@ class CommandHelperSpecification extends Specification { when: def latch2 = new CountDownLatch(1) executeCommandAsync('admin', new BsonDocument('non-existent-command', new BsonInt32(1)), getClusterConnectionMode(), - getServerApi(), connection, OPERATION_CONTEXT) + getServerApi(), connection, createOperationContext()) { document, exception -> receivedDocument = document; receivedException = exception; latch2.countDown() } latch2.await() diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/DefaultConnectionPoolTest.java b/driver-core/src/test/functional/com/mongodb/internal/connection/DefaultConnectionPoolTest.java index 81e778b4a61..5187f692459 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/DefaultConnectionPoolTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/DefaultConnectionPoolTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoConnectionPoolClearedException; import com.mongodb.MongoServerUnavailableException; import com.mongodb.ServerAddress; @@ -60,7 +61,6 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Stream; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.OPERATION_CONTEXT_FACTORY; import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; import static com.mongodb.ClusterFixture.createOperationContext; @@ -173,7 +173,7 @@ public void shouldThrowOnPoolClosed() { String expectedExceptionMessage = "The server at 127.0.0.1:27017 is no longer available"; MongoServerUnavailableException exception; - exception = assertThrows(MongoServerUnavailableException.class, () -> provider.get(OPERATION_CONTEXT)); + exception = assertThrows(MongoServerUnavailableException.class, () -> provider.get(ClusterFixture.createOperationContext())); assertEquals(expectedExceptionMessage, exception.getMessage()); SupplyingCallback supplyingCallback = new SupplyingCallback<>(); provider.getAsync(createOperationContext(TIMEOUT_SETTINGS.withMaxWaitTimeMS(50)), supplyingCallback); @@ -194,10 +194,10 @@ public void shouldExpireConnectionAfterMaxLifeTime() throws InterruptedException provider.ready(); // when - provider.get(OPERATION_CONTEXT).close(); + provider.get(ClusterFixture.createOperationContext()).close(); sleep(100); provider.doMaintenance(); - provider.get(OPERATION_CONTEXT); + provider.get(ClusterFixture.createOperationContext()); // then assertTrue(connectionFactory.getNumCreatedConnections() >= 2); // should really be two, but it's racy @@ -215,7 +215,7 @@ public void shouldExpireConnectionAfterLifeTimeOnClose() throws InterruptedExcep provider.ready(); // when - InternalConnection connection = provider.get(OPERATION_CONTEXT); + InternalConnection connection = provider.get(ClusterFixture.createOperationContext()); sleep(50); connection.close(); @@ -236,10 +236,10 @@ public void shouldExpireConnectionAfterMaxIdleTime() throws InterruptedException provider.ready(); // when - provider.get(OPERATION_CONTEXT).close(); + provider.get(ClusterFixture.createOperationContext()).close(); sleep(100); provider.doMaintenance(); - provider.get(OPERATION_CONTEXT); + provider.get(ClusterFixture.createOperationContext()); // then assertTrue(connectionFactory.getNumCreatedConnections() >= 2); // should really be two, but it's racy @@ -258,10 +258,10 @@ public void shouldCloseConnectionAfterExpiration() throws InterruptedException { provider.ready(); // when - provider.get(OPERATION_CONTEXT).close(); + provider.get(ClusterFixture.createOperationContext()).close(); sleep(50); provider.doMaintenance(); - provider.get(OPERATION_CONTEXT); + provider.get(ClusterFixture.createOperationContext()); // then assertTrue(connectionFactory.getCreatedConnections().get(0).isClosed()); @@ -280,10 +280,10 @@ public void shouldCreateNewConnectionAfterExpiration() throws InterruptedExcepti provider.ready(); // when - provider.get(OPERATION_CONTEXT).close(); + provider.get(ClusterFixture.createOperationContext()).close(); sleep(50); provider.doMaintenance(); - InternalConnection secondConnection = provider.get(OPERATION_CONTEXT); + InternalConnection secondConnection = provider.get(ClusterFixture.createOperationContext()); // then assertNotNull(secondConnection); @@ -302,7 +302,7 @@ public void shouldPruneAfterMaintenanceTaskRuns() throws InterruptedException { .build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY); provider.ready(); - provider.get(OPERATION_CONTEXT).close(); + provider.get(ClusterFixture.createOperationContext()).close(); // when @@ -322,7 +322,7 @@ void infiniteMaxSize() { List connections = new ArrayList<>(); try { for (int i = 0; i < 2 * defaultMaxSize; i++) { - connections.add(provider.get(OPERATION_CONTEXT)); + connections.add(provider.get(ClusterFixture.createOperationContext())); } } finally { connections.forEach(connection -> { diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticationSpecification.groovy index cc3e0401bb5..fa649022aaa 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticationSpecification.groovy @@ -36,7 +36,7 @@ import javax.security.auth.Subject import javax.security.auth.login.LoginContext import static com.mongodb.AuthenticationMechanism.GSSAPI -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getClusterConnectionMode import static com.mongodb.ClusterFixture.getConnectionString import static com.mongodb.ClusterFixture.getCredential @@ -58,7 +58,7 @@ class GSSAPIAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: thrown(MongoCommandException) @@ -77,7 +77,7 @@ class GSSAPIAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: true @@ -99,7 +99,7 @@ class GSSAPIAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: thrown(MongoSecurityException) @@ -131,7 +131,7 @@ class GSSAPIAuthenticationSpecification extends Specification { def connection = createConnection(async, getMongoCredential(subject)) openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: true @@ -175,7 +175,7 @@ class GSSAPIAuthenticationSpecification extends Specification { def connection = createConnection(async, getMongoCredential(saslClientProperties)) openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: true @@ -219,10 +219,10 @@ class GSSAPIAuthenticationSpecification extends Specification { private static void openConnection(final InternalConnection connection, final boolean async) { if (async) { FutureResultCallback futureResultCallback = new FutureResultCallback() - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get(ClusterFixture.TIMEOUT, SECONDS) } else { - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) } } } diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticatorSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticatorSpecification.groovy index 223698d561c..f7fd3534960 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticatorSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/GSSAPIAuthenticatorSpecification.groovy @@ -30,7 +30,7 @@ import spock.lang.Specification import javax.security.auth.login.LoginContext import static com.mongodb.AuthenticationMechanism.GSSAPI -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getLoginContextName import static com.mongodb.ClusterFixture.getPrimary import static com.mongodb.ClusterFixture.getServerApi @@ -57,7 +57,7 @@ class GSSAPIAuthenticatorSpecification extends Specification { .create(new ServerId(new ClusterId(), getPrimary())) when: - internalConnection.open(OPERATION_CONTEXT) + internalConnection.open(createOperationContext()) then: 1 * subjectProvider.getSubject() >> subject diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticationSpecification.groovy index e8c2a408220..b1078711f7d 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticationSpecification.groovy @@ -32,7 +32,7 @@ import spock.lang.IgnoreIf import spock.lang.Specification import static com.mongodb.AuthenticationMechanism.PLAIN -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getClusterConnectionMode import static com.mongodb.ClusterFixture.getConnectionString import static com.mongodb.ClusterFixture.getCredential @@ -52,7 +52,7 @@ class PlainAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: thrown(MongoCommandException) @@ -71,7 +71,7 @@ class PlainAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: true @@ -90,7 +90,7 @@ class PlainAuthenticationSpecification extends Specification { when: openConnection(connection, async) executeCommand(getConnectionString().getDatabase(), new BsonDocument('count', new BsonString('test')), - getClusterConnectionMode(), null, connection, OPERATION_CONTEXT) + getClusterConnectionMode(), null, connection, createOperationContext()) then: thrown(MongoSecurityException) @@ -123,10 +123,10 @@ class PlainAuthenticationSpecification extends Specification { private static void openConnection(final InternalConnection connection, final boolean async) { if (async) { FutureResultCallback futureResultCallback = new FutureResultCallback() - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get(ClusterFixture.TIMEOUT, SECONDS) } else { - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) } } } diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticatorTest.java b/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticatorTest.java index b95b9c96894..6fb9f48d078 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticatorTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/PlainAuthenticatorTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.LoggerSettings; import com.mongodb.MongoCredential; import com.mongodb.MongoSecurityException; @@ -33,7 +34,6 @@ import java.util.Collections; import static com.mongodb.ClusterFixture.CLIENT_METADATA; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getClusterConnectionMode; import static com.mongodb.ClusterFixture.getServerApi; import static com.mongodb.ClusterFixture.getSslSettings; @@ -69,14 +69,14 @@ public void tearDown() { public void testSuccessfulAuthentication() { PlainAuthenticator authenticator = new PlainAuthenticator(getCredentialWithCache(userName, source, password.toCharArray()), getClusterConnectionMode(), getServerApi()); - authenticator.authenticate(internalConnection, connectionDescription, OPERATION_CONTEXT); + authenticator.authenticate(internalConnection, connectionDescription, ClusterFixture.createOperationContext()); } @Test(expected = MongoSecurityException.class) public void testUnsuccessfulAuthentication() { PlainAuthenticator authenticator = new PlainAuthenticator(getCredentialWithCache(userName, source, "wrong".toCharArray()), getClusterConnectionMode(), getServerApi()); - authenticator.authenticate(internalConnection, connectionDescription, OPERATION_CONTEXT); + authenticator.authenticate(internalConnection, connectionDescription, ClusterFixture.createOperationContext()); } private static MongoCredentialWithCache getCredentialWithCache(final String userName, final String source, final char[] password) { diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/ScramSha256AuthenticationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/ScramSha256AuthenticationSpecification.groovy index 36aac9b6908..b5baa3837f3 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/ScramSha256AuthenticationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/ScramSha256AuthenticationSpecification.groovy @@ -33,7 +33,7 @@ import org.bson.codecs.DocumentCodec import spock.lang.IgnoreIf import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.createAsyncCluster import static com.mongodb.ClusterFixture.createCluster import static com.mongodb.ClusterFixture.getBinding @@ -88,12 +88,12 @@ class ScramSha256AuthenticationSpecification extends Specification { def binding = getBinding() new CommandReadOperation<>('admin', new BsonDocumentWrapper(createUserCommand, new DocumentCodec()), new DocumentCodec()) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) } def dropUser(final String userName) { def binding = getBinding() - def operationContext = ClusterFixture.getOperationContext(binding.getReadPreference()) + def operationContext = ClusterFixture.createOperationContext(binding.getReadPreference()) new CommandReadOperation<>('admin', new BsonDocument('dropUser', new BsonString(userName)), new BsonDocumentCodec()).execute(binding, operationContext) } @@ -105,7 +105,7 @@ class ScramSha256AuthenticationSpecification extends Specification { when: new CommandReadOperation('admin', new BsonDocumentWrapper(new Document('dbstats', 1), new DocumentCodec()), new DocumentCodec()) - .execute(new ClusterBinding(cluster, ReadPreference.primary()), OPERATION_CONTEXT) + .execute(new ClusterBinding(cluster, ReadPreference.primary()), createOperationContext()) then: noExceptionThrown() @@ -128,7 +128,7 @@ class ScramSha256AuthenticationSpecification extends Specification { def binding = new AsyncClusterBinding(cluster, ReadPreference.primary()) new CommandReadOperation('admin', new BsonDocumentWrapper(new Document('dbstats', 1), new DocumentCodec()), new DocumentCodec()) - .executeAsync(binding, OPERATION_CONTEXT, callback) + .executeAsync(binding, createOperationContext(), callback) callback.get() then: @@ -148,7 +148,7 @@ class ScramSha256AuthenticationSpecification extends Specification { when: new CommandReadOperation('admin', new BsonDocumentWrapper(new Document('dbstats', 1), new DocumentCodec()), new DocumentCodec()) - .execute(new ClusterBinding(cluster, ReadPreference.primary()), OPERATION_CONTEXT) + .execute(new ClusterBinding(cluster, ReadPreference.primary()), createOperationContext()) then: thrown(MongoSecurityException) @@ -168,7 +168,7 @@ class ScramSha256AuthenticationSpecification extends Specification { when: new CommandReadOperation('admin', new BsonDocumentWrapper(new Document('dbstats', 1), new DocumentCodec()), new DocumentCodec()) - .executeAsync(new AsyncClusterBinding(cluster, ReadPreference.primary()), OPERATION_CONTEXT, + .executeAsync(new AsyncClusterBinding(cluster, ReadPreference.primary()), createOperationContext(), callback) callback.get() @@ -189,7 +189,7 @@ class ScramSha256AuthenticationSpecification extends Specification { when: new CommandReadOperation('admin', new BsonDocumentWrapper(new Document('dbstats', 1), new DocumentCodec()), new DocumentCodec()) - .execute(new ClusterBinding(cluster, ReadPreference.primary()), OPERATION_CONTEXT) + .execute(new ClusterBinding(cluster, ReadPreference.primary()), createOperationContext()) then: noExceptionThrown() @@ -209,7 +209,7 @@ class ScramSha256AuthenticationSpecification extends Specification { when: new CommandReadOperation('admin', new BsonDocumentWrapper(new Document('dbstats', 1), new DocumentCodec()), new DocumentCodec()) - .executeAsync(new AsyncClusterBinding(cluster, ReadPreference.primary()), OPERATION_CONTEXT, + .executeAsync(new AsyncClusterBinding(cluster, ReadPreference.primary()), createOperationContext(), callback) callback.get() diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/ServerHelper.java b/driver-core/src/test/functional/com/mongodb/internal/connection/ServerHelper.java index 0295e8c1f9f..8e9b2385ee5 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/ServerHelper.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/ServerHelper.java @@ -23,7 +23,6 @@ import com.mongodb.internal.binding.AsyncConnectionSource; import com.mongodb.internal.selector.ServerAddressSelector; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getAsyncCluster; import static com.mongodb.ClusterFixture.getCluster; import static com.mongodb.assertions.Assertions.fail; @@ -54,7 +53,7 @@ public static void waitForLastRelease(final Cluster cluster) { public static void waitForLastRelease(final ServerAddress address, final Cluster cluster) { ConcurrentPool pool = connectionPool( - cluster.selectServer(new ServerAddressSelector(address), OPERATION_CONTEXT).getServer()); + cluster.selectServer(new ServerAddressSelector(address), ClusterFixture.createOperationContext()).getServer()); long startTime = System.currentTimeMillis(); while (pool.getInUseCount() > 0) { try { @@ -70,7 +69,7 @@ public static void waitForLastRelease(final ServerAddress address, final Cluster } private static ConcurrentPool getConnectionPool(final ServerAddress address, final Cluster cluster) { - return connectionPool(cluster.selectServer(new ServerAddressSelector(address), OPERATION_CONTEXT).getServer()); + return connectionPool(cluster.selectServer(new ServerAddressSelector(address), ClusterFixture.createOperationContext()).getServer()); } private static void checkPool(final ServerAddress address, final Cluster cluster) { diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/SingleServerClusterTest.java b/driver-core/src/test/functional/com/mongodb/internal/connection/SingleServerClusterTest.java index 62fa6c27032..a624a27454c 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/SingleServerClusterTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/SingleServerClusterTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.LoggerSettings; import com.mongodb.ReadPreference; import com.mongodb.ServerAddress; @@ -37,7 +38,6 @@ import java.util.Collections; import static com.mongodb.ClusterFixture.CLIENT_METADATA; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.OPERATION_CONTEXT_FACTORY; import static com.mongodb.ClusterFixture.getCredential; import static com.mongodb.ClusterFixture.getDefaultDatabaseName; @@ -93,7 +93,7 @@ public void shouldGetServerWithOkDescription() { setUpCluster(getPrimary()); // when - ServerTuple serverTuple = cluster.selectServer(clusterDescription -> getPrimaries(clusterDescription), OPERATION_CONTEXT); + ServerTuple serverTuple = cluster.selectServer(clusterDescription -> getPrimaries(clusterDescription), ClusterFixture.createOperationContext()); // then assertTrue(serverTuple.getServerDescription().isOk()); @@ -102,7 +102,7 @@ public void shouldGetServerWithOkDescription() { @Test public void shouldSuccessfullyQueryASecondaryWithPrimaryReadPreference() { // given - OperationContext operationContext = OPERATION_CONTEXT; + OperationContext operationContext = ClusterFixture.createOperationContext(); ServerAddress secondary = getSecondary(); setUpCluster(secondary); String collectionName = getClass().getName(); diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/SocketStreamHelperSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/SocketStreamHelperSpecification.groovy index 68a82fcbf74..ef0e7d09264 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/SocketStreamHelperSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/SocketStreamHelperSpecification.groovy @@ -33,7 +33,6 @@ import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocketFactory import java.lang.reflect.Method -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getPrimary @@ -87,7 +86,7 @@ class SocketStreamHelperSpecification extends Specification { when: SocketStreamHelper.initialize( - OPERATION_CONTEXT.withTimeoutContext(new TimeoutContext( + createOperationContext().withTimeoutContext(new TimeoutContext( new TimeoutSettings( 1, 100, @@ -110,7 +109,8 @@ class SocketStreamHelperSpecification extends Specification { Socket socket = SocketFactory.default.createSocket() when: - SocketStreamHelper.initialize(OPERATION_CONTEXT, socket, getSocketAddresses(getPrimary(), new DefaultInetAddressResolver()).get(0), + SocketStreamHelper.initialize(createOperationContext(), socket, getSocketAddresses(getPrimary(), + new DefaultInetAddressResolver()).get(0), SocketSettings.builder().build(), SslSettings.builder().build()) then: @@ -126,7 +126,8 @@ class SocketStreamHelperSpecification extends Specification { SSLSocket socket = SSLSocketFactory.default.createSocket() when: - SocketStreamHelper.initialize(OPERATION_CONTEXT, socket, getSocketAddresses(getPrimary(), new DefaultInetAddressResolver()).get(0), + SocketStreamHelper.initialize(createOperationContext(), socket, getSocketAddresses(getPrimary(), + new DefaultInetAddressResolver()).get(0), SocketSettings.builder().build(), sslSettings) then: @@ -147,7 +148,8 @@ class SocketStreamHelperSpecification extends Specification { SSLSocket socket = SSLSocketFactory.default.createSocket() when: - SocketStreamHelper.initialize(OPERATION_CONTEXT, socket, getSocketAddresses(getPrimary(), new DefaultInetAddressResolver()).get(0), + SocketStreamHelper.initialize(createOperationContext(), socket, getSocketAddresses(getPrimary(), + new DefaultInetAddressResolver()).get(0), SocketSettings.builder().build(), sslSettings) then: @@ -166,7 +168,8 @@ class SocketStreamHelperSpecification extends Specification { Socket socket = SocketFactory.default.createSocket() when: - SocketStreamHelper.initialize(OPERATION_CONTEXT, socket, getSocketAddresses(getPrimary(), new DefaultInetAddressResolver()).get(0), + SocketStreamHelper.initialize(createOperationContext(), socket, getSocketAddresses(getPrimary(), + new DefaultInetAddressResolver()).get(0), SocketSettings.builder().build(), SslSettings.builder().enabled(true).build()) then: diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/StreamSocketAddressSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/StreamSocketAddressSpecification.groovy index 0283ce44f7b..520dd3932de 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/StreamSocketAddressSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/StreamSocketAddressSpecification.groovy @@ -13,7 +13,7 @@ import com.mongodb.spock.Slow import javax.net.SocketFactory import java.util.concurrent.TimeUnit -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getSslSettings class StreamSocketAddressSpecification extends Specification { @@ -44,7 +44,7 @@ class StreamSocketAddressSpecification extends Specification { def socketStream = new SocketStream(serverAddress, null, socketSettings, sslSettings, socketFactory, bufferProvider) when: - socketStream.open(OPERATION_CONTEXT) + socketStream.open(createOperationContext()) then: !socket0.isConnected() @@ -83,7 +83,7 @@ class StreamSocketAddressSpecification extends Specification { def socketStream = new SocketStream(serverAddress, inetAddressResolver, socketSettings, sslSettings, socketFactory, bufferProvider) when: - socketStream.open(OPERATION_CONTEXT) + socketStream.open(createOperationContext()) then: thrown(MongoSocketOpenException) diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java index 3af1eaa33e1..46e0cc6f964 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java @@ -184,11 +184,11 @@ void shouldNotCallBeginHandshakeMoreThenOnceDuringTlsSessionEstablishment() thro .build()); Stream stream = streamFactory.create(getPrimaryServerDescription().getAddress()); - stream.open(ClusterFixture.OPERATION_CONTEXT); + stream.open(ClusterFixture.createOperationContext()); ByteBuf wrap = new ByteBufNIO(ByteBuffer.wrap(new byte[]{1, 3, 4})); //when - stream.write(Collections.singletonList(wrap), ClusterFixture.OPERATION_CONTEXT); + stream.write(Collections.singletonList(wrap), ClusterFixture.createOperationContext()); //then SECONDS.sleep(5); diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateOperationSpecification.groovy index aa7506d6516..a39b7ca6448 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateOperationSpecification.groovy @@ -52,12 +52,11 @@ import org.bson.codecs.BsonDocumentCodec import org.bson.codecs.DocumentCodec import spock.lang.IgnoreIf -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.ClusterFixture.collectCursorResults import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.ClusterFixture.getAsyncCluster import static com.mongodb.ClusterFixture.getCluster -import static com.mongodb.ClusterFixture.getOperationContext +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.isSharded import static com.mongodb.ClusterFixture.isStandalone import static com.mongodb.ExplainVerbosity.QUERY_PLANNER @@ -232,7 +231,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { def binding = ClusterFixture.getBinding(ClusterFixture.getCluster()) new CreateViewOperation(getDatabaseName(), viewName, getCollectionName(), [], WriteConcern.ACKNOWLEDGED) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) when: AggregateOperation operation = new AggregateOperation(viewNamespace, [], new DocumentCodec()) @@ -246,7 +245,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { cleanup: binding = ClusterFixture.getBinding(ClusterFixture.getCluster()) new DropCollectionOperation(viewNamespace, WriteConcern.ACKNOWLEDGED) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) where: async << [true, false] @@ -273,7 +272,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { .allowDiskUse(allowDiskUse) def binding = ClusterFixture.getBinding() - def cursor = operation.execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) then: cursor.next()*.getString('name') == ['Pete', 'Sam', 'Pete'] @@ -288,7 +287,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { .batchSize(batchSize) def binding = ClusterFixture.getBinding() - def cursor = operation.execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) then: cursor.next()*.getString('name') == ['Pete', 'Sam', 'Pete'] @@ -356,7 +355,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { def binding = ClusterFixture.getBinding() new CommandReadOperation<>(getDatabaseName(), new BsonDocument('profile', new BsonInt32(2)), - new BsonDocumentCodec()).execute(binding, getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, createOperationContext(binding.getReadPreference())) def expectedComment = 'this is a comment' def operation = new AggregateOperation(getNamespace(), [], new DocumentCodec()) .comment(new BsonString(expectedComment)) @@ -372,7 +371,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { cleanup: binding = ClusterFixture.getBinding() new CommandReadOperation<>(getDatabaseName(), new BsonDocument('profile', new BsonInt32(0)), - new BsonDocumentCodec()).execute(binding, getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, createOperationContext(binding.getReadPreference())) profileCollectionHelper.drop() where: @@ -381,7 +380,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { def 'should add read concern to command'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(ReadBinding) def source = Stub(ConnectionSource) def connection = Mock(Connection) @@ -423,7 +422,7 @@ class AggregateOperationSpecification extends OperationFunctionalSpecification { def 'should add read concern to command asynchronously'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(AsyncReadBinding) def source = Stub(AsyncConnectionSource) def connection = Mock(AsyncConnection) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateToCollectionOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateToCollectionOperationSpecification.groovy index 6ebdcdc6b40..a14c4323fdd 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateToCollectionOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/AggregateToCollectionOperationSpecification.groovy @@ -278,7 +278,7 @@ class AggregateToCollectionOperationSpecification extends OperationFunctionalSpe def profileCollectionHelper = getCollectionHelper(new MongoNamespace(getDatabaseName(), 'system.profile')) def binding = getBinding() new CommandReadOperation<>(getDatabaseName(), new BsonDocument('profile', new BsonInt32(2)), - new BsonDocumentCodec()).execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) def expectedComment = 'this is a comment' AggregateToCollectionOperation operation = createOperation(getNamespace(), [Aggregates.out('outputCollection').toBsonDocument(BsonDocument, registry)], ACKNOWLEDGED) @@ -293,7 +293,7 @@ class AggregateToCollectionOperationSpecification extends OperationFunctionalSpe cleanup: new CommandReadOperation<>(getDatabaseName(), new BsonDocument('profile', new BsonInt32(0)), - new BsonDocumentCodec()).execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) profileCollectionHelper.drop() where: diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/AsyncCommandBatchCursorFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/internal/operation/AsyncCommandBatchCursorFunctionalTest.java index 58e3e47ba74..103a18df32e 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/AsyncCommandBatchCursorFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/AsyncCommandBatchCursorFunctionalTest.java @@ -17,6 +17,7 @@ package com.mongodb.internal.operation; +import com.mongodb.ClusterFixture; import com.mongodb.MongoCursorNotFoundException; import com.mongodb.MongoQueryException; import com.mongodb.ReadPreference; @@ -55,7 +56,6 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.checkReferenceCountReachesTarget; import static com.mongodb.ClusterFixture.getAsyncBinding; import static com.mongodb.ClusterFixture.getConnection; @@ -111,7 +111,7 @@ void cleanup() { void shouldExhaustCursorAsyncWithMultipleBatches() { // given BsonDocument commandResult = executeFindCommand(0, 3); // Fetch in batches of size 3 - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); // when @@ -133,7 +133,7 @@ void shouldExhaustCursorAsyncWithMultipleBatches() { void shouldExhaustCursorAsyncWithClosedCursor() { // given BsonDocument commandResult = executeFindCommand(0, 3); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); cursor.close(); @@ -156,7 +156,7 @@ void shouldExhaustCursorAsyncWithEmptyCursor() { getCollectionHelper().deleteMany(Filters.empty()); BsonDocument commandResult = executeFindCommand(0, 3); // No documents to fetch - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); // when @@ -175,7 +175,7 @@ void theServerCursorShouldNotBeNull() { BsonDocument commandResult = executeFindCommand(2); AsyncCommandCursor coreCursor = new AsyncCommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), coreCursor); assertNotNull(coreCursor.getServerCursor()); @@ -187,7 +187,7 @@ void shouldGetExceptionsForOperationsOnTheCursorAfterClosing() { BsonDocument commandResult = executeFindCommand(5); AsyncCommandCursor coreCursor = new AsyncCommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), coreCursor); cursor.close(); @@ -202,7 +202,7 @@ void shouldGetExceptionsForOperationsOnTheCursorAfterClosing() { @DisplayName("should throw an Exception when going off the end") void shouldThrowAnExceptionWhenGoingOffTheEnd() { BsonDocument commandResult = executeFindCommand(2, 1); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); cursorNext(); @@ -216,7 +216,7 @@ void shouldThrowAnExceptionWhenGoingOffTheEnd() { @DisplayName("test normal exhaustion") void testNormalExhaustion() { BsonDocument commandResult = executeFindCommand(); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(10, cursorFlatten().size()); @@ -227,7 +227,7 @@ void testNormalExhaustion() { @DisplayName("test limit exhaustion") void testLimitExhaustion(final int limit, final int batchSize, final int expectedTotal) { BsonDocument commandResult = executeFindCommand(limit, batchSize); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, batchSize, DOCUMENT_DECODER, null, connectionSource, connection)); @@ -246,7 +246,7 @@ void shouldBlockWaitingForNextBatchOnATailableCursor(final boolean awaitData, fi BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, awaitData); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, maxTimeMS, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, maxTimeMS, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertFalse(cursor.isClosed()); @@ -269,7 +269,7 @@ void testTailableInterrupt() throws InterruptedException { BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, true); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); CountDownLatch latch = new CountDownLatch(1); @@ -304,7 +304,7 @@ void shouldKillCursorIfLimitIsReachedOnInitialQuery() { BsonDocument commandResult = executeFindCommand(5, 10); AsyncCommandCursor coreCursor = new AsyncCommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), coreCursor); assertNotNull(cursorNext()); @@ -319,7 +319,7 @@ void shouldKillCursorIfLimitIsReachedOnGetMore() { BsonDocument commandResult = executeFindCommand(5, 3); AsyncCommandCursor coreCursor = new AsyncCommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), coreCursor); ServerCursor serverCursor = coreCursor.getServerCursor(); @@ -341,7 +341,7 @@ void shouldReleaseConnectionSourceIfLimitIsReachedOnInitialQuery() { BsonDocument commandResult = executeFindCommand(5, 10); AsyncCommandCursor coreCursor = new AsyncCommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), coreCursor); assertDoesNotThrow(() -> checkReferenceCountReachesTarget(connectionSource, 1)); @@ -354,7 +354,7 @@ void shouldReleaseConnectionSourceIfLimitIsReachedOnInitialQuery() { void shouldReleaseConnectionSourceIfLimitIsReachedOnGetMore() { assumeFalse(isSharded()); BsonDocument commandResult = executeFindCommand(5, 3); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursorNext()); @@ -367,7 +367,7 @@ void shouldReleaseConnectionSourceIfLimitIsReachedOnGetMore() { @DisplayName("test limit with get more") void testLimitWithGetMore() { BsonDocument commandResult = executeFindCommand(5, 2); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursorNext()); @@ -390,7 +390,7 @@ void testLimitWithLargeDocuments() { ); BsonDocument commandResult = executeFindCommand(300, 0); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(300, cursorFlatten().size()); @@ -400,7 +400,7 @@ void testLimitWithLargeDocuments() { @DisplayName("should respect batch size") void shouldRespectBatchSize() { BsonDocument commandResult = executeFindCommand(2); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new AsyncCommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(2, cursor.getBatchSize()); @@ -419,7 +419,7 @@ void shouldThrowCursorNotFoundException() throws Throwable { BsonDocument commandResult = executeFindCommand(2); AsyncCommandCursor coreCursor = new AsyncCommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection); - cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new AsyncCommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), coreCursor); ServerCursor serverCursor = coreCursor.getServerCursor(); @@ -428,7 +428,7 @@ void shouldThrowCursorNotFoundException() throws Throwable { this.block(cb -> localConnection.commandAsync(getNamespace().getDatabaseName(), new BsonDocument("killCursors", new BsonString(getNamespace().getCollectionName())) .append("cursors", new BsonArray(singletonList(new BsonInt64(serverCursor.getId())))), - NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), OPERATION_CONTEXT, cb)); + NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), ClusterFixture.createOperationContext(), cb)); localConnection.release(); cursorNext(); @@ -494,7 +494,7 @@ private BsonDocument executeFindCommand(final BsonDocument filter, final int lim BsonDocument results = block(cb -> connection.commandAsync(getDatabaseName(), findCommand, NoOpFieldNameValidator.INSTANCE, readPreference, CommandResultDocumentCodec.create(DOCUMENT_DECODER, FIRST_BATCH), - OPERATION_CONTEXT, cb)); + ClusterFixture.createOperationContext(), cb)); assertNotNull(results); return results; diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy index 19285eda077..f2374e92160 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy @@ -53,7 +53,7 @@ import org.bson.codecs.DocumentCodec import org.bson.codecs.ValueCodecProvider import spock.lang.IgnoreIf -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getAsyncCluster import static com.mongodb.ClusterFixture.getCluster import static com.mongodb.ClusterFixture.isStandalone @@ -635,7 +635,7 @@ class ChangeStreamOperationSpecification extends OperationFunctionalSpecificatio def 'should set the startAtOperationTime on the sync cursor'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext( + def operationContext = createOperationContext().withSessionContext( Stub(SessionContext) { getReadConcern() >> ReadConcern.DEFAULT getOperationTime() >> new BsonTimestamp() @@ -690,7 +690,7 @@ class ChangeStreamOperationSpecification extends OperationFunctionalSpecificatio def 'should set the startAtOperationTime on the async cursor'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext( + def operationContext = createOperationContext().withSessionContext( Stub(SessionContext) { getReadConcern() >> ReadConcern.DEFAULT getOperationTime() >> new BsonTimestamp() diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/CommandBatchCursorFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/internal/operation/CommandBatchCursorFunctionalTest.java index 407b03f5246..946e5504db3 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/CommandBatchCursorFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/CommandBatchCursorFunctionalTest.java @@ -27,6 +27,7 @@ import com.mongodb.client.model.OperationTest; import com.mongodb.internal.binding.ConnectionSource; import com.mongodb.internal.connection.Connection; +import com.mongodb.internal.connection.OperationContext; import com.mongodb.internal.validator.NoOpFieldNameValidator; import org.bson.BsonArray; import org.bson.BsonBoolean; @@ -55,7 +56,6 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.checkReferenceCountReachesTarget; import static com.mongodb.ClusterFixture.getBinding; import static com.mongodb.ClusterFixture.getReferenceCountAfterTimeout; @@ -87,8 +87,9 @@ void setup() { .collect(Collectors.toList()); getCollectionHelper().insertDocuments(documents); - connectionSource = getBinding().getWriteConnectionSource(ClusterFixture.OPERATION_CONTEXT); - connection = connectionSource.getConnection(ClusterFixture.OPERATION_CONTEXT); + OperationContext operationContext = ClusterFixture.createOperationContext(); + connectionSource = getBinding().getWriteConnectionSource(operationContext); + connection = connectionSource.getConnection(operationContext); } @AfterEach @@ -109,7 +110,7 @@ void cleanup() { void shouldExhaustCursorWithMultipleBatches() { // given BsonDocument commandResult = executeFindCommand(0, 3); // Fetch in batches of size 3 - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); // when @@ -127,7 +128,7 @@ void shouldExhaustCursorWithMultipleBatches() { void shouldExhaustCursorWithClosedCursor() { // given BsonDocument commandResult = executeFindCommand(0, 3); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); cursor.close(); @@ -143,7 +144,7 @@ void shouldExhaustCursorWithEmptyCursor() { getCollectionHelper().deleteMany(Filters.empty()); BsonDocument commandResult = executeFindCommand(0, 3); // No documents to fetch - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); // when @@ -157,7 +158,7 @@ void shouldExhaustCursorWithEmptyCursor() { @DisplayName("server cursor should not be null") void theServerCursorShouldNotBeNull() { BsonDocument commandResult = executeFindCommand(2); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursor.getServerCursor()); @@ -167,7 +168,7 @@ void theServerCursorShouldNotBeNull() { @DisplayName("test server address should not be null") void theServerAddressShouldNotNull() { BsonDocument commandResult = executeFindCommand(); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursor.getServerAddress()); @@ -177,7 +178,7 @@ void theServerAddressShouldNotNull() { @DisplayName("should get Exceptions for operations on the cursor after closing") void shouldGetExceptionsForOperationsOnTheCursorAfterClosing() { BsonDocument commandResult = executeFindCommand(); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); cursor.close(); @@ -192,7 +193,7 @@ void shouldGetExceptionsForOperationsOnTheCursorAfterClosing() { @DisplayName("should throw an Exception when going off the end") void shouldThrowAnExceptionWhenGoingOffTheEnd() { BsonDocument commandResult = executeFindCommand(1); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); cursor.next(); @@ -204,7 +205,7 @@ void shouldThrowAnExceptionWhenGoingOffTheEnd() { @DisplayName("test cursor remove") void testCursorRemove() { BsonDocument commandResult = executeFindCommand(); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertThrows(UnsupportedOperationException.class, () -> cursor.remove()); @@ -214,7 +215,7 @@ void testCursorRemove() { @DisplayName("test normal exhaustion") void testNormalExhaustion() { BsonDocument commandResult = executeFindCommand(); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(10, cursorFlatten().size()); @@ -225,7 +226,7 @@ void testNormalExhaustion() { @DisplayName("test limit exhaustion") void testLimitExhaustion(final int limit, final int batchSize, final int expectedTotal) { BsonDocument commandResult = executeFindCommand(limit, batchSize); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(expectedTotal, cursorFlatten().size()); @@ -244,7 +245,7 @@ void shouldBlockWaitingForNextBatchOnATailableCursor(final boolean awaitData, fi BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, awaitData); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, maxTimeMS, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, maxTimeMS, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertTrue(cursor.hasNext()); @@ -267,7 +268,7 @@ void testTryNextWithTailable() { BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, true); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); List nextBatch = cursor.tryNext(); @@ -293,7 +294,7 @@ void hasNextShouldThrowWhenCursorIsClosedInAnotherThread() throws InterruptedExc BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, true); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertTrue(cursor.hasNext()); @@ -320,7 +321,7 @@ void testMaxTimeMS() { long maxTimeMS = 500; BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, true); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, maxTimeMS, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, maxTimeMS, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); List nextBatch = cursor.tryNext(); @@ -344,7 +345,7 @@ void testTailableInterrupt() throws InterruptedException { BsonDocument commandResult = executeFindCommand(new BsonDocument("ts", new BsonDocument("$gte", new BsonTimestamp(5, 0))), 0, 2, true, true); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); CountDownLatch latch = new CountDownLatch(1); @@ -377,7 +378,7 @@ void testTailableInterrupt() throws InterruptedException { void shouldKillCursorIfLimitIsReachedOnInitialQuery() { assumeFalse(isSharded()); BsonDocument commandResult = executeFindCommand(5, 10); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursor.next()); @@ -390,7 +391,7 @@ void shouldKillCursorIfLimitIsReachedOnInitialQuery() { void shouldKillCursorIfLimitIsReachedOnGetMore() { assumeFalse(isSharded()); BsonDocument commandResult = executeFindCommand(5, 3); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); ServerCursor serverCursor = cursor.getServerCursor(); @@ -409,7 +410,7 @@ void shouldKillCursorIfLimitIsReachedOnGetMore() { void shouldReleaseConnectionSourceIfLimitIsReachedOnInitialQuery() { assumeFalse(isSharded()); BsonDocument commandResult = executeFindCommand(5, 10); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertNull(cursor.getServerCursor()); @@ -422,7 +423,7 @@ void shouldReleaseConnectionSourceIfLimitIsReachedOnInitialQuery() { void shouldReleaseConnectionSourceIfLimitIsReachedOnGetMore() { assumeFalse(isSharded()); BsonDocument commandResult = executeFindCommand(5, 3); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 3, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursor.next()); @@ -435,7 +436,7 @@ void shouldReleaseConnectionSourceIfLimitIsReachedOnGetMore() { @DisplayName("test limit with get more") void testLimitWithGetMore() { BsonDocument commandResult = executeFindCommand(5, 2); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertNotNull(cursor.next()); @@ -456,7 +457,7 @@ void testLimitWithLargeDocuments() { ); BsonDocument commandResult = executeFindCommand(300, 0); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 0, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(300, cursorFlatten().size()); @@ -466,7 +467,7 @@ void testLimitWithLargeDocuments() { @DisplayName("should respect batch size") void shouldRespectBatchSize() { BsonDocument commandResult = executeFindCommand(2); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(2, cursor.getBatchSize()); @@ -483,16 +484,16 @@ void shouldRespectBatchSize() { @DisplayName("should throw cursor not found exception") void shouldThrowCursorNotFoundException() { BsonDocument commandResult = executeFindCommand(2); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); ServerCursor serverCursor = cursor.getServerCursor(); assertNotNull(serverCursor); - Connection localConnection = connectionSource.getConnection(OPERATION_CONTEXT); + Connection localConnection = connectionSource.getConnection(ClusterFixture.createOperationContext()); localConnection.command(getNamespace().getDatabaseName(), new BsonDocument("killCursors", new BsonString(getNamespace().getCollectionName())) .append("cursors", new BsonArray(singletonList(new BsonInt64(serverCursor.getId())))), - NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), OPERATION_CONTEXT); + NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), ClusterFixture.createOperationContext()); localConnection.release(); cursor.next(); @@ -506,7 +507,7 @@ void shouldThrowCursorNotFoundException() { @DisplayName("should report available documents") void shouldReportAvailableDocuments() { BsonDocument commandResult = executeFindCommand(3); - cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, OPERATION_CONTEXT, + cursor = new CommandBatchCursor<>(TimeoutMode.CURSOR_LIFETIME, 0, ClusterFixture.createOperationContext(), new CommandCursor<>(commandResult, 2, DOCUMENT_DECODER, null, connectionSource, connection)); assertEquals(3, cursor.available()); @@ -584,7 +585,7 @@ private BsonDocument executeFindCommand(final BsonDocument filter, final int lim BsonDocument results = connection.command(getDatabaseName(), findCommand, NoOpFieldNameValidator.INSTANCE, readPreference, CommandResultDocumentCodec.create(DOCUMENT_DECODER, FIRST_BATCH), - OPERATION_CONTEXT); + ClusterFixture.createOperationContext()); assertNotNull(results); return results; diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/CountDocumentsOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/CountDocumentsOperationSpecification.groovy index 1e538b1af11..dc9746053c3 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/CountDocumentsOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/CountDocumentsOperationSpecification.groovy @@ -46,7 +46,7 @@ import org.bson.BsonTimestamp import org.bson.Document import org.bson.codecs.DocumentCodec -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.connection.ServerType.STANDALONE import static com.mongodb.internal.operation.OperationReadConcernHelper.appendReadConcernToCommand @@ -156,7 +156,7 @@ class CountDocumentsOperationSpecification extends OperationFunctionalSpecificat def binding = ClusterFixture.getBinding() new CreateIndexesOperation(getNamespace(), [new IndexRequest(indexDefinition).sparse(true)], null) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) def operation = new CountDocumentsOperation(getNamespace()).hint(indexDefinition) when: @@ -259,7 +259,7 @@ class CountDocumentsOperationSpecification extends OperationFunctionalSpecificat def 'should add read concern to command'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(ReadBinding) def source = Stub(ConnectionSource) def connection = Mock(Connection) @@ -297,7 +297,7 @@ class CountDocumentsOperationSpecification extends OperationFunctionalSpecificat def 'should add read concern to command asynchronously'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(AsyncReadBinding) def source = Stub(AsyncConnectionSource) def connection = Mock(AsyncConnection) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/CreateCollectionOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/CreateCollectionOperationSpecification.groovy index 860ffb4a2bf..a0b80cc178a 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/CreateCollectionOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/CreateCollectionOperationSpecification.groovy @@ -113,7 +113,7 @@ class CreateCollectionOperationSpecification extends OperationFunctionalSpecific then: def binding = ClusterFixture.getBinding() new ListCollectionsOperation(getDatabaseName(), new BsonDocumentCodec()) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) .next() .find { it -> it.getString('name').value == getCollectionName() } .getDocument('options').getDocument('storageEngine') == operation.storageEngineOptions @@ -134,7 +134,7 @@ class CreateCollectionOperationSpecification extends OperationFunctionalSpecific then: def binding = ClusterFixture.getBinding() new ListCollectionsOperation(getDatabaseName(), new BsonDocumentCodec()) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) .next() .find { it -> it.getString('name').value == getCollectionName() } .getDocument('options').getDocument('storageEngine') == operation.storageEngineOptions @@ -255,7 +255,7 @@ class CreateCollectionOperationSpecification extends OperationFunctionalSpecific def binding = getBinding() new ListCollectionsOperation(databaseName, new BsonDocumentCodec()).filter(new BsonDocument('name', new BsonString(collectionName))).execute(binding, - ClusterFixture.getOperationContext(binding.getReadPreference())).tryNext()?.head() + ClusterFixture.createOperationContext(binding.getReadPreference())).tryNext()?.head() } def collectionNameExists(String collectionName) { @@ -268,13 +268,13 @@ class CreateCollectionOperationSpecification extends OperationFunctionalSpecific def binding = getBinding() return new CommandReadOperation<>(getDatabaseName(), new BsonDocument('collStats', new BsonString(getCollectionName())), - new BsonDocumentCodec()).execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) } def binding = ClusterFixture.getBinding() BatchCursor cursor = new AggregateOperation( getNamespace(), singletonList(new BsonDocument('$collStats', new BsonDocument('storageStats', new BsonDocument()))), - new BsonDocumentCodec()).execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) try { return cursor.next().first().getDocument('storageStats') } finally { diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/CreateIndexesOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/CreateIndexesOperationSpecification.groovy index fce0904b786..5365f19f1de 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/CreateIndexesOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/CreateIndexesOperationSpecification.groovy @@ -494,7 +494,7 @@ class CreateIndexesOperationSpecification extends OperationFunctionalSpecificati def binding = ClusterFixture.getBinding() def cursor = new ListIndexesOperation(getNamespace(), new DocumentCodec()) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) while (cursor.hasNext()) { indexes.addAll(cursor.next()) } diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/CreateViewOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/CreateViewOperationSpecification.groovy index b8145de44b4..3e90c21363e 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/CreateViewOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/CreateViewOperationSpecification.groovy @@ -29,8 +29,8 @@ import org.bson.BsonString import org.bson.codecs.BsonDocumentCodec import spock.lang.IgnoreIf +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.getBinding -import static com.mongodb.ClusterFixture.getOperationContext import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet class CreateViewOperationSpecification extends OperationFunctionalSpecification { @@ -124,7 +124,7 @@ class CreateViewOperationSpecification extends OperationFunctionalSpecification def getCollectionInfo(String collectionName) { def binding = getBinding() new ListCollectionsOperation(databaseName, new BsonDocumentCodec()).filter(new BsonDocument('name', - new BsonString(collectionName))).execute(binding, getOperationContext(binding.getReadPreference())).tryNext()?.head() + new BsonString(collectionName))).execute(binding, createOperationContext(binding.getReadPreference())).tryNext()?.head() } def collectionNameExists(String collectionName) { diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/DistinctOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/DistinctOperationSpecification.groovy index f73c301d422..66936080558 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/DistinctOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/DistinctOperationSpecification.groovy @@ -51,7 +51,7 @@ import org.bson.codecs.StringCodec import org.bson.codecs.ValueCodecProvider import org.bson.types.ObjectId -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.connection.ServerType.STANDALONE import static com.mongodb.internal.operation.OperationReadConcernHelper.appendReadConcernToCommand @@ -227,7 +227,7 @@ class DistinctOperationSpecification extends OperationFunctionalSpecification { def 'should add read concern to command'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(ReadBinding) def source = Stub(ConnectionSource) def connection = Mock(Connection) @@ -266,7 +266,7 @@ class DistinctOperationSpecification extends OperationFunctionalSpecification { def 'should add read concern to command asynchronously'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(AsyncReadBinding) def source = Stub(AsyncConnectionSource) def connection = Mock(AsyncConnection) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/DropCollectionOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/DropCollectionOperationSpecification.groovy index eb8f3efa573..703d0e14212 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/DropCollectionOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/DropCollectionOperationSpecification.groovy @@ -39,7 +39,7 @@ class DropCollectionOperationSpecification extends OperationFunctionalSpecificat when: def binding = getBinding() new DropCollectionOperation(getNamespace(), WriteConcern.ACKNOWLEDGED) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) then: !collectionNameExists(getCollectionName()) @@ -64,7 +64,7 @@ class DropCollectionOperationSpecification extends OperationFunctionalSpecificat when: new DropCollectionOperation(namespace, WriteConcern.ACKNOWLEDGED) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) then: !collectionNameExists('nonExistingCollection') @@ -91,7 +91,7 @@ class DropCollectionOperationSpecification extends OperationFunctionalSpecificat when: def binding = getBinding() - async ? executeAsync(operation) : operation.execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + async ? executeAsync(operation) : operation.execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) then: def ex = thrown(MongoWriteConcernException) @@ -104,7 +104,7 @@ class DropCollectionOperationSpecification extends OperationFunctionalSpecificat def collectionNameExists(String collectionName) { def cursor = new ListCollectionsOperation(databaseName, new DocumentCodec()) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) if (!cursor.hasNext()) { return false } diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/DropDatabaseOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/DropDatabaseOperationSpecification.groovy index b56e2c1fe50..955b5efcaa3 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/DropDatabaseOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/DropDatabaseOperationSpecification.groovy @@ -16,7 +16,6 @@ package com.mongodb.internal.operation - import com.mongodb.MongoWriteConcernException import com.mongodb.OperationFunctionalSpecification import com.mongodb.WriteConcern @@ -25,10 +24,10 @@ import org.bson.Document import org.bson.codecs.DocumentCodec import spock.lang.IgnoreIf +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.configureFailPoint import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.ClusterFixture.getBinding -import static com.mongodb.ClusterFixture.getOperationContext import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet import static com.mongodb.ClusterFixture.isSharded @@ -80,7 +79,7 @@ class DropDatabaseOperationSpecification extends OperationFunctionalSpecificatio def binding = getBinding() when: - async ? executeAsync(operation) : operation.execute(binding, getOperationContext(binding.getReadPreference())) + async ? executeAsync(operation) : operation.execute(binding, createOperationContext(binding.getReadPreference())) then: def ex = thrown(MongoWriteConcernException) @@ -93,7 +92,7 @@ class DropDatabaseOperationSpecification extends OperationFunctionalSpecificatio def databaseNameExists(String databaseName) { new ListDatabasesOperation(new DocumentCodec()).execute(binding, - getOperationContext(binding.getReadPreference())).next()*.name.contains(databaseName) + createOperationContext(binding.getReadPreference())).next()*.name.contains(databaseName) } } diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/DropIndexOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/DropIndexOperationSpecification.groovy index 7b1f5b2a392..0aff76df1cb 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/DropIndexOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/DropIndexOperationSpecification.groovy @@ -159,7 +159,7 @@ class DropIndexOperationSpecification extends OperationFunctionalSpecification { def indexes = [] def binding = getBinding() def cursor = new ListIndexesOperation(getNamespace(), new DocumentCodec()) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) while (cursor.hasNext()) { indexes.addAll(cursor.next()) } diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/FindOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/FindOperationSpecification.groovy index 5eb707201d5..c584ee463f9 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/FindOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/FindOperationSpecification.groovy @@ -54,13 +54,12 @@ import org.bson.codecs.BsonDocumentCodec import org.bson.codecs.DocumentCodec import spock.lang.IgnoreIf -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.ClusterFixture.executeSync import static com.mongodb.ClusterFixture.getAsyncCluster import static com.mongodb.ClusterFixture.getBinding import static com.mongodb.ClusterFixture.getCluster -import static com.mongodb.ClusterFixture.getOperationContext +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.isSharded import static com.mongodb.ClusterFixture.serverVersionLessThan import static com.mongodb.CursorType.NonTailable @@ -390,7 +389,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { def binding = getBinding() new CommandReadOperation<>(getDatabaseName(), new BsonDocument('profile', new BsonInt32(2)), - new BsonDocumentCodec()).execute(binding, getOperationContext(binding.getReadPreference())) + new BsonDocumentCodec()).execute(binding, createOperationContext(binding.getReadPreference())) def expectedComment = 'this is a comment' def operation = new FindOperation(getNamespace(), new DocumentCodec()) .comment(new BsonString(expectedComment)) @@ -405,7 +404,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { cleanup: new CommandReadOperation<>(getDatabaseName(), new BsonDocument('profile', new BsonInt32(0)), new BsonDocumentCodec()) - .execute(binding, getOperationContext(binding.getReadPreference())) + .execute(binding, createOperationContext(binding.getReadPreference())) profileCollectionHelper.drop() where: @@ -482,7 +481,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { def 'should add read concern to command'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(ReadBinding) def source = Stub(ConnectionSource) def connection = Mock(Connection) @@ -522,7 +521,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { def 'should add read concern to command asynchronously'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(AsyncReadBinding) def source = Stub(AsyncConnectionSource) def connection = Mock(AsyncConnection) @@ -562,7 +561,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { def 'should add allowDiskUse to command if the server version >= 3.2'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(ReadBinding) def source = Stub(ConnectionSource) def connection = Mock(Connection) @@ -602,7 +601,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { def 'should add allowDiskUse to command if the server version >= 3.2 asynchronously'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(AsyncReadBinding) def source = Stub(AsyncConnectionSource) def connection = Mock(AsyncConnection) @@ -646,7 +645,7 @@ class FindOperationSpecification extends OperationFunctionalSpecification { def (cursorType, long maxAwaitTimeMS, long maxTimeMSForCursor) = cursorDetails def timeoutSettings = ClusterFixture.TIMEOUT_SETTINGS_WITH_INFINITE_TIMEOUT.withMaxAwaitTimeMS(maxAwaitTimeMS) def timeoutContext = new TimeoutContext(timeoutSettings) - def operationContext = OPERATION_CONTEXT.withTimeoutContext(timeoutContext) + def operationContext = createOperationContext().withTimeoutContext(timeoutContext) collectionHelper.create(getCollectionName(), new CreateCollectionOptions().capped(true).sizeInBytes(1000)) def operation = new FindOperation(namespace, new BsonDocumentCodec()) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/ListCollectionsOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/ListCollectionsOperationSpecification.groovy index ad55b706ba2..b44b341d202 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/ListCollectionsOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/ListCollectionsOperationSpecification.groovy @@ -16,6 +16,7 @@ package com.mongodb.internal.operation +import com.mongodb.ClusterFixture import com.mongodb.MongoNamespace import com.mongodb.OperationFunctionalSpecification import com.mongodb.ReadPreference @@ -43,10 +44,9 @@ import org.bson.Document import org.bson.codecs.Decoder import org.bson.codecs.DocumentCodec -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.ClusterFixture.getBinding -import static com.mongodb.ClusterFixture.getOperationContext import static org.junit.jupiter.api.Assertions.assertEquals class ListCollectionsOperationSpecification extends OperationFunctionalSpecification { @@ -60,7 +60,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) then: !cursor.hasNext() @@ -98,7 +98,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collections = cursor.next() def names = collections*.get('name') @@ -121,7 +121,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference()) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference()) ) def collections = cursor.next() def names = collections*.get('name') @@ -143,7 +143,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collections = cursor.next() def names = collections*.get('name') @@ -161,7 +161,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collection = cursor.next()[0] then: @@ -178,7 +178,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collection = cursor.next()[0] then: @@ -195,7 +195,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collection = cursor.next()[0] then: @@ -227,14 +227,14 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() given: new DropDatabaseOperation(databaseName, WriteConcern.ACKNOWLEDGED) - .execute(binding, getOperationContext(binding.getReadPreference())) + .execute(binding, createOperationContext(binding.getReadPreference())) addSeveralIndexes() def operation = new ListCollectionsOperation(databaseName, new DocumentCodec()).batchSize(2) when: binding = getBinding() - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) then: cursor.hasNext() @@ -247,13 +247,13 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() given: new DropDatabaseOperation(databaseName, WriteConcern.ACKNOWLEDGED) - .execute(binding, getOperationContext(binding.getReadPreference())) + .execute(binding, createOperationContext(binding.getReadPreference())) addSeveralIndexes() def operation = new ListCollectionsOperation(databaseName, new DocumentCodec()).batchSize(2) when: binding = getBinding() - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def list = cursorToListWithNext(cursor) then: @@ -272,14 +272,14 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def binding = getBinding() given: new DropDatabaseOperation(databaseName, WriteConcern.ACKNOWLEDGED) - .execute(binding, getOperationContext(binding.getReadPreference())) + .execute(binding, createOperationContext(binding.getReadPreference())) addSeveralIndexes() def operation = new ListCollectionsOperation(databaseName, new DocumentCodec()).batchSize(2) when: binding = getBinding() - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) then: cursor.hasNext() @@ -298,13 +298,13 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica given: def binding = getBinding() new DropDatabaseOperation(databaseName, WriteConcern.ACKNOWLEDGED) - .execute(binding, getOperationContext(binding.getReadPreference())) + .execute(binding, createOperationContext(binding.getReadPreference())) addSeveralIndexes() def operation = new ListCollectionsOperation(databaseName, new DocumentCodec()).batchSize(2) when: binding = getBinding() - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def list = cursorToListWithTryNext(cursor) then: @@ -318,7 +318,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica given: def binding = getBinding() new DropDatabaseOperation(databaseName, WriteConcern.ACKNOWLEDGED) - .execute(binding, getOperationContext(binding.getReadPreference())) + .execute(binding, createOperationContext(binding.getReadPreference())) addSeveralIndexes() def operation = new ListCollectionsOperation(databaseName, new DocumentCodec()).batchSize(2) @@ -344,7 +344,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica when: def binding = getBinding() - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collections = cursor.next() then: @@ -398,6 +398,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def 'should use the readPreference to set secondaryOk'() { given: + def operationContext = ClusterFixture.createOperationContext() def connection = Mock(Connection) def connectionSource = Stub(ConnectionSource) { getConnection(_) >> connection @@ -410,12 +411,12 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def operation = new ListCollectionsOperation(helper.dbName, helper.decoder) when: '3.6.0' - operation.execute(readBinding, OPERATION_CONTEXT) + operation.execute(readBinding, operationContext) then: _ * connection.getDescription() >> helper.threeSixConnectionDescription 1 * connection.command(_, _, _, readPreference, _, _) >> { - assertEquals(((OperationContext) it[5]).getId(), OPERATION_CONTEXT.getId()) + assertEquals(((OperationContext) it[5]).getId(), operationContext.getId()) helper.commandResult } 1 * connection.release() @@ -426,6 +427,7 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica def 'should use the readPreference to set secondaryOk in async'() { given: + def operationContext = ClusterFixture.createOperationContext() def connection = Mock(AsyncConnection) def connectionSource = Stub(AsyncConnectionSource) { getConnection(_, _) >> { it[1].onResult(connection, null) } @@ -436,14 +438,13 @@ class ListCollectionsOperationSpecification extends OperationFunctionalSpecifica getReadPreference() >> readPreference } def operation = new ListCollectionsOperation(helper.dbName, helper.decoder) - when: '3.6.0' - operation.executeAsync(readBinding, OPERATION_CONTEXT, Stub(SingleResultCallback)) + operation.executeAsync(readBinding, operationContext, Stub(SingleResultCallback)) then: _ * connection.getDescription() >> helper.threeSixConnectionDescription 1 * connection.commandAsync(helper.dbName, _, _, readPreference, _, _, *_) >> { - assertEquals(((OperationContext) it[5]).getId(), OPERATION_CONTEXT.getId()) + assertEquals(((OperationContext) it[5]).getId(), operationContext.getId()) it.last().onResult(helper.commandResult, null) } where: diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/ListDatabasesOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/ListDatabasesOperationSpecification.groovy index 55504d0babc..a6ed542bde2 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/ListDatabasesOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/ListDatabasesOperationSpecification.groovy @@ -33,7 +33,7 @@ import org.bson.Document import org.bson.codecs.Decoder import org.bson.codecs.DocumentCodec -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext class ListDatabasesOperationSpecification extends OperationFunctionalSpecification { def codec = new DocumentCodec() @@ -82,7 +82,7 @@ class ListDatabasesOperationSpecification extends OperationFunctionalSpecificati def operation = new ListDatabasesOperation(helper.decoder) when: - operation.execute(readBinding, OPERATION_CONTEXT) + operation.execute(readBinding, createOperationContext()) then: _ * connection.getDescription() >> helper.connectionDescription @@ -107,7 +107,7 @@ class ListDatabasesOperationSpecification extends OperationFunctionalSpecificati def operation = new ListDatabasesOperation(helper.decoder) when: - operation.executeAsync(readBinding, OPERATION_CONTEXT, Stub(SingleResultCallback)) + operation.executeAsync(readBinding, createOperationContext(), Stub(SingleResultCallback)) then: _ * connection.getDescription() >> helper.connectionDescription diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/ListIndexesOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/ListIndexesOperationSpecification.groovy index c11d67bcf22..823de9bfd91 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/ListIndexesOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/ListIndexesOperationSpecification.groovy @@ -16,7 +16,7 @@ package com.mongodb.internal.operation - +import com.mongodb.ClusterFixture import com.mongodb.MongoNamespace import com.mongodb.OperationFunctionalSpecification import com.mongodb.ReadPreference @@ -44,10 +44,9 @@ import org.bson.codecs.Decoder import org.bson.codecs.DocumentCodec import org.junit.jupiter.api.Assertions -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.ClusterFixture.getBinding -import static com.mongodb.ClusterFixture.getOperationContext +import static com.mongodb.ClusterFixture.createOperationContext class ListIndexesOperationSpecification extends OperationFunctionalSpecification { @@ -58,7 +57,7 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) then: !cursor.hasNext() @@ -87,7 +86,7 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def binding = getBinding() when: - BatchCursor indexes = operation.execute(binding, getOperationContext(binding.getReadPreference())) + BatchCursor indexes = operation.execute(binding, createOperationContext(binding.getReadPreference())) then: def firstBatch = indexes.next() @@ -122,11 +121,11 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def binding = getBinding() new CreateIndexesOperation(namespace, [new IndexRequest(new BsonDocument('unique', new BsonInt32(1))).unique(true)], null).execute(binding, - getOperationContext(binding.getReadPreference())) + createOperationContext(binding.getReadPreference())) when: binding = getBinding() - BatchCursor cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + BatchCursor cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) then: def indexes = cursor.next() @@ -146,7 +145,7 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def binding = getBinding() new CreateIndexesOperation(namespace, [new IndexRequest(new BsonDocument('unique', new BsonInt32(1))).unique(true)], null).execute(binding, - getOperationContext(binding.getReadPreference())) + createOperationContext(binding.getReadPreference())) when: def cursor = executeAsync(operation) @@ -172,7 +171,7 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def binding = getBinding() when: - def cursor = operation.execute(binding, getOperationContext(binding.getReadPreference())) + def cursor = operation.execute(binding, createOperationContext(binding.getReadPreference())) def collections = cursor.next() then: @@ -226,6 +225,7 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def 'should use the readPreference to set secondaryOk'() { given: def connection = Mock(Connection) + def operationContext = ClusterFixture.createOperationContext() def connectionSource = Stub(ConnectionSource) { getConnection(_) >> connection getReadPreference() >> readPreference @@ -237,12 +237,12 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def operation = new ListIndexesOperation(helper.namespace, helper.decoder) when: '3.6.0' - operation.execute(readBinding, OPERATION_CONTEXT) + operation.execute(readBinding, operationContext) then: _ * connection.getDescription() >> helper.threeSixConnectionDescription 1 * connection.command(_, _, _, readPreference, _, _) >> { - Assertions.assertEquals(((OperationContext) it[5]).getId(), OPERATION_CONTEXT.getId()) + Assertions.assertEquals(((OperationContext) it[5]).getId(), operationContext.getId()) helper.commandResult } 1 * connection.release() @@ -265,7 +265,7 @@ class ListIndexesOperationSpecification extends OperationFunctionalSpecification def operation = new ListIndexesOperation(helper.namespace, helper.decoder) when: '3.6.0' - operation.executeAsync(readBinding, OPERATION_CONTEXT, Stub(SingleResultCallback)) + operation.executeAsync(readBinding, createOperationContext(), Stub(SingleResultCallback)) then: _ * connection.getDescription() >> helper.threeSixConnectionDescription diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceToCollectionOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceToCollectionOperationSpecification.groovy index 5d6be781d1f..31f8ed45715 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceToCollectionOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceToCollectionOperationSpecification.groovy @@ -64,7 +64,7 @@ class MapReduceToCollectionOperationSpecification extends OperationFunctionalSpe def cleanup() { def binding = getBinding() - def operationContext = ClusterFixture.getOperationContext(binding.getReadPreference()) + def operationContext = ClusterFixture.createOperationContext(binding.getReadPreference()) new DropCollectionOperation(mapReduceInputNamespace, WriteConcern.ACKNOWLEDGED) .execute(binding, operationContext) new DropCollectionOperation(mapReduceOutputNamespace, WriteConcern.ACKNOWLEDGED) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceWithInlineResultsOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceWithInlineResultsOperationSpecification.groovy index 8efd4e00f6c..14ee33d7ec5 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceWithInlineResultsOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/MapReduceWithInlineResultsOperationSpecification.groovy @@ -46,7 +46,7 @@ import org.bson.Document import org.bson.codecs.BsonDocumentCodec import org.bson.codecs.DocumentCodec -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.connection.ServerType.STANDALONE import static com.mongodb.internal.operation.OperationReadConcernHelper.appendReadConcernToCommand @@ -217,7 +217,7 @@ class MapReduceWithInlineResultsOperationSpecification extends OperationFunction def 'should add read concern to command'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(ReadBinding) def source = Stub(ConnectionSource) def connection = Mock(Connection) @@ -264,7 +264,7 @@ class MapReduceWithInlineResultsOperationSpecification extends OperationFunction def 'should add read concern to command asynchronously'() { given: - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) def binding = Stub(AsyncReadBinding) def source = Stub(AsyncConnectionSource) def connection = Mock(AsyncConnection) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/RenameCollectionOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/RenameCollectionOperationSpecification.groovy index bc55bf5a134..080861047f1 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/RenameCollectionOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/RenameCollectionOperationSpecification.groovy @@ -26,9 +26,9 @@ import org.bson.Document import org.bson.codecs.DocumentCodec import spock.lang.IgnoreIf +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.executeAsync import static com.mongodb.ClusterFixture.getBinding -import static com.mongodb.ClusterFixture.getOperationContext import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet import static com.mongodb.ClusterFixture.isSharded @@ -38,7 +38,7 @@ class RenameCollectionOperationSpecification extends OperationFunctionalSpecific def cleanup() { def binding = getBinding() new DropCollectionOperation(new MongoNamespace(getDatabaseName(), 'newCollection'), - WriteConcern.ACKNOWLEDGED).execute(binding, getOperationContext(binding.getReadPreference())) + WriteConcern.ACKNOWLEDGED).execute(binding, createOperationContext(binding.getReadPreference())) } def 'should return rename a collection'() { @@ -87,7 +87,7 @@ class RenameCollectionOperationSpecification extends OperationFunctionalSpecific def binding = getBinding() when: - async ? executeAsync(operation) : operation.execute(binding, getOperationContext(binding.getReadPreference())) + async ? executeAsync(operation) : operation.execute(binding, createOperationContext(binding.getReadPreference())) then: def ex = thrown(MongoWriteConcernException) @@ -101,7 +101,7 @@ class RenameCollectionOperationSpecification extends OperationFunctionalSpecific def collectionNameExists(String collectionName) { def binding = getBinding() def cursor = new ListCollectionsOperation(databaseName, new DocumentCodec()).execute(binding, - getOperationContext(binding.getReadPreference())) + createOperationContext(binding.getReadPreference())) if (!cursor.hasNext()) { return false } diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/TestOperationHelper.java b/driver-core/src/test/functional/com/mongodb/internal/operation/TestOperationHelper.java index 824517e10db..2565521deb7 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/TestOperationHelper.java +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/TestOperationHelper.java @@ -16,6 +16,7 @@ package com.mongodb.internal.operation; +import com.mongodb.ClusterFixture; import com.mongodb.MongoCommandException; import com.mongodb.MongoCursorNotFoundException; import com.mongodb.MongoNamespace; @@ -31,8 +32,6 @@ import org.bson.BsonString; import org.bson.codecs.BsonDocumentCodec; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; - final class TestOperationHelper { static BsonDocument getKeyPattern(final BsonDocument explainPlan) { @@ -56,7 +55,7 @@ static void makeAdditionalGetMoreCall(final MongoNamespace namespace, final Serv connection.command(namespace.getDatabaseName(), new BsonDocument("getMore", new BsonInt64(serverCursor.getId())) .append("collection", new BsonString(namespace.getCollectionName())), - NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), OPERATION_CONTEXT)); + NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), ClusterFixture.createOperationContext())); } static void makeAdditionalGetMoreCall(final MongoNamespace namespace, final ServerCursor serverCursor, @@ -66,7 +65,7 @@ static void makeAdditionalGetMoreCall(final MongoNamespace namespace, final Serv connection.commandAsync(namespace.getDatabaseName(), new BsonDocument("getMore", new BsonInt64(serverCursor.getId())) .append("collection", new BsonString(namespace.getCollectionName())), - NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), OPERATION_CONTEXT, callback); + NoOpFieldNameValidator.INSTANCE, ReadPreference.primary(), new BsonDocumentCodec(), ClusterFixture.createOperationContext(), callback); callback.get(); }); } diff --git a/driver-core/src/test/unit/com/mongodb/AbstractConnectionStringTest.java b/driver-core/src/test/unit/com/mongodb/AbstractConnectionStringTest.java index d511d2750eb..89b32fd6aab 100644 --- a/driver-core/src/test/unit/com/mongodb/AbstractConnectionStringTest.java +++ b/driver-core/src/test/unit/com/mongodb/AbstractConnectionStringTest.java @@ -112,7 +112,7 @@ protected void testValidOptions() { if (option.getKey().equals("authmechanism")) { String expected = option.getValue().asString().getValue(); - if (expected.equals("MONGODB-CR")) { + if (expected.equals("MONGODB-CR")) { assertNotNull(connectionString.getCredential()); assertNull(connectionString.getCredential().getAuthenticationMechanism()); } else { @@ -122,6 +122,9 @@ protected void testValidOptions() { } else if (option.getKey().equalsIgnoreCase("retrywrites")) { boolean expected = option.getValue().asBoolean().getValue(); assertEquals(expected, connectionString.getRetryWritesValue().booleanValue()); + } else if (option.getKey().equalsIgnoreCase("enableoverloadretargeting")) { + boolean expected = option.getValue().asBoolean().getValue(); + assertEquals(expected, connectionString.getEnableOverloadRetargeting().booleanValue()); } else if (option.getKey().equalsIgnoreCase("replicaset")) { String expected = option.getValue().asString().getValue(); assertEquals(expected, connectionString.getRequiredReplicaSetName()); diff --git a/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java b/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java index 0b3dd1a0814..1e72ce211b1 100644 --- a/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java +++ b/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java @@ -69,7 +69,10 @@ private static String encode(final String string) { } @ParameterizedTest - @ValueSource(strings = {DEFAULT_OPTIONS + "serverMonitoringMode=stream"}) + @ValueSource(strings = { + DEFAULT_OPTIONS + "serverMonitoringMode=stream", + DEFAULT_OPTIONS + "enableOverloadRetargeting=true" + }) void equalAndHashCode(final String connectionString) { ConnectionString default1 = new ConnectionString(DEFAULT_OPTIONS); ConnectionString default2 = new ConnectionString(DEFAULT_OPTIONS); @@ -94,6 +97,15 @@ void serverMonitoringMode() { ); } + @Test + void enableOverloadRetargeting() { + assertAll( + () -> assertNull(new ConnectionString("mongodb://localhost/").getEnableOverloadRetargeting()), + () -> assertEquals(false, new ConnectionString(DEFAULT_OPTIONS + "enableOverloadRetargeting=false").getEnableOverloadRetargeting()), + () -> assertEquals(true, new ConnectionString(DEFAULT_OPTIONS + "enableOverloadRetargeting=true").getEnableOverloadRetargeting()), + () -> assertNull(new ConnectionString(DEFAULT_OPTIONS + "enableOverloadRetargeting=foos").getEnableOverloadRetargeting()) + ); + } @ParameterizedTest @ValueSource(strings = {"mongodb://foo:bar/@hostname/java?", "mongodb://foo:bar?@hostname/java/", diff --git a/driver-core/src/test/unit/com/mongodb/MongoClientSettingsSpecification.groovy b/driver-core/src/test/unit/com/mongodb/MongoClientSettingsSpecification.groovy index c8910751552..2ba4dd3a1da 100644 --- a/driver-core/src/test/unit/com/mongodb/MongoClientSettingsSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/MongoClientSettingsSpecification.groovy @@ -552,6 +552,7 @@ class MongoClientSettingsSpecification extends Specification { def actual = MongoClientSettings.Builder.declaredFields.grep { !it.synthetic } *.name.sort() def expected = ['applicationName', 'autoEncryptionSettings', 'clusterSettingsBuilder', 'codecRegistry', 'commandListeners', 'compressorList', 'connectionPoolSettingsBuilder', 'contextProvider', 'credential', 'dnsClient', + 'enableOverloadRetargeting', 'heartbeatConnectTimeoutMS', 'heartbeatSocketTimeoutMS', 'inetAddressResolver', 'loggerSettingsBuilder', 'observabilitySettings', 'readConcern', 'readPreference', 'retryReads', @@ -571,6 +572,7 @@ class MongoClientSettingsSpecification extends Specification { 'applyToConnectionPoolSettings', 'applyToLoggerSettings', 'applyToServerSettings', 'applyToSocketSettings', 'applyToSslSettings', 'autoEncryptionSettings', 'build', 'codecRegistry', 'commandListenerList', 'compressorList', 'contextProvider', 'credential', 'dnsClient', + 'enableOverloadRetargeting', 'heartbeatConnectTimeoutMS', 'heartbeatSocketTimeoutMS', 'inetAddressResolver', 'observabilitySettings', 'readConcern', 'readPreference', diff --git a/driver-core/src/test/unit/com/mongodb/UriOptionsTest.java b/driver-core/src/test/unit/com/mongodb/UriOptionsTest.java index 736e3f5d201..ae456cec0eb 100644 --- a/driver-core/src/test/unit/com/mongodb/UriOptionsTest.java +++ b/driver-core/src/test/unit/com/mongodb/UriOptionsTest.java @@ -46,6 +46,8 @@ public void shouldPassAllOutcomes() { // No CANONICALIZE_HOST_NAME support https://jira.mongodb.org/browse/JAVA-4278 assumeFalse(getDescription().equals("Valid auth options are parsed correctly (GSSAPI)")); + // TODO-BACKPRESSURE Valentin add support for maxAdaptiveRetries. + assumeFalse(getDescription().contains("maxAdaptiveRetries")); if (getDefinition().getBoolean("valid", BsonBoolean.TRUE).getValue()) { testValidOptions(); diff --git a/driver-core/src/test/unit/com/mongodb/internal/binding/SingleServerBindingSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/binding/SingleServerBindingSpecification.groovy index d52fb593a70..64bd904aaed 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/binding/SingleServerBindingSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/binding/SingleServerBindingSpecification.groovy @@ -26,7 +26,7 @@ import com.mongodb.internal.connection.Server import com.mongodb.internal.connection.ServerTuple import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext class SingleServerBindingSpecification extends Specification { @@ -68,7 +68,7 @@ class SingleServerBindingSpecification extends Specification { binding.count == 1 when: - def source = binding.getReadConnectionSource(OPERATION_CONTEXT) + def source = binding.getReadConnectionSource(createOperationContext()) then: source.count == 1 @@ -96,7 +96,7 @@ class SingleServerBindingSpecification extends Specification { binding.count == 1 when: - source = binding.getWriteConnectionSource(OPERATION_CONTEXT) + source = binding.getWriteConnectionSource(createOperationContext()) then: source.count == 1 diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractConnectionPoolTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractConnectionPoolTest.java index 69a2c236048..deaeacafb07 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractConnectionPoolTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractConnectionPoolTest.java @@ -77,7 +77,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.OPERATION_CONTEXT_FACTORY; import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; import static com.mongodb.assertions.Assertions.assertFalse; @@ -542,7 +541,7 @@ private Event getNextEvent(final Iterator eventsIterator, final private static void executeAdminCommand(final BsonDocument command) { new CommandReadOperation<>("admin", command, new BsonDocumentCodec()) - .execute(ClusterFixture.getBinding(), OPERATION_CONTEXT); + .execute(ClusterFixture.getBinding(), ClusterFixture.createOperationContext()); } private void setFailPoint() { diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractServerDiscoveryAndMonitoringTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractServerDiscoveryAndMonitoringTest.java index e187e94da7b..d1b1f27a901 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractServerDiscoveryAndMonitoringTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/AbstractServerDiscoveryAndMonitoringTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.ConnectionString; import com.mongodb.MongoSocketReadException; import com.mongodb.MongoSocketReadTimeoutException; @@ -43,7 +44,6 @@ import java.util.concurrent.TimeUnit; import static com.mongodb.ClusterFixture.CLIENT_METADATA; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; import static com.mongodb.connection.ServerConnectionState.CONNECTING; import static com.mongodb.internal.connection.DescriptionHelper.createServerDescription; @@ -82,7 +82,8 @@ protected void applyResponse(final BsonArray response) { } protected void applyApplicationError(final BsonDocument applicationError) { - Timeout serverSelectionTimeout = OPERATION_CONTEXT.getTimeoutContext().computeServerSelectionTimeout(); + OperationContext operationContext = ClusterFixture.createOperationContext(); + Timeout serverSelectionTimeout = operationContext.getTimeoutContext().computeServerSelectionTimeout(); ServerAddress serverAddress = new ServerAddress(applicationError.getString("address").getValue()); TimeoutContext timeoutContext = new TimeoutContext(TIMEOUT_SETTINGS); int errorGeneration = applicationError.getNumber("generation", @@ -98,7 +99,7 @@ protected void applyApplicationError(final BsonDocument applicationError) { switch (type) { case "command": exception = getCommandFailureException(applicationError.getDocument("response"), serverAddress, - OPERATION_CONTEXT.getTimeoutContext()); + operationContext.getTimeoutContext()); break; case "network": exception = new MongoSocketReadException("Read error", serverAddress, new IOException()); diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterSpecification.groovy index 56c500c6183..25a1b904e1f 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterSpecification.groovy @@ -42,7 +42,6 @@ import spock.lang.Specification import java.util.concurrent.CountDownLatch import static com.mongodb.ClusterFixture.CLIENT_METADATA -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE @@ -135,7 +134,7 @@ class BaseClusterSpecification extends Specification { factory.sendNotification(thirdServer, REPLICA_SET_PRIMARY, allServers) expect: - cluster.selectServer(new ReadPreferenceServerSelector(ReadPreference.secondary()), OPERATION_CONTEXT) + cluster.selectServer(new ReadPreferenceServerSelector(ReadPreference.secondary()), createOperationContext()) .serverDescription.address == firstServer } @@ -171,7 +170,7 @@ class BaseClusterSpecification extends Specification { factory.sendNotification(thirdServer, 1, REPLICA_SET_PRIMARY, allServers) expect: - cluster.selectServer(new ReadPreferenceServerSelector(ReadPreference.nearest()), OPERATION_CONTEXT) + cluster.selectServer(new ReadPreferenceServerSelector(ReadPreference.nearest()), createOperationContext()) .serverDescription.address == firstServer } @@ -189,7 +188,7 @@ class BaseClusterSpecification extends Specification { factory.sendNotification(thirdServer, 1, REPLICA_SET_PRIMARY, allServers) expect: // firstServer is the only secondary within the latency threshold - cluster.selectServer(new ReadPreferenceServerSelector(ReadPreference.secondary()), OPERATION_CONTEXT) + cluster.selectServer(new ReadPreferenceServerSelector(ReadPreference.secondary()), createOperationContext()) .serverDescription.address == firstServer } diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterTest.java index 1cba6d91c3c..d1e6c454bc9 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/BaseClusterTest.java @@ -48,7 +48,7 @@ void selectServerToleratesWhenThereIsNoServerForTheSelectedAddress() { new ServerAddressSelector(serverAddressA), clusterDescriptionAB, serversSnapshotB, - ClusterFixture.OPERATION_CONTEXT.getServerDeprioritization(), + ClusterFixture.createOperationContext().getServerDeprioritization(), ClusterSettings.builder().build())); } diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultConnectionPoolSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultConnectionPoolSpecification.groovy index b3e78d2dc54..3872f6cb1e2 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultConnectionPoolSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultConnectionPoolSpecification.groovy @@ -41,7 +41,6 @@ import java.util.concurrent.CountDownLatch import java.util.regex.Matcher import java.util.regex.Pattern -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.ClusterFixture.OPERATION_CONTEXT_FACTORY import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS import static com.mongodb.ClusterFixture.createOperationContext @@ -78,7 +77,7 @@ class DefaultConnectionPoolSpecification extends Specification { pool.ready() expect: - pool.get(OPERATION_CONTEXT) != null + pool.get(createOperationContext()) != null } def 'should reuse released connection'() throws InterruptedException { @@ -86,10 +85,11 @@ class DefaultConnectionPoolSpecification extends Specification { pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().maxSize(1).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) pool.ready() + def operationContext = createOperationContext() when: - pool.get(OPERATION_CONTEXT).close() - pool.get(OPERATION_CONTEXT) + pool.get(operationContext).close() + pool.get(operationContext) then: 1 * connectionFactory.create(SERVER_ID, _) @@ -102,7 +102,7 @@ class DefaultConnectionPoolSpecification extends Specification { pool.ready() when: - pool.get(OPERATION_CONTEXT).close() + pool.get(createOperationContext()).close() then: !connectionFactory.getCreatedConnections().get(0).isClosed() @@ -220,7 +220,7 @@ class DefaultConnectionPoolSpecification extends Specification { when: pool.ready() - pool.get(OPERATION_CONTEXT) + pool.get(createOperationContext()) then: 1 * listener.connectionCreated { it.connectionId.serverId == SERVER_ID } @@ -239,6 +239,7 @@ class DefaultConnectionPoolSpecification extends Specification { connectionDescription.getConnectionId() >> id connection.getDescription() >> connectionDescription connection.opened() >> false + def operationContext = createOperationContext() when: 'connection pool is created' pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, settings, mockSdamProvider(), OPERATION_CONTEXT_FACTORY) @@ -257,7 +258,7 @@ class DefaultConnectionPoolSpecification extends Specification { "Connection pool ready for ${SERVER_ADDRESS.getHost()}:${SERVER_ADDRESS.getPort()}" == poolReadyLogMessage when: 'connection is created' - pool.get(OPERATION_CONTEXT) + pool.get(operationContext) then: '"connection created" and "connection ready" log messages are emitted' def createdLogMessage = getMessage( "Connection created") def readyLogMessage = getMessage("Connection ready") @@ -267,7 +268,7 @@ class DefaultConnectionPoolSpecification extends Specification { ", driver-generated ID=${driverConnectionId}, established in=\\d+ ms" when: 'connection is released back into the pool on close' - pool.get(OPERATION_CONTEXT).close() + pool.get(operationContext).close() then: '"connection check out" and "connection checked in" log messages are emitted' def checkoutStartedMessage = getMessage("Connection checkout started") def connectionCheckedInMessage = getMessage("Connection checked in") @@ -302,7 +303,7 @@ class DefaultConnectionPoolSpecification extends Specification { "Connection pool closed for ${SERVER_ADDRESS.getHost()}:${SERVER_ADDRESS.getPort()}" == poolClosedLogMessage when: 'connection checked out on closed pool' - pool.get(OPERATION_CONTEXT) + pool.get(operationContext) then: thrown(MongoServerUnavailableException) def connectionCheckoutFailedInMessage = getMessage("Connection checkout failed") @@ -351,7 +352,7 @@ class DefaultConnectionPoolSpecification extends Specification { when: pool.ready() - pool.get(OPERATION_CONTEXT).close() + pool.get(createOperationContext()).close() //not cool - but we have no way of waiting for connection to become idle Thread.sleep(500) pool.close(); @@ -386,11 +387,12 @@ class DefaultConnectionPoolSpecification extends Specification { def 'should log connection checkout failed with Reason.CONNECTION_ERROR if fails to open a connection'() { given: + def operationContext = createOperationContext() def listener = Mock(ConnectionPoolListener) def connection = Mock(InternalConnection) connection.getDescription() >> new ConnectionDescription(SERVER_ID) connection.opened() >> false - connection.open(OPERATION_CONTEXT) >> { throw new UncheckedIOException('expected failure', new IOException()) } + connection.open(operationContext) >> { throw new UncheckedIOException('expected failure', new IOException()) } connectionFactory.create(SERVER_ID, _) >> connection pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().addConnectionPoolListener(listener).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) @@ -398,7 +400,7 @@ class DefaultConnectionPoolSpecification extends Specification { when: try { - pool.get(OPERATION_CONTEXT) + pool.get(operationContext) } catch (UncheckedIOException e) { if ('expected failure' != e.getMessage()) { throw e @@ -435,7 +437,7 @@ class DefaultConnectionPoolSpecification extends Specification { pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().maxSize(10) .addConnectionPoolListener(listener).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) pool.ready() - def connection = pool.get(OPERATION_CONTEXT) + def connection = pool.get(createOperationContext()) connection.close() when: @@ -463,15 +465,16 @@ class DefaultConnectionPoolSpecification extends Specification { def 'should fire connection pool events on check out and check in'() { given: + def operationContext = createOperationContext() def listener = Mock(ConnectionPoolListener) pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().maxSize(1) .addConnectionPoolListener(listener).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) pool.ready() - def connection = pool.get(OPERATION_CONTEXT) + def connection = pool.get(operationContext) connection.close() when: - connection = pool.get(OPERATION_CONTEXT) + connection = pool.get(operationContext) then: 1 * listener.connectionCheckedOut { it.connectionId.serverId == SERVER_ID } @@ -493,7 +496,7 @@ class DefaultConnectionPoolSpecification extends Specification { connection.close() when: - connection = pool.get(OPERATION_CONTEXT) + connection = pool.get(createOperationContext()) then: 1 * listener.connectionCheckedOut { it.connectionId.serverId == SERVER_ID } @@ -507,11 +510,12 @@ class DefaultConnectionPoolSpecification extends Specification { def 'should fire connection checkout failed with Reason.CONNECTION_ERROR if fails to open a connection'() { given: + def operationContext = createOperationContext() def listener = Mock(ConnectionPoolListener) def connection = Mock(InternalConnection) connection.getDescription() >> new ConnectionDescription(SERVER_ID) connection.opened() >> false - connection.open(OPERATION_CONTEXT) >> { throw new UncheckedIOException('expected failure', new IOException()) } + connection.open(operationContext) >> { throw new UncheckedIOException('expected failure', new IOException()) } connectionFactory.create(SERVER_ID, _) >> connection pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().addConnectionPoolListener(listener).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) @@ -519,7 +523,7 @@ class DefaultConnectionPoolSpecification extends Specification { when: try { - pool.get(OPERATION_CONTEXT) + pool.get(operationContext) } catch (UncheckedIOException e) { if ('expected failure' != e.getMessage()) { throw e @@ -564,7 +568,7 @@ class DefaultConnectionPoolSpecification extends Specification { when: try { - pool.get(OPERATION_CONTEXT) + pool.get(createOperationContext()) } catch (MongoConnectionPoolClearedException e) { caught = e } @@ -579,7 +583,7 @@ class DefaultConnectionPoolSpecification extends Specification { CompletableFuture caught = new CompletableFuture<>() when: - pool.getAsync(OPERATION_CONTEXT) { InternalConnection result, Throwable t -> + pool.getAsync(createOperationContext()) { InternalConnection result, Throwable t -> if (t != null) { caught.complete(t) } @@ -599,7 +603,7 @@ class DefaultConnectionPoolSpecification extends Specification { when: pool.invalidate(cause) try { - pool.get(OPERATION_CONTEXT) + pool.get(createOperationContext()) } catch (MongoConnectionPoolClearedException e) { caught = e } @@ -630,7 +634,7 @@ class DefaultConnectionPoolSpecification extends Specification { pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().maxSize(1) .addConnectionPoolListener(listener).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) pool.ready() - def connection = pool.get(OPERATION_CONTEXT) + def connection = pool.get(createOperationContext()) pool.close() when: @@ -674,7 +678,7 @@ class DefaultConnectionPoolSpecification extends Specification { pool.ready() when: - def connection = pool.get(OPERATION_CONTEXT) + def connection = pool.get(createOperationContext()) def connectionLatch = selectConnectionAsync(pool) connection.close() @@ -684,12 +688,13 @@ class DefaultConnectionPoolSpecification extends Specification { def 'when getting a connection asynchronously should send MongoTimeoutException to callback after timeout period'() { given: + def operationContext = createOperationContext() pool = new DefaultConnectionPool(SERVER_ID, connectionFactory, builder().maxSize(1).maxWaitTime(5, MILLISECONDS).build(), mockSdamProvider(), OPERATION_CONTEXT_FACTORY) pool.ready() - pool.get(OPERATION_CONTEXT) - def firstConnectionLatch = selectConnectionAsync(pool) - def secondConnectionLatch = selectConnectionAsync(pool) + pool.get(operationContext) + def firstConnectionLatch = selectConnectionAsync(pool, operationContext) + def secondConnectionLatch = selectConnectionAsync(pool, operationContext) when: firstConnectionLatch.get() @@ -721,9 +726,9 @@ class DefaultConnectionPoolSpecification extends Specification { selectConnectionAsync(pool).get() } - def selectConnectionAsync(DefaultConnectionPool pool) { + def selectConnectionAsync(DefaultConnectionPool pool, operationContext = createOperationContext()) { def serverLatch = new ConnectionLatch() - pool.getAsync(OPERATION_CONTEXT) { InternalConnection result, Throwable e -> + pool.getAsync(operationContext) { InternalConnection result, Throwable e -> serverLatch.connection = result serverLatch.throwable = e serverLatch.latch.countDown() diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerConnectionSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerConnectionSpecification.groovy index be6fbe06b83..26348f16198 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerConnectionSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerConnectionSpecification.groovy @@ -16,7 +16,7 @@ package com.mongodb.internal.connection - +import com.mongodb.ClusterFixture import com.mongodb.ReadPreference import com.mongodb.connection.ClusterConnectionMode import com.mongodb.internal.async.SingleResultCallback @@ -27,7 +27,6 @@ import org.bson.BsonInt32 import org.bson.codecs.BsonDocumentCodec import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT import static com.mongodb.CustomMatchers.compare import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback import static com.mongodb.internal.connection.MessageHelper.LEGACY_HELLO_LOWER @@ -43,14 +42,16 @@ class DefaultServerConnectionSpecification extends Specification { def codec = new BsonDocumentCodec() def executor = Mock(ProtocolExecutor) def connection = new DefaultServerConnection(internalConnection, executor, ClusterConnectionMode.MULTIPLE) + def operationContext = ClusterFixture.createOperationContext() + when: - connection.commandAsync('test', command, validator, ReadPreference.primary(), codec, OPERATION_CONTEXT, callback) + connection.commandAsync('test', command, validator, ReadPreference.primary(), codec, operationContext, callback) then: 1 * executor.executeAsync({ compare(new CommandProtocolImpl('test', command, validator, ReadPreference.primary(), codec, true, - MessageSequences.EmptyMessageSequences.INSTANCE, ClusterConnectionMode.MULTIPLE, OPERATION_CONTEXT), it) - }, internalConnection, OPERATION_CONTEXT.getSessionContext(), callback) + MessageSequences.EmptyMessageSequences.INSTANCE, ClusterConnectionMode.MULTIPLE, operationContext), it) + }, internalConnection, operationContext.getSessionContext(), callback) } } diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerSpecification.groovy index 3910da575f0..230301e9033 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerSpecification.groovy @@ -54,7 +54,7 @@ import spock.lang.Specification import java.util.concurrent.CountDownLatch import static com.mongodb.ClusterFixture.CLIENT_METADATA -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.MongoCredential.createCredential import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE import static com.mongodb.connection.ClusterConnectionMode.SINGLE @@ -74,7 +74,7 @@ class DefaultServerSpecification extends Specification { Mock(SdamServerDescriptionManager), Mock(ServerListener), Mock(CommandListener), new ClusterClock(), false) when: - def receivedConnection = server.getConnection(OPERATION_CONTEXT) + def receivedConnection = server.getConnection(createOperationContext()) then: receivedConnection @@ -100,7 +100,7 @@ class DefaultServerSpecification extends Specification { when: def callback = new SupplyingCallback() - server.getConnectionAsync(OPERATION_CONTEXT, callback) + server.getConnectionAsync(createOperationContext(), callback) then: callback.get() == connection @@ -117,7 +117,7 @@ class DefaultServerSpecification extends Specification { server.close() when: - server.getConnection(OPERATION_CONTEXT) + server.getConnection(createOperationContext()) then: def ex = thrown(MongoServerUnavailableException) @@ -127,7 +127,7 @@ class DefaultServerSpecification extends Specification { def latch = new CountDownLatch(1) def receivedConnection = null def receivedThrowable = null - server.getConnectionAsync(OPERATION_CONTEXT) { + server.getConnectionAsync(createOperationContext()) { result, throwable -> receivedConnection = result; receivedThrowable = throwable; latch.countDown() } @@ -210,7 +210,6 @@ class DefaultServerSpecification extends Specification { given: def connectionPool = Mock(ConnectionPool) def serverMonitor = Mock(ServerMonitor) - connectionPool.get(OPERATION_CONTEXT) >> { throw exceptionToThrow } def server = defaultServer(connectionPool, serverMonitor) server.close() @@ -242,7 +241,7 @@ class DefaultServerSpecification extends Specification { def server = defaultServer(connectionPool, serverMonitor) when: - server.getConnection(OPERATION_CONTEXT) + server.getConnection(createOperationContext()) then: def e = thrown(MongoException) @@ -267,7 +266,7 @@ class DefaultServerSpecification extends Specification { def server = defaultServer(connectionPool, serverMonitor) when: - server.getConnection(OPERATION_CONTEXT) + server.getConnection(createOperationContext()) then: def e = thrown(MongoSecurityException) @@ -292,7 +291,7 @@ class DefaultServerSpecification extends Specification { def latch = new CountDownLatch(1) def receivedConnection = null def receivedThrowable = null - server.getConnectionAsync(OPERATION_CONTEXT) { + server.getConnectionAsync(createOperationContext()) { result, throwable -> receivedConnection = result; receivedThrowable = throwable; latch.countDown() } @@ -325,7 +324,7 @@ class DefaultServerSpecification extends Specification { def latch = new CountDownLatch(1) def receivedConnection = null def receivedThrowable = null - server.getConnectionAsync(OPERATION_CONTEXT) { + server.getConnectionAsync(createOperationContext()) { result, throwable -> receivedConnection = result; receivedThrowable = throwable; latch.countDown() } @@ -350,7 +349,7 @@ class DefaultServerSpecification extends Specification { clusterClock.advance(clusterClockClusterTime) def server = new DefaultServer(serverId, SINGLE, Mock(ConnectionPool), new TestConnectionFactory(), Mock(ServerMonitor), Mock(SdamServerDescriptionManager), Mock(ServerListener), Mock(CommandListener), clusterClock, false) - def testConnection = (TestConnection) server.getConnection(OPERATION_CONTEXT) + def testConnection = (TestConnection) server.getConnection(createOperationContext()) def sessionContext = new TestSessionContext(initialClusterTime) def response = BsonDocument.parse( '''{ @@ -361,7 +360,7 @@ class DefaultServerSpecification extends Specification { ''') def protocol = new TestCommandProtocol(response) testConnection.enqueueProtocol(protocol) - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) when: if (async) { diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionSpecification.groovy index 3cdabf31da3..10074ba9d3c 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/InternalStreamConnectionSpecification.groovy @@ -58,7 +58,7 @@ import java.util.concurrent.CountDownLatch import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS_WITH_INFINITE_TIMEOUT import static com.mongodb.ReadPreference.primary import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE @@ -114,7 +114,7 @@ class InternalStreamConnectionSpecification extends Specification { def getOpenedConnection() { def connection = getConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) connection } @@ -132,7 +132,7 @@ class InternalStreamConnectionSpecification extends Specification { .lastUpdateTimeNanos(connection.getInitialServerDescription().getLastUpdateTime(NANOSECONDS)) .build() when: - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) then: connection.opened() @@ -159,7 +159,7 @@ class InternalStreamConnectionSpecification extends Specification { .build() when: - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get() then: @@ -177,7 +177,7 @@ class InternalStreamConnectionSpecification extends Specification { failedInitializer) when: - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) then: thrown MongoInternalException @@ -195,7 +195,7 @@ class InternalStreamConnectionSpecification extends Specification { when: def futureResultCallback = new FutureResultCallback() - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get() then: @@ -212,14 +212,14 @@ class InternalStreamConnectionSpecification extends Specification { def (buffers2, messageId2) = helper.hello() when: - connection.sendMessage(buffers1, messageId1, OPERATION_CONTEXT) + connection.sendMessage(buffers1, messageId1, createOperationContext()) then: connection.isClosed() thrown MongoSocketWriteException when: - connection.sendMessage(buffers2, messageId2, OPERATION_CONTEXT) + connection.sendMessage(buffers2, messageId2, createOperationContext()) then: thrown MongoSocketClosedException @@ -243,7 +243,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.sendMessageAsync(buffers1, messageId1, OPERATION_CONTEXT, sndCallbck1) + connection.sendMessageAsync(buffers1, messageId1, createOperationContext(), sndCallbck1) sndCallbck1.get(10, SECONDS) then: @@ -251,7 +251,7 @@ class InternalStreamConnectionSpecification extends Specification { connection.isClosed() when: - connection.sendMessageAsync(buffers2, messageId2, OPERATION_CONTEXT, sndCallbck2) + connection.sendMessageAsync(buffers2, messageId2, createOperationContext(), sndCallbck2) sndCallbck2.get(10, SECONDS) then: @@ -267,16 +267,16 @@ class InternalStreamConnectionSpecification extends Specification { def (buffers2, messageId2) = helper.hello() when: - connection.sendMessage(buffers1, messageId1, OPERATION_CONTEXT) - connection.sendMessage(buffers2, messageId2, OPERATION_CONTEXT) - connection.receiveMessage(messageId1, OPERATION_CONTEXT) + connection.sendMessage(buffers1, messageId1, createOperationContext()) + connection.sendMessage(buffers2, messageId2, createOperationContext()) + connection.receiveMessage(messageId1, createOperationContext()) then: connection.isClosed() thrown MongoSocketReadException when: - connection.receiveMessage(messageId2, OPERATION_CONTEXT) + connection.receiveMessage(messageId2, createOperationContext()) then: thrown MongoSocketClosedException @@ -289,7 +289,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: thrown(MongoInternalException) @@ -306,7 +306,7 @@ class InternalStreamConnectionSpecification extends Specification { def callback = new FutureResultCallback() when: - connection.receiveMessageAsync(1, OPERATION_CONTEXT, callback) + connection.receiveMessageAsync(1, createOperationContext(), callback) callback.get() then: @@ -321,7 +321,7 @@ class InternalStreamConnectionSpecification extends Specification { Thread.currentThread().interrupt() when: - connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, OPERATION_CONTEXT) + connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, createOperationContext()) then: Thread.interrupted() @@ -335,7 +335,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, OPERATION_CONTEXT) + connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, createOperationContext()) then: !Thread.interrupted() @@ -350,7 +350,7 @@ class InternalStreamConnectionSpecification extends Specification { Thread.currentThread().interrupt() when: - connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, OPERATION_CONTEXT) + connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, createOperationContext()) then: Thread.interrupted() @@ -365,7 +365,7 @@ class InternalStreamConnectionSpecification extends Specification { Thread.currentThread().interrupt() when: - connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, OPERATION_CONTEXT) + connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, createOperationContext()) then: Thread.interrupted() @@ -379,7 +379,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, OPERATION_CONTEXT) + connection.sendMessage([new ByteBufNIO(ByteBuffer.allocate(1))], 1, createOperationContext()) then: thrown(MongoSocketWriteException) @@ -393,7 +393,7 @@ class InternalStreamConnectionSpecification extends Specification { Thread.currentThread().interrupt() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: Thread.interrupted() @@ -407,7 +407,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: !Thread.interrupted() @@ -422,7 +422,7 @@ class InternalStreamConnectionSpecification extends Specification { Thread.currentThread().interrupt() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: Thread.interrupted() @@ -437,7 +437,7 @@ class InternalStreamConnectionSpecification extends Specification { Thread.currentThread().interrupt() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: Thread.interrupted() @@ -451,7 +451,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: thrown(MongoSocketReadException) @@ -464,7 +464,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.receiveMessage(1, OPERATION_CONTEXT.withTimeoutContext( + connection.receiveMessage(1, createOperationContext().withTimeoutContext( new TimeoutContext(TIMEOUT_SETTINGS_WITH_INFINITE_TIMEOUT))) then: @@ -482,7 +482,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.receiveMessage(1, OPERATION_CONTEXT.withTimeoutContext( + connection.receiveMessage(1, createOperationContext().withTimeoutContext( new TimeoutContext(TIMEOUT_SETTINGS_WITH_INFINITE_TIMEOUT))) then: @@ -502,7 +502,7 @@ class InternalStreamConnectionSpecification extends Specification { } def connection = getOpenedConnection() def callback = new FutureResultCallback() - def operationContext = OPERATION_CONTEXT.withTimeoutContext( + def operationContext = createOperationContext().withTimeoutContext( new TimeoutContext(TIMEOUT_SETTINGS_WITH_INFINITE_TIMEOUT)) when: connection.receiveMessageAsync(1, operationContext, callback) @@ -525,7 +525,7 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() def callback = new FutureResultCallback() - def operationContext = OPERATION_CONTEXT.withTimeoutContext( + def operationContext = createOperationContext().withTimeoutContext( new TimeoutContext(TIMEOUT_SETTINGS_WITH_INFINITE_TIMEOUT)) when: connection.receiveMessageAsync(1, operationContext, callback) @@ -563,10 +563,10 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.sendMessageAsync(buffers1, messageId1, OPERATION_CONTEXT, sndCallbck1) - connection.sendMessageAsync(buffers2, messageId2, OPERATION_CONTEXT, sndCallbck2) - connection.receiveMessageAsync(messageId1, OPERATION_CONTEXT, rcvdCallbck1) - connection.receiveMessageAsync(messageId2, OPERATION_CONTEXT, rcvdCallbck2) + connection.sendMessageAsync(buffers1, messageId1, createOperationContext(), sndCallbck1) + connection.sendMessageAsync(buffers2, messageId2, createOperationContext(), sndCallbck2) + connection.receiveMessageAsync(messageId1, createOperationContext(), rcvdCallbck1) + connection.receiveMessageAsync(messageId2, createOperationContext(), rcvdCallbck2) rcvdCallbck1.get(1, SECONDS) then: @@ -588,14 +588,14 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: connection.isClosed() thrown MongoSocketReadException when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: thrown MongoSocketClosedException @@ -620,9 +620,9 @@ class InternalStreamConnectionSpecification extends Specification { def connection = getOpenedConnection() when: - connection.sendMessageAsync(buffers1, messageId1, OPERATION_CONTEXT, sndCallbck1) - connection.sendMessageAsync(buffers2, messageId2, OPERATION_CONTEXT, sndCallbck2) - connection.receiveMessageAsync(messageId1, OPERATION_CONTEXT, rcvdCallbck1) + connection.sendMessageAsync(buffers1, messageId1, createOperationContext(), sndCallbck1) + connection.sendMessageAsync(buffers2, messageId2, createOperationContext(), sndCallbck2) + connection.receiveMessageAsync(messageId1, createOperationContext(), rcvdCallbck1) rcvdCallbck1.get(1, SECONDS) then: @@ -630,7 +630,7 @@ class InternalStreamConnectionSpecification extends Specification { connection.isClosed() when: - connection.receiveMessageAsync(messageId2, OPERATION_CONTEXT, rcvdCallbck2) + connection.receiveMessageAsync(messageId2, createOperationContext(), rcvdCallbck2) rcvdCallbck2.get(1, SECONDS) then: @@ -649,7 +649,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(_, _) >> helper.reply(response) when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: thrown(MongoCommandException) @@ -677,7 +677,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: @@ -705,7 +705,7 @@ class InternalStreamConnectionSpecification extends Specification { def callbacks = [] (1..numberOfOperations).each { n -> def (buffers, messageId, sndCallbck, rcvdCallbck) = messages.pop() - connection.sendMessageAsync(buffers, messageId, OPERATION_CONTEXT, sndCallbck) + connection.sendMessageAsync(buffers, messageId, createOperationContext(), sndCallbck) callbacks.add(sndCallbck) } streamLatch.countDown() @@ -730,7 +730,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(90, _) >> helper.defaultReply() when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: commandListener.eventsWereDelivered([ @@ -753,7 +753,7 @@ class InternalStreamConnectionSpecification extends Specification { when: connection.sendAndReceive(commandMessage, { BsonReader reader, DecoderContext decoderContext -> throw new CodecConfigurationException('') - }, OPERATION_CONTEXT) + }, createOperationContext()) then: thrown(CodecConfigurationException) @@ -783,7 +783,7 @@ class InternalStreamConnectionSpecification extends Specification { 1 * advanceClusterTime(BsonDocument.parse(response).getDocument('$clusterTime')) getReadConcern() >> ReadConcern.DEFAULT } - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) when: connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), operationContext) @@ -819,7 +819,7 @@ class InternalStreamConnectionSpecification extends Specification { 1 * advanceClusterTime(BsonDocument.parse(response).getDocument('$clusterTime')) getReadConcern() >> ReadConcern.DEFAULT } - def operationContext = OPERATION_CONTEXT.withSessionContext(sessionContext) + def operationContext = createOperationContext().withSessionContext(sessionContext) when: connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), operationContext, callback) @@ -839,7 +839,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.write(_, _) >> { throw new MongoSocketWriteException('Failed to write', serverAddress, new IOException()) } when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: def e = thrown(MongoSocketWriteException) @@ -859,7 +859,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(16, _) >> { throw new MongoSocketReadException('Failed to read', serverAddress) } when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: def e = thrown(MongoSocketReadException) @@ -880,7 +880,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(90, _) >> { throw new MongoSocketReadException('Failed to read', serverAddress) } when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: def e = thrown(MongoSocketException) @@ -902,7 +902,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(_, _) >> helper.reply(response) when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: def e = thrown(MongoCommandException) @@ -923,7 +923,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(90, _) >> helper.defaultReply() when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: commandListener.eventsWereDelivered([ @@ -959,7 +959,7 @@ class InternalStreamConnectionSpecification extends Specification { stream.read(_, _) >> helper.reply('{ok : 0, errmsg : "failed"}') when: - connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT) + connection.sendAndReceive(commandMessage, new BsonDocumentCodec(), createOperationContext()) then: thrown(MongoCommandException) @@ -1005,7 +1005,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: @@ -1038,7 +1038,7 @@ class InternalStreamConnectionSpecification extends Specification { when: connection.sendAndReceiveAsync(commandMessage, { BsonReader reader, DecoderContext decoderContext -> throw new CodecConfigurationException('') - }, OPERATION_CONTEXT, callback) + }, createOperationContext(), callback) callback.get() then: @@ -1065,7 +1065,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: @@ -1093,7 +1093,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: @@ -1124,7 +1124,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: @@ -1156,7 +1156,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: @@ -1187,7 +1187,7 @@ class InternalStreamConnectionSpecification extends Specification { } when: - connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), OPERATION_CONTEXT, callback) + connection.sendAndReceiveAsync(commandMessage, new BsonDocumentCodec(), createOperationContext(), callback) callback.get() then: diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/JMXConnectionPoolListenerSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/JMXConnectionPoolListenerSpecification.groovy index 374687f7d01..5a7bcd3e492 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/JMXConnectionPoolListenerSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/JMXConnectionPoolListenerSpecification.groovy @@ -29,7 +29,7 @@ import spock.lang.Unroll import javax.management.ObjectName import java.lang.management.ManagementFactory -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.OPERATION_CONTEXT_FACTORY class JMXConnectionPoolListenerSpecification extends Specification { @@ -50,8 +50,8 @@ class JMXConnectionPoolListenerSpecification extends Specification { provider.ready() when: - provider.get(OPERATION_CONTEXT) - provider.get(OPERATION_CONTEXT).close() + provider.get(createOperationContext()) + provider.get(createOperationContext()).close() then: with(jmxListener.getMBean(SERVER_ID)) { diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/LoadBalancedClusterTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/LoadBalancedClusterTest.java index 7366a03b584..87dd1581045 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/LoadBalancedClusterTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/LoadBalancedClusterTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoClientException; import com.mongodb.MongoConfigurationException; import com.mongodb.MongoException; @@ -52,7 +53,6 @@ import java.util.concurrent.atomic.AtomicReference; import static com.mongodb.ClusterFixture.CLIENT_METADATA; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; import static com.mongodb.ClusterFixture.createOperationContext; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -96,14 +96,14 @@ public void shouldSelectServerWhenThereIsNoSRVLookup() { mock(DnsSrvRecordMonitorFactory.class)); // when - ServerTuple serverTuple = cluster.selectServer(mock(ServerSelector.class), OPERATION_CONTEXT); + ServerTuple serverTuple = cluster.selectServer(mock(ServerSelector.class), ClusterFixture.createOperationContext()); // then assertServerTupleExpectations(serverAddress, expectedServer, serverTuple); // when FutureResultCallback callback = new FutureResultCallback<>(); - cluster.selectServerAsync(mock(ServerSelector.class), OPERATION_CONTEXT, callback); + cluster.selectServerAsync(mock(ServerSelector.class), ClusterFixture.createOperationContext(), callback); serverTuple = callback.get(); // then @@ -131,7 +131,7 @@ public void shouldSelectServerWhenThereIsSRVLookup() { cluster = new LoadBalancedCluster(new ClusterId(), clusterSettings, serverFactory, CLIENT_METADATA, dnsSrvRecordMonitorFactory); // when - ServerTuple serverTuple = cluster.selectServer(mock(ServerSelector.class), OPERATION_CONTEXT); + ServerTuple serverTuple = cluster.selectServer(mock(ServerSelector.class), ClusterFixture.createOperationContext()); // then assertServerTupleExpectations(resolvedServerAddress, expectedServer, serverTuple); @@ -159,7 +159,7 @@ public void shouldSelectServerAsynchronouslyWhenThereIsSRVLookup() { // when FutureResultCallback callback = new FutureResultCallback<>(); - cluster.selectServerAsync(mock(ServerSelector.class), OPERATION_CONTEXT, callback); + cluster.selectServerAsync(mock(ServerSelector.class), ClusterFixture.createOperationContext(), callback); ServerTuple serverTuple = callback.get(); // then @@ -185,7 +185,7 @@ public void shouldFailSelectServerWhenThereIsSRVMisconfiguration() { cluster = new LoadBalancedCluster(new ClusterId(), clusterSettings, serverFactory, CLIENT_METADATA, dnsSrvRecordMonitorFactory); MongoClientException exception = assertThrows(MongoClientException.class, () -> cluster.selectServer(mock(ServerSelector.class), - OPERATION_CONTEXT)); + ClusterFixture.createOperationContext())); assertEquals("In load balancing mode, the host must resolve to a single SRV record, but instead it resolved to multiple hosts", exception.getMessage()); } @@ -209,7 +209,7 @@ public void shouldFailSelectServerAsynchronouslyWhenThereIsSRVMisconfiguration() cluster = new LoadBalancedCluster(new ClusterId(), clusterSettings, serverFactory, CLIENT_METADATA, dnsSrvRecordMonitorFactory); FutureResultCallback callback = new FutureResultCallback<>(); - cluster.selectServerAsync(mock(ServerSelector.class), OPERATION_CONTEXT, callback); + cluster.selectServerAsync(mock(ServerSelector.class), ClusterFixture.createOperationContext(), callback); MongoClientException exception = assertThrows(MongoClientException.class, callback::get); assertEquals("In load balancing mode, the host must resolve to a single SRV record, but instead it resolved to multiple hosts", diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/LoggingCommandEventSenderSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/LoggingCommandEventSenderSpecification.groovy index e6f6afb02e0..de12c35af5e 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/LoggingCommandEventSenderSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/LoggingCommandEventSenderSpecification.groovy @@ -39,7 +39,7 @@ import org.bson.BsonInt32 import org.bson.BsonString import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE import static com.mongodb.connection.ClusterConnectionMode.SINGLE import static com.mongodb.internal.operation.ServerVersionHelper.LATEST_WIRE_VERSION @@ -63,7 +63,7 @@ class LoggingCommandEventSenderSpecification extends Specification { def logger = Stub(Logger) { isDebugEnabled() >> debugLoggingEnabled } - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() def sender = new LoggingCommandEventSender([] as Set, [] as Set, connectionDescription, commandListener, operationContext, message, message.getCommandDocument(bsonOutput), new StructuredLogger(logger), LoggerSettings.builder().build()) @@ -109,7 +109,7 @@ class LoggingCommandEventSenderSpecification extends Specification { def logger = Mock(Logger) { isDebugEnabled() >> true } - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() def sender = new LoggingCommandEventSender([] as Set, [] as Set, connectionDescription, commandListener, operationContext, message, message.getCommandDocument(bsonOutput), new StructuredLogger(logger), LoggerSettings.builder().build()) @@ -166,7 +166,7 @@ class LoggingCommandEventSenderSpecification extends Specification { def logger = Mock(Logger) { isDebugEnabled() >> true } - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() def sender = new LoggingCommandEventSender([] as Set, [] as Set, connectionDescription, null, operationContext, message, message.getCommandDocument(bsonOutput), new StructuredLogger(logger), LoggerSettings.builder().build()) @@ -200,7 +200,7 @@ class LoggingCommandEventSenderSpecification extends Specification { def logger = Mock(Logger) { isDebugEnabled() >> true } - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() def sender = new LoggingCommandEventSender(['createUser'] as Set, [] as Set, connectionDescription, null, operationContext, message, message.getCommandDocument(bsonOutput), new StructuredLogger(logger), LoggerSettings.builder().build()) diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/MultiServerClusterSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/MultiServerClusterSpecification.groovy index a3cf8104fd3..737aead0300 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/MultiServerClusterSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/MultiServerClusterSpecification.groovy @@ -29,7 +29,7 @@ import org.bson.types.ObjectId import spock.lang.Specification import static com.mongodb.ClusterFixture.CLIENT_METADATA -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE import static com.mongodb.connection.ClusterType.REPLICA_SET import static com.mongodb.connection.ClusterType.SHARDED @@ -93,11 +93,12 @@ class MultiServerClusterSpecification extends Specification { def cluster = new MultiServerCluster(CLUSTER_ID, ClusterSettings.builder().hosts(Arrays.asList(firstServer)).mode(MULTIPLE).build(), factory, CLIENT_METADATA) cluster.close() + def operationContext = createOperationContext() when: cluster.getServersSnapshot( - OPERATION_CONTEXT.getTimeoutContext().computeServerSelectionTimeout(), - OPERATION_CONTEXT.getTimeoutContext()) + operationContext.getTimeoutContext().computeServerSelectionTimeout(), + operationContext.getTimeoutContext()) then: thrown(IllegalStateException) @@ -386,7 +387,7 @@ class MultiServerClusterSpecification extends Specification { cluster.close() when: - cluster.selectServer(new WritableServerSelector(), OPERATION_CONTEXT) + cluster.selectServer(new WritableServerSelector(), createOperationContext()) then: thrown(IllegalStateException) diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/PlainAuthenticatorUnitTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/PlainAuthenticatorUnitTest.java index 12d8e9fa7c3..a535262b4b4 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/PlainAuthenticatorUnitTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/PlainAuthenticatorUnitTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import com.mongodb.async.FutureResultCallback; @@ -30,7 +31,6 @@ import java.util.List; import java.util.concurrent.ExecutionException; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getServerApi; import static com.mongodb.internal.connection.MessageHelper.getApiVersionField; import static com.mongodb.internal.connection.MessageHelper.getDbField; @@ -54,7 +54,7 @@ public void before() { public void testSuccessfulAuthentication() { enqueueSuccessfulReply(); - subject.authenticate(connection, connectionDescription, OPERATION_CONTEXT); + subject.authenticate(connection, connectionDescription, ClusterFixture.createOperationContext()); validateMessages(); } @@ -64,7 +64,7 @@ public void testSuccessfulAuthenticationAsync() throws ExecutionException, Inter enqueueSuccessfulReply(); FutureResultCallback futureCallback = new FutureResultCallback<>(); - subject.authenticateAsync(connection, connectionDescription, OPERATION_CONTEXT, futureCallback); + subject.authenticateAsync(connection, connectionDescription, ClusterFixture.createOperationContext(), futureCallback); futureCallback.get(); validateMessages(); diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDeprioritizationTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDeprioritizationTest.java index f1c8f69eb29..9ac2bbe7d40 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDeprioritizationTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDeprioritizationTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; import com.mongodb.MongoConnectionPoolClearedException; +import com.mongodb.MongoException; import com.mongodb.ServerAddress; import com.mongodb.connection.ClusterConnectionMode; import com.mongodb.connection.ClusterDescription; @@ -25,93 +26,237 @@ import com.mongodb.connection.ServerDescription; import com.mongodb.connection.ServerId; import com.mongodb.internal.connection.OperationContext.ServerDeprioritization; +import com.mongodb.internal.mockito.MongoMockito; +import com.mongodb.selector.ServerSelector; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; -import static com.mongodb.ClusterFixture.createOperationContext; +import static java.lang.String.format; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.Collections.unmodifiableList; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.params.provider.EnumSource.Mode.EXCLUDE; +import static org.junit.jupiter.params.provider.Arguments.of; +import static org.mockito.ArgumentMatchers.any; final class ServerDeprioritizationTest { private static final ServerDescription SERVER_A = serverDescription("a"); private static final ServerDescription SERVER_B = serverDescription("b"); private static final ServerDescription SERVER_C = serverDescription("c"); private static final List ALL_SERVERS = unmodifiableList(asList(SERVER_A, SERVER_B, SERVER_C)); - private static final ClusterDescription REPLICA_SET = clusterDescription(ClusterType.REPLICA_SET); - private static final ClusterDescription SHARDED_CLUSTER = clusterDescription(ClusterType.SHARDED); - + private static final ClusterDescription REPLICA_SET_CLUSTER = multipleModeClusterDescription(ClusterType.REPLICA_SET); + private static final ClusterDescription SHARDED_CLUSTER = multipleModeClusterDescription(ClusterType.SHARDED); + private static final ClusterDescription UNKNOWN_CLUSTER = multipleModeClusterDescription(ClusterType.UNKNOWN); + private static final List CLUSTERS = asList(SHARDED_CLUSTER, REPLICA_SET_CLUSTER, UNKNOWN_CLUSTER); + private static final RuntimeException RUNTIME_EXCEPTION = new RuntimeException(); + private static final MongoException MONGO_EXCEPTION_NO_LABEL = new MongoException(0, "test"); private ServerDeprioritization serverDeprioritization; @BeforeEach void beforeEach() { - serverDeprioritization = createOperationContext(TIMEOUT_SETTINGS).getServerDeprioritization(); + serverDeprioritization = new OperationContext.ServerDeprioritization(true); } - @Test - void selectNoneDeprioritized() { - assertAll( - () -> assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(SHARDED_CLUSTER)), - () -> assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(REPLICA_SET)) - ); + private static Stream selectNoneDeprioritized() { + return CLUSTERS.stream().flatMap(clusterDescription -> + Stream.of( + namedArguments(clusterDescription), + namedArguments(clusterDescription, SERVER_A), + namedArguments(clusterDescription, SERVER_B), + namedArguments(clusterDescription, SERVER_C), + namedArguments(clusterDescription, SERVER_A, SERVER_B), + namedArguments(clusterDescription, SERVER_B, SERVER_A), + namedArguments(clusterDescription, SERVER_A, SERVER_C), + namedArguments(clusterDescription, SERVER_C, SERVER_A), + namedArguments(clusterDescription, SERVER_A, SERVER_B, SERVER_C) + )); } - @Test - void selectSomeDeprioritized() { - deprioritize(SERVER_B); + @ParameterizedTest + @MethodSource + void selectNoneDeprioritized(final ClusterDescription clusterDescription, final List selectorResult) { + ServerSelector wrappedSelector = createAssertingSelector(ALL_SERVERS, selectorResult); + assertEquals(selectorResult, serverDeprioritization.apply(wrappedSelector).select(clusterDescription)); + } + + @ParameterizedTest + @EnumSource(value = ClusterType.class, names = {"STANDALONE", "LOAD_BALANCED"}) + void selectNoneDeprioritizedSingleServerCluster(final ClusterType clusterType) { + ClusterDescription cluster = singleModeClusterDescription(clusterType); + ServerSelector wrappedSelector = createAssertingSelector(singletonList(SERVER_A), singletonList(SERVER_A)); + ServerSelector emptyListWrappedSelector = createAssertingSelector(singletonList(SERVER_A), emptyList()); assertAll( - () -> assertEquals(asList(SERVER_A, SERVER_C), serverDeprioritization.getServerSelector().select(SHARDED_CLUSTER)), - () -> assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(REPLICA_SET)) + () -> assertEquals(singletonList(SERVER_A), serverDeprioritization.apply(wrappedSelector).select(cluster)), + () -> assertEquals(emptyList(), serverDeprioritization.apply(emptyListWrappedSelector).select(cluster)) ); } - @Test - void selectAllDeprioritized() { - deprioritize(SERVER_A); - deprioritize(SERVER_B); - deprioritize(SERVER_C); - assertAll( - () -> assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(SHARDED_CLUSTER)), - () -> assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(REPLICA_SET)) + private static Stream deprioritizableClusters() { + return Stream.of( + of(SHARDED_CLUSTER, RUNTIME_EXCEPTION), + of(SHARDED_CLUSTER, MONGO_EXCEPTION_NO_LABEL), + of(REPLICA_SET_CLUSTER, createSystemOverloadedError()), + of(UNKNOWN_CLUSTER, createSystemOverloadedError()) ); } + private static Stream selectSomeDeprioritized() { + return deprioritizableClusters().flatMap(args -> { + ClusterDescription clusterDescription = (ClusterDescription) args.get()[0]; + Throwable exception = (Throwable) args.get()[1]; + return Stream.of( + namedArguments(clusterDescription, exception, SERVER_A), + namedArguments(clusterDescription, exception, SERVER_C), + namedArguments(clusterDescription, exception, SERVER_A, SERVER_C), + namedArguments(clusterDescription, exception, SERVER_C, SERVER_A) + ); + }); + } + @ParameterizedTest - @EnumSource(value = ClusterType.class, mode = EXCLUDE, names = {"SHARDED"}) - void serverSelectorSelectsAllIfNotShardedCluster(final ClusterType clusterType) { - serverDeprioritization.updateCandidate(SERVER_A.getAddress()); - serverDeprioritization.onAttemptFailure(new RuntimeException()); - assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(clusterDescription(clusterType))); + @MethodSource + void selectSomeDeprioritized(final ClusterDescription clusterDescription, final Throwable exception, + final List selectorResult) { + deprioritize(clusterDescription.getType(), exception, SERVER_B); + List expectedWrappedSelectorFilteredInput = asList(SERVER_A, SERVER_C); + ServerSelector wrappedSelector = createAssertingSelector(expectedWrappedSelectorFilteredInput, selectorResult); + assertEquals(selectorResult, serverDeprioritization.apply(wrappedSelector).select(clusterDescription)); + } + + private static Stream selectAllDeprioritized() { + return deprioritizableClusters().flatMap(args -> { + ClusterDescription clusterDescription = (ClusterDescription) args.get()[0]; + Throwable exception = (Throwable) args.get()[1]; + return Stream.of( + namedArguments(clusterDescription, exception), + namedArguments(clusterDescription, exception, SERVER_A), + namedArguments(clusterDescription, exception, SERVER_B), + namedArguments(clusterDescription, exception, SERVER_C), + namedArguments(clusterDescription, exception, SERVER_A, SERVER_B), + namedArguments(clusterDescription, exception, SERVER_B, SERVER_A), + namedArguments(clusterDescription, exception, SERVER_A, SERVER_C), + namedArguments(clusterDescription, exception, SERVER_C, SERVER_A), + namedArguments(clusterDescription, exception, SERVER_A, SERVER_B, SERVER_C) + ); + }); + } + + @ParameterizedTest + @MethodSource + void selectAllDeprioritized(final ClusterDescription clusterDescription, final Throwable exception, + final List selectorResult) { + deprioritize(clusterDescription.getType(), exception, SERVER_A); + deprioritize(clusterDescription.getType(), exception, SERVER_B); + deprioritize(clusterDescription.getType(), exception, SERVER_C); + ServerSelector selector = createAssertingSelector(ALL_SERVERS, selectorResult); + assertEquals(selectorResult, serverDeprioritization.apply(selector).select(clusterDescription)); + } + + @ParameterizedTest + @EnumSource(value = ClusterType.class, names = {"STANDALONE", "LOAD_BALANCED"}) + void selectAllDeprioritizedSingleServerCluster(final ClusterType clusterType) { + ClusterDescription cluster = singleModeClusterDescription(clusterType); + deprioritize(clusterType, createSystemOverloadedError(), SERVER_A); + ServerSelector selector = createAssertingSelector(singletonList(SERVER_A), singletonList(SERVER_A)); + assertEquals(singletonList(SERVER_A), serverDeprioritization.apply(selector).select(cluster)); + } + + @ParameterizedTest + @MethodSource("selectSomeDeprioritized") + void selectWithRetryWhenWrappedReturnsEmpty(final ClusterDescription clusterDescription, + final Throwable exception, + final List selectorResult) { + deprioritize(clusterDescription.getType(), exception, SERVER_B); + ServerSelector selector = MongoMockito.mock(ServerSelector.class, tuner -> + Mockito.when(tuner.select(any(ClusterDescription.class))) + .thenAnswer(invocation -> { + assertEquals(asList(SERVER_A, SERVER_C), invocation.getArgument(0).getServerDescriptions()); + return emptyList(); + }) + .thenAnswer(invocation -> { + assertEquals(ALL_SERVERS, invocation.getArgument(0).getServerDescriptions()); + return selectorResult; + }) + ); + assertEquals(selectorResult, serverDeprioritization.apply(selector).select(clusterDescription)); } @Test void onAttemptFailureIgnoresIfPoolClearedException() { - serverDeprioritization.updateCandidate(SERVER_A.getAddress()); + serverDeprioritization.updateCandidate(SERVER_A.getAddress(), ClusterType.SHARDED); serverDeprioritization.onAttemptFailure( new MongoConnectionPoolClearedException(new ServerId(new ClusterId(), new ServerAddress()), null)); - assertEquals(ALL_SERVERS, serverDeprioritization.getServerSelector().select(SHARDED_CLUSTER)); + ServerSelector selector = createAssertingSelector(ALL_SERVERS, ALL_SERVERS); + assertEquals(ALL_SERVERS, serverDeprioritization.apply(selector).select(SHARDED_CLUSTER)); } @Test void onAttemptFailureDoesNotThrowIfNoCandidate() { - assertDoesNotThrow(() -> serverDeprioritization.onAttemptFailure(new RuntimeException())); + assertDoesNotThrow(() -> serverDeprioritization.onAttemptFailure(RUNTIME_EXCEPTION)); } - private void deprioritize(final ServerDescription... serverDescriptions) { + @ParameterizedTest + @EnumSource(value = ClusterType.class, names = "SHARDED", mode = EnumSource.Mode.EXCLUDE) + void onAttemptFailureIgnoresIfNonShardedWithoutOverloadError(final ClusterType clusterType) { + ClusterDescription cluster = multipleModeClusterDescription(clusterType); + ServerSelector selector = createAssertingSelector(ALL_SERVERS, singletonList(SERVER_A)); + + assertAll(() -> { + deprioritize(clusterType, RUNTIME_EXCEPTION, SERVER_B); + assertEquals(singletonList(SERVER_A), serverDeprioritization.apply(selector).select(cluster), + format("Expected no deprioritization for %s with RuntimeException", clusterType)); + }, + () -> { + deprioritize(clusterType, MONGO_EXCEPTION_NO_LABEL, SERVER_B); + assertEquals(singletonList(SERVER_A), serverDeprioritization.apply(selector).select(cluster), + format("Expected no deprioritization for %s with MongoException without SystemOverloadedError", clusterType)); + } + ); + } + + @ParameterizedTest + @EnumSource(value = ClusterType.class, names = "SHARDED", mode = EnumSource.Mode.EXCLUDE) + void onAttemptFailureIgnoresIfNonShardedWithOverloadErrorAndDisabledOverloadRetargeting(final ClusterType clusterType) { + ClusterDescription cluster = multipleModeClusterDescription(clusterType); + ServerSelector selector = createAssertingSelector(ALL_SERVERS, singletonList(SERVER_A)); + + ServerDeprioritization serverDeprioritization = new OperationContext.ServerDeprioritization(false); + serverDeprioritization.updateCandidate(SERVER_B.getAddress(), clusterType); + serverDeprioritization.onAttemptFailure(createSystemOverloadedError()); + + assertEquals(singletonList(SERVER_A), serverDeprioritization.apply(selector).select(cluster), + format("Expected no deprioritization when overloadRetargeting is disabled for %s with SystemOverloadedError", clusterType)); + } + + private void deprioritize(final ClusterType clusterType, final Throwable exception, final ServerDescription... serverDescriptions) { for (ServerDescription serverDescription : serverDescriptions) { - serverDeprioritization.updateCandidate(serverDescription.getAddress()); - serverDeprioritization.onAttemptFailure(new RuntimeException()); + serverDeprioritization.updateCandidate(serverDescription.getAddress(), clusterType); + serverDeprioritization.onAttemptFailure(exception); } } + private static ServerSelector createAssertingSelector( + final List expectedInput, + final List selectorResult) { + return clusterDescription -> { + assertEquals(expectedInput, clusterDescription.getServerDescriptions()); + return selectorResult; + }; + } + private static ServerDescription serverDescription(final String host) { return ServerDescription.builder() .state(ServerConnectionState.CONNECTED) @@ -120,7 +265,39 @@ private static ServerDescription serverDescription(final String host) { .build(); } - private static ClusterDescription clusterDescription(final ClusterType clusterType) { + private static ClusterDescription multipleModeClusterDescription(final ClusterType clusterType) { return new ClusterDescription(ClusterConnectionMode.MULTIPLE, clusterType, ALL_SERVERS); } + + private static ClusterDescription singleModeClusterDescription(final ClusterType clusterType) { + return new ClusterDescription(ClusterConnectionMode.SINGLE, clusterType, singletonList(SERVER_A)); + } + + private static MongoException createSystemOverloadedError() { + MongoException e = new MongoException(6, "overloaded"); + e.addLabel("SystemOverloadedError"); + return e; + } + + private static Arguments namedArguments(final ClusterDescription clusterDescription, final ServerDescription... serverDescriptions) { + return of(Named.of(generateArgumentName(clusterDescription), clusterDescription), + Named.of(generateArgumentName(asList(serverDescriptions)), asList(serverDescriptions))); + } + + private static Arguments namedArguments(final ClusterDescription clusterDescription, final Throwable exception, final ServerDescription... serverDescriptions) { + return of(Named.of(generateArgumentName(clusterDescription), clusterDescription), + exception, + Named.of(generateArgumentName(asList(serverDescriptions)), asList(serverDescriptions))); + } + + private static String generateArgumentName(final List servers) { + return "[" + servers.stream() + .map(ServerDescription::getAddress) + .map(ServerAddress::getHost) + .collect(Collectors.joining(", ")) + "]"; + } + + private static String generateArgumentName(final ClusterDescription clusterDescription) { + return "[" + clusterDescription.getType() + ", " + generateArgumentName(clusterDescription.getServerDescriptions()) + "]"; + } } diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDiscoveryAndMonitoringTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDiscoveryAndMonitoringTest.java index dc81e5071e1..095372a6cee 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDiscoveryAndMonitoringTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerDiscoveryAndMonitoringTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.ServerAddress; import com.mongodb.connection.ClusterType; import com.mongodb.connection.ServerDescription; @@ -32,7 +33,6 @@ import java.util.Collection; import java.util.stream.Collectors; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getClusterDescription; import static com.mongodb.internal.connection.ClusterDescriptionHelper.getPrimaries; import static com.mongodb.internal.event.EventListenerHelper.NO_OP_CLUSTER_LISTENER; @@ -154,9 +154,10 @@ private void assertServer(final String serverName, final BsonDocument expectedSe if (expectedServerDescriptionDocument.isDocument("pool")) { int expectedGeneration = expectedServerDescriptionDocument.getDocument("pool").getNumber("generation").intValue(); - Timeout serverSelectionTimeout = OPERATION_CONTEXT.getTimeoutContext().computeServerSelectionTimeout(); + OperationContext operationContext = ClusterFixture.createOperationContext(); + Timeout serverSelectionTimeout = operationContext.getTimeoutContext().computeServerSelectionTimeout(); DefaultServer server = (DefaultServer) getCluster() - .getServersSnapshot(serverSelectionTimeout, OPERATION_CONTEXT.getTimeoutContext()) + .getServersSnapshot(serverSelectionTimeout, operationContext.getTimeoutContext()) .getServer(new ServerAddress(serverName)); assertEquals(expectedGeneration, server.getConnectionPool().getGeneration()); } diff --git a/driver-core/src/test/unit/com/mongodb/connection/ServerSelectionSelectionTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionSelectionTest.java similarity index 55% rename from driver-core/src/test/unit/com/mongodb/connection/ServerSelectionSelectionTest.java rename to driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionSelectionTest.java index 8b878fa77c5..5d6b5e0e1e3 100644 --- a/driver-core/src/test/unit/com/mongodb/connection/ServerSelectionSelectionTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionSelectionTest.java @@ -14,19 +14,36 @@ * limitations under the License. */ -package com.mongodb.connection; +package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoConfigurationException; +import com.mongodb.MongoException; +import com.mongodb.MongoTimeoutException; import com.mongodb.ReadPreference; import com.mongodb.ServerAddress; import com.mongodb.Tag; import com.mongodb.TagSet; -import com.mongodb.internal.selector.LatencyMinimizingServerSelector; +import com.mongodb.assertions.Assertions; +import com.mongodb.connection.ClusterConnectionMode; +import com.mongodb.connection.ClusterDescription; +import com.mongodb.connection.ClusterId; +import com.mongodb.connection.ClusterSettings; +import com.mongodb.connection.ClusterType; +import com.mongodb.connection.ServerConnectionState; +import com.mongodb.connection.ServerDescription; +import com.mongodb.connection.ServerSettings; +import com.mongodb.connection.ServerType; +import com.mongodb.event.ServerDescriptionChangedEvent; +import com.mongodb.internal.IgnorableRequestContext; +import com.mongodb.internal.TimeoutContext; +import com.mongodb.internal.mockito.MongoMockito; +import com.mongodb.internal.observability.micrometer.TracingManager; import com.mongodb.internal.selector.ReadPreferenceServerSelector; import com.mongodb.internal.selector.WritableServerSelector; +import com.mongodb.internal.time.Timeout; import com.mongodb.lang.NonNull; import com.mongodb.lang.Nullable; -import com.mongodb.selector.CompositeServerSelector; import com.mongodb.selector.ServerSelector; import org.bson.BsonArray; import org.bson.BsonBoolean; @@ -34,36 +51,54 @@ import org.bson.BsonInt64; import org.bson.BsonString; import org.bson.BsonValue; +import org.bson.json.JsonWriterSettings; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import util.JsonPoweredTestHelper; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; -import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; +import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; +import static com.mongodb.connection.ServerDescription.MIN_DRIVER_WIRE_VERSION; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; +import static org.mockito.Mockito.when; -// See https://github.com/mongodb/specifications/tree/master/source/server-selection/tests +/** + * See Server Selection Tests. + */ @RunWith(Parameterized.class) public class ServerSelectionSelectionTest { private final String description; private final BsonDocument definition; private final ClusterDescription clusterDescription; - private final long heartbeatFrequencyMS; private final boolean error; + private static final Set TOPOLOGY_DESCRIPTION_FIELDS = new HashSet<>(Arrays.asList("type", "servers")); + private static final Set SERVER_DESCRIPTION_FIELDS = new HashSet<>(Arrays.asList( + "address", "type", "tags", "avg_rtt_ms", "lastWrite", "lastUpdateTime", "maxWireVersion")); + private static final Set READ_PREFERENCE_FIELDS = new HashSet<>( + Arrays.asList("mode", "tag_sets", "maxStalenessSeconds")); + public ServerSelectionSelectionTest(final String description, final BsonDocument definition) { this.description = description; this.definition = definition; - this.heartbeatFrequencyMS = definition.getNumber("heartbeatFrequencyMS", new BsonInt64(10000)).longValue(); + + long heartbeatFrequencyMS = definition.getNumber("heartbeatFrequencyMS", new BsonInt64(10000)).longValue(); this.error = definition.getBoolean("error", BsonBoolean.FALSE).getValue(); this.clusterDescription = buildClusterDescription(definition.getDocument("topology_description"), ServerSettings.builder().heartbeatFrequency(heartbeatFrequencyMS, TimeUnit.MILLISECONDS).build()); @@ -73,37 +108,38 @@ public ServerSelectionSelectionTest(final String description, final BsonDocument public void shouldPassAllOutcomes() { // skip this test because the driver prohibits maxStaleness or tagSets with mode of primary at a much lower level assumeFalse(description.endsWith("/max-staleness/tests/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.json")); - assumeFalse(description.contains("Deprioritized")); // TODO JAVA-6021 deprioritized server selection" - - ServerSelector serverSelector = null; - List suitableServers = buildServerDescriptions(definition.getArray("suitable_servers", new BsonArray())); - List selectedServers = null; - try { - serverSelector = getServerSelector(); - selectedServers = serverSelector.select(clusterDescription); + ServerTuple serverTuple; + ServerSelector serverSelector = getServerSelector(); + OperationContext operationContext = createOperationContext(); + Cluster.ServersSnapshot serversSnapshot = createServersSnapshot(clusterDescription); + List inLatencyWindowServers = buildServerDescriptions(definition.getArray("in_latency_window", new BsonArray())); + + try (BaseCluster cluster = new TestCluster(clusterDescription, serversSnapshot)) { + serverTuple = cluster.selectServer(serverSelector, operationContext); if (error) { - fail("Should have thrown exception"); + fail(format("Should have thrown exception")); } } catch (MongoConfigurationException e) { if (!error) { - fail("Should not have thrown exception: " + e); + fail(format("Should not have thrown exception: %s", e)); } return; + } catch (MongoTimeoutException mongoTimeoutException) { + assertTrue(format("Expected empty but was %s", inLatencyWindowServers.size()), + inLatencyWindowServers.isEmpty()); + return; } - assertServers(selectedServers, suitableServers); - - ServerSelector latencyBasedServerSelector = new CompositeServerSelector(asList(serverSelector, - new LatencyMinimizingServerSelector(15, TimeUnit.MILLISECONDS))); - List inLatencyWindowServers = buildServerDescriptions(definition.getArray("in_latency_window")); - List latencyBasedSelectedServers = latencyBasedServerSelector.select(clusterDescription); - assertServers(latencyBasedSelectedServers, inLatencyWindowServers); + assertNotNull(format("Server tuple should not be null"), serverTuple); + assertTrue(format("Selected server should be in latency window. Selected server: %s", serverTuple.getServerDescription()), + inLatencyWindowServers.stream().anyMatch(s -> s.equals(serverTuple.getServerDescription()))); } @Parameterized.Parameters(name = "{0}") public static Collection data() { List data = new ArrayList<>(); for (BsonDocument testDocument : JsonPoweredTestHelper.getSpecTestDocuments("server-selection/tests/server_selection")) { - data.add(new Object[]{testDocument.getString("resourcePath").getValue(), testDocument}); + String resourcePath = testDocument.getString("resourcePath").getValue(); + data.add(new Object[]{resourcePath, testDocument}); } for (BsonDocument testDocument : JsonPoweredTestHelper.getSpecTestDocuments("max-staleness/tests")) { data.add(new Object[]{testDocument.getString("resourcePath").getValue(), testDocument}); @@ -112,11 +148,12 @@ public static Collection data() { } public static ClusterDescription buildClusterDescription(final BsonDocument topologyDescription, - @Nullable final ServerSettings serverSettings) { + @Nullable final ServerSettings serverSettings) { + validateTestDescriptionFields(topologyDescription.keySet(), TOPOLOGY_DESCRIPTION_FIELDS); ClusterType clusterType = getClusterType(topologyDescription.getString("type").getValue()); ClusterConnectionMode connectionMode = getClusterConnectionMode(clusterType); List servers = buildServerDescriptions(topologyDescription.getArray("servers")); - return new ClusterDescription(connectionMode, clusterType, servers, null, + return new ClusterDescription(connectionMode, clusterType, servers, ClusterSettings.builder().build(), serverSettings == null ? ServerSettings.builder().build() : serverSettings); } @@ -153,6 +190,7 @@ private static List buildServerDescriptions(final BsonArray s } private static ServerDescription buildServerDescription(final BsonDocument serverDescription) { + validateTestDescriptionFields(serverDescription.keySet(), SERVER_DESCRIPTION_FIELDS); ServerDescription.Builder builder = ServerDescription.builder(); builder.address(new ServerAddress(serverDescription.getString("address").getValue())); ServerType serverType = getServerType(serverDescription.getString("type").getValue()); @@ -175,6 +213,8 @@ private static ServerDescription buildServerDescription(final BsonDocument serve } if (serverDescription.containsKey("maxWireVersion")) { builder.maxWireVersion(serverDescription.getNumber("maxWireVersion").intValue()); + } else { + builder.maxWireVersion(MIN_DRIVER_WIRE_VERSION); } return builder.build(); } @@ -229,6 +269,7 @@ private ServerSelector getServerSelector() { return new WritableServerSelector(); } else { BsonDocument readPreferenceDefinition = definition.getDocument("read_preference"); + validateTestDescriptionFields(readPreferenceDefinition.keySet(), READ_PREFERENCE_FIELDS); ReadPreference readPreference; if (readPreferenceDefinition.getString("mode").getValue().equals("Primary")) { readPreference = ReadPreference.valueOf("Primary"); @@ -244,8 +285,88 @@ private ServerSelector getServerSelector() { } } - private void assertServers(final List actual, final List expected) { - assertEquals(expected.size(), actual.size()); - assertTrue(actual.containsAll(expected)); + private static List extractDeprioritizedServerAddresses(final BsonDocument definition) { + if (!definition.containsKey("deprioritized_servers")) { + return Collections.emptyList(); + } + return definition.getArray("deprioritized_servers") + .stream() + .map(BsonValue::asDocument) + .map(ServerSelectionSelectionTest::buildServerDescription) + .map(ServerDescription::getAddress) + .collect(Collectors.toList()); + } + + private OperationContext createOperationContext() { + OperationContext operationContext = + new OperationContext( + IgnorableRequestContext.INSTANCE, + NoOpSessionContext.INSTANCE, + new TimeoutContext(TIMEOUT_SETTINGS.withServerSelectionTimeoutMS(0)), + TracingManager.NO_OP, + null, + null, + new OperationContext.ServerDeprioritization(true)); + OperationContext.ServerDeprioritization serverDeprioritization = operationContext.getServerDeprioritization(); + for (ServerAddress address : extractDeprioritizedServerAddresses(definition)) { + serverDeprioritization.updateCandidate(address, clusterDescription.getType()); + // The spec defines deprioritized_servers as a pre-populated list to feed into the selection mechanism - not as "simulate the + // failure that caused deprioritization." Thus, SystemOverloadedError used unconditionally regardless of the cluster type. + MongoException error = new MongoException("test"); + error.addLabel(MongoException.SYSTEM_OVERLOADED_ERROR_LABEL); + serverDeprioritization.onAttemptFailure(error); + } + return operationContext; + } + + private static Cluster.ServersSnapshot createServersSnapshot( + final ClusterDescription clusterDescription) { + Map serverMap = new HashMap<>(); + for (ServerDescription desc : clusterDescription.getServerDescriptions()) { + serverMap.put(desc.getAddress(), MongoMockito.mock(Server.class, server -> { + // `MinimumOperationCountServerSelector` should select any server since they all have 0 operation count. + when(server.operationCount()).thenReturn(0); + })); + } + return serverMap::get; + } + + private static void validateTestDescriptionFields(final Set actualFields, final Set knownFields) { + Set unknownFields = new HashSet<>(actualFields); + unknownFields.removeAll(knownFields); + if (!unknownFields.isEmpty()) { + throw new UnsupportedOperationException("Unknown fields: " + unknownFields); + } + } + + private static class TestCluster extends BaseCluster { + private final ServersSnapshot serversSnapshot; + + TestCluster(final ClusterDescription clusterDescription, final ServersSnapshot serversSnapshot) { + super(new ClusterId(), clusterDescription.getClusterSettings(), new TestClusterableServerFactory(), + ClusterFixture.CLIENT_METADATA); + this.serversSnapshot = serversSnapshot; + updateDescription(clusterDescription); + } + + @Override + protected void connect() { + // NOOP: this method may be invoked in test cases where no server is expected to be selected. + } + + @Override + public ServersSnapshot getServersSnapshot(final Timeout serverSelectionTimeout, final TimeoutContext timeoutContext) { + return serversSnapshot; + } + + @Override + public void onChange(final ServerDescriptionChangedEvent event) { + Assertions.fail(); + } + } + + private String format(final String messageFormat, final Object... args) { + String message = String.format(messageFormat, args); + return message + "\nTest Definition:\n" + definition.toJson(JsonWriterSettings.builder().indent(true).build()); } } diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionWithinLatencyWindowTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionWithinLatencyWindowTest.java index 14d6c59b0c6..23e1f59d3a7 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionWithinLatencyWindowTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/ServerSelectionWithinLatencyWindowTest.java @@ -43,7 +43,7 @@ import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS; import static com.mongodb.ClusterFixture.createOperationContext; -import static com.mongodb.connection.ServerSelectionSelectionTest.buildClusterDescription; +import static com.mongodb.internal.connection.ServerSelectionSelectionTest.buildClusterDescription; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toMap; import static org.junit.Assert.assertEquals; diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/SingleServerClusterSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/SingleServerClusterSpecification.groovy index faa04a188f9..126cadce0c0 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/SingleServerClusterSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/SingleServerClusterSpecification.groovy @@ -29,7 +29,7 @@ import com.mongodb.internal.selector.WritableServerSelector import spock.lang.Specification import static com.mongodb.ClusterFixture.CLIENT_METADATA -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.connection.ClusterConnectionMode.SINGLE import static com.mongodb.connection.ClusterType.REPLICA_SET import static com.mongodb.connection.ClusterType.UNKNOWN @@ -78,10 +78,9 @@ class SingleServerClusterSpecification extends Specification { sendNotification(firstServer, STANDALONE) then: - cluster.getServersSnapshot(OPERATION_CONTEXT - .getTimeoutContext() - .computeServerSelectionTimeout(), - OPERATION_CONTEXT.getTimeoutContext()).getServer(firstServer) == factory.getServer(firstServer) + def operationContext = createOperationContext() + cluster.getServersSnapshot(operationContext.getTimeoutContext().computeServerSelectionTimeout(), + operationContext.getTimeoutContext()).getServer(firstServer) == factory.getServer(firstServer) cleanup: cluster?.close() @@ -95,8 +94,9 @@ class SingleServerClusterSpecification extends Specification { cluster.close() when: - cluster.getServersSnapshot(OPERATION_CONTEXT.getTimeoutContext().computeServerSelectionTimeout(), - OPERATION_CONTEXT.getTimeoutContext()) + def operationContext = createOperationContext() + cluster.getServersSnapshot(operationContext.getTimeoutContext().computeServerSelectionTimeout(), + operationContext.getTimeoutContext()) then: thrown(IllegalStateException) @@ -146,7 +146,7 @@ class SingleServerClusterSpecification extends Specification { sendNotification(firstServer, getBuilder(firstServer).minWireVersion(1000).maxWireVersion(1000).build()) when: - cluster.selectServer(new WritableServerSelector(), OPERATION_CONTEXT) + cluster.selectServer(new WritableServerSelector(), createOperationContext()) then: thrown(MongoIncompatibleDriverException) diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/UsageTrackingConnectionSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/UsageTrackingConnectionSpecification.groovy index 78d79fba8b2..379d60a2fe7 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/UsageTrackingConnectionSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/UsageTrackingConnectionSpecification.groovy @@ -26,7 +26,7 @@ import org.bson.BsonInt32 import org.bson.codecs.BsonDocumentCodec import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ReadPreference.primary import static com.mongodb.connection.ClusterConnectionMode.SINGLE @@ -49,7 +49,7 @@ class UsageTrackingConnectionSpecification extends Specification { connection.openedAt == Long.MAX_VALUE when: - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) then: connection.openedAt <= System.currentTimeMillis() @@ -65,7 +65,7 @@ class UsageTrackingConnectionSpecification extends Specification { connection.openedAt == Long.MAX_VALUE when: - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get() then: @@ -80,7 +80,7 @@ class UsageTrackingConnectionSpecification extends Specification { connection.lastUsedAt == Long.MAX_VALUE when: - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) then: connection.lastUsedAt <= System.currentTimeMillis() @@ -96,7 +96,7 @@ class UsageTrackingConnectionSpecification extends Specification { connection.lastUsedAt == Long.MAX_VALUE when: - connection.openAsync(OPERATION_CONTEXT, futureResultCallback) + connection.openAsync(createOperationContext(), futureResultCallback) futureResultCallback.get() then: @@ -106,11 +106,11 @@ class UsageTrackingConnectionSpecification extends Specification { def 'lastUsedAt should be set on sendMessage'() { given: def connection = createConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) def openedLastUsedAt = connection.lastUsedAt when: - connection.sendMessage([], 1, OPERATION_CONTEXT) + connection.sendMessage([], 1, createOperationContext()) then: connection.lastUsedAt >= openedLastUsedAt @@ -121,12 +121,12 @@ class UsageTrackingConnectionSpecification extends Specification { def 'lastUsedAt should be set on sendMessage asynchronously'() { given: def connection = createConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) def openedLastUsedAt = connection.lastUsedAt def futureResultCallback = new FutureResultCallback() when: - connection.sendMessageAsync([], 1, OPERATION_CONTEXT, futureResultCallback) + connection.sendMessageAsync([], 1, createOperationContext(), futureResultCallback) futureResultCallback.get() then: @@ -137,10 +137,10 @@ class UsageTrackingConnectionSpecification extends Specification { def 'lastUsedAt should be set on receiveMessage'() { given: def connection = createConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) def openedLastUsedAt = connection.lastUsedAt when: - connection.receiveMessage(1, OPERATION_CONTEXT) + connection.receiveMessage(1, createOperationContext()) then: connection.lastUsedAt >= openedLastUsedAt @@ -150,12 +150,12 @@ class UsageTrackingConnectionSpecification extends Specification { def 'lastUsedAt should be set on receiveMessage asynchronously'() { given: def connection = createConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) def openedLastUsedAt = connection.lastUsedAt def futureResultCallback = new FutureResultCallback() when: - connection.receiveMessageAsync(1, OPERATION_CONTEXT, futureResultCallback) + connection.receiveMessageAsync(1, createOperationContext(), futureResultCallback) futureResultCallback.get() then: @@ -166,13 +166,13 @@ class UsageTrackingConnectionSpecification extends Specification { def 'lastUsedAt should be set on sendAndReceive'() { given: def connection = createConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) def openedLastUsedAt = connection.lastUsedAt when: connection.sendAndReceive(new CommandMessage('test', new BsonDocument('ping', new BsonInt32(1)), NoOpFieldNameValidator.INSTANCE, primary(), - MessageSettings.builder().build(), SINGLE, null), new BsonDocumentCodec(), OPERATION_CONTEXT) + MessageSettings.builder().build(), SINGLE, null), new BsonDocumentCodec(), createOperationContext()) then: connection.lastUsedAt >= openedLastUsedAt @@ -182,7 +182,7 @@ class UsageTrackingConnectionSpecification extends Specification { def 'lastUsedAt should be set on sendAndReceive asynchronously'() { given: def connection = createConnection() - connection.open(OPERATION_CONTEXT) + connection.open(createOperationContext()) def openedLastUsedAt = connection.lastUsedAt def futureResultCallback = new FutureResultCallback() @@ -190,7 +190,7 @@ class UsageTrackingConnectionSpecification extends Specification { connection.sendAndReceiveAsync(new CommandMessage('test', new BsonDocument('ping', new BsonInt32(1)), NoOpFieldNameValidator.INSTANCE, primary(), MessageSettings.builder().build(), SINGLE, null), - new BsonDocumentCodec(), OPERATION_CONTEXT, futureResultCallback) + new BsonDocumentCodec(), createOperationContext(), futureResultCallback) futureResultCallback.get() then: diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorNoUserNameTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorNoUserNameTest.java index 5326c8c723d..0259b41930a 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorNoUserNameTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorNoUserNameTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import com.mongodb.async.FutureResultCallback; @@ -32,7 +33,6 @@ import java.util.List; import java.util.concurrent.ExecutionException; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getServerApi; import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE; import static com.mongodb.internal.connection.MessageHelper.buildSuccessfulReply; @@ -58,7 +58,7 @@ public void testSuccessfulAuthentication() { enqueueSuccessfulAuthenticationReply(); new X509Authenticator(getCredentialWithCache(), MULTIPLE, getServerApi()) - .authenticate(connection, connectionDescriptionThreeSix, OPERATION_CONTEXT); + .authenticate(connection, connectionDescriptionThreeSix, ClusterFixture.createOperationContext()); validateMessages(); } @@ -69,7 +69,7 @@ public void testSuccessfulAuthenticationAsync() throws ExecutionException, Inter FutureResultCallback futureCallback = new FutureResultCallback<>(); new X509Authenticator(getCredentialWithCache(), MULTIPLE, getServerApi()).authenticateAsync(connection, - connectionDescriptionThreeSix, OPERATION_CONTEXT, futureCallback); + connectionDescriptionThreeSix, ClusterFixture.createOperationContext(), futureCallback); futureCallback.get(); diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorUnitTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorUnitTest.java index a8b2d7b71d5..80d0b2c0411 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorUnitTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/X509AuthenticatorUnitTest.java @@ -16,6 +16,7 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoCredential; import com.mongodb.MongoSecurityException; import com.mongodb.ServerAddress; @@ -31,7 +32,6 @@ import java.util.List; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getServerApi; import static com.mongodb.internal.connection.MessageHelper.buildSuccessfulReply; import static com.mongodb.internal.connection.MessageHelper.getApiVersionField; @@ -58,7 +58,7 @@ public void testFailedAuthentication() { enqueueFailedAuthenticationReply(); try { - subject.authenticate(connection, connectionDescription, OPERATION_CONTEXT); + subject.authenticate(connection, connectionDescription, ClusterFixture.createOperationContext()); fail(); } catch (MongoSecurityException e) { // all good @@ -70,7 +70,7 @@ public void testFailedAuthenticationAsync() { enqueueFailedAuthenticationReply(); FutureResultCallback futureCallback = new FutureResultCallback<>(); - subject.authenticateAsync(connection, connectionDescription, OPERATION_CONTEXT, futureCallback); + subject.authenticateAsync(connection, connectionDescription, ClusterFixture.createOperationContext(), futureCallback); try { futureCallback.get(); @@ -92,7 +92,7 @@ private void enqueueFailedAuthenticationReply() { public void testSuccessfulAuthentication() { enqueueSuccessfulAuthenticationReply(); - subject.authenticate(connection, connectionDescription, OPERATION_CONTEXT); + subject.authenticate(connection, connectionDescription, ClusterFixture.createOperationContext()); validateMessages(); } @@ -102,7 +102,7 @@ public void testSuccessfulAuthenticationAsync() { enqueueSuccessfulAuthenticationReply(); FutureResultCallback futureCallback = new FutureResultCallback<>(); - subject.authenticateAsync(connection, connectionDescription, OPERATION_CONTEXT, futureCallback); + subject.authenticateAsync(connection, connectionDescription, ClusterFixture.createOperationContext(), futureCallback); futureCallback.get(); @@ -117,7 +117,7 @@ public void testSpeculativeAuthentication() { + "user: \"CN=client,OU=kerneluser,O=10Gen,L=New York City,ST=New York,C=US\", " + "mechanism: \"MONGODB-X509\", db: \"$external\"}"); subject.setSpeculativeAuthenticateResponse(BsonDocument.parse(speculativeAuthenticateResponse)); - subject.authenticate(connection, connectionDescription, OPERATION_CONTEXT); + subject.authenticate(connection, connectionDescription, ClusterFixture.createOperationContext()); assertEquals(connection.getSent().size(), 0); assertEquals(expectedSpeculativeAuthenticateCommand, subject.createSpeculativeAuthenticateCommand(connection)); diff --git a/driver-core/src/test/unit/com/mongodb/internal/mockito/InsufficientStubbingDetectorDemoTest.java b/driver-core/src/test/unit/com/mongodb/internal/mockito/InsufficientStubbingDetectorDemoTest.java index 5d8bd8e61b1..9142a097678 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/mockito/InsufficientStubbingDetectorDemoTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/mockito/InsufficientStubbingDetectorDemoTest.java @@ -15,6 +15,7 @@ */ package com.mongodb.internal.mockito; +import com.mongodb.ClusterFixture; import com.mongodb.internal.binding.ReadBinding; import com.mongodb.internal.operation.ListCollectionsOperation; import org.bson.BsonDocument; @@ -24,7 +25,6 @@ import org.mockito.Mockito; import org.mockito.internal.stubbing.answers.ThrowsException; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; @@ -40,33 +40,33 @@ void beforeEach() { @Test void mockObjectWithDefaultAnswer() { ReadBinding binding = Mockito.mock(ReadBinding.class); - assertThrows(NullPointerException.class, () -> operation.execute(binding, OPERATION_CONTEXT)); + assertThrows(NullPointerException.class, () -> operation.execute(binding, ClusterFixture.createOperationContext())); } @Test void mockObjectWithThrowsException() { ReadBinding binding = Mockito.mock(ReadBinding.class, new ThrowsException(new AssertionError("Insufficient stubbing for " + ReadBinding.class))); - assertThrows(AssertionError.class, () -> operation.execute(binding, OPERATION_CONTEXT)); + assertThrows(AssertionError.class, () -> operation.execute(binding, ClusterFixture.createOperationContext())); } @Test void mockObjectWithInsufficientStubbingDetector() { ReadBinding binding = MongoMockito.mock(ReadBinding.class); - assertThrows(AssertionError.class, () -> operation.execute(binding, OPERATION_CONTEXT)); + assertThrows(AssertionError.class, () -> operation.execute(binding, ClusterFixture.createOperationContext())); } @Test void stubbingWithThrowsException() { ReadBinding binding = Mockito.mock(ReadBinding.class, new ThrowsException(new AssertionError("Unfortunately, you cannot do stubbing"))); - assertThrows(AssertionError.class, () -> when(binding.getReadConnectionSource(OPERATION_CONTEXT)).thenReturn(null)); + assertThrows(AssertionError.class, () -> when(binding.getReadConnectionSource(ClusterFixture.createOperationContext())).thenReturn(null)); } @Test void stubbingWithInsufficientStubbingDetector() { MongoMockito.mock(ReadBinding.class, bindingMock -> - when(bindingMock.getReadConnectionSource(OPERATION_CONTEXT)).thenReturn(null) + when(bindingMock.getReadConnectionSource(ClusterFixture.createOperationContext())).thenReturn(null) ); } } diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/AsyncOperationHelperSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/operation/AsyncOperationHelperSpecification.groovy index d573822cab7..6080f8bb727 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/AsyncOperationHelperSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/AsyncOperationHelperSpecification.groovy @@ -36,7 +36,7 @@ import org.bson.codecs.BsonDocumentCodec import org.bson.codecs.Decoder import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ReadPreference.primary import static com.mongodb.internal.operation.AsyncOperationHelper.CommandReadTransformerAsync import static com.mongodb.internal.operation.AsyncOperationHelper.executeCommandAsync @@ -74,7 +74,7 @@ class AsyncOperationHelperSpecification extends Specification { _ * getDescription() >> connectionDescription } - def operationContext = OPERATION_CONTEXT.withSessionContext( + def operationContext = createOperationContext().withSessionContext( Stub(SessionContext) { hasSession() >> true hasActiveTransaction() >> false @@ -116,7 +116,7 @@ class AsyncOperationHelperSpecification extends Specification { def connectionDescription = Stub(ConnectionDescription) when: - executeCommandAsync(asyncWriteBinding, OPERATION_CONTEXT, dbName, command, connection, { t, conn -> t }, callback) + executeCommandAsync(asyncWriteBinding, createOperationContext(), dbName, command, connection, { t, conn -> t }, callback) then: _ * connection.getDescription() >> connectionDescription @@ -143,7 +143,7 @@ class AsyncOperationHelperSpecification extends Specification { def connectionDescription = Stub(ConnectionDescription) when: - executeRetryableReadAsync(asyncReadBinding, OPERATION_CONTEXT, dbName, commandCreator, decoder, function, false, callback) + executeRetryableReadAsync(asyncReadBinding, createOperationContext(), dbName, commandCreator, decoder, function, false, callback) then: _ * connection.getDescription() >> connectionDescription diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/ClientBulkWriteOperationTest.java b/driver-core/src/test/unit/com/mongodb/internal/operation/ClientBulkWriteOperationTest.java index 5de1992b69d..18a66816abf 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/ClientBulkWriteOperationTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/ClientBulkWriteOperationTest.java @@ -124,7 +124,7 @@ void shouldIgnoreSuccessfulCursorResultWhenVerboseResultIsFalse() { false, getDefaultCodecRegistry()); //when - ClientBulkWriteResult result = op.execute(binding, ClusterFixture.OPERATION_CONTEXT); + ClientBulkWriteResult result = op.execute(binding, ClusterFixture.createOperationContext()); //then assertEquals( @@ -176,7 +176,7 @@ void shouldUseDefaultNumberOfModifiedDocumentsWhenMissingInCursor() { false, getDefaultCodecRegistry()); //when - ClientBulkWriteResult result = op.execute(binding, ClusterFixture.OPERATION_CONTEXT); + ClientBulkWriteResult result = op.execute(binding, ClusterFixture.createOperationContext()); //then assertEquals(1, result.getInsertedCount()); diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/CommitTransactionOperationUnitSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/operation/CommitTransactionOperationUnitSpecification.groovy index 75ed9e6c5f3..aa4db2372ff 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/CommitTransactionOperationUnitSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/CommitTransactionOperationUnitSpecification.groovy @@ -27,7 +27,7 @@ import com.mongodb.internal.binding.WriteBinding import com.mongodb.internal.connection.OperationContext import com.mongodb.internal.session.SessionContext -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext class CommitTransactionOperationUnitSpecification extends OperationUnitSpecification { def 'should add UnknownTransactionCommitResult error label to MongoTimeoutException'() { @@ -42,7 +42,7 @@ class CommitTransactionOperationUnitSpecification extends OperationUnitSpecifica def operation = new CommitTransactionOperation(WriteConcern.ACKNOWLEDGED) when: - operation.execute(writeBinding, OPERATION_CONTEXT.withSessionContext(sessionContext)) + operation.execute(writeBinding, createOperationContext().withSessionContext(sessionContext)) then: def e = thrown(MongoTimeoutException) @@ -64,7 +64,7 @@ class CommitTransactionOperationUnitSpecification extends OperationUnitSpecifica def callback = new FutureResultCallback() when: - operation.executeAsync(writeBinding, OPERATION_CONTEXT.withSessionContext(sessionContext), callback) + operation.executeAsync(writeBinding, createOperationContext().withSessionContext(sessionContext), callback) callback.get() then: diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/CursorResourceManagerTest.java b/driver-core/src/test/unit/com/mongodb/internal/operation/CursorResourceManagerTest.java index 68b3bf7f606..26fd6e6eab5 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/CursorResourceManagerTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/CursorResourceManagerTest.java @@ -15,6 +15,7 @@ */ package com.mongodb.internal.operation; +import com.mongodb.ClusterFixture; import com.mongodb.MongoNamespace; import com.mongodb.ServerCursor; import com.mongodb.internal.binding.AsyncConnectionSource; @@ -24,7 +25,6 @@ import com.mongodb.internal.mockito.MongoMockito; import org.junit.jupiter.api.Test; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.Mockito.when; @@ -50,12 +50,12 @@ void doClose(final OperationContext operationContext) { cursorResourceManager.tryStartOperation(); try { assertDoesNotThrow(() -> { - cursorResourceManager.close(OPERATION_CONTEXT); - cursorResourceManager.close(OPERATION_CONTEXT); + cursorResourceManager.close(ClusterFixture.createOperationContext()); + cursorResourceManager.close(ClusterFixture.createOperationContext()); cursorResourceManager.setServerCursor(null); }); } finally { - cursorResourceManager.endOperation(OPERATION_CONTEXT); + cursorResourceManager.endOperation(ClusterFixture.createOperationContext()); } } } diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/ListCollectionsOperationTest.java b/driver-core/src/test/unit/com/mongodb/internal/operation/ListCollectionsOperationTest.java index de1bfe405ed..ca7730ff2b6 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/ListCollectionsOperationTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/ListCollectionsOperationTest.java @@ -15,6 +15,7 @@ */ package com.mongodb.internal.operation; +import com.mongodb.ClusterFixture; import com.mongodb.MongoNamespace; import com.mongodb.ReadPreference; import com.mongodb.ServerAddress; @@ -39,7 +40,6 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.assertions.Assertions.assertNotNull; import static com.mongodb.internal.mockito.MongoMockito.mock; import static java.util.Collections.emptyList; @@ -99,7 +99,7 @@ void authorizedCollectionsIsFalseByDefault() { } private BsonDocument executeOperationAndCaptureCommand() { - operation.execute(mocks.readBinding(), OPERATION_CONTEXT); + operation.execute(mocks.readBinding(), ClusterFixture.createOperationContext()); ArgumentCaptor commandCaptor = forClass(BsonDocument.class); verify(mocks.connection()).command(any(), commandCaptor.capture(), any(), any(), any(), any()); return commandCaptor.getValue(); diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/OperationHelperSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/operation/OperationHelperSpecification.groovy index fd9786e8dbf..ac51ebcede5 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/OperationHelperSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/OperationHelperSpecification.groovy @@ -32,7 +32,7 @@ import org.bson.BsonArray import org.bson.BsonDocument import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.WriteConcern.ACKNOWLEDGED import static com.mongodb.WriteConcern.UNACKNOWLEDGED import static com.mongodb.connection.ServerConnectionState.CONNECTED @@ -108,8 +108,8 @@ class OperationHelperSpecification extends Specification { } expect: - canRetryRead(retryableServerDescription, OPERATION_CONTEXT.withSessionContext(noTransactionSessionContext)) - !canRetryRead(retryableServerDescription, OPERATION_CONTEXT.withSessionContext(activeTransactionSessionContext)) + canRetryRead(retryableServerDescription, createOperationContext().withSessionContext(noTransactionSessionContext)) + !canRetryRead(retryableServerDescription, createOperationContext().withSessionContext(activeTransactionSessionContext)) } diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/OperationUnitSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/operation/OperationUnitSpecification.groovy index ec5cb74156f..52934c3bfad 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/OperationUnitSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/OperationUnitSpecification.groovy @@ -41,7 +41,7 @@ import spock.lang.Specification import java.util.concurrent.TimeUnit -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext class OperationUnitSpecification extends Specification { @@ -97,7 +97,7 @@ class OperationUnitSpecification extends Specification { def testSyncOperation(operation, List serverVersion, result, Boolean checkCommand=true, BsonDocument expectedCommand=null, Boolean checkSecondaryOk=false, ReadPreference readPreference=ReadPreference.primary()) { - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() .withSessionContext(Stub(SessionContext) { hasActiveTransaction() >> false getReadConcern() >> ReadConcern.DEFAULT @@ -151,7 +151,7 @@ class OperationUnitSpecification extends Specification { Boolean checkCommand=true, BsonDocument expectedCommand=null, Boolean checkSecondaryOk=false, ReadPreference readPreference=ReadPreference.primary()) { - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() .withSessionContext(Stub(SessionContext) { hasActiveTransaction() >> false getReadConcern() >> ReadConcern.DEFAULT diff --git a/driver-core/src/test/unit/com/mongodb/internal/operation/SyncOperationHelperSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/operation/SyncOperationHelperSpecification.groovy index bd9bd2f2578..8b66947c026 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/operation/SyncOperationHelperSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/operation/SyncOperationHelperSpecification.groovy @@ -34,7 +34,7 @@ import org.bson.codecs.BsonDocumentCodec import org.bson.codecs.Decoder import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ReadPreference.primary import static com.mongodb.internal.operation.OperationUnitSpecification.getMaxWireVersionForServerVersion import static com.mongodb.internal.operation.SyncOperationHelper.CommandReadTransformer @@ -61,7 +61,7 @@ class SyncOperationHelperSpecification extends Specification { def connectionDescription = Stub(ConnectionDescription) when: - executeCommand(writeBinding, OPERATION_CONTEXT, dbName, command, decoder, function) + executeCommand(writeBinding, createOperationContext(), dbName, command, decoder, function) then: _ * connection.getDescription() >> connectionDescription @@ -71,7 +71,7 @@ class SyncOperationHelperSpecification extends Specification { def 'should retry with retryable exception'() { given: - def operationContext = OPERATION_CONTEXT + def operationContext = createOperationContext() .withSessionContext(Stub(SessionContext) { hasSession() >> true hasActiveTransaction() >> false @@ -132,7 +132,7 @@ class SyncOperationHelperSpecification extends Specification { def connectionDescription = Stub(ConnectionDescription) when: - executeRetryableRead(readBinding, OPERATION_CONTEXT, dbName, commandCreator, decoder, function, false) + executeRetryableRead(readBinding, createOperationContext(), dbName, commandCreator, decoder, function, false) then: _ * connection.getDescription() >> connectionDescription diff --git a/driver-core/src/test/unit/com/mongodb/internal/session/BaseClientSessionImplTest.java b/driver-core/src/test/unit/com/mongodb/internal/session/BaseClientSessionImplTest.java index c7fc1d73e20..495523f90a3 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/session/BaseClientSessionImplTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/session/BaseClientSessionImplTest.java @@ -17,10 +17,10 @@ package com.mongodb.internal.session; import com.mongodb.ClientSessionOptions; +import com.mongodb.ClusterFixture; import com.mongodb.session.ClientSession; import org.junit.jupiter.api.Test; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.getCluster; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -28,7 +28,7 @@ class BaseClientSessionImplTest { @Test void shouldNotCheckoutServerSessionIfNeverRequested() { - ServerSessionPool serverSessionPool = new ServerSessionPool(getCluster(), OPERATION_CONTEXT); + ServerSessionPool serverSessionPool = new ServerSessionPool(getCluster(), ClusterFixture.createOperationContext()); ClientSession clientSession = new BaseClientSessionImpl(serverSessionPool, new Object(), ClientSessionOptions.builder().build()); assertEquals(0, serverSessionPool.getInUseCount()); @@ -40,7 +40,7 @@ void shouldNotCheckoutServerSessionIfNeverRequested() { @Test void shouldDelayServerSessionCheckoutUntilRequested() { - ServerSessionPool serverSessionPool = new ServerSessionPool(getCluster(), OPERATION_CONTEXT); + ServerSessionPool serverSessionPool = new ServerSessionPool(getCluster(), ClusterFixture.createOperationContext()); ClientSession clientSession = new BaseClientSessionImpl(serverSessionPool, new Object(), ClientSessionOptions.builder().build()); assertEquals(0, serverSessionPool.getInUseCount()); diff --git a/driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolSpecification.groovy index 19bfa994200..0fc4564d322 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/session/ServerSessionPoolSpecification.groovy @@ -32,7 +32,7 @@ import org.bson.BsonDocument import org.bson.codecs.BsonDocumentCodec import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext import static com.mongodb.ClusterFixture.TIMEOUT_SETTINGS import static com.mongodb.ClusterFixture.getServerApi import static com.mongodb.ReadPreference.primaryPreferred @@ -120,7 +120,7 @@ class ServerSessionPoolSpecification extends Specification { millis() >>> [0, MINUTES.toMillis(29) + 1, ] } - def pool = new ServerSessionPool(cluster, OPERATION_CONTEXT, clock) + def pool = new ServerSessionPool(cluster, createOperationContext(), clock) def sessionOne = pool.get() when: @@ -146,7 +146,7 @@ class ServerSessionPoolSpecification extends Specification { def clock = Stub(ServerSessionPool.Clock) { millis() >>> [0, 0, 0] } - def pool = new ServerSessionPool(cluster, OPERATION_CONTEXT, clock) + def pool = new ServerSessionPool(cluster, createOperationContext(), clock) def session = pool.get() when: @@ -165,7 +165,7 @@ class ServerSessionPoolSpecification extends Specification { def clock = Stub(ServerSessionPool.Clock) { millis() >> 42 } - def pool = new ServerSessionPool(cluster, OPERATION_CONTEXT, clock) + def pool = new ServerSessionPool(cluster, createOperationContext(), clock) when: def session = pool.get() as ServerSessionPool.ServerSessionImpl @@ -187,7 +187,7 @@ class ServerSessionPoolSpecification extends Specification { def clock = Stub(ServerSessionPool.Clock) { millis() >> 42 } - def pool = new ServerSessionPool(cluster, OPERATION_CONTEXT, clock) + def pool = new ServerSessionPool(cluster, createOperationContext(), clock) when: def session = pool.get() as ServerSessionPool.ServerSessionImpl diff --git a/driver-legacy/src/main/com/mongodb/MongoClientOptions.java b/driver-legacy/src/main/com/mongodb/MongoClientOptions.java index 1f19fba3484..2fcfba0c806 100644 --- a/driver-legacy/src/main/com/mongodb/MongoClientOptions.java +++ b/driver-legacy/src/main/com/mongodb/MongoClientOptions.java @@ -465,6 +465,18 @@ public boolean getRetryReads() { return wrapped.getRetryReads(); } + /** + * Returns whether overload retargeting is enabled. + * See {@link MongoClientSettings.Builder#enableOverloadRetargeting(boolean)} for more information. + * + * @return the enableOverloadRetargeting value + * @see MongoClientSettings.Builder#enableOverloadRetargeting(boolean) + * @since 5.7 + */ + public boolean getEnableOverloadRetargeting() { + return wrapped.getEnableOverloadRetargeting(); + } + /** *

    The read concern to use.

    * @@ -1049,6 +1061,20 @@ public Builder retryReads(final boolean retryReads) { return this; } + /** + * Sets whether to enable overload retargeting. + * See {@link MongoClientSettings.Builder#enableOverloadRetargeting(boolean)} for more information. + * + * @param enableOverloadRetargeting whether to enable overload retargeting + * @return {@code this} + * @see #getEnableOverloadRetargeting() + * @since 5.7 + */ + public Builder enableOverloadRetargeting(final boolean enableOverloadRetargeting) { + wrapped.enableOverloadRetargeting(enableOverloadRetargeting); + return this; + } + /** * Sets the read concern. * diff --git a/driver-legacy/src/main/com/mongodb/MongoClientURI.java b/driver-legacy/src/main/com/mongodb/MongoClientURI.java index e471bbf1686..fc8f70651c8 100644 --- a/driver-legacy/src/main/com/mongodb/MongoClientURI.java +++ b/driver-legacy/src/main/com/mongodb/MongoClientURI.java @@ -151,6 +151,9 @@ * Defaults to false. *
  • {@code retryReads=true|false}. If true the driver will retry supported read operations if they fail due to a network error. * Defaults to false.
  • + *
  • {@code enableOverloadRetargeting=true|false}. If true the driver may route a request to a different server on a subsequent + * retry attempt if the previously used server is overloaded. Does not take effect for + * {@linkplain com.mongodb.connection.ClusterType#SHARDED sharded clusters}. Defaults to false.
  • * * * @@ -218,6 +221,9 @@ * Defaults to true. *
  • {@code retryReads=true|false}. If true the driver will retry supported read operations if they fail due to a network error. * Defaults to true.
  • + *
  • {@code enableOverloadRetargeting=true|false}. If true the driver may route a request to a different server on a subsequent + * retry attempt if the previously used server is overloaded. Does not take effect for + * {@linkplain com.mongodb.connection.ClusterType#SHARDED sharded clusters}. Defaults to false.
  • *
  • {@code uuidRepresentation=unspecified|standard|javaLegacy|csharpLegacy|pythonLegacy}. See * {@link MongoClientOptions#getUuidRepresentation()} for documentation of semantics of this parameter. Defaults to "javaLegacy", but * will change to "unspecified" in the next major release.
  • @@ -387,6 +393,11 @@ public MongoClientOptions getOptions() { builder.retryReads(retryReads); } + Boolean enableOverloadRetargeting = proxied.getEnableOverloadRetargeting(); + if (enableOverloadRetargeting != null) { + builder.enableOverloadRetargeting(enableOverloadRetargeting); + } + Integer maxConnectionPoolSize = proxied.getMaxConnectionPoolSize(); if (maxConnectionPoolSize != null) { builder.connectionsPerHost(maxConnectionPoolSize); diff --git a/driver-legacy/src/test/functional/com/mongodb/DBTest.java b/driver-legacy/src/test/functional/com/mongodb/DBTest.java index cf44573a2b4..b483e326081 100644 --- a/driver-legacy/src/test/functional/com/mongodb/DBTest.java +++ b/driver-legacy/src/test/functional/com/mongodb/DBTest.java @@ -31,7 +31,6 @@ import java.util.Locale; import java.util.UUID; -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT; import static com.mongodb.ClusterFixture.disableMaxTimeFailPoint; import static com.mongodb.ClusterFixture.enableMaxTimeFailPoint; import static com.mongodb.ClusterFixture.getBinding; @@ -345,7 +344,7 @@ public void shouldApplyUuidRepresentationToCommandEncodingAndDecoding() { BsonDocument getCollectionInfo(final String collectionName) { return new ListCollectionsOperation<>(getDefaultDatabaseName(), new BsonDocumentCodec()) - .filter(new BsonDocument("name", new BsonString(collectionName))).execute(getBinding(), OPERATION_CONTEXT).next().get(0); + .filter(new BsonDocument("name", new BsonString(collectionName))).execute(getBinding(), ClusterFixture.createOperationContext()).next().get(0); } private boolean isCapped(final DBCollection collection) { diff --git a/driver-legacy/src/test/functional/com/mongodb/LegacyMixedBulkWriteOperationSpecification.groovy b/driver-legacy/src/test/functional/com/mongodb/LegacyMixedBulkWriteOperationSpecification.groovy index 6a9c511c3bc..2db1da67e22 100644 --- a/driver-legacy/src/test/functional/com/mongodb/LegacyMixedBulkWriteOperationSpecification.groovy +++ b/driver-legacy/src/test/functional/com/mongodb/LegacyMixedBulkWriteOperationSpecification.groovy @@ -184,7 +184,7 @@ class LegacyMixedBulkWriteOperationSpecification extends OperationFunctionalSpec def insert = new InsertRequest(new BsonDocument('_id', new BsonInt32(1))) def binding = getBinding() createBulkWriteOperationForInsert(getNamespace(), true, ACKNOWLEDGED, false, asList(insert)) - .execute(binding, ClusterFixture.getOperationContext(binding.getReadPreference())) + .execute(binding, ClusterFixture.createOperationContext(binding.getReadPreference())) def replacement = new UpdateRequest(new BsonDocument('_id', new BsonInt32(1)), new BsonDocument('_id', new BsonInt32(1)).append('x', new BsonInt32(1)), REPLACE) diff --git a/driver-legacy/src/test/unit/com/mongodb/MongoClientOptionsSpecification.groovy b/driver-legacy/src/test/unit/com/mongodb/MongoClientOptionsSpecification.groovy index ae1d332674c..057a60cf65f 100644 --- a/driver-legacy/src/test/unit/com/mongodb/MongoClientOptionsSpecification.groovy +++ b/driver-legacy/src/test/unit/com/mongodb/MongoClientOptionsSpecification.groovy @@ -46,6 +46,7 @@ class MongoClientOptionsSpecification extends Specification { options.getWriteConcern() == WriteConcern.ACKNOWLEDGED options.getRetryWrites() options.getRetryReads() + !options.getEnableOverloadRetargeting() options.getCodecRegistry() == MongoClientSettings.defaultCodecRegistry options.getUuidRepresentation() == UuidRepresentation.UNSPECIFIED options.getMinConnectionsPerHost() == 0 @@ -116,6 +117,7 @@ class MongoClientOptionsSpecification extends Specification { .readPreference(ReadPreference.secondary()) .retryWrites(true) .retryReads(false) + .enableOverloadRetargeting(true) .writeConcern(WriteConcern.JOURNALED) .readConcern(ReadConcern.MAJORITY) .minConnectionsPerHost(30) @@ -162,6 +164,7 @@ class MongoClientOptionsSpecification extends Specification { options.getServerSelector() == serverSelector options.getRetryWrites() !options.getRetryReads() + options.getEnableOverloadRetargeting() options.getServerSelectionTimeout() == 150 options.getTimeout() == 10_000 options.getMaxWaitTime() == 200 @@ -318,6 +321,7 @@ class MongoClientOptionsSpecification extends Specification { .applicationName('appName') .readPreference(ReadPreference.secondary()) .retryReads(true) + .enableOverloadRetargeting(true) .uuidRepresentation(UuidRepresentation.STANDARD) .writeConcern(WriteConcern.JOURNALED) .minConnectionsPerHost(30) @@ -619,6 +623,7 @@ class MongoClientOptionsSpecification extends Specification { .writeConcern(WriteConcern.JOURNALED) .retryWrites(true) .retryReads(true) + .enableOverloadRetargeting(true) .uuidRepresentation(UuidRepresentation.STANDARD) .minConnectionsPerHost(30) .connectionsPerHost(500) diff --git a/driver-legacy/src/test/unit/com/mongodb/MongoClientURISpecification.groovy b/driver-legacy/src/test/unit/com/mongodb/MongoClientURISpecification.groovy index 241ac958c8a..1801b7c4749 100644 --- a/driver-legacy/src/test/unit/com/mongodb/MongoClientURISpecification.groovy +++ b/driver-legacy/src/test/unit/com/mongodb/MongoClientURISpecification.groovy @@ -131,6 +131,7 @@ class MongoClientURISpecification extends Specification { + 'heartbeatFrequencyMS=20000&' + 'retryWrites=true&' + 'retryReads=true&' + + 'enableOverloadRetargeting=true&' + 'uuidRepresentation=csharpLegacy&' + 'appName=app1&' + 'timeoutMS=10000') @@ -158,6 +159,7 @@ class MongoClientURISpecification extends Specification { options.getHeartbeatFrequency() == 20000 options.getRetryWrites() options.getRetryReads() + options.getEnableOverloadRetargeting() options.getUuidRepresentation() == UuidRepresentation.C_SHARP_LEGACY options.getApplicationName() == 'app1' } @@ -178,6 +180,7 @@ class MongoClientURISpecification extends Specification { !options.isSslEnabled() options.getRetryWrites() options.getRetryReads() + !options.getEnableOverloadRetargeting() options.getUuidRepresentation() == UuidRepresentation.UNSPECIFIED } @@ -188,6 +191,7 @@ class MongoClientURISpecification extends Specification { .readPreference(ReadPreference.secondary()) .retryWrites(true) .retryReads(true) + .enableOverloadRetargeting(true) .writeConcern(WriteConcern.JOURNALED) .minConnectionsPerHost(30) .connectionsPerHost(500) @@ -220,6 +224,7 @@ class MongoClientURISpecification extends Specification { options.getWriteConcern() == WriteConcern.JOURNALED options.getRetryWrites() options.getRetryReads() + options.getEnableOverloadRetargeting() options.getTimeout() == 10_000 options.getServerSelectionTimeout() == 150 options.getMaxWaitTime() == 200 @@ -314,24 +319,33 @@ class MongoClientURISpecification extends Specification { def 'should respect MongoClientOptions builder'() { given: - def uri = new MongoClientURI('mongodb://localhost/', MongoClientOptions.builder().connectionsPerHost(200)) + def uri = new MongoClientURI('mongodb://localhost/', MongoClientOptions.builder() + .connectionsPerHost(200) + .enableOverloadRetargeting(true)) when: def options = uri.getOptions() then: options.getConnectionsPerHost() == 200 + options.getEnableOverloadRetargeting() } def 'should override MongoClientOptions builder'() { given: - def uri = new MongoClientURI('mongodb://localhost/?maxPoolSize=250', MongoClientOptions.builder().connectionsPerHost(200)) + def uri = new MongoClientURI('mongodb://localhost/?' + + 'maxPoolSize=250' + + '&enableOverloadRetargeting=false', + MongoClientOptions.builder() + .connectionsPerHost(200) + .enableOverloadRetargeting(true)) when: def options = uri.getOptions() then: options.getConnectionsPerHost() == 250 + !options.getEnableOverloadRetargeting() } def 'should be equal to another MongoClientURI with the same string values'() { diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/OperationExecutorImpl.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/OperationExecutorImpl.java index ef18c2c6b1f..35ff27f79ec 100644 --- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/OperationExecutorImpl.java +++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/OperationExecutorImpl.java @@ -216,7 +216,8 @@ private OperationContext getOperationContext(final RequestContext requestContext createTimeoutContext(session, timeoutSettings), TracingManager.NO_OP, mongoClient.getSettings().getServerApi(), - commandName); + commandName, + new OperationContext.ServerDeprioritization(mongoClient.getSettings().getEnableOverloadRetargeting())); } private ReadPreference getReadPreferenceForBinding(final ReadPreference readPreference, @Nullable final ClientSession session) { diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/RetryableReadsProseTest.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/RetryableReadsProseTest.java index 84dd0d733bf..bb748f00601 100644 --- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/RetryableReadsProseTest.java +++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/RetryableReadsProseTest.java @@ -16,57 +16,14 @@ package com.mongodb.reactivestreams.client; -import com.mongodb.client.MongoCursor; -import com.mongodb.client.RetryableWritesProseTest; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.AbstractRetryableReadsProseTest; +import com.mongodb.client.MongoClient; import com.mongodb.reactivestreams.client.syncadapter.SyncMongoClient; -import org.bson.Document; -import org.junit.jupiter.api.Test; -import static com.mongodb.client.model.Filters.eq; - -/** - * - * Prose Tests. - */ -final class RetryableReadsProseTest { - /** - * - * 1. PoolClearedError Retryability Test. - */ - @Test - void poolClearedExceptionMustBeRetryable() throws Exception { - RetryableWritesProseTest.poolClearedExceptionMustBeRetryable( - SyncMongoClient::new, - mongoCollection -> mongoCollection.find(eq(0)).iterator().hasNext(), "find", false); - } - - /** - * - * 2.1 Retryable Reads Are Retried on a Different mongos When One is Available. - */ - @Test - void retriesOnDifferentMongosWhenAvailable() { - RetryableWritesProseTest.retriesOnDifferentMongosWhenAvailable( - SyncMongoClient::new, - mongoCollection -> { - try (MongoCursor cursor = mongoCollection.find().iterator()) { - return cursor.hasNext(); - } - }, "find", false); - } - - /** - * - * 2.2 Retryable Reads Are Retried on the Same mongos When No Others are Available. - */ - @Test - void retriesOnSameMongosWhenAnotherNotAvailable() { - RetryableWritesProseTest.retriesOnSameMongosWhenAnotherNotAvailable( - SyncMongoClient::new, - mongoCollection -> { - try (MongoCursor cursor = mongoCollection.find().iterator()) { - return cursor.hasNext(); - } - }, "find", false); +final class RetryableReadsProseTest extends AbstractRetryableReadsProseTest { + @Override + protected MongoClient createClient(final MongoClientSettings settings) { + return new SyncMongoClient(settings); } } diff --git a/driver-reactive-streams/src/test/unit/com/mongodb/reactivestreams/client/internal/ClientSessionBindingSpecification.groovy b/driver-reactive-streams/src/test/unit/com/mongodb/reactivestreams/client/internal/ClientSessionBindingSpecification.groovy index cfe66a8031f..0fcbb5ac31a 100644 --- a/driver-reactive-streams/src/test/unit/com/mongodb/reactivestreams/client/internal/ClientSessionBindingSpecification.groovy +++ b/driver-reactive-streams/src/test/unit/com/mongodb/reactivestreams/client/internal/ClientSessionBindingSpecification.groovy @@ -16,6 +16,7 @@ package com.mongodb.reactivestreams.client.internal +import com.mongodb.ClusterFixture import com.mongodb.ReadPreference import com.mongodb.ServerAddress import com.mongodb.async.FutureResultCallback @@ -31,32 +32,34 @@ import com.mongodb.internal.connection.ServerTuple import com.mongodb.reactivestreams.client.ClientSession import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT +import static com.mongodb.ClusterFixture.createOperationContext class ClientSessionBindingSpecification extends Specification { def 'should return the session context from the connection source'() { given: def session = Stub(ClientSession) + def operationContext = ClusterFixture.createOperationContext() def wrappedBinding = Mock(AsyncClusterAwareReadWriteBinding); wrappedBinding.retain() >> wrappedBinding def binding = new ClientSessionBinding(session, false, wrappedBinding) when: def futureResultCallback = new FutureResultCallback() - binding.getReadConnectionSource(OPERATION_CONTEXT, futureResultCallback) + + binding.getReadConnectionSource(operationContext, futureResultCallback) then: - 1 * wrappedBinding.getReadConnectionSource(OPERATION_CONTEXT, _) >> { + 1 * wrappedBinding.getReadConnectionSource(operationContext, _) >> { it[1].onResult(Stub(AsyncConnectionSource), null) } when: futureResultCallback = new FutureResultCallback() - binding.getWriteConnectionSource(OPERATION_CONTEXT, futureResultCallback) + binding.getWriteConnectionSource(operationContext, futureResultCallback) then: - 1 * wrappedBinding.getWriteConnectionSource(OPERATION_CONTEXT, _) >> { + 1 * wrappedBinding.getWriteConnectionSource(operationContext, _) >> { it[1].onResult(Stub(AsyncConnectionSource), null) } } @@ -87,10 +90,10 @@ class ClientSessionBindingSpecification extends Specification { def wrappedBinding = createStubBinding() def binding = new ClientSessionBinding(session, true, wrappedBinding) def futureResultCallback = new FutureResultCallback() - binding.getReadConnectionSource(OPERATION_CONTEXT, futureResultCallback) + binding.getReadConnectionSource(createOperationContext(), futureResultCallback) def readConnectionSource = futureResultCallback.get() futureResultCallback = new FutureResultCallback() - binding.getWriteConnectionSource(OPERATION_CONTEXT, futureResultCallback) + binding.getWriteConnectionSource(createOperationContext(), futureResultCallback) def writeConnectionSource = futureResultCallback.get() when: diff --git a/driver-sync/src/main/com/mongodb/client/internal/MongoClientImpl.java b/driver-sync/src/main/com/mongodb/client/internal/MongoClientImpl.java index bbeb7419bc7..9ba2139f18c 100644 --- a/driver-sync/src/main/com/mongodb/client/internal/MongoClientImpl.java +++ b/driver-sync/src/main/com/mongodb/client/internal/MongoClientImpl.java @@ -105,7 +105,7 @@ public MongoClientImpl(final Cluster cluster, (SynchronousContextProvider) settings.getContextProvider(), autoEncryptionSettings == null ? null : createCrypt(settings, autoEncryptionSettings), this, operationExecutor, settings.getReadConcern(), settings.getReadPreference(), settings.getRetryReads(), - settings.getRetryWrites(), settings.getServerApi(), + settings.getRetryWrites(), settings.getEnableOverloadRetargeting(), settings.getServerApi(), new ServerSessionPool(cluster, TimeoutSettings.create(settings), settings.getServerApi()), TimeoutSettings.create(settings), settings.getUuidRepresentation(), settings.getWriteConcern(), new TracingManager(settings.getObservabilitySettings())); diff --git a/driver-sync/src/main/com/mongodb/client/internal/MongoClusterImpl.java b/driver-sync/src/main/com/mongodb/client/internal/MongoClusterImpl.java index 920feb1f986..b5604a7a846 100644 --- a/driver-sync/src/main/com/mongodb/client/internal/MongoClusterImpl.java +++ b/driver-sync/src/main/com/mongodb/client/internal/MongoClusterImpl.java @@ -104,6 +104,7 @@ final class MongoClusterImpl implements MongoCluster { private final ReadPreference readPreference; private final boolean retryReads; private final boolean retryWrites; + private final boolean enableOverloadRetargeting; @Nullable private final ServerApi serverApi; private final ServerSessionPool serverSessionPool; @@ -117,10 +118,9 @@ final class MongoClusterImpl implements MongoCluster { @Nullable final AutoEncryptionSettings autoEncryptionSettings, final Cluster cluster, final CodecRegistry codecRegistry, @Nullable final SynchronousContextProvider contextProvider, @Nullable final Crypt crypt, final Object originator, @Nullable final OperationExecutor operationExecutor, final ReadConcern readConcern, final ReadPreference readPreference, - final boolean retryReads, final boolean retryWrites, @Nullable final ServerApi serverApi, - final ServerSessionPool serverSessionPool, final TimeoutSettings timeoutSettings, final UuidRepresentation uuidRepresentation, - final WriteConcern writeConcern, - final TracingManager tracingManager) { + final boolean retryReads, final boolean retryWrites, final boolean enableOverloadRetargeting, + @Nullable final ServerApi serverApi, final ServerSessionPool serverSessionPool, final TimeoutSettings timeoutSettings, + final UuidRepresentation uuidRepresentation, final WriteConcern writeConcern, final TracingManager tracingManager) { this.autoEncryptionSettings = autoEncryptionSettings; this.cluster = cluster; this.codecRegistry = codecRegistry; @@ -132,6 +132,7 @@ final class MongoClusterImpl implements MongoCluster { this.readPreference = readPreference; this.retryReads = retryReads; this.retryWrites = retryWrites; + this.enableOverloadRetargeting = enableOverloadRetargeting; this.serverApi = serverApi; this.serverSessionPool = serverSessionPool; this.timeoutSettings = timeoutSettings; @@ -180,35 +181,35 @@ public Long getTimeout(final TimeUnit timeUnit) { @Override public MongoCluster withCodecRegistry(final CodecRegistry codecRegistry) { return new MongoClusterImpl(autoEncryptionSettings, cluster, codecRegistry, contextProvider, crypt, originator, - operationExecutor, readConcern, readPreference, retryReads, retryWrites, serverApi, serverSessionPool, timeoutSettings, + operationExecutor, readConcern, readPreference, retryReads, retryWrites, enableOverloadRetargeting, serverApi, serverSessionPool, timeoutSettings, uuidRepresentation, writeConcern, tracingManager); } @Override public MongoCluster withReadPreference(final ReadPreference readPreference) { return new MongoClusterImpl(autoEncryptionSettings, cluster, codecRegistry, contextProvider, crypt, originator, - operationExecutor, readConcern, readPreference, retryReads, retryWrites, serverApi, serverSessionPool, timeoutSettings, + operationExecutor, readConcern, readPreference, retryReads, retryWrites, enableOverloadRetargeting, serverApi, serverSessionPool, timeoutSettings, uuidRepresentation, writeConcern, tracingManager); } @Override public MongoCluster withWriteConcern(final WriteConcern writeConcern) { return new MongoClusterImpl(autoEncryptionSettings, cluster, codecRegistry, contextProvider, crypt, originator, - operationExecutor, readConcern, readPreference, retryReads, retryWrites, serverApi, serverSessionPool, timeoutSettings, + operationExecutor, readConcern, readPreference, retryReads, retryWrites, enableOverloadRetargeting, serverApi, serverSessionPool, timeoutSettings, uuidRepresentation, writeConcern, tracingManager); } @Override public MongoCluster withReadConcern(final ReadConcern readConcern) { return new MongoClusterImpl(autoEncryptionSettings, cluster, codecRegistry, contextProvider, crypt, originator, - operationExecutor, readConcern, readPreference, retryReads, retryWrites, serverApi, serverSessionPool, timeoutSettings, + operationExecutor, readConcern, readPreference, retryReads, retryWrites, enableOverloadRetargeting, serverApi, serverSessionPool, timeoutSettings, uuidRepresentation, writeConcern, tracingManager); } @Override public MongoCluster withTimeout(final long timeout, final TimeUnit timeUnit) { return new MongoClusterImpl(autoEncryptionSettings, cluster, codecRegistry, contextProvider, crypt, originator, - operationExecutor, readConcern, readPreference, retryReads, retryWrites, serverApi, serverSessionPool, + operationExecutor, readConcern, readPreference, retryReads, retryWrites, enableOverloadRetargeting, serverApi, serverSessionPool, timeoutSettings.withTimeout(timeout, timeUnit), uuidRepresentation, writeConcern, tracingManager); } @@ -530,7 +531,8 @@ private OperationContext getOperationContext(final ClientSession session, final createTimeoutContext(session, executorTimeoutSettings), tracingManager, serverApi, - commandName); + commandName, + new OperationContext.ServerDeprioritization(enableOverloadRetargeting)); } private RequestContext getRequestContext() { @@ -591,9 +593,9 @@ ClientSession getClientSession(@Nullable final ClientSession clientSessionFromOp * Create a tracing span for the given operation, and set it on operation context. * * @param actualClientSession the session that the operation is part of - * @param operationContext the operation context for the operation - * @param commandName the name of the command - * @param namespace the namespace of the command + * @param operationContext the operation context for the operation + * @param commandName the name of the command + * @param namespace the namespace of the command * @return the created span, or null if tracing is not enabled */ @Nullable diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsProseTest.java new file mode 100644 index 00000000000..ede7b099662 --- /dev/null +++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractRetryableReadsProseTest.java @@ -0,0 +1,224 @@ +/* + * 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; + +import com.mongodb.MongoClientSettings; +import com.mongodb.ReadPreference; +import com.mongodb.ServerAddress; +import com.mongodb.client.test.CollectionHelper; +import com.mongodb.event.CommandFailedEvent; +import com.mongodb.event.CommandSucceededEvent; +import com.mongodb.internal.connection.TestCommandListener; +import org.bson.BsonDocument; +import org.bson.Document; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet; +import static com.mongodb.ClusterFixture.serverVersionAtLeast; +import static com.mongodb.MongoException.RETRYABLE_ERROR_LABEL; +import static com.mongodb.MongoException.SYSTEM_OVERLOADED_ERROR_LABEL; +import static com.mongodb.client.Fixture.getDefaultDatabaseName; +import static com.mongodb.client.Fixture.getMongoClientSettingsBuilder; +import static com.mongodb.client.Fixture.getPrimary; +import static com.mongodb.client.model.Filters.eq; +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +/** + * + * Prose Tests. + */ +public abstract class AbstractRetryableReadsProseTest { + + private static final String COLLECTION_NAME = "test"; + + protected abstract MongoClient createClient(MongoClientSettings settings); + + @AfterEach + void afterEach() { + CollectionHelper.dropDatabase(getDefaultDatabaseName()); + } + + /** + * + * 1. PoolClearedError Retryability Test. + */ + @Test + void poolClearedExceptionMustBeRetryable() throws Exception { + RetryableWritesProseTest.poolClearedExceptionMustBeRetryable(this::createClient, + mongoCollection -> mongoCollection.find(eq(0)).iterator().hasNext(), "find", false); + } + + /** + * + * 2.1 Retryable Reads Are Retried on a Different mongos When One is Available. + */ + @Test + void retriesOnDifferentMongosWhenAvailable() { + RetryableWritesProseTest.retriesOnDifferentMongosWhenAvailable(this::createClient, + mongoCollection -> { + try (MongoCursor cursor = mongoCollection.find().iterator()) { + return cursor.hasNext(); + } + }, "find", false); + } + + /** + * + * 2.2 Retryable Reads Are Retried on the Same mongos When No Others are Available. + */ + @Test + void retriesOnSameMongosWhenAnotherNotAvailable() { + RetryableWritesProseTest.retriesOnSameMongosWhenAnotherNotAvailable(this::createClient, + mongoCollection -> { + try (MongoCursor cursor = mongoCollection.find().iterator()) { + return cursor.hasNext(); + } + }, "find", false); + } + + /** + * + * 3.1 Retryable Reads Caused by Overload Errors Are Retried on a Different Replicaset Server When One is Available and enableOverloadRetargeting is enabled. + */ + @Test + void overloadErrorRetriedOnDifferentReplicaSetServer() throws InterruptedException { + //given + assumeTrue(serverVersionAtLeast(4, 4)); + assumeTrue(isDiscoverableReplicaSet()); + ServerAddress primaryServerAddress = getPrimary(); + TestCommandListener commandListener = new TestCommandListener(asList("commandFailedEvent", "commandSucceededEvent"), emptyList()); + BsonDocument configureFailPoint = BsonDocument.parse( + "{\n" + + " configureFailPoint: \"failCommand\",\n" + + " mode: { times: 1 },\n" + + " data: {\n" + + " failCommands: [\"find\"],\n" + + " errorLabels: ['" + RETRYABLE_ERROR_LABEL + "', '" + SYSTEM_OVERLOADED_ERROR_LABEL + "'],\n" + + " errorCode: 6\n" + + " }\n" + + "}\n"); + + try (FailPoint ignored = FailPoint.enable(configureFailPoint, primaryServerAddress); + MongoClient client = createClient(getMongoClientSettingsBuilder() + .retryReads(true) + .readPreference(ReadPreference.primaryPreferred()) + .enableOverloadRetargeting(true) + .addCommandListener(commandListener) + .build())) { + + MongoCollection collection = client.getDatabase(getDefaultDatabaseName()) + .getCollection(COLLECTION_NAME); + commandListener.reset(); + + //when + collection.find().first(); + + //then + List commandFailedEvents = commandListener.getCommandFailedEvents(); + assertEquals(1, commandFailedEvents.size()); + List commandSucceededEvents = commandListener.getCommandSucceededEvents(); + assertEquals(1, commandSucceededEvents.size()); + + ServerAddress failedServer = commandFailedEvents.get(0).getConnectionDescription().getServerAddress(); + ServerAddress succeededServer = commandSucceededEvents.get(0).getConnectionDescription().getServerAddress(); + + assertNotEquals(failedServer, succeededServer, + format("Expected retry on different server but both were %s", failedServer)); + } + } + + /** + * + * 3.2 Retryable Reads Caused by Non-Overload Errors Are Retried on the Same Replicaset Server. + */ + @Test + void nonOverloadErrorRetriedOnSameReplicaSetServer() throws InterruptedException { + BsonDocument configureFailPoint = BsonDocument.parse( + "{\n" + + " configureFailPoint: \"failCommand\",\n" + + " mode: { times: 1 },\n" + + " data: {\n" + + " failCommands: [\"find\"],\n" + + " errorLabels: ['" + RETRYABLE_ERROR_LABEL + "'],\n" + + " errorCode: 6\n" + + " }\n" + + "}\n"); + testRetriedOnTheSameServer(configureFailPoint); + } + + /** + * + * 3.3 Retryable Reads Caused by Overload Errors Are Retried on Same Replicaset Server When enableOverloadRetargeting is disabled. + */ + @Test + void overloadErrorRetriedOnSameReplicaSetServerWhenRetargetingDisabled() throws InterruptedException { + BsonDocument configureFailPoint = BsonDocument.parse( + "{\n" + + " configureFailPoint: \"failCommand\",\n" + + " mode: { times: 1 },\n" + + " data: {\n" + + " failCommands: [\"find\"],\n" + + " errorLabels: ['" + RETRYABLE_ERROR_LABEL + "', '" + SYSTEM_OVERLOADED_ERROR_LABEL + "'],\n" + + " errorCode: 6\n" + + " }\n" + + "}\n"); + testRetriedOnTheSameServer(configureFailPoint); + } + + private void testRetriedOnTheSameServer(final BsonDocument configureFailPoint) throws InterruptedException { + //given + assumeTrue(serverVersionAtLeast(4, 4)); + assumeTrue(isDiscoverableReplicaSet()); + ServerAddress primaryServerAddress = getPrimary(); + TestCommandListener commandListener = new TestCommandListener(asList("commandFailedEvent", "commandSucceededEvent"), emptyList()); + + try (FailPoint ignored = FailPoint.enable(configureFailPoint, primaryServerAddress); + MongoClient client = createClient(getMongoClientSettingsBuilder() + .retryReads(true) + .readPreference(ReadPreference.primaryPreferred()) + .addCommandListener(commandListener) + .build())) { + + MongoCollection collection = client.getDatabase(getDefaultDatabaseName()) + .getCollection(COLLECTION_NAME); + commandListener.reset(); + + //when + collection.find().first(); + + //then + List commandFailedEvents = commandListener.getCommandFailedEvents(); + assertEquals(1, commandFailedEvents.size()); + List commandSucceededEvents = commandListener.getCommandSucceededEvents(); + assertEquals(1, commandSucceededEvents.size()); + + ServerAddress failedServer = commandFailedEvents.get(0).getConnectionDescription().getServerAddress(); + ServerAddress succeededServer = commandSucceededEvents.get(0).getConnectionDescription().getServerAddress(); + + assertEquals(failedServer, succeededServer, + format("Expected retry on same server but got %s and %s", failedServer, succeededServer)); + } + } +} diff --git a/driver-sync/src/test/functional/com/mongodb/client/RetryableReadsProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/RetryableReadsProseTest.java index 59b6a9aad19..5ca0f75d56b 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/RetryableReadsProseTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/RetryableReadsProseTest.java @@ -16,51 +16,11 @@ package com.mongodb.client; -import org.bson.Document; -import org.junit.jupiter.api.Test; +import com.mongodb.MongoClientSettings; -import static com.mongodb.client.model.Filters.eq; - -/** - * - * Prose Tests. - */ -final class RetryableReadsProseTest { - /** - * - * 1. PoolClearedError Retryability Test. - */ - @Test - void poolClearedExceptionMustBeRetryable() throws Exception { - RetryableWritesProseTest.poolClearedExceptionMustBeRetryable(MongoClients::create, - mongoCollection -> mongoCollection.find(eq(0)).iterator().hasNext(), "find", false); - } - - /** - * - * 2.1 Retryable Reads Are Retried on a Different mongos When One is Available. - */ - @Test - void retriesOnDifferentMongosWhenAvailable() { - RetryableWritesProseTest.retriesOnDifferentMongosWhenAvailable(MongoClients::create, - mongoCollection -> { - try (MongoCursor cursor = mongoCollection.find().iterator()) { - return cursor.hasNext(); - } - }, "find", false); - } - - /** - * - * 2.2 Retryable Reads Are Retried on the Same mongos When No Others are Available. - */ - @Test - void retriesOnSameMongosWhenAnotherNotAvailable() { - RetryableWritesProseTest.retriesOnSameMongosWhenAnotherNotAvailable(MongoClients::create, - mongoCollection -> { - try (MongoCursor cursor = mongoCollection.find().iterator()) { - return cursor.hasNext(); - } - }, "find", false); +final class RetryableReadsProseTest extends AbstractRetryableReadsProseTest { + @Override + protected MongoClient createClient(final MongoClientSettings settings) { + return MongoClients.create(settings); } } diff --git a/driver-sync/src/test/unit/com/mongodb/client/internal/ClientSessionBindingSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/internal/ClientSessionBindingSpecification.groovy index e2e664f324d..f2ecac0c170 100644 --- a/driver-sync/src/test/unit/com/mongodb/client/internal/ClientSessionBindingSpecification.groovy +++ b/driver-sync/src/test/unit/com/mongodb/client/internal/ClientSessionBindingSpecification.groovy @@ -16,7 +16,7 @@ package com.mongodb.client.internal - +import com.mongodb.ClusterFixture import com.mongodb.ReadPreference import com.mongodb.client.ClientSession import com.mongodb.internal.binding.ClusterBinding @@ -25,29 +25,28 @@ import com.mongodb.internal.binding.ReadWriteBinding import com.mongodb.internal.connection.Cluster import spock.lang.Specification -import static com.mongodb.ClusterFixture.OPERATION_CONTEXT - class ClientSessionBindingSpecification extends Specification { def 'should call underlying wrapped binding'() { given: def session = Stub(ClientSession) + def operationContext = ClusterFixture.createOperationContext() def wrappedBinding = Mock(ClusterBinding); def binding = new ClientSessionBinding(session, false, wrappedBinding) when: - binding.getReadConnectionSource(OPERATION_CONTEXT) + binding.getReadConnectionSource(operationContext) then: - 1 * wrappedBinding.getReadConnectionSource(OPERATION_CONTEXT) >> { + 1 * wrappedBinding.getReadConnectionSource(operationContext) >> { Stub(ConnectionSource) } when: - binding.getWriteConnectionSource(OPERATION_CONTEXT) + binding.getWriteConnectionSource(operationContext) then: - 1 * wrappedBinding.getWriteConnectionSource(OPERATION_CONTEXT) >> { + 1 * wrappedBinding.getWriteConnectionSource(operationContext) >> { Stub(ConnectionSource) } } @@ -77,8 +76,9 @@ class ClientSessionBindingSpecification extends Specification { def session = Mock(ClientSession) def wrappedBinding = createStubBinding() def binding = new ClientSessionBinding(session, true, wrappedBinding) - def readConnectionSource = binding.getReadConnectionSource(OPERATION_CONTEXT) - def writeConnectionSource = binding.getWriteConnectionSource(OPERATION_CONTEXT) + def operationContext = ClusterFixture.createOperationContext() + def readConnectionSource = binding.getReadConnectionSource(operationContext) + def writeConnectionSource = binding.getWriteConnectionSource(operationContext) when: binding.release() diff --git a/driver-sync/src/test/unit/com/mongodb/client/internal/CryptConnectionSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/internal/CryptConnectionSpecification.groovy index 8a38f966754..3ec9a889e29 100644 --- a/driver-sync/src/test/unit/com/mongodb/client/internal/CryptConnectionSpecification.groovy +++ b/driver-sync/src/test/unit/com/mongodb/client/internal/CryptConnectionSpecification.groovy @@ -61,7 +61,7 @@ class CryptConnectionSpecification extends Specification { def cryptConnection = new CryptConnection(wrappedConnection, crypt) def codec = new DocumentCodec() def timeoutContext = Mock(TimeoutContext) - def operationContext = ClusterFixture.OPERATION_CONTEXT.withTimeoutContext(timeoutContext) + def operationContext = ClusterFixture.createOperationContext().withTimeoutContext(timeoutContext) def operationTimeout = Mock(Timeout) timeoutContext.getTimeout() >> operationTimeout @@ -127,7 +127,7 @@ class CryptConnectionSpecification extends Specification { def encryptedResponse = toRaw(new BsonDocument('ok', new BsonInt32(1))) def decryptedResponse = encryptedResponse def timeoutContext = Mock(TimeoutContext) - def operationContext = ClusterFixture.OPERATION_CONTEXT.withTimeoutContext(timeoutContext) + def operationContext = ClusterFixture.createOperationContext().withTimeoutContext(timeoutContext) def operationTimeout = Mock(Timeout) timeoutContext.getTimeout() >> operationTimeout @@ -183,7 +183,7 @@ class CryptConnectionSpecification extends Specification { def encryptedResponse = toRaw(new BsonDocument('ok', new BsonInt32(1))) def decryptedResponse = encryptedResponse def timeoutContext = Mock(TimeoutContext) - def operationContext = ClusterFixture.OPERATION_CONTEXT.withTimeoutContext(timeoutContext) + def operationContext = ClusterFixture.createOperationContext().withTimeoutContext(timeoutContext) def operationTimeout = Mock(Timeout) timeoutContext.getTimeout() >> operationTimeout diff --git a/driver-sync/src/test/unit/com/mongodb/client/internal/MongoClusterSpecification.groovy b/driver-sync/src/test/unit/com/mongodb/client/internal/MongoClusterSpecification.groovy index c75a4255595..34f46e7b007 100644 --- a/driver-sync/src/test/unit/com/mongodb/client/internal/MongoClusterSpecification.groovy +++ b/driver-sync/src/test/unit/com/mongodb/client/internal/MongoClusterSpecification.groovy @@ -259,7 +259,7 @@ class MongoClusterSpecification extends Specification { MongoClusterImpl createMongoCluster(final MongoClientSettings settings, final OperationExecutor operationExecutor) { new MongoClusterImpl(null, cluster, settings.codecRegistry, null, null, originator, operationExecutor, settings.readConcern, settings.readPreference, settings.retryReads, settings.retryWrites, - null, serverSessionPool, TimeoutSettings.create(settings), settings.uuidRepresentation, + settings.enableOverloadRetargeting, null, serverSessionPool, TimeoutSettings.create(settings), settings.uuidRepresentation, settings.writeConcern, TracingManager.NO_OP) } } diff --git a/testing/resources/specifications b/testing/resources/specifications index bb9dddd8176..1b15cd29901 160000 --- a/testing/resources/specifications +++ b/testing/resources/specifications @@ -1 +1 @@ -Subproject commit bb9dddd8176eddbb9424f9bebedfe8c6bbf28c3a +Subproject commit 1b15cd299011172f941893cbe3c9d4737cb2ee5d