Skip to content

Commit 548b007

Browse files
committed
CSHARP-6089: Gate baseBackoffMS integration test on a server feature and adapt tests to the new OperationContext API
- Add Feature.ClientBackpressureBaseBackoffMs (wire version Server90) and gate the integration test on it instead of a server-version string, so it runs on 9.0 pre-release servers rather than skipping until GA. - Adopt the updated spec test 5 shape (absolute backoff bounds + assert the driver parsed baseBackoffMS) for the mocked unit test. - Fix GetOperationRetryBackoffDelay test bounds for the 2^attempt exponent. - Adapt tests to the CSHARP-6011 change (Session moved onto OperationContext; OperationContext(TimeSpan, CancellationToken) and NoTimeout removed).
1 parent e1d4551 commit 548b007

6 files changed

Lines changed: 32 additions & 14 deletions

File tree

src/MongoDB.Driver/Core/Misc/Feature.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ public class Feature
112112
/// </summary>
113113
public static Feature ChangeStreamSplitEventStage { get; } = new("ChangeStreamSplitEventStage", WireVersion.Server70);
114114

115+
/// <summary>
116+
/// Gets the client backpressure baseBackoffMS feature.
117+
/// </summary>
118+
public static Feature ClientBackpressureBaseBackoffMs { get; } = new("ClientBackpressureBaseBackoffMs", WireVersion.Server90);
119+
115120
/// <summary>
116121
/// Gets the client bulk write feature.
117122
/// </summary>

tests/MongoDB.Driver.Tests/Core/Operations/RetryabilityHelperTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,10 @@ public void GetBaseBackoffMs_should_return_expected_result(string resultJson, in
317317
}
318318

319319
[Theory]
320-
[InlineData(1, null, 0, 100)]
321-
[InlineData(2, null, 0, 200)]
322-
[InlineData(1, 50, 0, 50)]
323-
[InlineData(2, 50, 0, 100)]
320+
[InlineData(1, null, 0, 200)]
321+
[InlineData(2, null, 0, 400)]
322+
[InlineData(1, 50, 0, 100)]
323+
[InlineData(2, 50, 0, 200)]
324324
[InlineData(1, 10000, 0, 10000)]
325325
[InlineData(2, 20000, 0, 10000)]
326326
public void GetOperationRetryBackoffDelay_should_apply_baseBackoffMs_override(int attempt, int? baseBackoffMs, int expectedRangeMin, int expectedRangeMax)

