Skip to content

Commit

Permalink
Fix CA1062 warnings (#2223)
Browse files Browse the repository at this point in the history
Fix warnings for `AsyncRateLimitPolicy`.
  • Loading branch information
Zombach authored Jul 22, 2024
1 parent 6d2b4e9 commit ed1c79b
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 9 deletions.
45 changes: 38 additions & 7 deletions src/Polly/RateLimit/AsyncRateLimitPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ namespace Polly.RateLimit;
/// <summary>
/// A rate-limit policy that can be applied to asynchronous delegates.
/// </summary>
#pragma warning disable CA1062 // Validate arguments of public methods
public class AsyncRateLimitPolicy : AsyncPolicy, IRateLimitPolicy
{
private readonly IRateLimiter _rateLimiter;
Expand All @@ -14,9 +13,25 @@ internal AsyncRateLimitPolicy(IRateLimiter rateLimiter) =>

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

return AsyncRateLimitEngine.ImplementationAsync(
_rateLimiter,
null,
action,
context,
continueOnCapturedContext,
cancellationToken);
}
}

/// <summary>
Expand All @@ -38,7 +53,23 @@ internal AsyncRateLimitPolicy(

/// <inheritdoc/>
[DebuggerStepThrough]
protected override Task<TResult> ImplementationAsync(Func<Context, CancellationToken, Task<TResult>> action, Context context, CancellationToken cancellationToken,
bool continueOnCapturedContext) =>
AsyncRateLimitEngine.ImplementationAsync(_rateLimiter, _retryAfterFactory, action, context, continueOnCapturedContext, cancellationToken);
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 AsyncRateLimitEngine.ImplementationAsync(
_rateLimiter,
_retryAfterFactory,
action,
context,
continueOnCapturedContext,
cancellationToken);
}
}
3 changes: 2 additions & 1 deletion test/Polly.Specs/NoOp/NoOpSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public void Should_throw_when_action_is_null()

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

[Fact]
Expand Down
3 changes: 2 additions & 1 deletion test/Polly.Specs/NoOp/NoOpTResultAsyncSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public void Should_throw_when_action_is_null()

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

[Fact]
Expand Down
26 changes: 26 additions & 0 deletions test/Polly.Specs/RateLimit/AsyncRateLimitPolicySpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,30 @@ protected override (bool, TimeSpan) TryExecuteThroughPolicy(IRateLimitPolicy pol
throw new InvalidOperationException("Unexpected policy type in test construction.");
}
}

[Fact]
public void Should_throw_when_action_is_null()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
Func<Context, CancellationToken, Task<EmptyStruct>> action = null!;
IRateLimiter rateLimiter = RateLimiterFactory.Create(TimeSpan.FromSeconds(1), 1);

var instance = Activator.CreateInstance(
typeof(AsyncRateLimitPolicy),
flags,
null,
[rateLimiter],
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");
}
}
26 changes: 26 additions & 0 deletions test/Polly.Specs/RateLimit/AsyncRateLimitPolicyTResultSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,30 @@ protected override TResult TryExecuteThroughPolicy<TResult>(IRateLimitPolicy<TRe
throw new InvalidOperationException("Unexpected policy type in test construction.");
}
}

[Fact]
public void Should_throw_when_action_is_null()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
Func<Context, CancellationToken, Task<EmptyStruct>> action = null!;
IRateLimiter rateLimiter = RateLimiterFactory.Create(TimeSpan.FromSeconds(1), 1);
Func<TimeSpan, Context, EmptyStruct>? retryAfterFactory = null!;

var instance = Activator.CreateInstance(
typeof(AsyncRateLimitPolicy<EmptyStruct>),
flags,
null,
[rateLimiter, retryAfterFactory],
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");
}
}

0 comments on commit ed1c79b

Please sign in to comment.