Skip to content

Commit

Permalink
Fix CA1062 warnings (#2225)
Browse files Browse the repository at this point in the history
Fix warnings for `AsyncRetryPolicy`.
  • Loading branch information
Zombach authored Jul 22, 2024
1 parent 80421c2 commit 6d2b4e9
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 4 deletions.
22 changes: 18 additions & 4 deletions src/Polly/Retry/AsyncRetryPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
/// <summary>
/// A retry policy that can be applied to asynchronous delegates.
/// </summary>
#pragma warning disable CA1062 // Validate arguments of public methods
public class AsyncRetryPolicy : AsyncPolicy, IRetryPolicy
{
private readonly Func<Exception, TimeSpan, int, Context, Task> _onRetryAsync;
Expand Down Expand Up @@ -34,6 +33,11 @@ protected override Task<TResult> ImplementationAsync<TResult>(
CancellationToken cancellationToken,
bool continueOnCapturedContext)
{
if (action is null)
{
throw new ArgumentNullException(nameof(action));
}

var sleepDurationProvider = _sleepDurationProvider != null
? (retryCount, outcome, ctx) => _sleepDurationProvider(retryCount, outcome.Exception, ctx)
: (Func<int, DelegateResult<TResult>, Context, TimeSpan>)null;
Expand Down Expand Up @@ -79,9 +83,18 @@ internal AsyncRetryPolicy(

/// <inheritdoc/>
[DebuggerStepThrough]
protected override Task<TResult> ImplementationAsync(Func<Context, CancellationToken, Task<TResult>> action, Context context, CancellationToken cancellationToken,
bool continueOnCapturedContext) =>
AsyncRetryEngine.ImplementationAsync(
protected override Task<TResult> ImplementationAsync(
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
CancellationToken cancellationToken,
bool continueOnCapturedContext)
{
if (action is null)
{
throw new ArgumentNullException(nameof(action));
}

return AsyncRetryEngine.ImplementationAsync(
action,
context,
ExceptionPredicates,
Expand All @@ -92,5 +105,6 @@ protected override Task<TResult> ImplementationAsync(Func<Context, CancellationT
_sleepDurationsEnumerable,
_sleepDurationProvider,
continueOnCapturedContext);
}
}

30 changes: 30 additions & 0 deletions test/Polly.Specs/Retry/RetryAsyncSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,36 @@ namespace Polly.Specs.Retry;

public class RetryAsyncSpecs
{
[Fact]
public void Should_throw_when_action_is_null()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
Func<Context, CancellationToken, Task<EmptyStruct>> action = null!;
var policyBuilder = new PolicyBuilder(exception => exception);
Func<Exception, TimeSpan, int, Context, Task> onRetryAsync = (_, _, _, _) => Task.CompletedTask;
int permittedRetryCount = int.MaxValue;
IEnumerable<TimeSpan>? sleepDurationsEnumerable = null;
Func<int, Exception, Context, TimeSpan> sleepDurationProvider = null!;

var instance = Activator.CreateInstance(
typeof(AsyncRetryPolicy),
flags,
null,
[policyBuilder, onRetryAsync, permittedRetryCount, sleepDurationsEnumerable, sleepDurationProvider],
null)!;
var instanceType = instance.GetType();
var methods = instanceType.GetMethods(flags);
var methodInfo = methods.First(method => method is { Name: "ImplementationAsync", ReturnType.Name: "Task`1" });
var generic = methodInfo.MakeGenericMethod(typeof(EmptyStruct));

var func = () => generic.Invoke(instance, [action, new Context(), CancellationToken.None, false]);

var exceptionAssertions = func.Should().Throw<TargetInvocationException>();
exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation.");
exceptionAssertions.And.InnerException.Should().BeOfType<ArgumentNullException>()
.Which.ParamName.Should().Be("action");
}

[Fact]
public void Should_throw_when_retry_count_is_less_than_zero_without_context()
{
Expand Down
29 changes: 29 additions & 0 deletions test/Polly.Specs/Retry/RetryTResultSpecsAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@ namespace Polly.Specs.Retry;

public class RetryTResultSpecsAsync
{
[Fact]
public void Should_throw_when_action_is_null()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
Func<Context, CancellationToken, Task<EmptyStruct>> action = null!;
var policyBuilder = new PolicyBuilder<EmptyStruct>(exception => exception);
Func<DelegateResult<EmptyStruct>, TimeSpan, int, Context, Task> onRetryAsync = (_, _, _, _) => Task.CompletedTask;
int permittedRetryCount = int.MaxValue;
IEnumerable<TimeSpan>? sleepDurationsEnumerable = null;
Func<int, DelegateResult<EmptyStruct>, Context, TimeSpan> sleepDurationProvider = null!;

var instance = Activator.CreateInstance(
typeof(AsyncRetryPolicy<EmptyStruct>),
flags,
null,
[policyBuilder, onRetryAsync, permittedRetryCount, sleepDurationsEnumerable, sleepDurationProvider],
null)!;
var instanceType = instance.GetType();
var methods = instanceType.GetMethods(flags);
var methodInfo = methods.First(method => method is { Name: "ImplementationAsync", ReturnType.Name: "Task`1" });

var func = () => methodInfo.Invoke(instance, [action, new Context(), CancellationToken.None, false]);

var exceptionAssertions = func.Should().Throw<TargetInvocationException>();
exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation.");
exceptionAssertions.And.InnerException.Should().BeOfType<ArgumentNullException>()
.Which.ParamName.Should().Be("action");
}

[Fact]
public void Should_throw_when_retry_count_is_less_than_zero_without_context()
{
Expand Down

0 comments on commit 6d2b4e9

Please sign in to comment.