tests/MongoDB.Driver.Tests/Core/Operations/RetryableReadOperationExecutorTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,10 @@ public void ShouldRetry_with_baseBackoffMs_should_use_it_as_backoff_base(
147147
int expectedRangeMinMs,
148148
int expectedRangeMaxMs)
149149
{
150-
var context = CreateContext(retryRequested: true, isInTransaction: false);
150+
var context = CreateContext(retryRequested: true);
151151
var result = BsonDocument.Parse($"{{ ok : 0, code : 2, baseBackoffMS : {baseBackoffMs} }}");
152152
var exception = CoreExceptionHelper.CreateMongoCommandExceptionWithLabels(result, "SystemOverloadedError", "RetryableError");
153-
var operationContext = new OperationContext(null, CancellationToken.None);
153+
using var operationContext = new OperationContext(NoCoreSession.NewHandle());
154154
var randomMock = new Mock<IRandom>();
155155
randomMock.Setup(r => r.NextDouble()).Returns(1.0);
156156

tests/MongoDB.Driver.Tests/Core/Operations/RetryableWriteOperationExecutorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public void ShouldRetry_with_baseBackoffMs_should_use_it_as_backoff_base(
104104
var context = CreateContext(retryRequested: true, areRetryableWritesSupported: true, hasSessionId: true, isInTransaction: false);
105105
var result = BsonDocument.Parse($"{{ ok : 0, code : 2, baseBackoffMS : {baseBackoffMs} }}");
106106
var exception = CoreExceptionHelper.CreateMongoCommandExceptionWithLabels(result, "SystemOverloadedError", "RetryableError");
107-
var operationContext = new OperationContext(null, CancellationToken.None);
107+
using var operationContext = new OperationContext(NoCoreSession.NewHandle());
108108
var randomMock = new Mock<IRandom>();
109109
randomMock.Setup(r => r.NextDouble()).Returns(1.0);
110110

tests/MongoDB.Driver.Tests/Core/WireProtocol/CommandWriteProtocolTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,9 +516,10 @@ public async Task Execute_should_preserve_server_supplied_baseBackoffMS_in_the_c
516516
null, // serverApi
517517
TimeSpan.FromMilliseconds(42));
518518

519+
using var operationContext = new OperationContext(NoCoreSession.NewHandle());
519520
var exception = async
520-
? await Record.ExceptionAsync(() => subject.ExecuteAsync(OperationContext.NoTimeout, connection))
521-
: Record.Exception(() => subject.Execute(OperationContext.NoTimeout, connection));
521+
? await Record.ExceptionAsync(() => subject.ExecuteAsync(operationContext, connection))
522+
: Record.Exception(() => subject.Execute(operationContext, connection));
522523

523524
var commandException = exception.Should().BeOfType<MongoCommandException>().Subject;
524525
commandException.Result["baseBackoffMS"].ToInt32().Should().Be(50);

tests/MongoDB.Driver.Tests/Specifications/client-backpressure/prose-tests/ClientBackpressureProseTests.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ private async Task AssertBaseBackoffMsOverridesBackoff<TOperation, TContext>(
183183
Action<OperationContext, TOperation, TContext> executeSync,
184184
Func<OperationContext, TOperation, TContext, Task> executeAsync)
185185
{
186-
var operationContext = new OperationContext(TimeSpan.FromSeconds(30), CancellationToken.None);
186+
using var session = NoCoreSession.NewHandle();
187+
using var operationContext = new OperationContext(session, timeout: TimeSpan.FromSeconds(30));
187188

188189
var fullJitterRandom = new Mock<IRandom>();
189190
fullJitterRandom.Setup(r => r.NextDouble()).Returns(1.0);
@@ -197,9 +198,20 @@ private async Task AssertBaseBackoffMsOverridesBackoff<TOperation, TContext>(
197198
var overrideException = CoreExceptionHelper.CreateMongoCommandExceptionWithLabels(overrideResult, "SystemOverloadedError", "RetryableError");
198199
var withBaseBackoffMs = await MeasureBackoff(async, executeSync, executeAsync, operationContext, createOperation(overrideException), createContext(fullJitterRandom.Object));
199200

200-
// Per the spec: assertTrue(abs(exponential_backoff_time - (with_base_backoff_ms_time + 0.3s)) < 0.3s)
201-
Math.Abs(exponentialMs - (withBaseBackoffMs + 300)).Should().BeLessThan(300,
202-
$"baseBackoffMS should shorten the backoff base (exponential: {exponentialMs}ms, withBaseBackoffMS: {withBaseBackoffMs}ms)");
201+
// The driver must have parsed the server-supplied baseBackoffMS off the error.
202+
RetryabilityHelper.GetBaseBackoffMs(overrideException).Should().Be(50);
203+
204+
// Per the spec (jitter pinned to 1): the default backoffs sum to 0.2 + 0.4 = 0.6s and the
205+
// baseBackoffMS = 50 backoffs sum to 0.1 + 0.2 = 0.3s. A run can never be faster than the sum of its backoffs.
206+
// The operations here are mocked, so there is no server-round-trip cushion above the raw sleeps; allow a small
207+
// tolerance on the lower bounds for timer granularity while still asserting baseBackoffMS shortens the backoff.
208+
const long timerToleranceMs = 50;
209+
exponentialMs.Should().BeGreaterOrEqualTo(600 - timerToleranceMs,
210+
$"the default exponential backoff should sum to ~600ms (got {exponentialMs}ms)");
211+
withBaseBackoffMs.Should().BeGreaterOrEqualTo(300 - timerToleranceMs,
212+
$"the baseBackoffMS=50 backoff should sum to ~300ms (got {withBaseBackoffMs}ms)");
213+
withBaseBackoffMs.Should().BeLessThan(600,
214+
$"baseBackoffMS should shorten the backoff base (withBaseBackoffMS: {withBaseBackoffMs}ms, exponential: {exponentialMs}ms)");
203215
}
204216

205217
private static async Task<long> MeasureBackoff<TOperation, TContext>(
@@ -374,7 +386,7 @@ public void Overload_errors_with_baseBackoffMS_shorten_the_backoff_base()
374386
{
375387
RequireServer.Check()
376388
.ClusterTypes(ClusterType.ReplicaSet)
377-
.VersionGreaterThanOrEqualTo("9.0.0");
389+
.Supports(Feature.ClientBackpressureBaseBackoffMs);
378390

379391
var failPointCommand = BsonDocument.Parse(
380392
@"{

0 commit comments

Comments
 (0)