From e22fefbdb1c0016229e63a41054dac27bcef6d7f Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 12:59:43 +0000 Subject: [PATCH 1/9] Add missing coverage - Add missing code coverage for retry policies. - Avoid allocating empty delegates. --- src/Polly/Retry/AsyncRetryTResultSyntax.cs | 65 ++---- .../Retry/WaitAndRetryAsyncSpecs.cs | 44 ++-- .../WaitAndRetryForeverTResultAsyncSpecs.cs | 196 ++++++++++++++++++ .../Retry/WaitAndRetryTResultAsyncSpecs.cs | 184 ++++++++++++++-- 4 files changed, 404 insertions(+), 85 deletions(-) diff --git a/src/Polly/Retry/AsyncRetryTResultSyntax.cs b/src/Polly/Retry/AsyncRetryTResultSyntax.cs index a55aabe0186..b2de912ae2d 100644 --- a/src/Polly/Retry/AsyncRetryTResultSyntax.cs +++ b/src/Polly/Retry/AsyncRetryTResultSyntax.cs @@ -22,11 +22,7 @@ public static AsyncRetryPolicy RetryAsync(this PolicyBuilderThe retry count. /// The policy instance. public static AsyncRetryPolicy RetryAsync(this PolicyBuilder policyBuilder, int retryCount) - { - Action, int> doNothing = (_, _) => { }; - - return policyBuilder.RetryAsync(retryCount, doNothing); - } + => policyBuilder.RetryAsync(retryCount, static (_, _) => { }); /// /// Builds an that will retry once @@ -183,11 +179,7 @@ public static AsyncRetryPolicy RetryAsync(this PolicyBuilderThe policy builder. /// The policy instance. public static AsyncRetryPolicy RetryForeverAsync(this PolicyBuilder policyBuilder) - { - Action> doNothing = _ => { }; - - return policyBuilder.RetryForeverAsync(doNothing); - } + => policyBuilder.RetryForeverAsync(static _ => { }); /// /// Builds an that will retry indefinitely @@ -368,11 +360,7 @@ public static AsyncRetryPolicy RetryForeverAsync(this PolicyBu /// The function that provides the duration to wait for a particular retry attempt. /// The policy instance. public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBuilder policyBuilder, int retryCount, Func sleepDurationProvider) - { - Action, TimeSpan> doNothing = (_, _) => { }; - - return policyBuilder.WaitAndRetryAsync(retryCount, sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetryAsync(retryCount, sleepDurationProvider, EmptyAction); /// /// Builds an that will wait and retry times @@ -667,8 +655,11 @@ public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBu /// The policy instance. /// retryCount;Value must be greater than or equal to zero. /// Thrown when or is . - public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBuilder policyBuilder, int retryCount, - Func sleepDurationProvider, Func, TimeSpan, int, Context, Task> onRetryAsync) + public static AsyncRetryPolicy WaitAndRetryAsync( + this PolicyBuilder policyBuilder, + int retryCount, + Func sleepDurationProvider, + Func, TimeSpan, int, Context, Task> onRetryAsync) { if (sleepDurationProvider == null) { @@ -695,8 +686,11 @@ public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBu /// The policy instance. /// retryCount;Value must be greater than or equal to zero. /// Thrown when or is . - public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBuilder policyBuilder, int retryCount, - Func, Context, TimeSpan> sleepDurationProvider, Func, TimeSpan, int, Context, Task> onRetryAsync) + public static AsyncRetryPolicy WaitAndRetryAsync( + this PolicyBuilder policyBuilder, + int retryCount, + Func, Context, TimeSpan> sleepDurationProvider, + Func, TimeSpan, int, Context, Task> onRetryAsync) { if (retryCount < 0) { @@ -730,11 +724,7 @@ public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBu /// The sleep durations to wait for on each retry. /// The policy instance. public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBuilder policyBuilder, IEnumerable sleepDurations) - { - Action, TimeSpan> doNothing = (_, _) => { }; - - return policyBuilder.WaitAndRetryAsync(sleepDurations, doNothing); - } + => policyBuilder.WaitAndRetryAsync(sleepDurations, EmptyAction); /// /// Builds an that will wait and retry as many times as there are provided @@ -903,16 +893,7 @@ public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBu /// The policy instance. /// Thrown when is . public static AsyncRetryPolicy WaitAndRetryForeverAsync(this PolicyBuilder policyBuilder, Func sleepDurationProvider) - { - if (sleepDurationProvider == null) - { - throw new ArgumentNullException(nameof(sleepDurationProvider)); - } - - Action, TimeSpan> doNothing = (_, _) => { }; - - return policyBuilder.WaitAndRetryForeverAsync(sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetryForeverAsync(sleepDurationProvider, EmptyAction); /// /// Builds an that will wait and retry indefinitely until the action succeeds. @@ -925,16 +906,7 @@ public static AsyncRetryPolicy WaitAndRetryForeverAsync(this P /// The policy instance. /// Thrown when is . public static AsyncRetryPolicy WaitAndRetryForeverAsync(this PolicyBuilder policyBuilder, Func sleepDurationProvider) - { - if (sleepDurationProvider == null) - { - throw new ArgumentNullException(nameof(sleepDurationProvider)); - } - - Action, TimeSpan, Context> doNothing = (_, _, _) => { }; - - return policyBuilder.WaitAndRetryForeverAsync(sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetryForeverAsync(sleepDurationProvider, static (_, _, _) => { }); /// /// Builds an that will wait and retry indefinitely until the action succeeds, @@ -1221,5 +1193,10 @@ public static AsyncRetryPolicy WaitAndRetryForeverAsync(this P (exception, timespan, i, ctx) => onRetryAsync(exception, i, timespan, ctx), sleepDurationProvider: sleepDurationProvider); } + + private static void EmptyAction(DelegateResult result, TimeSpan retryAfter) + { + // No-op + } } diff --git a/test/Polly.Specs/Retry/WaitAndRetryAsyncSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryAsyncSpecs.cs index fdba78adb7e..fd269c8ae5a 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryAsyncSpecs.cs @@ -509,7 +509,7 @@ await policy.RaiseExceptionAsync( } [Fact] - public void Should_throw_when_retry_count_is_less_than_zero_without_context() + public void Should_throw_when_retry_count_is_less_than_zero() { Action onRetry = (_, _) => { }; @@ -529,7 +529,7 @@ public void Should_throw_when_retry_count_is_less_than_zero_without_context() } [Fact] - public void Should_not_throw_when_retry_count_is_zero_without_context() + public void Should_not_throw_when_arguments_are_valid() { Action policy = () => Policy .Handle() @@ -542,6 +542,18 @@ public void Should_not_throw_when_retry_count_is_zero_without_context() .WaitAndRetryAsync(0, (_, _, _) => TimeSpan.Zero, (_, _, _, _) => TaskHelper.EmptyTask); Should.NotThrow(policy); + + policy = () => Policy + .Handle() + .WaitAndRetryAsync([], (_, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .Handle() + .WaitAndRetryAsync([], (_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); } [Fact] @@ -558,7 +570,7 @@ public void Should_throw_when_sleep_duration_provider_is_null_without_context() } [Fact] - public void Should_throw_when_onretry_action_is_null_without_context_when_using_provider_overload() + public void Should_throw_when_onretry_action_is_null() { Action nullOnRetry = null!; @@ -571,7 +583,7 @@ public void Should_throw_when_onretry_action_is_null_without_context_when_using_ } [Fact] - public void Should_throw_when_onretryasync_action_is_null_without_context() + public void Should_throw_when_onretryasync_action_is_null() { Func onRetryWithContextAsync = null!; @@ -599,32 +611,10 @@ public void Should_throw_when_onretryasync_action_is_null_without_context() Should.Throw(policy) .ParamName.ShouldBe("onRetryAsync"); - } - - [Fact] - public void Should_not_throw_when_onretryasync_action_has_context() - { - Action policy = () => Policy - .Handle() - .WaitAndRetryAsync([], (_, _) => TaskHelper.EmptyTask); - - Should.NotThrow(policy); policy = () => Policy .Handle() - .WaitAndRetryAsync([], (_, _, _) => TaskHelper.EmptyTask); - - Should.NotThrow(policy); - } - - [Fact] - public void Should_throw_when_onretryasync_action_is_null_with_context() - { - Func onRetryAsync = null!; - - Action policy = () => Policy - .Handle() - .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, onRetryAsync); + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, onRetryWithContextAsync); Should.Throw(policy) .ParamName.ShouldBe("onRetryAsync"); diff --git a/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs index 2c6785b2d2d..af3be4c43ed 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs @@ -41,6 +41,202 @@ await policy.ExecuteAsync(async () => actualRetryWaits.ShouldBe(expectedRetryWaits.Values); } + [Fact] + public void Should_throw_if_onRetry_is_null() + { + Action, TimeSpan> onRetry = null!; + + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, onRetry); + + Should.Throw(policy).ParamName.ShouldBe("onRetry"); + + Action, int, TimeSpan> onRetryAttempts = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, onRetryAttempts); + + Should.Throw(policy).ParamName.ShouldBe("onRetry"); + + Action, TimeSpan, Context> onRetryContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero, onRetryContext); + + Should.Throw(policy).ParamName.ShouldBe("onRetry"); + + Action, int, TimeSpan, Context> onRetryAttemptsContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero, onRetryAttemptsContext); + + Should.Throw(policy).ParamName.ShouldBe("onRetry"); + } + + [Fact] + public void Should_throw_if_onRetryAsync_is_null() + { + Func, TimeSpan, Task> onRetryAsync = null!; + + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, onRetryAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, int, TimeSpan, Task> onRetryAttemptsAsync = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, onRetryAttemptsAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, int, TimeSpan, Context, Task> onRetryResultAsync = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _, _) => TimeSpan.Zero, onRetryResultAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + } + + [Fact] + public void Should_throw_if_sleepDurationProvider_is_null() + { + Func sleepDurationProvider = null!; + + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProvider); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + Func sleepDurationProviderContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProviderContext); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProvider, (_, _) => { }); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProvider, (_, _, _) => { }); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProvider, (_, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProvider, (_, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProviderContext, (_, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProviderContext, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + Func, Context, TimeSpan> sleepDurationProviderFunc = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProviderFunc, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + } + + [Fact] + public void Should_not_throw_if_arguments_are_valid() + { + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, (_, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, (_, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_) => TimeSpan.Zero, (_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero, (_, _, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero, (_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _) => TimeSpan.Zero, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _, _) => TimeSpan.Zero, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + } + public void Dispose() => SystemClock.Reset(); } diff --git a/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs index 2a5a952af43..a9cbd803b6a 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs @@ -88,14 +88,64 @@ public void Should_not_throw_when_retry_count_is_zero() [Fact] public void Should_throw_when_onRetryAsync_is_null() { - Action configure = () => Policy + Action policy = () => Policy .HandleResult(ResultPrimitive.Fault) .WaitAndRetryAsync( 2, (_, _, _) => default, null); - Should.Throw(configure).ParamName.ShouldBe("onRetryAsync"); + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, TimeSpan, Task> onRetryAsync = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, TimeSpan, Context, Task> onRetryAsyncContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryAsyncContext); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, TimeSpan, Context, Task> onRetryWithContextAsync = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, onRetryWithContextAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], onRetryAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], onRetryWithContextAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], onRetryWithContextAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, TimeSpan, int, Context, Task> onRetryWithAttemptsAsync = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], onRetryWithAttemptsAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); } [Fact] @@ -109,47 +159,87 @@ public void Should_throw_when_onretry_action_is_null() Should.Throw(policy).ParamName.ShouldBe("onRetry"); - Func, TimeSpan, Task> onRetryAsync = null!; + Action, TimeSpan, Context> onRetryContext = null!; policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryAsync); + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryContext); - Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + Should.Throw(policy).ParamName.ShouldBe("onRetry"); - Action, TimeSpan, Context> onRetryContext = null!; + Action, TimeSpan, int, Context> onRetryAttemptsResult = null!; policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryContext); + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryAttemptsResult); Should.Throw(policy).ParamName.ShouldBe("onRetry"); - Func, TimeSpan, Context, Task> onRetryAsyncContext = null!; + Action, TimeSpan, Context> onRetryResult = null!; policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryAsyncContext); + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, onRetryResult); - Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + Should.Throw(policy).ParamName.ShouldBe("onRetry"); - Action, TimeSpan, int, Context> onRetryAttemptsResult = null!; + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, onRetryAttemptsResult); + + Should.Throw(policy).ParamName.ShouldBe("onRetry"); policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryAttemptsResult); + .WaitAndRetryAsync([], onRetry); Should.Throw(policy).ParamName.ShouldBe("onRetry"); - Action, TimeSpan, Context> onRetryResult = null!; + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], onRetryContext); + + Should.Throw(policy).ParamName.ShouldBe("onRetry"); policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, onRetryResult); + .WaitAndRetryAsync([], onRetryAttemptsResult); Should.Throw(policy).ParamName.ShouldBe("onRetry"); } + [Fact] + public void Should_throw_sleepDurationProvider_is_null() + { + Func sleepDurationProvider = null!; + + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, sleepDurationProvider, (_, _, _, _) => { }); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + Func sleepDurationProviderContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, sleepDurationProviderContext, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + } + + [Fact] + public void Should_throw_sleepDurations_is_null() + { + IEnumerable sleepDurations = null!; + + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(sleepDurations, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurations"); + } + [Fact] public void Should_not_throw_arguments_valid() { @@ -158,6 +248,72 @@ public void Should_not_throw_arguments_valid() .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, (_, _, _, _) => { }); Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, (_, _, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, (_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_, _) => TimeSpan.Zero, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], (_, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], (_, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], (_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], (_, _, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([], (_, _, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); } public void Dispose() => From c0384038a9cfb14bc939464b3900ca634889e5fa Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 13:17:29 +0000 Subject: [PATCH 2/9] Avoid empty delegates Avoid allocating empty delegates. --- src/Polly/Bulkhead/BulkheadSyntax.cs | 15 +++-- src/Polly/Bulkhead/BulkheadTResultSyntax.cs | 10 +--- src/Polly/Fallback/AsyncFallbackSyntax.cs | 31 +---------- src/Polly/Fallback/FallbackSyntax.cs | 55 +++++------------- src/Polly/Retry/RetrySyntax.cs | 62 ++++++--------------- src/Polly/Timeout/TimeoutTResultSyntax.cs | 32 +++-------- 6 files changed, 52 insertions(+), 153 deletions(-) diff --git a/src/Polly/Bulkhead/BulkheadSyntax.cs b/src/Polly/Bulkhead/BulkheadSyntax.cs index afd10398d9d..cdbea4998b1 100644 --- a/src/Polly/Bulkhead/BulkheadSyntax.cs +++ b/src/Polly/Bulkhead/BulkheadSyntax.cs @@ -11,10 +11,7 @@ public partial class Policy /// maxParallelization;Value must be greater than zero. /// The policy instance. public static BulkheadPolicy Bulkhead(int maxParallelization) - { - Action doNothing = _ => { }; - return Bulkhead(maxParallelization, 0, doNothing); - } + => Bulkhead(maxParallelization, 0, EmptyAction); /// /// Builds a bulkhead isolation , which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. @@ -38,10 +35,7 @@ public static BulkheadPolicy Bulkhead(int maxParallelization, Action on /// maxParallelization;Value must be greater than zero. /// maxQueuingActions;Value must be greater than or equal to zero. public static BulkheadPolicy Bulkhead(int maxParallelization, int maxQueuingActions) - { - Action doNothing = _ => { }; - return Bulkhead(maxParallelization, maxQueuingActions, doNothing); - } + => Bulkhead(maxParallelization, maxQueuingActions, EmptyAction); /// /// Builds a bulkhead isolation , which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. @@ -76,4 +70,9 @@ public static BulkheadPolicy Bulkhead(int maxParallelization, int maxQueuingActi maxQueuingActions, onBulkheadRejected); } + + private static void EmptyAction(Context context) + { + // No-op + } } diff --git a/src/Polly/Bulkhead/BulkheadTResultSyntax.cs b/src/Polly/Bulkhead/BulkheadTResultSyntax.cs index c3661c15628..92c0e127919 100644 --- a/src/Polly/Bulkhead/BulkheadTResultSyntax.cs +++ b/src/Polly/Bulkhead/BulkheadTResultSyntax.cs @@ -12,10 +12,7 @@ public partial class Policy /// maxParallelization;Value must be greater than zero. /// The policy instance. public static BulkheadPolicy Bulkhead(int maxParallelization) - { - Action doNothing = _ => { }; - return Bulkhead(maxParallelization, 0, doNothing); - } + => Bulkhead(maxParallelization, 0, EmptyAction); /// /// Builds a bulkhead isolation , which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. @@ -41,10 +38,7 @@ public static BulkheadPolicy Bulkhead(int maxParallelization, /// maxParallelization;Value must be greater than zero. /// maxQueuingActions;Value must be greater than or equal to zero. public static BulkheadPolicy Bulkhead(int maxParallelization, int maxQueuingActions) - { - Action doNothing = _ => { }; - return Bulkhead(maxParallelization, maxQueuingActions, doNothing); - } + => Bulkhead(maxParallelization, maxQueuingActions, EmptyAction); /// /// Builds a bulkhead isolation , which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. diff --git a/src/Polly/Fallback/AsyncFallbackSyntax.cs b/src/Polly/Fallback/AsyncFallbackSyntax.cs index 933d6c6db24..4874364a379 100644 --- a/src/Polly/Fallback/AsyncFallbackSyntax.cs +++ b/src/Polly/Fallback/AsyncFallbackSyntax.cs @@ -14,17 +14,7 @@ public static class AsyncFallbackSyntax /// Thrown when is . /// The policy instance. public static AsyncFallbackPolicy FallbackAsync(this PolicyBuilder policyBuilder, Func fallbackAction) - { - if (fallbackAction == null) - { - throw new ArgumentNullException(nameof(fallbackAction)); - } - - Func doNothing = _ => TaskHelper.EmptyTask; - return policyBuilder.FallbackAsync( - fallbackAction, - doNothing); - } + => policyBuilder.FallbackAsync(fallbackAction, static _ => TaskHelper.EmptyTask); /// /// Builds an which provides a fallback action if the main execution fails. Executes the main delegate asynchronously, but if this throws a handled exception, first asynchronously calls with details of the handled exception; then asynchronously calls . @@ -114,12 +104,7 @@ public static class AsyncFallbackTResultSyntax /// The fallback value to provide. /// The policy instance. public static AsyncFallbackPolicy FallbackAsync(this PolicyBuilder policyBuilder, TResult fallbackValue) - { - Func, Task> doNothing = _ => TaskHelper.EmptyTask; - return policyBuilder.FallbackAsync( - _ => Task.FromResult(fallbackValue), - doNothing); - } + => policyBuilder.FallbackAsync(_ => Task.FromResult(fallbackValue), static _ => TaskHelper.EmptyTask); /// /// Builds an which provides a fallback value if the main execution fails. Executes the main delegate asynchronously, but if this throws a handled exception or raises a handled result, asynchronously calls and returns its result. @@ -130,17 +115,7 @@ public static AsyncFallbackPolicy FallbackAsync(this PolicyBui /// Thrown when is . /// The policy instance. public static AsyncFallbackPolicy FallbackAsync(this PolicyBuilder policyBuilder, Func> fallbackAction) - { - if (fallbackAction == null) - { - throw new ArgumentNullException(nameof(fallbackAction)); - } - - Func, Task> doNothing = _ => TaskHelper.EmptyTask; - return policyBuilder.FallbackAsync( - fallbackAction, - doNothing); - } + => policyBuilder.FallbackAsync(fallbackAction, static _ => TaskHelper.EmptyTask); /// /// Builds an which provides a fallback value if the main execution fails. Executes the main delegate asynchronously, but if this throws a handled exception or raises a handled result, first asynchronously calls with details of the handled exception or result; then returns . diff --git a/src/Polly/Fallback/FallbackSyntax.cs b/src/Polly/Fallback/FallbackSyntax.cs index 0fa17a1f430..616f291930b 100644 --- a/src/Polly/Fallback/FallbackSyntax.cs +++ b/src/Polly/Fallback/FallbackSyntax.cs @@ -14,15 +14,7 @@ public static class FallbackSyntax /// Thrown when is . /// The policy instance. public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Action fallbackAction) - { - if (fallbackAction == null) - { - throw new ArgumentNullException(nameof(fallbackAction)); - } - - Action doNothing = _ => { }; - return policyBuilder.Fallback(fallbackAction, doNothing); - } + => policyBuilder.Fallback(fallbackAction, EmptyAction); /// /// Builds a which provides a fallback action if the main execution fails. Executes the main delegate, but if this throws a handled exception, calls . @@ -32,15 +24,7 @@ public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Action f /// Thrown when is . /// The policy instance. public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Action fallbackAction) - { - if (fallbackAction == null) - { - throw new ArgumentNullException(nameof(fallbackAction)); - } - - Action doNothing = _ => { }; - return policyBuilder.Fallback(fallbackAction, doNothing); - } + => policyBuilder.Fallback(fallbackAction, EmptyAction); /// /// Builds a which provides a fallback action if the main execution fails. Executes the main delegate, but if this throws a handled exception, first calls with details of the handled exception; then calls . @@ -164,6 +148,11 @@ public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Action @@ -179,10 +168,7 @@ public static class FallbackTResultSyntax /// The fallback value to provide. /// The policy instance. public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, TResult fallbackValue) - { - Action> doNothing = _ => { }; - return policyBuilder.Fallback(() => fallbackValue, doNothing); - } + => policyBuilder.Fallback(() => fallbackValue, EmptyAction); /// /// Builds a which provides a fallback value if the main execution fails. Executes the main delegate, but if this throws a handled exception or raises a handled result, calls and returns its result. @@ -193,15 +179,7 @@ public static FallbackPolicy Fallback(this PolicyBuilderThrown when is . /// The policy instance. public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Func fallbackAction) - { - if (fallbackAction == null) - { - throw new ArgumentNullException(nameof(fallbackAction)); - } - - Action> doNothing = _ => { }; - return policyBuilder.Fallback(fallbackAction, doNothing); - } + => policyBuilder.Fallback(fallbackAction, EmptyAction); /// /// Builds a which provides a fallback value if the main execution fails. Executes the main delegate, but if this throws a handled exception or raises a handled result, calls and returns its result. @@ -212,15 +190,7 @@ public static FallbackPolicy Fallback(this PolicyBuilderThrown when is . /// The policy instance. public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Func fallbackAction) - { - if (fallbackAction == null) - { - throw new ArgumentNullException(nameof(fallbackAction)); - } - - Action> doNothing = _ => { }; - return policyBuilder.Fallback(fallbackAction, doNothing); - } + => policyBuilder.Fallback(fallbackAction, EmptyAction); /// /// Builds a which provides a fallback value if the main execution fails. Executes the main delegate, but if this throws a handled exception or raises a handled result, first calls with details of the handled exception or result; then returns . @@ -387,4 +357,9 @@ public static FallbackPolicy Fallback(this PolicyBuilder(DelegateResult result) + { + // No-op + } } diff --git a/src/Polly/Retry/RetrySyntax.cs b/src/Polly/Retry/RetrySyntax.cs index fb13862da0b..f21133b1d5f 100644 --- a/src/Polly/Retry/RetrySyntax.cs +++ b/src/Polly/Retry/RetrySyntax.cs @@ -20,11 +20,7 @@ public static RetryPolicy Retry(this PolicyBuilder policyBuilder) => /// The retry count. /// The policy instance. public static RetryPolicy Retry(this PolicyBuilder policyBuilder, int retryCount) - { - Action doNothing = (_, _) => { }; - - return policyBuilder.Retry(retryCount, doNothing); - } + => policyBuilder.Retry(retryCount, static (_, _) => { }); /// /// Builds a that will retry once @@ -107,11 +103,7 @@ public static RetryPolicy Retry(this PolicyBuilder policyBuilder, int retryCount /// The policy builder. /// The policy instance. public static RetryPolicy RetryForever(this PolicyBuilder policyBuilder) - { - Action doNothing = _ => { }; - - return policyBuilder.RetryForever(doNothing); - } + => policyBuilder.RetryForever(static _ => { }); /// /// Builds a that will retry indefinitely @@ -199,11 +191,7 @@ public static RetryPolicy RetryForever(this PolicyBuilder policyBuilder, Action< /// The function that provides the duration to wait for a particular retry attempt. /// The policy instance. public static RetryPolicy WaitAndRetry(this PolicyBuilder policyBuilder, int retryCount, Func sleepDurationProvider) - { - Action doNothing = (_, _, _, _) => { }; - - return policyBuilder.WaitAndRetry(retryCount, sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetry(retryCount, sleepDurationProvider, EmptyHandlerWithContext); /// /// Builds a that will wait and retry times @@ -307,11 +295,7 @@ public static RetryPolicy WaitAndRetry(this PolicyBuilder policyBuilder, int ret /// The function that provides the duration to wait for a particular retry attempt. /// The policy instance. public static RetryPolicy WaitAndRetry(this PolicyBuilder policyBuilder, int retryCount, Func sleepDurationProvider) - { - Action doNothing = (_, _, _, _) => { }; - - return policyBuilder.WaitAndRetry(retryCount, sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetry(retryCount, sleepDurationProvider, EmptyHandlerWithContext); /// /// Builds a that will wait and retry times @@ -410,11 +394,7 @@ public static RetryPolicy WaitAndRetry(this PolicyBuilder policyBuilder, int ret /// The sleep durations to wait for on each retry. /// The policy instance. public static RetryPolicy WaitAndRetry(this PolicyBuilder policyBuilder, IEnumerable sleepDurations) - { - Action doNothing = (_, _) => { }; - - return policyBuilder.WaitAndRetry(sleepDurations, doNothing); - } + => policyBuilder.WaitAndRetry(sleepDurations, EmptyHandler); /// /// Builds a that will wait and retry as many times as there are provided @@ -494,16 +474,7 @@ public static RetryPolicy WaitAndRetry(this PolicyBuilder policyBuilder, IEnumer /// The policy instance. /// Thrown when is . public static RetryPolicy WaitAndRetryForever(this PolicyBuilder policyBuilder, Func sleepDurationProvider) - { - if (sleepDurationProvider == null) - { - throw new ArgumentNullException(nameof(sleepDurationProvider)); - } - - Action doNothing = (_, _) => { }; - - return policyBuilder.WaitAndRetryForever(sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetryForever(sleepDurationProvider, EmptyHandler); /// /// Builds a that will wait and retry indefinitely until the action succeeds. @@ -515,16 +486,7 @@ public static RetryPolicy WaitAndRetryForever(this PolicyBuilder policyBuilder, /// The policy instance. /// Thrown when is . public static RetryPolicy WaitAndRetryForever(this PolicyBuilder policyBuilder, Func sleepDurationProvider) - { - if (sleepDurationProvider == null) - { - throw new ArgumentNullException(nameof(sleepDurationProvider)); - } - - Action doNothing = (_, _, _) => { }; - - return policyBuilder.WaitAndRetryForever(sleepDurationProvider, doNothing); - } + => policyBuilder.WaitAndRetryForever(sleepDurationProvider, static (_, _, _) => { }); /// /// Builds a that will wait and retry indefinitely until the action succeeds, @@ -691,4 +653,14 @@ public static RetryPolicy WaitAndRetryForever(this PolicyBuilder policyBuilder, (exception, timespan, i, ctx) => onRetry(exception, i, timespan, ctx), sleepDurationProvider: sleepDurationProvider); } + + private static void EmptyHandler(Exception exception, TimeSpan retryAfter) + { + // No-op + } + + private static void EmptyHandlerWithContext(Exception exception, TimeSpan retryAfter, int attempts, Context context) + { + // No-op + } } diff --git a/src/Polly/Timeout/TimeoutTResultSyntax.cs b/src/Polly/Timeout/TimeoutTResultSyntax.cs index 878feb8f36c..1856c38270e 100644 --- a/src/Polly/Timeout/TimeoutTResultSyntax.cs +++ b/src/Polly/Timeout/TimeoutTResultSyntax.cs @@ -12,9 +12,7 @@ public partial class Policy public static TimeoutPolicy Timeout(int seconds) { TimeoutValidator.ValidateSecondsTimeout(seconds); - Action doNothing = (_, _, _, _) => { }; - - return Timeout(_ => TimeSpan.FromSeconds(seconds), TimeoutStrategy.Optimistic, doNothing); + return Timeout(_ => TimeSpan.FromSeconds(seconds), TimeoutStrategy.Optimistic, EmptyHandler); } /// @@ -28,9 +26,7 @@ public static TimeoutPolicy Timeout(int seconds) public static TimeoutPolicy Timeout(int seconds, TimeoutStrategy timeoutStrategy) { TimeoutValidator.ValidateSecondsTimeout(seconds); - Action doNothing = (_, _, _, _) => { }; - - return Timeout(_ => TimeSpan.FromSeconds(seconds), timeoutStrategy, doNothing); + return Timeout(_ => TimeSpan.FromSeconds(seconds), timeoutStrategy, EmptyHandler); } /// @@ -120,9 +116,7 @@ public static TimeoutPolicy Timeout(TimeSpan timeout) #pragma warning restore S3872 { TimeoutValidator.ValidateTimeSpanTimeout(timeout); - Action doNothing = (_, _, _, _) => { }; - - return Timeout(_ => timeout, TimeoutStrategy.Optimistic, doNothing); + return Timeout(_ => timeout, TimeoutStrategy.Optimistic, EmptyHandler); } #pragma warning disable S3872 @@ -138,9 +132,7 @@ public static TimeoutPolicy Timeout(TimeSpan timeout, TimeoutS #pragma warning restore S3872 { TimeoutValidator.ValidateTimeSpanTimeout(timeout); - Action doNothing = (_, _, _, _) => { }; - - return Timeout(_ => timeout, timeoutStrategy, doNothing); + return Timeout(_ => timeout, timeoutStrategy, EmptyHandler); } #pragma warning disable S3872 @@ -231,8 +223,7 @@ public static TimeoutPolicy Timeout(Func timeoutProv throw new ArgumentNullException(nameof(timeoutProvider)); } - Action doNothing = (_, _, _, _) => { }; - return Timeout(_ => timeoutProvider(), TimeoutStrategy.Optimistic, doNothing); + return Timeout(_ => timeoutProvider(), TimeoutStrategy.Optimistic, EmptyHandler); } /// @@ -250,8 +241,7 @@ public static TimeoutPolicy Timeout(Func timeoutProv throw new ArgumentNullException(nameof(timeoutProvider)); } - Action doNothing = (_, _, _, _) => { }; - return Timeout(_ => timeoutProvider(), timeoutStrategy, doNothing); + return Timeout(_ => timeoutProvider(), timeoutStrategy, EmptyHandler); } /// @@ -344,10 +334,7 @@ public static TimeoutPolicy Timeout(Func timeoutProv /// Thrown when is . /// The policy instance. public static TimeoutPolicy Timeout(Func timeoutProvider) - { - Action doNothing = (_, _, _, _) => { }; - return Timeout(timeoutProvider, TimeoutStrategy.Optimistic, doNothing); - } + => Timeout(timeoutProvider, TimeoutStrategy.Optimistic, EmptyHandler); /// /// Builds a that will wait for a delegate to complete for a specified period of time. A will be thrown if the delegate does not complete within the configured timeout. @@ -358,10 +345,7 @@ public static TimeoutPolicy Timeout(Func ti /// The policy instance. /// Thrown when is . public static TimeoutPolicy Timeout(Func timeoutProvider, TimeoutStrategy timeoutStrategy) - { - Action doNothing = (_, _, _, _) => { }; - return Timeout(timeoutProvider, timeoutStrategy, doNothing); - } + => Timeout(timeoutProvider, timeoutStrategy, EmptyHandler); /// /// Builds a that will wait for a delegate to complete for a specified period of time. A will be thrown if the delegate does not complete within the configured timeout. From 88e7b09b95327d9e514814ab2b8d78751561e0cc Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 14:25:56 +0000 Subject: [PATCH 3/9] Add test coverage Add missing coverage for retry and timeout. --- src/Polly/Retry/AsyncRetryTResultSyntax.cs | 7 +- test/Polly.Specs/Retry/RetryForeverSpecs.cs | 80 +++++------ test/Polly.Specs/Retry/RetrySpecs.cs | 38 +++-- .../Retry/RetryTResultAsyncSpecs.cs | 84 ++++++++++- .../Retry/WaitAndRetryForeverSpecs.cs | 127 +++++++++-------- .../WaitAndRetryForeverTResultAsyncSpecs.cs | 16 ++- test/Polly.Specs/Retry/WaitAndRetrySpecs.cs | 134 ++++++++++-------- .../Retry/WaitAndRetryTResultAsyncSpecs.cs | 38 +++++ .../Timeout/TimeoutTResultSpecs.cs | 99 ++++++++----- 9 files changed, 407 insertions(+), 216 deletions(-) diff --git a/src/Polly/Retry/AsyncRetryTResultSyntax.cs b/src/Polly/Retry/AsyncRetryTResultSyntax.cs index b2de912ae2d..668a8812601 100644 --- a/src/Polly/Retry/AsyncRetryTResultSyntax.cs +++ b/src/Polly/Retry/AsyncRetryTResultSyntax.cs @@ -376,8 +376,11 @@ public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBu /// The policy instance. /// retryCount;Value must be greater than or equal to zero. /// Thrown when or is . - public static AsyncRetryPolicy WaitAndRetryAsync(this PolicyBuilder policyBuilder, int retryCount, - Func sleepDurationProvider, Action, TimeSpan> onRetry) + public static AsyncRetryPolicy WaitAndRetryAsync( + this PolicyBuilder policyBuilder, + int retryCount, + Func sleepDurationProvider, + Action, TimeSpan> onRetry) { if (onRetry == null) { diff --git a/test/Polly.Specs/Retry/RetryForeverSpecs.cs b/test/Polly.Specs/Retry/RetryForeverSpecs.cs index d8bd7a61330..1badb0026b4 100644 --- a/test/Polly.Specs/Retry/RetryForeverSpecs.cs +++ b/test/Polly.Specs/Retry/RetryForeverSpecs.cs @@ -3,68 +3,68 @@ public class RetryForeverSpecs { [Fact] - public void Should_throw_when_onretry_action_without_context_is_null() + public void Should_throw_when_onretry_action_is_null() { - Action nullOnRetry = null!; + Action onRetry = null!; Action policy = () => Policy - .Handle() - .RetryForever(nullOnRetry); + .Handle() + .RetryForever(onRetry); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); - } + .ParamName.ShouldBe("onRetry"); - [Fact] - public void Should_throw_when_onretry_action_with_context_is_null() - { - Action nullOnRetry = null!; + Action onRetryContext = null!; - Action policy = () => Policy - .Handle() - .RetryForever(nullOnRetry); + policy = () => Policy + .Handle() + .RetryForever(onRetryContext); Should.Throw(policy) .ParamName.ShouldBe("onRetry"); - } - [Fact] - public void Should_throw_when_onretry_action_is_null() - { - Action> nullOnRetry = null!; + Action> onRetryResult = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .RetryForever(nullOnRetry); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForever(onRetryResult); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); - } + .ParamName.ShouldBe("onRetry"); - [Fact] - public void Should_throw_when_onretry_action_with_int_is_null() - { - Action, int> nullOnRetry = null!; + Action, int> onRetryResultAttempts = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .RetryForever(nullOnRetry); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForever(onRetryResultAttempts); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); - } + .ParamName.ShouldBe("onRetry"); - [Fact] - public void Should_throw_when_onretry_for_result_action_with_context_is_null() - { - Action, Context> nullOnRetry = null!; + Action, Context> onRetryResultContext = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .RetryForever(nullOnRetry); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForever(onRetryResultContext); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); + .ParamName.ShouldBe("onRetry"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForever(onRetryResultContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + Action onRetryAttempts = null!; + + policy = () => Policy + .Handle() + .RetryForever(onRetryAttempts); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); } [Fact] diff --git a/test/Polly.Specs/Retry/RetrySpecs.cs b/test/Polly.Specs/Retry/RetrySpecs.cs index 1b83df0fe69..3813d78c355 100644 --- a/test/Polly.Specs/Retry/RetrySpecs.cs +++ b/test/Polly.Specs/Retry/RetrySpecs.cs @@ -46,29 +46,39 @@ public void Should_throw_when_retry_count_is_less_than_zero_without_context() } [Fact] - public void Should_throw_when_onretry_action_without_context_is_null() + public void Should_throw_when_onretry_action_is_null() { - Action nullOnRetry = null!; + Action onRetry = null!; Action policy = () => Policy - .Handle() - .Retry(1, nullOnRetry); + .Handle() + .Retry(1, onRetry); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); - } + .ParamName.ShouldBe("onRetry"); - [Fact] - public void Should_throw_when_retry_count_is_less_than_zero_with_context() - { - Action onRetry = (_, _, _) => { }; + policy = () => Policy + .Handle() + .Retry(onRetry); - Action policy = () => Policy - .Handle() - .Retry(-1, onRetry); + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + Action onRetryContext = (_, _, _) => { }; + + policy = () => Policy + .Handle() + .Retry(-1, onRetryContext); Should.Throw(policy) - .ParamName.ShouldBe("retryCount"); + .ParamName.ShouldBe("retryCount"); + + policy = () => Policy + .Handle() + .Retry(-1, onRetryContext); + + Should.Throw(policy) + .ParamName.ShouldBe("retryCount"); } [Fact] diff --git a/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs index 27915fa8cdc..9ee022e28f4 100644 --- a/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs @@ -33,14 +33,94 @@ public void Should_throw_when_action_is_null() .ParamName.ShouldBe("action"); } + [Fact] + public void Should_not_throw_when_arguments_are_valid() + { + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryAsync(1, (_, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryAsync((_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync(); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((DelegateResult _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((DelegateResult _, int _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((_) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((DelegateResult _, int _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((DelegateResult _, Context _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + } + [Fact] public void Should_throw_when_onretryasync_is_null() { Func, int, Task> onRetryAsync = null!; Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .RetryAsync(1, onRetryAsync); + .HandleResult(ResultPrimitive.Fault) + .RetryAsync(1, onRetryAsync); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetryAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryAsync(1, onRetryAsync); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetryAsync"); + + Func, int, Context, Task> onRetryAsyncContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryAsync(1, onRetryAsyncContext); Should.Throw(policy) .ParamName.ShouldBe("onRetryAsync"); diff --git a/test/Polly.Specs/Retry/WaitAndRetryForeverSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryForeverSpecs.cs index b01bce504dd..ec656149444 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryForeverSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryForeverSpecs.cs @@ -6,99 +6,114 @@ public class WaitAndRetryForeverSpecs : IDisposable public WaitAndRetryForeverSpecs() => SystemClock.Sleep = (_, _) => { }; [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_without_context() + public void Should_throw_when_sleep_duration_provider_is_null() { Func sleepDurationProvider = null!; Action policy = () => Policy - .Handle() - .WaitAndRetryForever(sleepDurationProvider); + .Handle() + .WaitAndRetryForever(sleepDurationProvider); Should.Throw(policy) - .ParamName.ShouldBe("sleepDurationProvider"); - } + .ParamName.ShouldBe("sleepDurationProvider"); - [Fact] - public void Should_throw_not_when_sleep_duration_provider_is_not_null_with_context() - { - Func sleepDurationProvider = (_, _) => TimeSpan.Zero; + policy = () => Policy + .Handle() + .WaitAndRetryForever(null, (_, _) => { }); - Action policy = () => Policy - .Handle() - .WaitAndRetryForever(sleepDurationProvider); + Should.Throw(policy) + .ParamName.ShouldBe("sleepDurationProvider"); - Should.NotThrow(policy); - } + policy = () => Policy + .Handle() + .WaitAndRetryForever(sleepDurationProvider, (_, _, _) => { }); - [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_without_context_with_onretry() - { - Action onRetry = (_, _) => { }; + Should.Throw(policy) + .ParamName.ShouldBe("sleepDurationProvider"); - Action policy = () => Policy - .Handle() - .WaitAndRetryForever(null, onRetry); + policy = () => Policy + .Handle() + .WaitAndRetryForever(sleepDurationProvider, (_, _, _, _) => { }); Should.Throw(policy) - .ParamName.ShouldBe("sleepDurationProvider"); - } + .ParamName.ShouldBe("sleepDurationProvider"); - [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_with_context() - { - Action onRetry = (_, _, _) => { }; + policy = () => Policy + .Handle() + .WaitAndRetryForever((Func)null!, (_, _, _) => { }); - Func sleepDurationProvider = null!; + Should.Throw(policy) + .ParamName.ShouldBe("sleepDurationProvider"); - Action policy = () => Policy - .Handle() - .WaitAndRetryForever(sleepDurationProvider, onRetry); + policy = () => Policy + .Handle() + .WaitAndRetryForever((Func)null!, (_, _, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => Policy + .Handle() + .WaitAndRetryForever((Func)null!, (_, _, _, _) => { }); Should.Throw(policy) - .ParamName.ShouldBe("sleepDurationProvider"); + .ParamName.ShouldBe("sleepDurationProvider"); } [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_with_context_and_onretry_with_attempt() + public void Should_throw_not_when_argumets_are_valid() { - Action onRetry = (_, _, _, _) => { }; + Action policy = () => Policy + .Handle() + .WaitAndRetryForever((_, _) => TimeSpan.Zero); - Func sleepDurationProvider = null!; + Should.NotThrow(policy); - Action policy = () => Policy - .Handle() - .WaitAndRetryForever(sleepDurationProvider, onRetry); + policy = () => Policy + .Handle() + .WaitAndRetryForever((_, _) => TimeSpan.Zero, (_, _, _, _) => { }); - Should.Throw(policy) - .ParamName.ShouldBe("sleepDurationProvider"); + Should.NotThrow(policy); } [Fact] - public void Should_throw_when_onretry_action_is_null_without_context() + public void Should_throw_when_onretry_action_is_null() { - Action nullOnRetry = null!; - Func provider = _ => TimeSpan.Zero; + Action onRetry = null!; Action policy = () => Policy - .Handle() - .WaitAndRetryForever(provider, nullOnRetry); + .Handle() + .WaitAndRetryForever(_ => TimeSpan.Zero, onRetry); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); - } + .ParamName.ShouldBe("onRetry"); - [Fact] - public void Should_throw_when_onretry_action_is_null_with_context() - { - Action nullOnRetry = null!; - Func provider = (_, _) => TimeSpan.Zero; + Action onRetryContext = null!; - Action policy = () => Policy - .Handle() - .WaitAndRetryForever(provider, nullOnRetry); + policy = () => Policy + .Handle() + .WaitAndRetryForever((_, _) => TimeSpan.Zero, onRetryContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + Action onRetryAttempts = null!; + + policy = () => Policy + .Handle() + .WaitAndRetryForever((_) => TimeSpan.Zero, onRetryAttempts); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + Action onRetryAttemptsContext = null!; + + policy = () => Policy + .Handle() + .WaitAndRetryForever((_, _, _) => TimeSpan.Zero, onRetryAttemptsContext); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); + .ParamName.ShouldBe("onRetry"); } [Fact] diff --git a/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs index af3be4c43ed..48ae30ba709 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs @@ -96,7 +96,15 @@ public void Should_throw_if_onRetryAsync_is_null() Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); - Func, int, TimeSpan, Context, Task> onRetryResultAsync = null!; + Func, TimeSpan, Context, Task> onRetryResultRetryAfterAsync = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync((_, _, _) => TimeSpan.Zero, onRetryResultRetryAfterAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, TimeSpan, Context, Task> onRetryResultAsync = null!; policy = () => Policy .HandleResult(ResultPrimitive.Fault) @@ -162,6 +170,12 @@ public void Should_throw_if_sleepDurationProvider_is_null() Func, Context, TimeSpan> sleepDurationProviderFunc = null!; + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProviderFunc, (_, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + policy = () => Policy .HandleResult(ResultPrimitive.Fault) .WaitAndRetryForeverAsync(sleepDurationProviderFunc, (_, _, _, _) => TaskHelper.EmptyTask); diff --git a/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs b/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs index 70c387ae999..e9330e99a32 100644 --- a/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs @@ -45,39 +45,66 @@ public void Should_throw_when_sleep_durations_is_null_with_attempts_with_context } [Fact] - public void Should_throw_when_onretry_action_is_null_without_context() + public void Should_throw_when_onretry_action_is_null() { - Action nullOnRetry = null!; + Action onRetry = null!; Action policy = () => Policy.Handle() - .WaitAndRetry([], nullOnRetry); + .WaitAndRetry([], onRetry); Should.Throw(policy) .ParamName.ShouldBe("onRetry"); - } - [Fact] - public void Should_throw_when_onretry_action_is_null_with_context() - { - Action nullOnRetry = null!; + Action onRetryContext = null!; - Action policy = () => + policy = () => Policy.Handle() - .WaitAndRetry([], nullOnRetry); + .WaitAndRetry([], onRetryContext); Should.Throw(policy) .ParamName.ShouldBe("onRetry"); - } - [Fact] - public void Should_throw_when_onretry_action_is_null_with_attempts_with_context() - { - Action nullOnRetry = null!; + Action onRetryAttemptsContext = null!; - Action policy = () => + policy = () => + Policy.Handle() + .WaitAndRetry([], onRetryAttemptsContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + policy = () => + Policy.Handle() + .WaitAndRetry(1, _ => default, onRetry); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + policy = () => Policy.Handle() - .WaitAndRetry([], nullOnRetry); + .WaitAndRetry(1, _ => default, onRetryContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + policy = () => + Policy.Handle() + .WaitAndRetry(1, _ => default, onRetryAttemptsContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + policy = () => + Policy.Handle() + .WaitAndRetry(1, (_, _) => default, onRetryContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); + + policy = () => + Policy.Handle() + .WaitAndRetry(1, (_, _) => default, onRetryAttemptsContext); Should.Throw(policy) .ParamName.ShouldBe("onRetry"); @@ -516,6 +543,22 @@ public void Should_throw_when_retry_count_is_less_than_zero() .ParamName.ShouldBe("retryCount"); } + [Fact] + public void Should_not_throw_if_arguments_are_valid() + { + var policy = () => + Policy.Handle() + .WaitAndRetry(1, _ => TimeSpan.Zero); + + Should.NotThrow(policy); + + policy = () => + Policy.Handle() + .WaitAndRetry(1, (_, _) => TimeSpan.Zero); + + Should.NotThrow(policy); + } + [Fact] public void Should_not_throw_when_retry_count_is_zero() { @@ -570,78 +613,43 @@ public void Should_throw_when_retry_count_is_less_than_zero_with_attempts_with_c } [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_without_context() + public void Should_throw_when_sleep_duration_provider_is_null() { - Action onRetry = (_, _) => { }; - Action policy = () => Policy.Handle() - .WaitAndRetry(1, null, onRetry); + .WaitAndRetry(1, null, (_, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("sleepDurationProvider"); - } - [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_with_context() - { - Action onRetry = (_, _, _) => { }; - - Action policy = () => + policy = () => Policy.Handle() - .WaitAndRetry(1, (Func)null!, onRetry); + .WaitAndRetry(1, (Func)null!, (_, _, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("sleepDurationProvider"); - } - - [Fact] - public void Should_throw_when_sleep_duration_provider_is_null_with_attempts_with_context() - { - Action onRetry = (_, _, _, _) => { }; - Action policy = () => + policy = () => Policy.Handle() - .WaitAndRetry(1, (Func)null!, onRetry); + .WaitAndRetry(1, (Func)null!, (_, _, _, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("sleepDurationProvider"); - } - - [Fact] - public void Should_throw_when_onretry_action_is_null_without_context_when_using_provider_overload() - { - Action nullOnRetry = null!; - Action policy = () => - Policy.Handle() - .WaitAndRetry(1, _ => default, nullOnRetry); - - Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); - } - - [Fact] - public void Should_throw_when_onretry_action_is_null_with_context_when_using_provider_overload() - { - Action nullOnRetry = null!; - - Action policy = () => + policy = () => Policy.Handle() - .WaitAndRetry(1, _ => default, nullOnRetry); + .WaitAndRetry(1, (Func)null!, (_, _, _, _) => { }); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); + .ParamName.ShouldBe("sleepDurationProvider"); } [Fact] - public void Should_throw_when_onretry_action_is_null_with_attempts_with_context_when_using_provider_overload() + public void Should_throw_when_onRetry_is_null() { - Action nullOnRetry = null!; - Action policy = () => Policy.Handle() - .WaitAndRetry(1, _ => default, nullOnRetry); + .WaitAndRetry(1, (_, _, _) => TimeSpan.Zero, null); Should.Throw(policy) .ParamName.ShouldBe("onRetry"); diff --git a/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs index a9cbd803b6a..31db6949e04 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs @@ -146,6 +146,12 @@ public void Should_throw_when_onRetryAsync_is_null() .WaitAndRetryAsync([], onRetryWithAttemptsAsync); Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, onRetryWithAttemptsAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); } [Fact] @@ -226,6 +232,14 @@ public void Should_throw_sleepDurationProvider_is_null() .WaitAndRetryAsync(1, sleepDurationProviderContext, (_, _, _, _) => TaskHelper.EmptyTask); Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); + + Func, Context, TimeSpan> sleepDurationProviderResultContext = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, sleepDurationProviderResultContext, (_, _, _, _) => TaskHelper.EmptyTask); + + Should.Throw(policy).ParamName.ShouldBe("sleepDurationProvider"); } [Fact] @@ -314,6 +328,30 @@ public void Should_not_throw_arguments_valid() .WaitAndRetryAsync([], (_, _, _, _) => TaskHelper.EmptyTask); Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, (_, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync(1, (_) => TimeSpan.Zero, (_, _, _) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryAsync([]); + + Should.NotThrow(policy); } public void Dispose() => diff --git a/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs b/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs index da4b7414fbb..451c711bb14 100644 --- a/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs +++ b/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs @@ -69,67 +69,65 @@ public void Should_throw_when_timeout_is_less_than_zero_by_seconds() } [Fact] - public void Should_not_throw_when_timeout_is_greater_than_zero_by_timespan() + public void Should_not_throw_when_arguments_are_valid() { Action policy = () => Policy.Timeout(TimeSpan.FromMilliseconds(1)); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_is_greater_than_zero_by_seconds() - { - Action policy = () => Policy.Timeout(3); + policy = () => Policy.Timeout(3); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_is_maxvalue() - { - Action policy = () => Policy.Timeout(TimeSpan.MaxValue); + policy = () => Policy.Timeout(TimeSpan.MaxValue); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_seconds_is_maxvalue() - { - Action policy = () => Policy.Timeout(int.MaxValue); + policy = () => Policy.Timeout(int.MaxValue); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_is_infinitetimespan() - { - Action policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan); + policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_is_infinitetimespan_with_timeoutstrategy() - { - Action policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan, TimeoutStrategy.Optimistic); + policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan, TimeoutStrategy.Optimistic); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_is_infinitetimespan_with_ontimeout() - { - Action doNothing = (_, _, _) => { }; - Action policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan, doNothing); + policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan, (_, _, _) => { }); Should.NotThrow(policy); - } - [Fact] - public void Should_not_throw_when_timeout_is_infinitetimespan_with_timeoutstrategy_and_ontimeout() - { - Action doNothing = (_, _, _) => { }; - Action policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan, TimeoutStrategy.Optimistic, doNothing); + policy = () => Policy.Timeout(System.Threading.Timeout.InfiniteTimeSpan, TimeoutStrategy.Optimistic, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout(1, TimeoutStrategy.Optimistic, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout(1, TimeoutStrategy.Optimistic, (_, _, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout(() => TimeSpan.Zero, TimeoutStrategy.Optimistic); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout((_) => TimeSpan.Zero); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout((_) => TimeSpan.Zero, TimeoutStrategy.Optimistic); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout((_) => TimeSpan.Zero, TimeoutStrategy.Optimistic, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout((_) => TimeSpan.Zero, TimeoutStrategy.Optimistic, (_, _, _, _) => { }); Should.NotThrow(policy); } @@ -206,6 +204,31 @@ public void Should_throw_when_timeoutProvider_is_null() { Action policy = () => Policy.Timeout((Func)null!); + Should.Throw(policy) + .ParamName.ShouldBe("timeoutProvider"); + + policy = () => Policy.Timeout((Func)null!, (_, _, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("timeoutProvider"); + + policy = () => Policy.Timeout((Func)null!, (_, _, _, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("timeoutProvider"); + + policy = () => Policy.Timeout((Func)null!, TimeoutStrategy.Pessimistic, (_, _, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("timeoutProvider"); + + policy = () => Policy.Timeout((Func)null!, TimeoutStrategy.Pessimistic, (_, _, _, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("timeoutProvider"); + + policy = () => Policy.Timeout((Func)null!, TimeoutStrategy.Pessimistic, (_, _, _, _) => { }); + Should.Throw(policy) .ParamName.ShouldBe("timeoutProvider"); } From 0d036abadd90f9fe78535ef0621d2a36c5d282c0 Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 14:31:44 +0000 Subject: [PATCH 4/9] Fix S3257 warnings Fix three S3257 warnings, two of which are false positives. --- test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs index 9ee022e28f4..0b41857e261 100644 --- a/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/RetryTResultAsyncSpecs.cs @@ -56,7 +56,7 @@ public void Should_not_throw_when_arguments_are_valid() policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .RetryForeverAsync((DelegateResult _) => { }); + .RetryForeverAsync((_) => { }); Should.NotThrow(policy); @@ -72,15 +72,19 @@ public void Should_not_throw_when_arguments_are_valid() Should.NotThrow(policy); + Func, int, Task> onRetryAttempts = (_, _) => TaskHelper.EmptyTask; + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .RetryForeverAsync((DelegateResult _, int _) => TaskHelper.EmptyTask); + .RetryForeverAsync(onRetryAttempts); Should.NotThrow(policy); + Func, Context, Task> onRetryContext = (_, _) => TaskHelper.EmptyTask; + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .RetryForeverAsync((DelegateResult _, Context _) => TaskHelper.EmptyTask); + .RetryForeverAsync(onRetryContext); Should.NotThrow(policy); From 7af811da96d911b85573ab93b5dede61385b291c Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 14:53:50 +0000 Subject: [PATCH 5/9] Add missing coverage Add more missing code coverage. --- .../Retry/RetryForeverAsyncSpecs.cs | 25 ++++++++++++++++--- test/Polly.Specs/Retry/RetryForeverSpecs.cs | 9 +++++++ .../WaitAndRetryForeverTResultAsyncSpecs.cs | 13 ++++++++-- test/Polly.Specs/Retry/WaitAndRetrySpecs.cs | 7 ++++++ 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/test/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs b/test/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs index 2d70f969573..3f3a56a100d 100644 --- a/test/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs @@ -4,6 +4,16 @@ namespace Polly.Specs.Retry; public class RetryForeverAsyncSpecs { + [Fact] + public void Should_not_throw_if_arguments_are_valid() + { + Action policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync((DelegateResult _, Context _) => { }); + + Should.NotThrow(policy); + } + [Fact] public async Task Should_not_throw_regardless_of_how_many_times_the_specified_exception_is_raised() { @@ -108,11 +118,20 @@ public void Should_throw_when_onretry_is_null() Action> onRetry = null!; Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .RetryForeverAsync(onRetry); + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync(onRetry); Should.Throw(policy) - .ParamName.ShouldBe("onRetry"); + .ParamName.ShouldBe("onRetry"); + + Action, int> onRetryAttempts = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .RetryForeverAsync(onRetryAttempts); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); } [Fact] diff --git a/test/Polly.Specs/Retry/RetryForeverSpecs.cs b/test/Polly.Specs/Retry/RetryForeverSpecs.cs index 1badb0026b4..0fe51b2dbdf 100644 --- a/test/Polly.Specs/Retry/RetryForeverSpecs.cs +++ b/test/Polly.Specs/Retry/RetryForeverSpecs.cs @@ -65,6 +65,15 @@ public void Should_throw_when_onretry_action_is_null() Should.Throw(policy) .ParamName.ShouldBe("onRetry"); + + Action onRetryAttemptsContext = null!; + + policy = () => Policy + .Handle() + .RetryForever(onRetryAttemptsContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onRetry"); } [Fact] diff --git a/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs b/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs index 48ae30ba709..f7dd3c2e2e0 100644 --- a/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetryForeverTResultAsyncSpecs.cs @@ -104,11 +104,20 @@ public void Should_throw_if_onRetryAsync_is_null() Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); - Func, TimeSpan, Context, Task> onRetryResultAsync = null!; + Func, TimeSpan, Context, Task> onRetryResultTimeSpanAsync = null!; policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .WaitAndRetryForeverAsync((_, _, _) => TimeSpan.Zero, onRetryResultAsync); + .WaitAndRetryForeverAsync((_, _, _) => TimeSpan.Zero, onRetryResultTimeSpanAsync); + + Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); + + Func, int, TimeSpan, Context, Task> onRetryResultSecondsAsync = null!; + Func, Context, TimeSpan> sleepDurationProvider = (_, _, _) => TimeSpan.Zero; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .WaitAndRetryForeverAsync(sleepDurationProvider, onRetryResultSecondsAsync); Should.Throw(policy).ParamName.ShouldBe("onRetryAsync"); } diff --git a/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs b/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs index e9330e99a32..47763de318c 100644 --- a/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs +++ b/test/Polly.Specs/Retry/WaitAndRetrySpecs.cs @@ -642,6 +642,13 @@ public void Should_throw_when_sleep_duration_provider_is_null() Should.Throw(policy) .ParamName.ShouldBe("sleepDurationProvider"); + + policy = () => + Policy.Handle() + .WaitAndRetry(1, (Func)null!, (_, _, _, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("sleepDurationProvider"); } [Fact] From 37f82f9587c22645d0c863cfd695764442bbfe5f Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 15:21:47 +0000 Subject: [PATCH 6/9] Add missing coverage Add more missing coverage for edited files. --- test/Polly.Specs/Fallback/FallbackSpecs.cs | 95 ++++------- .../Fallback/FallbackTResultSpecs.cs | 150 +++++++----------- .../Timeout/TimeoutTResultSpecs.cs | 12 ++ 3 files changed, 101 insertions(+), 156 deletions(-) diff --git a/test/Polly.Specs/Fallback/FallbackSpecs.cs b/test/Polly.Specs/Fallback/FallbackSpecs.cs index 614d02b9f05..f573d058b0b 100644 --- a/test/Polly.Specs/Fallback/FallbackSpecs.cs +++ b/test/Polly.Specs/Fallback/FallbackSpecs.cs @@ -42,72 +42,44 @@ public void Should_throw_when_fallback_action_is_null() Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - - [Fact] - public void Should_throw_when_fallback_action_with_cancellation_is_null() - { - Action fallbackAction = null!; - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction); + .Fallback(fallbackAction, _ => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_is_null_with_onFallback() - { - Action fallbackAction = null!; - Action onFallback = _ => { }; - - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(fallbackActionToken, _ => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_with_cancellation_is_null_with_onFallback() - { - Action fallbackAction = null!; - Action onFallback = _ => { }; + Action fallbackActionContext = null!; - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(fallbackActionContext, (_, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_is_null_with_onFallback_with_context() - { - Action fallbackAction = null!; - Action onFallback = (_, _) => { }; + Action fallbackActionContextToken = null!; - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(fallbackActionContextToken, (_, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_with_cancellation_is_null_with_onFallback_with_context() - { - Action fallbackAction = null!; - Action onFallback = (_, _) => { }; + Action fallbackActionExceptionContextToken = null!; - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(fallbackActionExceptionContextToken, (_, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); @@ -116,54 +88,43 @@ public void Should_throw_when_fallback_action_with_cancellation_is_null_with_onF [Fact] public void Should_throw_when_onFallback_delegate_is_null() { - Action fallbackAction = () => { }; Action onFallback = null!; Action policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(() => { }, onFallback); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_action_with_cancellation() - { - Action fallbackAction = _ => { }; - Action onFallback = null!; + Action onFallbackException = null!; - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(_ => { }, onFallbackException); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_context() - { - Action fallbackAction = _ => { }; - Action onFallback = null!; + Action onFallbackExceptionContext = null!; - Action policy = () => Policy + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback(_ => { }, onFallbackExceptionContext); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_context_with_action_with_cancellation() - { - Action fallbackAction = (_, _) => { }; - Action onFallback = null!; + policy = () => Policy + .Handle() + .Fallback((_, _) => { }, onFallbackExceptionContext); - Action policy = () => Policy + Should.Throw(policy) + .ParamName.ShouldBe("onFallback"); + + policy = () => Policy .Handle() - .Fallback(fallbackAction, onFallback); + .Fallback((_, _, _) => { }, onFallbackExceptionContext); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); diff --git a/test/Polly.Specs/Fallback/FallbackTResultSpecs.cs b/test/Polly.Specs/Fallback/FallbackTResultSpecs.cs index ea4927349b4..a6c6f0e0be2 100644 --- a/test/Polly.Specs/Fallback/FallbackTResultSpecs.cs +++ b/test/Polly.Specs/Fallback/FallbackTResultSpecs.cs @@ -33,28 +33,6 @@ public void Should_throw_when_action_is_null() .ParamName.ShouldBe("action"); } - [Fact] - public void Should_throw_when_fallback_action_is_null() - { - Func fallbackAction = null!; - - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction); - - Should.Throw(policy) - .ParamName.ShouldBe("fallbackAction"); - - Func fallbackActionToken = null!; - - policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackActionToken); - - Should.Throw(policy) - .ParamName.ShouldBe("fallbackAction"); - } - [Fact] public void Should_not_throw_when_fallback_action_is_not_null() { @@ -69,12 +47,18 @@ public void Should_not_throw_when_fallback_action_is_not_null() .Fallback((_) => ResultPrimitive.Substitute); Should.NotThrow(policy); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(ResultPrimitive.Substitute, (_) => { }); + + Should.NotThrow(policy); } [Fact] - public void Should_throw_when_fallback_action_with_cancellation_is_null() + public void Should_throw_when_fallback_action_is_null() { - Func fallbackAction = null!; + Func fallbackAction = null!; Action policy = () => Policy .HandleResult(ResultPrimitive.Fault) @@ -82,59 +66,53 @@ public void Should_throw_when_fallback_action_with_cancellation_is_null() Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_is_null_with_onFallback() - { - Func fallbackAction = null!; - Action> onFallback = _ => { }; + Func fallbackActionToken = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(fallbackActionToken); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_with_cancellation_is_null_with_onFallback() - { - Func fallbackAction = null!; - Action> onFallback = _ => { }; + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(fallbackAction, _ => { }); - Action policy = () => Policy + Should.Throw(policy) + .ParamName.ShouldBe("fallbackAction"); + + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + .Fallback(fallbackActionToken, _ => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_is_null_with_onFallback_with_context() - { - Func fallbackAction = null!; - Action, Context> onFallback = (_, _) => { }; + Func fallbackActionContext = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(fallbackActionContext, (_, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_with_cancellation_is_null_with_onFallback_with_context() - { - Func fallbackAction = null!; - Action, Context> onFallback = (_, _) => { }; + Func fallbackActionContextToken = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(fallbackActionContextToken, (_, _) => { }); + + Should.Throw(policy) + .ParamName.ShouldBe("fallbackAction"); + + Func, Context, CancellationToken, ResultPrimitive> fallbackActionResultContextToken = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(fallbackActionResultContextToken, (_, _) => { }); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); @@ -143,12 +121,11 @@ public void Should_throw_when_fallback_action_with_cancellation_is_null_with_onF [Fact] public void Should_throw_when_onFallback_delegate_is_null() { - Func fallbackAction = () => ResultPrimitive.Substitute; Action> onFallback = null!; Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + .HandleResult(ResultPrimitive.Fault) + .Fallback(() => ResultPrimitive.Substitute, onFallback); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); @@ -159,45 +136,40 @@ public void Should_throw_when_onFallback_delegate_is_null() Should.Throw(policy) .ParamName.ShouldBe("onFallback"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_action_with_cancellation() - { - Func fallbackAction = _ => ResultPrimitive.Substitute; - Action> onFallback = null!; - - Action policy = () => Policy + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + .Fallback(_ => ResultPrimitive.Substitute, onFallback); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_context() - { - Func fallbackAction = _ => ResultPrimitive.Substitute; - Action, Context> onFallback = null!; + Action, Context> onFallbackContext = null!; - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(_ => ResultPrimitive.Substitute, onFallbackContext); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_context_with_action_with_cancellation() - { - Func fallbackAction = (_, _) => ResultPrimitive.Substitute; - Action, Context> onFallback = null!; + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback((_, _) => ResultPrimitive.Substitute, onFallbackContext); - Action policy = () => Policy - .HandleResult(ResultPrimitive.Fault) - .Fallback(fallbackAction, onFallback); + Should.Throw(policy) + .ParamName.ShouldBe("onFallback"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback(ResultPrimitive.Substitute, onFallbackContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onFallback"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .Fallback((_, _, _) => ResultPrimitive.Substitute, onFallbackContext); Should.Throw(policy) .ParamName.ShouldBe("onFallback"); diff --git a/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs b/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs index 451c711bb14..6fde711c9e6 100644 --- a/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs +++ b/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs @@ -130,6 +130,18 @@ public void Should_not_throw_when_arguments_are_valid() policy = () => Policy.Timeout((_) => TimeSpan.Zero, TimeoutStrategy.Optimistic, (_, _, _, _) => { }); Should.NotThrow(policy); + + policy = () => Policy.Timeout(() => TimeSpan.Zero, TimeoutStrategy.Optimistic, (_, _, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout((_) => TimeSpan.Zero, (_, _, _) => { }); + + Should.NotThrow(policy); + + policy = () => Policy.Timeout((_) => TimeSpan.Zero, (_, _, _, _) => { }); + + Should.NotThrow(policy); } [Fact] From e3a48bccdf90a2948b14234c0b71a8b344157b20 Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 15:36:17 +0000 Subject: [PATCH 7/9] Add more coverage Add some further missing coverage. --- src/Polly/Fallback/AsyncFallbackSyntax.cs | 6 +- .../Fallback/FallbackAsyncSpecs.cs | 54 +++++++----------- .../Fallback/FallbackTResultAsyncSpecs.cs | 57 ++++++++++--------- 3 files changed, 53 insertions(+), 64 deletions(-) diff --git a/src/Polly/Fallback/AsyncFallbackSyntax.cs b/src/Polly/Fallback/AsyncFallbackSyntax.cs index 4874364a379..b4c5fcb24ff 100644 --- a/src/Polly/Fallback/AsyncFallbackSyntax.cs +++ b/src/Polly/Fallback/AsyncFallbackSyntax.cs @@ -234,8 +234,8 @@ public static AsyncFallbackPolicy FallbackAsync(this PolicyBui } return new AsyncFallbackPolicy( - policyBuilder, - onFallbackAsync, - fallbackAction); + policyBuilder, + onFallbackAsync, + fallbackAction); } } diff --git a/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs b/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs index 3fad46ce4d2..1909dc41e4b 100644 --- a/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs +++ b/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs @@ -17,31 +17,28 @@ public void Should_throw_when_fallback_func_is_null() Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_func_is_null_with_onFallback() - { - Func fallbackActionAsync = null!; - Func onFallbackAsync = _ => TaskHelper.EmptyTask; + policy = () => Policy + .Handle() + .FallbackAsync(fallbackActionAsync, _ => TaskHelper.EmptyTask); - Action policy = () => Policy + Should.Throw(policy) + .ParamName.ShouldBe("fallbackAction"); + + Func fallbackActionAsyncContext = null!; + + policy = () => Policy .Handle() - .FallbackAsync(fallbackActionAsync, onFallbackAsync); + .FallbackAsync(fallbackActionAsyncContext, (_, _) => TaskHelper.EmptyTask); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_func_is_null_with_onFallback_with_context() - { - Func fallbackActionAsync = null!; - Func onFallbackAsync = (_, _) => TaskHelper.EmptyTask; + Func fallbackActionAsyncExceptionContext = null!; - Action policy = () => Policy - .Handle() - .FallbackAsync(fallbackActionAsync, onFallbackAsync); + policy = () => Policy + .Handle() + .FallbackAsync(fallbackActionAsyncExceptionContext, (_, _) => TaskHelper.EmptyTask); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); @@ -50,33 +47,20 @@ public void Should_throw_when_fallback_func_is_null_with_onFallback_with_context [Fact] public void Should_throw_when_onFallback_delegate_is_null() { - Func fallbackActionAsync = _ => TaskHelper.EmptyTask; Func onFallbackAsync = null!; Action policy = () => Policy - .Handle() - .FallbackAsync(fallbackActionAsync, onFallbackAsync); - - Should.Throw(policy) - .ParamName.ShouldBe("onFallbackAsync"); - - policy = () => Policy .Handle() - .FallbackAsync(fallbackActionAsync, onFallbackAsync); + .FallbackAsync(_ => TaskHelper.EmptyTask, onFallbackAsync); Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_context() - { - Func fallbackActionAsync = (_, _) => TaskHelper.EmptyTask; - Func onFallbackAsync = null!; + Func onFallbackAsyncContext = null!; - Action policy = () => Policy - .Handle() - .FallbackAsync(fallbackActionAsync, onFallbackAsync); + policy = () => Policy + .Handle() + .FallbackAsync((_, _, _) => TaskHelper.EmptyTask, onFallbackAsyncContext); Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); diff --git a/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs b/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs index ec823134f8a..4de38960cee 100644 --- a/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs @@ -44,31 +44,29 @@ public void Should_throw_when_fallback_action_is_null() Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - - [Fact] - public void Should_throw_when_fallback_action_is_null_with_onFallback() - { - Func> fallbackAction = null!; Func, Task> onFallbackAsync = _ => TaskHelper.EmptyTask; - Action policy = () => Policy + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .FallbackAsync(fallbackAction, onFallbackAsync); + .FallbackAsync(fallbackAction, _ => TaskHelper.EmptyTask); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); - } - [Fact] - public void Should_throw_when_fallback_action_is_null_with_onFallback_with_context() - { - Func> fallbackAction = null!; - Func, Context, Task> onFallbackAsync = (_, _) => TaskHelper.EmptyTask; + Func> fallbackActionContext = null!; - Action policy = () => Policy + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .FallbackAsync(fallbackAction, onFallbackAsync); + .FallbackAsync(fallbackActionContext, (_, _) => TaskHelper.EmptyTask); + + Should.Throw(policy) + .ParamName.ShouldBe("fallbackAction"); + + Func, Context, CancellationToken, Task> fallbackActionResult = null!; + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .FallbackAsync(fallbackActionResult, (_, _) => TaskHelper.EmptyTask); Should.Throw(policy) .ParamName.ShouldBe("fallbackAction"); @@ -77,12 +75,11 @@ public void Should_throw_when_fallback_action_is_null_with_onFallback_with_conte [Fact] public void Should_throw_when_onFallback_delegate_is_null() { - Func> fallbackAction = _ => Task.FromResult(ResultPrimitive.Substitute); Func, Task> onFallbackAsync = null!; Action policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .FallbackAsync(fallbackAction, onFallbackAsync); + .FallbackAsync(_ => Task.FromResult(ResultPrimitive.Substitute), onFallbackAsync); Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); @@ -93,17 +90,12 @@ public void Should_throw_when_onFallback_delegate_is_null() Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); - } - [Fact] - public void Should_throw_when_onFallback_delegate_is_null_with_context() - { - Func> fallbackAction = (_, _) => Task.FromResult(ResultPrimitive.Substitute); - Func, Context, Task> onFallbackAsync = null!; + Func, Context, Task> onFallbackAsyncContext = null!; - Action policy = () => Policy + policy = () => Policy .HandleResult(ResultPrimitive.Fault) - .FallbackAsync(fallbackAction, onFallbackAsync); + .FallbackAsync((_, _) => Task.FromResult(ResultPrimitive.Substitute), onFallbackAsyncContext); Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); @@ -114,6 +106,13 @@ public void Should_throw_when_onFallback_delegate_is_null_with_context() Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .FallbackAsync((_, _, _) => Task.FromResult(ResultPrimitive.Substitute), onFallbackAsyncContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onFallbackAsync"); } [Fact] @@ -125,6 +124,12 @@ public void Should_not_throw_when_onFallback_delegate_is_not_null() Should.NotThrow(policy); + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .FallbackAsync(ResultPrimitive.Substitute, (_) => TaskHelper.EmptyTask); + + Should.NotThrow(policy); + policy = () => Policy .HandleResult(ResultPrimitive.Fault) .FallbackAsync(ResultPrimitive.Substitute, (_, _) => TaskHelper.EmptyTask); From 2e34c399aff43105e445f2f3b1c4430b243b1e6f Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 15:49:56 +0000 Subject: [PATCH 8/9] Add missing coverage Add two remaining uncovered async fallback coverage branches. --- test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs | 7 +++++++ test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs b/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs index 1909dc41e4b..c87bf4e068e 100644 --- a/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs +++ b/test/Polly.Specs/Fallback/FallbackAsyncSpecs.cs @@ -58,6 +58,13 @@ public void Should_throw_when_onFallback_delegate_is_null() Func onFallbackAsyncContext = null!; + policy = () => Policy + .Handle() + .FallbackAsync((_, _) => TaskHelper.EmptyTask, onFallbackAsyncContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onFallbackAsync"); + policy = () => Policy .Handle() .FallbackAsync((_, _, _) => TaskHelper.EmptyTask, onFallbackAsyncContext); diff --git a/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs b/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs index 4de38960cee..6764b3f2787 100644 --- a/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs @@ -113,6 +113,13 @@ public void Should_throw_when_onFallback_delegate_is_null() Should.Throw(policy) .ParamName.ShouldBe("onFallbackAsync"); + + policy = () => Policy + .HandleResult(ResultPrimitive.Fault) + .FallbackAsync(ResultPrimitive.Substitute, onFallbackAsyncContext); + + Should.Throw(policy) + .ParamName.ShouldBe("onFallbackAsync"); } [Fact] From b1b3c4ca359baaf104dff9f60e31f32f4eb3d25b Mon Sep 17 00:00:00 2001 From: martincostello Date: Mon, 17 Feb 2025 16:00:56 +0000 Subject: [PATCH 9/9] Increase thresholds - Increase code coverage thresholds after new tests added. - Increase mutation score for Polly to 100. --- src/Polly/Polly.csproj | 2 +- test/Polly.Specs/Polly.Specs.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Polly/Polly.csproj b/src/Polly/Polly.csproj index 4078c2f8734..2d17bf02a62 100644 --- a/src/Polly/Polly.csproj +++ b/src/Polly/Polly.csproj @@ -5,7 +5,7 @@ Polly true Library - 97 + 100 true $(NoWarn);RS0037 diff --git a/test/Polly.Specs/Polly.Specs.csproj b/test/Polly.Specs/Polly.Specs.csproj index 4e9ee7cf1bd..0564c3aedef 100644 --- a/test/Polly.Specs/Polly.Specs.csproj +++ b/test/Polly.Specs/Polly.Specs.csproj @@ -5,7 +5,7 @@ $(TargetFrameworks);net481 enable Test - 85,80,85 + 91,90,89 [Polly]* true