From c332b155c206e25e152b039a4e56aff6e6c65ecb Mon Sep 17 00:00:00 2001 From: ZLoo Date: Tue, 23 Jul 2024 10:08:29 +0300 Subject: [PATCH] Fix CA1062 warnings (#2237) Fix CA1062 warnings for `AsyncBulkheadPolicy`. --- src/Polly/Bulkhead/AsyncBulkheadPolicy.cs | 46 ++++++++++++++++--- .../Bulkhead/BulkheadAsyncSpecs.cs | 28 +++++++++++ .../Bulkhead/BulkheadTResultAsyncSpecs.cs | 27 +++++++++++ 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs b/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs index a055a420c75..b0f787ea1df 100644 --- a/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs +++ b/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs @@ -4,7 +4,6 @@ namespace Polly.Bulkhead; /// /// A bulkhead-isolation policy which can be applied to delegates. /// -#pragma warning disable CA1062 // Validate arguments of public methods public class AsyncBulkheadPolicy : AsyncPolicy, IBulkheadPolicy { private readonly SemaphoreSlim _maxParallelizationSemaphore; @@ -35,9 +34,26 @@ internal AsyncBulkheadPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) => - AsyncBulkheadEngine.ImplementationAsync(action, context, _onBulkheadRejectedAsync, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, continueOnCapturedContext, cancellationToken); + protected override Task ImplementationAsync( + Func> action, + Context context, + CancellationToken cancellationToken, + bool continueOnCapturedContext) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + return AsyncBulkheadEngine.ImplementationAsync( + action, + context, + _onBulkheadRejectedAsync, + _maxParallelizationSemaphore, + _maxQueuedActionsSemaphore, + continueOnCapturedContext, + cancellationToken); + } /// public void Dispose() @@ -71,8 +87,26 @@ internal AsyncBulkheadPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => - AsyncBulkheadEngine.ImplementationAsync(action, context, _onBulkheadRejectedAsync, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, continueOnCapturedContext, cancellationToken); + protected override Task ImplementationAsync( + Func> action, + Context context, + CancellationToken cancellationToken, + bool continueOnCapturedContext) + { + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + return AsyncBulkheadEngine.ImplementationAsync( + action, + context, + _onBulkheadRejectedAsync, + _maxParallelizationSemaphore, + _maxQueuedActionsSemaphore, + continueOnCapturedContext, + cancellationToken); + } /// /// Gets the number of slots currently available for executing actions through the bulkhead. diff --git a/test/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs b/test/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs index 12bbd58788c..80a84ae62db 100644 --- a/test/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs +++ b/test/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs @@ -5,6 +5,34 @@ public class BulkheadAsyncSpecs(ITestOutputHelper testOutputHelper) : BulkheadSp { #region Configuration + [Fact] + public void Should_throw_when_action_is_null() + { + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + Func> action = null!; + var maxParallelization = 1; + var maxQueueingActions = 1; + Func onBulkheadRejectedAsync = (_) => Task.CompletedTask; + + var instance = Activator.CreateInstance( + typeof(AsyncBulkheadPolicy), + flags, + null, + [maxParallelization, maxQueueingActions, onBulkheadRejectedAsync], + 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(); + exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation."); + exceptionAssertions.And.InnerException.Should().BeOfType() + .Which.ParamName.Should().Be("action"); + } + [Fact] public void Should_throw_when_maxParallelization_less_or_equal_to_zero_and_no_maxQueuingActions() { diff --git a/test/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs b/test/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs index fe1fc1aa5f4..8c155ecccc8 100644 --- a/test/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs +++ b/test/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs @@ -10,6 +10,33 @@ public BulkheadTResultAsyncSpecs(ITestOutputHelper testOutputHelper) #region Configuration + [Fact] + public void Should_throw_when_action_is_null() + { + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + Func> action = null!; + var maxParallelization = 1; + var maxQueueingActions = 1; + Func onBulkheadRejectedAsync = (_) => Task.CompletedTask; + + var instance = Activator.CreateInstance( + typeof(AsyncBulkheadPolicy), + flags, + null, + [maxParallelization, maxQueueingActions, onBulkheadRejectedAsync], + 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(); + exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation."); + exceptionAssertions.And.InnerException.Should().BeOfType() + .Which.ParamName.Should().Be("action"); + } + [Fact] public void Should_throw_when_maxParallelization_less_or_equal_to_zero_and_no_maxQueuingActions() {