From bb4272813a0f9e4dde6531bf7c632c8f2a511289 Mon Sep 17 00:00:00 2001 From: martincostello Date: Tue, 27 Jun 2023 09:16:18 +0100 Subject: [PATCH] Prepare for .NET 8 Backport various changes from #1144: - Simplify NuGet package version management. - Simplify TimeProviderExtensions. - Enable .NET analyzers. - Remove `MockTimeProvider`. - Minor code formatting clean-ups. --- Directory.Packages.props | 33 ++++---- .../Polly.Core.Benchmarks.csproj | 1 + eng/Analyzers.targets | 1 + .../Timeout/TimeoutResilienceStrategy.cs | 4 +- .../Utils/TimeProviderExtensions.cs | 28 ++----- src/Polly.Extensions/Polly.Extensions.csproj | 3 +- .../Polly.RateLimiting.csproj | 2 +- .../Helpers/MockTimeProvider.cs | 52 ------------- test/Polly.Core.Tests/Polly.Core.Tests.csproj | 2 +- .../Retry/RetryResilienceStrategyTests.cs | 75 ++++++++++++++----- .../Timeout/TimeoutResilienceStrategyTests.cs | 2 +- .../Utils/CancellationTokenSourcePoolTests.cs | 1 + .../Utils/TimeProviderExtensionsTests.cs | 49 ++++-------- .../Polly.Extensions.Tests.csproj | 1 - test/Polly.TestUtils/Polly.TestUtils.csproj | 2 +- 15 files changed, 102 insertions(+), 154 deletions(-) delete mode 100644 test/Polly.Core.Tests/Helpers/MockTimeProvider.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 83a5f1b85b2..69fa2c0de1c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,5 +1,6 @@ + 7.0.0 true 8.0.0-alpha.4 @@ -8,13 +9,15 @@ - - - - - - - + + + + + + + + + @@ -27,23 +30,19 @@ - - + + - - - - - - + + - - + + diff --git a/bench/Polly.Core.Benchmarks/Polly.Core.Benchmarks.csproj b/bench/Polly.Core.Benchmarks/Polly.Core.Benchmarks.csproj index 85926fa8f13..d7742e9db96 100644 --- a/bench/Polly.Core.Benchmarks/Polly.Core.Benchmarks.csproj +++ b/bench/Polly.Core.Benchmarks/Polly.Core.Benchmarks.csproj @@ -1,6 +1,7 @@  net7.0 + Polly true Benchmark enable diff --git a/eng/Analyzers.targets b/eng/Analyzers.targets index 071b4825ccc..798450220ca 100644 --- a/eng/Analyzers.targets +++ b/eng/Analyzers.targets @@ -12,5 +12,6 @@ true true latest + true diff --git a/src/Polly.Core/Timeout/TimeoutResilienceStrategy.cs b/src/Polly.Core/Timeout/TimeoutResilienceStrategy.cs index 19365a1cab1..af3fb43a627 100644 --- a/src/Polly.Core/Timeout/TimeoutResilienceStrategy.cs +++ b/src/Polly.Core/Timeout/TimeoutResilienceStrategy.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Polly.Telemetry; namespace Polly.Timeout; @@ -23,7 +22,6 @@ public TimeoutResilienceStrategy(TimeoutStrategyOptions options, TimeProvider ti public Func? OnTimeout { get; } - [ExcludeFromCodeCoverage] protected internal override async ValueTask> ExecuteCoreAsync( Func>> callback, ResilienceContext context, @@ -50,7 +48,7 @@ protected internal override async ValueTask> ExecuteCoreAsync + - + diff --git a/src/Polly.RateLimiting/Polly.RateLimiting.csproj b/src/Polly.RateLimiting/Polly.RateLimiting.csproj index c4165fe48eb..9ebb23c6b01 100644 --- a/src/Polly.RateLimiting/Polly.RateLimiting.csproj +++ b/src/Polly.RateLimiting/Polly.RateLimiting.csproj @@ -9,7 +9,7 @@ 100 true - + diff --git a/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs b/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs deleted file mode 100644 index e602dce6628..00000000000 --- a/test/Polly.Core.Tests/Helpers/MockTimeProvider.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Moq; - -namespace Polly.Core.Tests.Helpers; - -internal class MockTimeProvider : Mock -{ - public MockTimeProvider() - : base(MockBehavior.Strict) - { - } - - public MockTimeProvider SetupAnyCreateTimer() - { - 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 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) - { - Verify(t => t.CreateTimer(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), times); - return this; - } - - public MockTimeProvider VerifyCreateTimer(TimeSpan delay, Times times) - { - 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/Polly.Core.Tests.csproj b/test/Polly.Core.Tests/Polly.Core.Tests.csproj index b729ad53fe6..0c709602b04 100644 --- a/test/Polly.Core.Tests/Polly.Core.Tests.csproj +++ b/test/Polly.Core.Tests/Polly.Core.Tests.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index d61b46fcb0b..3e45f210564 100644 --- a/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -1,3 +1,4 @@ +using FluentAssertions.Execution; using Microsoft.Extensions.Time.Testing; using Moq; using Polly.Retry; @@ -158,40 +159,76 @@ public void Retry_Infinite_Respected() [Fact] public async Task RetryDelayGenerator_Respected() { - int calls = 0; - _options.OnRetry = _ => { calls++; return default; }; + int retries = 0; + int generatedValues = 0; + + var delay = TimeSpan.FromMilliseconds(120); + var provider = TimeProvider.System; + _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(provider.Object); + _options.OnRetry = _ => + { + retries++; + return default; + }; + _options.RetryDelayGenerator = _ => + { + generatedValues++; + return new ValueTask(delay); + }; + + var before = provider.GetUtcNow(); + + var sut = CreateSut(provider); await sut.ExecuteAsync(_ => default); - provider.VerifyAll(); + retries.Should().Be(3); + generatedValues.Should().Be(3); + + var after = provider.GetUtcNow(); + (after - before).Should().BeGreaterThanOrEqualTo(delay.Add(delay).Add(delay)); } [Fact] public async Task RetryDelayGenerator_ZeroDelay_NoTimeProviderCalls() { - int calls = 0; - _options.OnRetry = _ => { calls++; return default; }; + int retries = 0; + int generatedValues = 0; + + var delay = TimeSpan.Zero; + var provider = new ThrowingFakeTimeProvider(); + _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); + _options.RetryCount = 3; + _options.BackoffType = RetryBackoffType.Constant; - var sut = CreateSut(provider.Object); + _options.OnRetry = _ => + { + retries++; + return default; + }; + _options.RetryDelayGenerator = _ => + { + generatedValues++; + return new ValueTask(delay); + }; + + var sut = CreateSut(provider); await sut.ExecuteAsync(_ => default); - provider.VerifyAll(); - provider.VerifyNoOtherCalls(); + retries.Should().Be(3); + generatedValues.Should().Be(3); + } + + private sealed class ThrowingFakeTimeProvider : FakeTimeProvider + { + public override DateTimeOffset GetUtcNow() => throw new AssertionFailedException("TimeProvider should not be used."); + + public override ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period) + => throw new AssertionFailedException("TimeProvider should not be used."); } [Fact] diff --git a/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs b/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs index 7cac4a0177e..9f86fa1367b 100644 --- a/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/Timeout/TimeoutResilienceStrategyTests.cs @@ -224,7 +224,7 @@ await sut.ExecuteAsync(async token => }, cts.Token); } - catch (OperationCanceledException) + catch (TaskCanceledException) { // ok } diff --git a/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs b/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs index 648e29cc198..75fe6db8077 100644 --- a/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs +++ b/test/Polly.Core.Tests/Utils/CancellationTokenSourcePoolTests.cs @@ -34,6 +34,7 @@ public void RentReturn_Reusable_EnsureProperBehavior(object timeProvider) pool.Return(cts); var cts2 = pool.Get(System.Threading.Timeout.InfiniteTimeSpan); + #if NET6_0_OR_GREATER if (timeProvider == TimeProvider.System) { diff --git a/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs b/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs index 2cbdc93f562..0768eff9b77 100644 --- a/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs +++ b/test/Polly.Core.Tests/Utils/TimeProviderExtensionsTests.cs @@ -4,38 +4,27 @@ namespace Polly.Core.Tests.Utils; public class TimeProviderExtensionsTests { - [InlineData(false, false, false)] - [InlineData(false, false, true)] - [InlineData(false, true, true)] - [InlineData(false, true, false)] - [InlineData(true, false, false)] - [InlineData(true, false, true)] - [InlineData(true, true, true)] - [InlineData(true, true, false)] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] [Theory] - public async Task DelayAsync_System_Ok(bool synchronous, bool mocked, bool hasCancellation) + public async Task DelayAsync_System_Ok(bool synchronous, bool hasCancellation) { using var tcs = new CancellationTokenSource(); var token = hasCancellation ? tcs.Token : default; var delay = TimeSpan.FromMilliseconds(10); - var mock = new MockTimeProvider(); - var timeProvider = mocked ? mock.Object : TimeProvider.System; + var timeProvider = TimeProvider.System; var context = ResilienceContext.Get(); context.Initialize(isSynchronous: synchronous); context.CancellationToken = token; - mock.SetupCreateTimer(delay); await TestUtilities.AssertWithTimeoutAsync(async () => { var task = timeProvider.DelayAsync(delay, context); - task.IsCompleted.Should().Be(synchronous || mocked); + task.IsCompleted.Should().Be(synchronous); await task; }); - - if (mocked) - { - mock.VerifyAll(); - } } [Fact] @@ -72,46 +61,38 @@ await TimeProvider.System }); } - [InlineData(false, false)] - [InlineData(false, true)] - [InlineData(true, false)] - [InlineData(true, true)] + [InlineData(false)] + [InlineData(true)] [Theory] - public async Task DelayAsync_CancellationRequestedBefore_Throws(bool synchronous, bool mocked) + public async Task DelayAsync_CancellationRequestedBefore_Throws(bool synchronous) { using var tcs = new CancellationTokenSource(); tcs.Cancel(); var token = tcs.Token; var delay = TimeSpan.FromMilliseconds(10); - var mock = new MockTimeProvider(); - var timeProvider = mocked ? mock.Object : TimeProvider.System; + var timeProvider = TimeProvider.System; var context = ResilienceContext.Get(); context.Initialize(isSynchronous: synchronous); context.CancellationToken = token; - mock.SetupCreateTimer(delay); await Assert.ThrowsAsync(() => timeProvider.DelayAsync(delay, context)); } - [InlineData(false, false)] - [InlineData(false, true)] - [InlineData(true, false)] - [InlineData(true, true)] + [InlineData(false)] + [InlineData(true)] [Theory] - public async Task DelayAsync_CancellationAfter_Throws(bool synchronous, bool mocked) + public async Task DelayAsync_CancellationAfter_Throws(bool synchronous) { var delay = TimeSpan.FromMilliseconds(20); await TestUtilities.AssertWithTimeoutAsync(async () => { - var mock = new MockTimeProvider(); using var tcs = new CancellationTokenSource(); var token = tcs.Token; - var timeProvider = mocked ? mock.Object : TimeProvider.System; + var timeProvider = TimeProvider.System; var context = ResilienceContext.Get(); context.Initialize(isSynchronous: synchronous); context.CancellationToken = token; - mock.SetupCreateTimerException(delay, new OperationCanceledException()); tcs.CancelAfter(TimeSpan.FromMilliseconds(5)); diff --git a/test/Polly.Extensions.Tests/Polly.Extensions.Tests.csproj b/test/Polly.Extensions.Tests/Polly.Extensions.Tests.csproj index cd8c555ac17..fd0d43615c3 100644 --- a/test/Polly.Extensions.Tests/Polly.Extensions.Tests.csproj +++ b/test/Polly.Extensions.Tests/Polly.Extensions.Tests.csproj @@ -10,7 +10,6 @@ - diff --git a/test/Polly.TestUtils/Polly.TestUtils.csproj b/test/Polly.TestUtils/Polly.TestUtils.csproj index 8f53558bf61..e7587e9e770 100644 --- a/test/Polly.TestUtils/Polly.TestUtils.csproj +++ b/test/Polly.TestUtils/Polly.TestUtils.csproj @@ -11,7 +11,7 @@ - +