From 061e20936e660afa5676f85193ee96e46f006610 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Mon, 26 Jun 2023 13:00:45 +0200 Subject: [PATCH 1/4] Drop TimeProvider.Delay --- src/Polly.Core/ToBeRemoved/TimeProvider.cs | 3 - .../HedgingExecutionContextTests.cs | 6 +- .../Hedging/HedgingResilienceStrategyTests.cs | 8 +-- .../Hedging/HedgingTimeProvider.cs | 33 ++++++--- .../Helpers/MockTimeProvider.cs | 35 +++++++-- .../IssuesTests.HandleMultipleResults_898.cs | 2 +- .../Retry/RetryResilienceStrategyTests.cs | 72 ++++++++++--------- .../Utils/TimeProviderExtensionsTests.cs | 6 +- 8 files changed, 102 insertions(+), 63 deletions(-) diff --git a/src/Polly.Core/ToBeRemoved/TimeProvider.cs b/src/Polly.Core/ToBeRemoved/TimeProvider.cs index 573be648b64..b6e644df1dc 100644 --- a/src/Polly.Core/ToBeRemoved/TimeProvider.cs +++ b/src/Polly.Core/ToBeRemoved/TimeProvider.cs @@ -58,9 +58,6 @@ public DateTimeOffset GetLocalNow() public virtual long GetTimestamp() => Stopwatch.GetTimestamp(); - // This one is not on TimeProvider, temporarly we need to use it - public virtual Task Delay(TimeSpan delay, CancellationToken cancellationToken = default) => Task.Delay(delay, cancellationToken); - public TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp) { long timestampFrequency = TimestampFrequency; diff --git a/test/Polly.Core.Tests/Hedging/Controller/HedgingExecutionContextTests.cs b/test/Polly.Core.Tests/Hedging/Controller/HedgingExecutionContextTests.cs index c0a435df3a2..08bc56967e6 100644 --- a/test/Polly.Core.Tests/Hedging/Controller/HedgingExecutionContextTests.cs +++ b/test/Polly.Core.Tests/Hedging/Controller/HedgingExecutionContextTests.cs @@ -159,11 +159,11 @@ public async Task TryWaitForCompletedExecutionAsync_HedgedExecution_Ok() } var hedgingDelay = TimeSpan.FromSeconds(5); - var count = _timeProvider.DelayEntries.Count; + var count = _timeProvider.TimerEntries.Count; var task = context.TryWaitForCompletedExecutionAsync(hedgingDelay).AsTask(); task.Wait(20).Should().BeFalse(); - _timeProvider.DelayEntries.Should().HaveCount(count + 1); - _timeProvider.DelayEntries.Last().Delay.Should().Be(hedgingDelay); + _timeProvider.TimerEntries.Should().HaveCount(count + 1); + _timeProvider.TimerEntries.Last().Delay.Should().Be(hedgingDelay); _timeProvider.Advance(TimeSpan.FromDays(1)); await task; await context.Tasks[0].ExecutionTaskSafe!; diff --git a/test/Polly.Core.Tests/Hedging/HedgingResilienceStrategyTests.cs b/test/Polly.Core.Tests/Hedging/HedgingResilienceStrategyTests.cs index 663067abc7e..95e725f1300 100644 --- a/test/Polly.Core.Tests/Hedging/HedgingResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Hedging/HedgingResilienceStrategyTests.cs @@ -96,11 +96,11 @@ public void ExecutePrimaryAndSecondary_EnsureAttemptReported() var attempts = _events.Select(v => v.Arguments).OfType().ToArray(); attempts[0].Handled.Should().BeTrue(); - attempts[0].ExecutionTime.Should().Be(_timeProvider.GetElapsedTime(0, 1000)); + attempts[0].ExecutionTime.Should().BeGreaterThan(TimeSpan.Zero); attempts[0].Attempt.Should().Be(0); attempts[1].Handled.Should().BeTrue(); - attempts[1].ExecutionTime.Should().Be(_timeProvider.GetElapsedTime(0, 1000)); + attempts[1].ExecutionTime.Should().BeGreaterThan(TimeSpan.Zero); attempts[1].Attempt.Should().Be(1); } @@ -164,7 +164,7 @@ public async Task ExecuteAsync_ShouldReturnAnyPossibleResult() var result = await strategy.ExecuteAsync(_primaryTasks.SlowTask); result.Should().NotBeNull(); - _timeProvider.DelayEntries.Should().HaveCount(5); + _timeProvider.TimerEntries.Should().HaveCount(5); result.Should().Be("Oranges"); } @@ -865,7 +865,7 @@ public async Task ExecuteAsync_EnsureHedgingDelayGeneratorRespected() _timeProvider.Advance(TimeSpan.FromHours(5)); (await task).Should().Be(Success); - _timeProvider.DelayEntries.Should().Contain(e => e.Delay == delay); + _timeProvider.TimerEntries.Should().Contain(e => e.Delay == delay); } [Fact] diff --git a/test/Polly.Core.Tests/Hedging/HedgingTimeProvider.cs b/test/Polly.Core.Tests/Hedging/HedgingTimeProvider.cs index b71c289f8b1..97d630c60be 100644 --- a/test/Polly.Core.Tests/Hedging/HedgingTimeProvider.cs +++ b/test/Polly.Core.Tests/Hedging/HedgingTimeProvider.cs @@ -12,7 +12,7 @@ public void Advance(TimeSpan diff) { _utcNow = _utcNow.Add(diff); - foreach (var entry in DelayEntries.Where(e => e.TimeStamp <= _utcNow)) + foreach (var entry in TimerEntries.Where(e => e.TimeStamp <= _utcNow)) { entry.Complete(); } @@ -20,25 +20,36 @@ public void Advance(TimeSpan diff) public Func TimeStampProvider { get; set; } = () => 0; - public List DelayEntries { get; } = new List(); + public List TimerEntries { get; } = new List(); public override DateTimeOffset GetUtcNow() => _utcNow; - public override long GetTimestamp() => TimeStampProvider(); - - public override Task Delay(TimeSpan delayValue, CancellationToken cancellationToken = default) + public override ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period) { - var entry = new DelayEntry(delayValue, new TaskCompletionSource(), _utcNow.Add(delayValue)); - cancellationToken.Register(() => entry.Source.TrySetCanceled(cancellationToken)); - DelayEntries.Add(entry); + var entry = new TimerEntry(dueTime, new TaskCompletionSource(), _utcNow.Add(dueTime), () => callback(state)); + TimerEntries.Add(entry); Advance(AutoAdvance); - return entry.Source.Task; + return entry; } - public record DelayEntry(TimeSpan Delay, TaskCompletionSource Source, DateTimeOffset TimeStamp) + public record TimerEntry(TimeSpan Delay, TaskCompletionSource Source, DateTimeOffset TimeStamp, Action Callback) : ITimer { - public void Complete() => Source.TrySetResult(true); + public bool Change(TimeSpan dueTime, TimeSpan period) => throw new NotSupportedException(); + + public void Complete() + { + Callback(); + Source.TrySetResult(true); + } + + public void Dispose() => Source.TrySetResult(true); + + public ValueTask DisposeAsync() + { + Source.TrySetResult(true); + return default; + } } } diff --git a/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs b/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs index 70d0d139f22..e602dce6628 100644 --- a/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs +++ b/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs @@ -9,21 +9,44 @@ public MockTimeProvider() { } - public MockTimeProvider SetupAnyDelay(CancellationToken cancellationToken = default) + public MockTimeProvider SetupAnyCreateTimer() { - Setup(x => x.Delay(It.IsAny(), cancellationToken)).Returns(Task.CompletedTask); + Setup(t => t.CreateTimer(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((TimerCallback callback, object? state, TimeSpan _, TimeSpan _) => callback(state)) + .Returns(Of()); + return this; } - public MockTimeProvider SetupDelay(TimeSpan delay, CancellationToken cancellationToken = default) + public Mock SetupCreateTimer(TimeSpan delay) + { + var timer = new Mock(MockBehavior.Loose); + + Setup(t => t.CreateTimer(It.IsAny(), It.IsAny(), delay, It.IsAny())) + .Callback((TimerCallback callback, object? state, TimeSpan _, TimeSpan _) => callback(state)) + .Returns(timer.Object); + + return timer; + } + + public MockTimeProvider VerifyCreateTimer(Times times) { - Setup(x => x.Delay(delay, cancellationToken)).Returns(Task.CompletedTask); + Verify(t => t.CreateTimer(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), times); return this; } - public MockTimeProvider SetupDelayCancelled(TimeSpan delay, CancellationToken cancellationToken = default) + public MockTimeProvider VerifyCreateTimer(TimeSpan delay, Times times) { - Setup(x => x.Delay(delay, cancellationToken)).ThrowsAsync(new OperationCanceledException()); + Verify(t => t.CreateTimer(It.IsAny(), It.IsAny(), delay, It.IsAny()), times); + return this; + } + + public MockTimeProvider SetupCreateTimerException(TimeSpan delay, Exception exception) + { + Setup(t => t.CreateTimer(It.IsAny(), It.IsAny(), delay, It.IsAny())) + .Callback((TimerCallback _, object? _, TimeSpan _, TimeSpan _) => throw exception) + .Returns(Of()); + return this; } } diff --git a/test/Polly.Core.Tests/Issues/IssuesTests.HandleMultipleResults_898.cs b/test/Polly.Core.Tests/Issues/IssuesTests.HandleMultipleResults_898.cs index 23bebf5f910..461e15bf04b 100644 --- a/test/Polly.Core.Tests/Issues/IssuesTests.HandleMultipleResults_898.cs +++ b/test/Polly.Core.Tests/Issues/IssuesTests.HandleMultipleResults_898.cs @@ -31,7 +31,7 @@ public void HandleMultipleResults_898() }; // create the strategy - var strategy = new ResilienceStrategyBuilder { TimeProvider = TimeProvider }.AddRetry(options).Build(); + var strategy = new ResilienceStrategyBuilder().AddRetry(options).Build(); // check that int-based results is retried bool isRetry = false; diff --git a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index 285b9c00c55..f7329c9ad2e 100644 --- a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Time.Testing; using Moq; using Polly.Retry; using Polly.Telemetry; @@ -7,7 +8,7 @@ namespace Polly.Core.Tests.Retry; public class RetryResilienceStrategyTests { private readonly RetryStrategyOptions _options = new(); - private readonly MockTimeProvider _timeProvider = new(); + private readonly FakeTimeProvider _timeProvider = new(); private readonly Mock _diagnosticSource = new(); private ResilienceStrategyTelemetry _telemetry; @@ -16,8 +17,6 @@ public RetryResilienceStrategyTests() _telemetry = TestUtilities.CreateResilienceTelemetry(_diagnosticSource.Object); _options.ShouldHandle = _ => new ValueTask(false); - _timeProvider.Setup(v => v.TimestampFrequency).Returns(Stopwatch.Frequency); - _timeProvider.SetupSequence(v => v.GetTimestamp()).Returns(0).Returns(100); } [Fact] @@ -74,7 +73,6 @@ public void ExecuteAsync_MultipleRetries_EnsureDiscardedResultsDisposed() // arrange _options.RetryCount = 5; SetupNoDelay(); - _timeProvider.SetupAnyDelay(); _options.ShouldHandle = _ => PredicateResult.True; var results = new List(); var sut = CreateSut(); @@ -158,7 +156,7 @@ public void Retry_Infinite_Respected() } [Fact] - public void RetryDelayGenerator_Respected() + public async Task RetryDelayGenerator_Respected() { int calls = 0; _options.OnRetry = _ => { calls++; return default; }; @@ -166,17 +164,14 @@ public void RetryDelayGenerator_Respected() _options.RetryCount = 3; _options.BackoffType = RetryBackoffType.Constant; _options.RetryDelayGenerator = _ => new ValueTask(TimeSpan.FromMilliseconds(123)); - _timeProvider.SetupDelay(TimeSpan.FromMilliseconds(123)); var sut = CreateSut(); - sut.Execute(() => 0); - - _timeProvider.Verify(v => v.Delay(TimeSpan.FromMilliseconds(123), default), Times.Exactly(3)); + await ExecuteAndAdvance(sut); } [Fact] - public void OnRetry_EnsureCorrectArguments() + public async void OnRetry_EnsureCorrectArguments() { var attempts = new List(); var delays = new List(); @@ -190,14 +185,15 @@ public void OnRetry_EnsureCorrectArguments() return default; }; - _options.ShouldHandle = args => args.Outcome.ResultPredicateAsync(0); + _options.ShouldHandle = args => PredicateResult.True; _options.RetryCount = 3; _options.BackoffType = RetryBackoffType.Linear; - _timeProvider.SetupAnyDelay(); var sut = CreateSut(); - sut.Execute(() => 0); + var executing = ExecuteAndAdvance(sut); + + await executing; attempts.Should().HaveCount(3); attempts[0].Should().Be(0); @@ -210,54 +206,56 @@ public void OnRetry_EnsureCorrectArguments() } [Fact] - public void OnRetry_EnsureExecutionTime() + public async Task OnRetry_EnsureExecutionTime() { _options.OnRetry = args => { - args.Arguments.ExecutionTime.Should().Be(_timeProvider.Object.GetElapsedTime(100, 1000)); + args.Arguments.ExecutionTime.Should().Be(TimeSpan.FromMinutes(1)); return default; }; _options.ShouldHandle = _ => PredicateResult.True; _options.RetryCount = 1; - _options.BackoffType = RetryBackoffType.Linear; - _timeProvider.SetupAnyDelay(); - _timeProvider - .SetupSequence(v => v.GetTimestamp()) - .Returns(100) - .Returns(1000) - .Returns(100) - .Returns(1000); + _options.BackoffType = RetryBackoffType.Constant; + _options.BaseDelay = TimeSpan.Zero; var sut = CreateSut(); - sut.Execute(() => 0); + await sut.ExecuteAsync(_ => + { + _timeProvider.Advance(TimeSpan.FromMinutes(1)); + return new ValueTask(0); + }).AsTask(); } [Fact] public void Execute_EnsureAttemptReported() { var called = false; - _timeProvider.SetupSequence(v => v.GetTimestamp()).Returns(100).Returns(1000); _telemetry = TestUtilities.CreateResilienceTelemetry(args => { var attempt = args.Arguments.Should().BeOfType().Subject; attempt.Handled.Should().BeFalse(); attempt.Attempt.Should().Be(0); - attempt.ExecutionTime.Should().Be(_timeProvider.Object.GetElapsedTime(100, 1000)); + attempt.ExecutionTime.Should().Be(TimeSpan.FromSeconds(1)); called = true; }); var sut = CreateSut(); - sut.Execute(() => 0); + sut.Execute(() => + { + _timeProvider.Advance(TimeSpan.FromSeconds(1)); + return 0; + }); + called.Should().BeTrue(); } [Fact] - public void OnRetry_EnsureTelemetry() + public async Task OnRetry_EnsureTelemetry() { var attempts = new List(); var delays = new List(); @@ -267,11 +265,10 @@ public void OnRetry_EnsureTelemetry() _options.ShouldHandle = args => args.Outcome.ResultPredicateAsync(0); _options.RetryCount = 3; _options.BackoffType = RetryBackoffType.Linear; - _timeProvider.SetupAnyDelay(); var sut = CreateSut(); - sut.Execute(() => 0); + await ExecuteAndAdvance(sut); _diagnosticSource.VerifyAll(); } @@ -295,7 +292,6 @@ public void RetryDelayGenerator_EnsureCorrectArguments() _options.ShouldHandle = args => args.Outcome.ResultPredicateAsync(0); _options.RetryCount = 3; _options.BackoffType = RetryBackoffType.Linear; - _timeProvider.SetupAnyDelay(); var sut = CreateSut(); @@ -313,10 +309,22 @@ public void RetryDelayGenerator_EnsureCorrectArguments() private void SetupNoDelay() => _options.RetryDelayGenerator = _ => new ValueTask(TimeSpan.Zero); + private async ValueTask ExecuteAndAdvance(RetryResilienceStrategy sut) + { + var executing = sut.ExecuteAsync(_ => new ValueTask(0)).AsTask(); + + while (!executing.IsCompleted) + { + _timeProvider.Advance(TimeSpan.FromMinutes(1)); + } + + return await executing; + } + private RetryResilienceStrategy CreateSut(TimeProvider? timeProvider = null) => new(_options, false, - timeProvider ?? _timeProvider.Object, + timeProvider ?? _timeProvider, _telemetry, () => 1.0); } diff --git a/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs b/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs index 9e30bbb0d04..2cbdc93f562 100644 --- a/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs +++ b/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs @@ -23,7 +23,7 @@ public async Task DelayAsync_System_Ok(bool synchronous, bool mocked, bool hasCa var context = ResilienceContext.Get(); context.Initialize(isSynchronous: synchronous); context.CancellationToken = token; - mock.SetupDelay(delay, token); + mock.SetupCreateTimer(delay); await TestUtilities.AssertWithTimeoutAsync(async () => { @@ -88,7 +88,7 @@ public async Task DelayAsync_CancellationRequestedBefore_Throws(bool synchronous var context = ResilienceContext.Get(); context.Initialize(isSynchronous: synchronous); context.CancellationToken = token; - mock.SetupDelayCancelled(delay, token); + mock.SetupCreateTimer(delay); await Assert.ThrowsAsync(() => timeProvider.DelayAsync(delay, context)); } @@ -111,7 +111,7 @@ await TestUtilities.AssertWithTimeoutAsync(async () => var context = ResilienceContext.Get(); context.Initialize(isSynchronous: synchronous); context.CancellationToken = token; - mock.SetupDelayCancelled(delay, token); + mock.SetupCreateTimerException(delay, new OperationCanceledException()); tcs.CancelAfter(TimeSpan.FromMilliseconds(5)); From 4ec653d65cbe69def6d123bfab5b9e3d8d7dfc1f Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Mon, 26 Jun 2023 13:17:54 +0200 Subject: [PATCH 2/4] fixes --- .../Retry/RetryResilienceStrategyTests.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index f7329c9ad2e..c2526b20d88 100644 --- a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -156,18 +156,23 @@ public void Retry_Infinite_Respected() } [Fact] - public async Task RetryDelayGenerator_Respected() + public void RetryDelayGenerator_Respected() { int calls = 0; _options.OnRetry = _ => { calls++; return default; }; - _options.ShouldHandle = args => args.Outcome.ResultPredicateAsync(0); + _options.ShouldHandle = _ => PredicateResult.True; _options.RetryCount = 3; _options.BackoffType = RetryBackoffType.Constant; _options.RetryDelayGenerator = _ => new ValueTask(TimeSpan.FromMilliseconds(123)); + var provider = new MockTimeProvider(); + provider.SetupCreateTimer(TimeSpan.FromMilliseconds(123)); + provider.Setup(p => p.GetTimestamp()).Returns(0); + provider.Setup(p => p.TimestampFrequency).Returns(10000); - var sut = CreateSut(); + var sut = CreateSut(provider.Object); + sut.Execute(_ => { }); - await ExecuteAndAdvance(sut); + provider.VerifyAll(); } [Fact] From 9107e3771852e7f623ae4d79b1c6f7bfb8f5b535 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Mon, 26 Jun 2023 13:50:32 +0200 Subject: [PATCH 3/4] kill mutants --- .../Retry/RetryResilienceStrategyTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index c2526b20d88..a7de98309d4 100644 --- a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -175,6 +175,25 @@ public void RetryDelayGenerator_Respected() provider.VerifyAll(); } + [Fact] + public void RetryDelayGenerator_ZeroDelay_NoTimeProviderCalls() + { + int calls = 0; + _options.OnRetry = _ => { calls++; return default; }; + _options.ShouldHandle = _ => PredicateResult.True; + _options.RetryCount = 1; + _options.RetryDelayGenerator = _ => new ValueTask(TimeSpan.FromMilliseconds(0)); + var provider = new MockTimeProvider(); + provider.Setup(p => p.GetTimestamp()).Returns(0); + provider.Setup(p => p.TimestampFrequency).Returns(10000); + + var sut = CreateSut(provider.Object); + sut.Execute(_ => { }); + + provider.VerifyAll(); + provider.VerifyNoOtherCalls(); + } + [Fact] public async void OnRetry_EnsureCorrectArguments() { From e4953758b378dc365a807e417fe5807ff623790e Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Mon, 26 Jun 2023 14:16:17 +0200 Subject: [PATCH 4/4] fixes --- src/Polly.Core/Retry/RetryResilienceStrategy.cs | 1 + .../Retry/RetryResilienceStrategyTests.cs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Polly.Core/Retry/RetryResilienceStrategy.cs b/src/Polly.Core/Retry/RetryResilienceStrategy.cs index c607f23a07b..a633dcb6fe0 100644 --- a/src/Polly.Core/Retry/RetryResilienceStrategy.cs +++ b/src/Polly.Core/Retry/RetryResilienceStrategy.cs @@ -86,6 +86,7 @@ protected override async ValueTask> ExecuteCallbackAsync(Func await DisposeHelper.TryDisposeSafeAsync(resultValue, context.IsSynchronous).ConfigureAwait(context.ContinueOnCapturedContext); } + // stryker disable once equality : no means to test this if (delay > TimeSpan.Zero) { try diff --git a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index a7de98309d4..d61b46fcb0b 100644 --- a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -156,7 +156,7 @@ public void Retry_Infinite_Respected() } [Fact] - public void RetryDelayGenerator_Respected() + public async Task RetryDelayGenerator_Respected() { int calls = 0; _options.OnRetry = _ => { calls++; return default; }; @@ -170,13 +170,13 @@ public void RetryDelayGenerator_Respected() provider.Setup(p => p.TimestampFrequency).Returns(10000); var sut = CreateSut(provider.Object); - sut.Execute(_ => { }); + await sut.ExecuteAsync(_ => default); provider.VerifyAll(); } [Fact] - public void RetryDelayGenerator_ZeroDelay_NoTimeProviderCalls() + public async Task RetryDelayGenerator_ZeroDelay_NoTimeProviderCalls() { int calls = 0; _options.OnRetry = _ => { calls++; return default; }; @@ -188,7 +188,7 @@ public void RetryDelayGenerator_ZeroDelay_NoTimeProviderCalls() provider.Setup(p => p.TimestampFrequency).Returns(10000); var sut = CreateSut(provider.Object); - sut.Execute(_ => { }); + await sut.ExecuteAsync(_ => default); provider.VerifyAll(); provider.VerifyNoOtherCalls();