Skip to content

Commit c380b2e

Browse files
authored
1 parent 44541fc commit c380b2e

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.reactivestreams.client;
18+
19+
import com.mongodb.MongoClientSettings;
20+
import com.mongodb.client.MongoClient;
21+
import com.mongodb.reactivestreams.client.syncadapter.SyncMongoClient;
22+
23+
/**
24+
* <a href="https://github.com/mongodb/specifications/blob/master/source/client-backpressure/tests/README.md#prose-tests">
25+
* Prose Tests</a>.
26+
*/
27+
final class BackpressureProseTest extends com.mongodb.client.BackpressureProseTest {
28+
@Override
29+
protected MongoClient createClient(final MongoClientSettings mongoClientSettings) {
30+
return new SyncMongoClient(mongoClientSettings);
31+
}
32+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.client;
18+
19+
import com.mongodb.MongoClientSettings;
20+
import com.mongodb.MongoServerException;
21+
import com.mongodb.internal.connection.TestCommandListener;
22+
import com.mongodb.internal.time.StartTime;
23+
import com.mongodb.lang.Nullable;
24+
import org.bson.BsonDocument;
25+
import org.bson.Document;
26+
import org.junit.jupiter.api.Disabled;
27+
import org.junit.jupiter.api.Test;
28+
29+
import java.time.Duration;
30+
31+
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
32+
import static com.mongodb.MongoException.RETRYABLE_ERROR_LABEL;
33+
import static com.mongodb.MongoException.SYSTEM_OVERLOADED_ERROR_LABEL;
34+
import static com.mongodb.client.Fixture.getDefaultDatabaseName;
35+
import static com.mongodb.client.Fixture.getMongoClientSettings;
36+
import static com.mongodb.client.Fixture.getPrimary;
37+
import static java.lang.String.format;
38+
import static org.junit.jupiter.api.Assertions.assertEquals;
39+
import static org.junit.jupiter.api.Assertions.assertThrows;
40+
import static org.junit.jupiter.api.Assertions.assertTrue;
41+
import static org.junit.jupiter.api.Assumptions.assumeTrue;
42+
43+
/**
44+
* <a href="https://github.com/mongodb/specifications/blob/master/source/client-backpressure/tests/README.md#prose-tests">
45+
* Prose Tests</a>.
46+
*/
47+
public class BackpressureProseTest {
48+
protected MongoClient createClient(final MongoClientSettings mongoClientSettings) {
49+
return MongoClients.create(mongoClientSettings);
50+
}
51+
52+
/**
53+
* <a href="https://github.com/mongodb/specifications/blob/master/source/client-backpressure/tests/README.md#test-1-operation-retry-uses-exponential-backoff">
54+
* Test 1: Operation Retry Uses Exponential Backoff</a>.
55+
*/
56+
@Test
57+
@Disabled("TODO-BACKPRESSURE Valentin Enable when implementing JAVA-5956, JAVA-6117, JAVA-6113, JAVA-6119, JAVA-6141 if PR 1899 is merged")
58+
void operationRetryUsesExponentialBackoff() throws InterruptedException {
59+
assumeTrue(serverVersionAtLeast(4, 4));
60+
BsonDocument configureFailPoint = BsonDocument.parse(
61+
"{\n"
62+
+ " configureFailPoint: 'failCommand',\n"
63+
+ " mode: 'alwaysOn',\n"
64+
+ " data: {\n"
65+
+ " failCommands: ['insert'],\n"
66+
+ " errorCode: 2,\n"
67+
+ " errorLabels: ['" + SYSTEM_OVERLOADED_ERROR_LABEL + "', '" + RETRYABLE_ERROR_LABEL + "']\n"
68+
+ " }\n"
69+
+ "}\n");
70+
try (MongoClient client = createClient(getMongoClientSettings());
71+
FailPoint ignored = FailPoint.enable(configureFailPoint, getPrimary())) {
72+
MongoCollection<Document> collection = dropAndGetCollection("operationRetryUsesExponentialBackoff", client);
73+
long noBackoffTimeMillis = measureFailedInsertDuration(collection, false).toMillis();
74+
long withBackoffTimeMillis = measureFailedInsertDuration(collection, true).toMillis();
75+
long expectedMaxVarianceMillis = 300;
76+
long maxTotalBackoffMillis = 300;
77+
long actualAbsDiffMillis = Math.abs(withBackoffTimeMillis - (noBackoffTimeMillis + maxTotalBackoffMillis));
78+
assertTrue(actualAbsDiffMillis < expectedMaxVarianceMillis,
79+
format("Expected actualAbsDiffMillis < %d ms, but was %d ms (|%d ms - (%d ms + %d ms)|)",
80+
expectedMaxVarianceMillis, actualAbsDiffMillis, withBackoffTimeMillis, noBackoffTimeMillis, maxTotalBackoffMillis));
81+
}
82+
}
83+
84+
private static Duration measureFailedInsertDuration(final MongoCollection<Document> collection, final boolean retryBackoff) {
85+
// TODO-BACKPRESSURE Valentin uncomment below when https://github.com/mongodb/mongo-java-driver/pull/1899 is merged
86+
// ExponentialBackoff.setTestJitterSupplier(() -> retryBackoff ? 1 : 0);
87+
try {
88+
StartTime startTime = StartTime.now();
89+
assertThrows(MongoServerException.class, () -> collection.insertOne(Document.parse("{a: 1}")));
90+
return startTime.elapsed();
91+
} finally {
92+
// TODO-BACKPRESSURE Valentin uncomment below when https://github.com/mongodb/mongo-java-driver/pull/1899 is merged
93+
// ExponentialBackoff.clearTestJitterSupplier();
94+
}
95+
}
96+
97+
/**
98+
* <a href="https://github.com/mongodb/specifications/blob/master/source/client-backpressure/tests/README.md#test-3-overload-errors-are-retried-a-maximum-of-max_retries-times">
99+
* Test 3: Overload Errors are Retried a Maximum of {@code MAX_RETRIES} times</a>.
100+
*/
101+
@Test
102+
@Disabled("TODO-BACKPRESSURE Valentin Enable when implementing JAVA-5956, JAVA-6117, JAVA-6113, JAVA-6119, JAVA-6141")
103+
void overloadErrorsAreRetriedAtMostMaxRetriesTimes() throws InterruptedException {
104+
overloadErrorsAreRetriedLimitedNumberOfTimes(null);
105+
}
106+
107+
/**
108+
* <a href="https://github.com/mongodb/specifications/blob/master/source/client-backpressure/tests/README.md#test-4-overload-errors-are-retried-a-maximum-of-maxadaptiveretries-times-when-configured">
109+
* Test 4: Overload Errors are Retried a Maximum of {@code maxAdaptiveRetries} times when configured</a>.
110+
*/
111+
@Test
112+
@Disabled("TODO-BACKPRESSURE Valentin Enable when implementing JAVA-5956, JAVA-6117, JAVA-6113, JAVA-6119, JAVA-6141")
113+
void overloadErrorsAreRetriedAtMostMaxAdaptiveRetriesTimesWhenConfigured() throws InterruptedException {
114+
overloadErrorsAreRetriedLimitedNumberOfTimes(1);
115+
}
116+
117+
private void overloadErrorsAreRetriedLimitedNumberOfTimes(@Nullable final Integer maxAdaptiveRetries)
118+
throws InterruptedException {
119+
assumeTrue(serverVersionAtLeast(4, 4));
120+
TestCommandListener commandListener = new TestCommandListener();
121+
BsonDocument configureFailPoint = BsonDocument.parse(
122+
"{\n"
123+
+ " configureFailPoint: 'failCommand',\n"
124+
+ " mode: 'alwaysOn',\n"
125+
+ " data: {\n"
126+
+ " failCommands: ['find'],\n"
127+
+ " errorCode: 462,\n"
128+
+ " errorLabels: ['" + SYSTEM_OVERLOADED_ERROR_LABEL + "', '" + RETRYABLE_ERROR_LABEL + "']\n"
129+
+ " }\n"
130+
+ "}\n");
131+
try (MongoClient client = createClient(MongoClientSettings.builder(getMongoClientSettings())
132+
.maxAdaptiveRetries(maxAdaptiveRetries)
133+
.addCommandListener(commandListener)
134+
.build());
135+
FailPoint ignored = FailPoint.enable(configureFailPoint, getPrimary())) {
136+
MongoCollection<Document> collection = dropAndGetCollection("overloadErrorsAreRetriedLimitedNumberOfTimes", client);
137+
commandListener.reset();
138+
MongoServerException exception = assertThrows(MongoServerException.class, () -> collection.find().first());
139+
assertTrue(exception.hasErrorLabel(SYSTEM_OVERLOADED_ERROR_LABEL));
140+
assertTrue(exception.hasErrorLabel(RETRYABLE_ERROR_LABEL));
141+
// TODO-BACKPRESSURE Valentin replace 2 with `MAX_RETRIES` when implementing JAVA-5956, JAVA-6117, JAVA-6113, JAVA-6119, JAVA-6141
142+
int expectedAttempts = (maxAdaptiveRetries == null ? 2 : maxAdaptiveRetries) + 1;
143+
assertEquals(expectedAttempts, commandListener.getCommandStartedEvents().size());
144+
}
145+
}
146+
147+
private static MongoCollection<Document> dropAndGetCollection(final String name, final MongoClient client) {
148+
MongoCollection<Document> result = client.getDatabase(getDefaultDatabaseName()).getCollection(name);
149+
result.drop();
150+
return result;
151+
}
152+
}

0 commit comments

Comments
 (0)