Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a506f02
Add core RateLimiter implementations
reisenberger Mar 23, 2019
e31aa32
Add example async TResult rate-limiter policy implementation
reisenberger Mar 23, 2019
12a276a
Add example syntax
reisenberger Mar 23, 2019
6e2da28
Make the retryAfterFactory take Timespan as an input parameter!
reisenberger Mar 24, 2019
f5435e4
Initial LockFreeTokenBucketRateLimiterTests
reisenberger Jul 4, 2019
adbefab
Factor out test helpers
reisenberger Jul 4, 2019
29a63fa
Factor out common tests; add tests on lock-based rate limiter
reisenberger Jul 4, 2019
6ff0448
Allow for slow-running on CI servers
reisenberger Jul 4, 2019
ead0d14
Add tests on full bucket capacity
reisenberger Jul 4, 2019
ce36ab2
Fix RateLimitRejectedException
reisenberger Jul 4, 2019
9b74ae1
Remove unused configuration overloads
reisenberger Jul 4, 2019
0e0d94f
Introduce a factory for obtaining the preferred rate-limiter implemen…
reisenberger Jul 4, 2019
3d83844
Pull some test helper methods into a common base-class
reisenberger Jul 4, 2019
23f26e8
Add first specs on async policy syntax
reisenberger Jul 4, 2019
d0f191b
Add full set of specs on rate-limit policies thus far
reisenberger Jul 5, 2019
705cda9
Add tests on retryAfterFactory
reisenberger Jul 5, 2019
68346c7
Add tests on context passed to retryAfterFactory
reisenberger Jul 5, 2019
1895edc
Add async non-generic syntax and specs
reisenberger Jul 5, 2019
dd10d3e
Improve code layout
reisenberger Jul 5, 2019
a734da2
Add sync rate-limit policies
reisenberger Jul 5, 2019
ba96aac
Add initial rate-limit doco; bump to v7.3.0
reisenberger Jul 9, 2019
f237d8f
Improve bulkhead doco in readme
reisenberger Jul 9, 2019
b41cac4
Minor expressivity refinements
reisenberger Jul 15, 2019
1370cdb
Neaten bulkhead tests commentary
reisenberger Jul 16, 2019
b890f01
Control visibility of IRateLimiter components
reisenberger Jul 16, 2019
f232595
Fix non-generic rate-limit tests to be genuinely non-generic
reisenberger Jul 16, 2019
e566ea9
Fix ShouldThrow syntax errors in specs
YarekTyshchenko Oct 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tests on retryAfterFactory
  • Loading branch information
reisenberger authored and YarekTyshchenko committed Oct 15, 2021
commit 705cda98ba4faab3b9e84571d1b115f47a489feb
21 changes: 21 additions & 0 deletions src/Polly.Specs/Helpers/RateLimit/ResultClassWithRetryAfter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;

namespace Polly.Specs.Helpers.RateLimit
{
internal class ResultClassWithRetryAfter : ResultClass
{
public TimeSpan RetryAfter { get; }

public ResultClassWithRetryAfter(ResultPrimitive result)
: base(result)
{
RetryAfter = TimeSpan.Zero;
}

public ResultClassWithRetryAfter(TimeSpan retryAfter)
: base(ResultPrimitive.Undefined)
{
RetryAfter = retryAfter;
}
}
}
29 changes: 24 additions & 5 deletions src/Polly.Specs/RateLimit/AsyncRateLimitPolicyTResultSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
using System.Threading.Tasks;
using Polly.RateLimit;
using Polly.Specs.Helpers;
using Polly.Specs.Helpers.RateLimit;
using Polly.Utilities;
using Xunit;

namespace Polly.Specs.RateLimit
{
[Collection(Polly.Specs.Helpers.Constants.SystemClockDependentTestCollection)]
public class AsyncRateLimitPolicyTResultSpecs : RateLimitPolicySpecsBase, IDisposable
public class AsyncRateLimitPolicyTResultSpecs : RateLimitPolicyTResultSpecsBase, IDisposable
{
public void Dispose()
{
Expand All @@ -17,21 +18,27 @@ public void Dispose()

protected override IRateLimitPolicy GetPolicyViaSyntax(int numberOfExecutions, TimeSpan perTimeSpan)
{
return Policy.RateLimitAsync<ResultClass>(numberOfExecutions, perTimeSpan);
return Policy.RateLimitAsync<ResultClassWithRetryAfter>(numberOfExecutions, perTimeSpan);
}

protected override IRateLimitPolicy GetPolicyViaSyntax(int numberOfExecutions, TimeSpan perTimeSpan, int maxBurst)
{
return Policy.RateLimitAsync<ResultClass>(numberOfExecutions, perTimeSpan, maxBurst);
return Policy.RateLimitAsync<ResultClassWithRetryAfter>(numberOfExecutions, perTimeSpan, maxBurst);
}

protected override IRateLimitPolicy<TResult> GetPolicyViaSyntax<TResult>(int numberOfExecutions, TimeSpan perTimeSpan, int maxBurst,
Func<TimeSpan, Context, TResult> retryAfterFactory)
{
return Policy.RateLimitAsync<TResult>(numberOfExecutions, perTimeSpan, maxBurst, retryAfterFactory);
}

protected override (bool, TimeSpan) TryExecuteThroughPolicy(IRateLimitPolicy policy)
{
if (policy is AsyncRateLimitPolicy<ResultClass> typedPolicy)
if (policy is AsyncRateLimitPolicy<ResultClassWithRetryAfter> typedPolicy)
{
try
{
typedPolicy.ExecuteAsync(() => Task.FromResult(new ResultClass(ResultPrimitive.Good))).GetAwaiter().GetResult();
typedPolicy.ExecuteAsync(() => Task.FromResult(new ResultClassWithRetryAfter(ResultPrimitive.Good))).GetAwaiter().GetResult();
return (true, TimeSpan.Zero);
}
catch (RateLimitRejectedException e)
Expand All @@ -44,5 +51,17 @@ protected override (bool, TimeSpan) TryExecuteThroughPolicy(IRateLimitPolicy pol
throw new InvalidOperationException("Unexpected policy type in test construction.");
}
}

protected override TResult TryExecuteThroughPolicy<TResult>(IRateLimitPolicy<TResult> policy, TResult resultIfExecutionPermitted)
{
if (policy is AsyncRateLimitPolicy<TResult> typedPolicy)
{
return typedPolicy.ExecuteAsync(() => Task.FromResult(resultIfExecutionPermitted)).GetAwaiter().GetResult();
}
else
{
throw new InvalidOperationException("Unexpected policy type in test construction.");
}
}
}
}
47 changes: 47 additions & 0 deletions src/Polly.Specs/RateLimit/RateLimitPolicyTResultSpecsBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using FluentAssertions;
using Polly.RateLimit;
using Polly.Specs.Helpers;
using Polly.Specs.Helpers.RateLimit;
using Xunit;

namespace Polly.Specs.RateLimit
{
public abstract class RateLimitPolicyTResultSpecsBase : RateLimitPolicySpecsBase
{
protected abstract IRateLimitPolicy<TResult> GetPolicyViaSyntax<TResult>(
int numberOfExecutions,
TimeSpan perTimeSpan,
int maxBurst,
Func<TimeSpan, Context, TResult> retryAfterFactory);

protected abstract TResult TryExecuteThroughPolicy<TResult>(IRateLimitPolicy<TResult> policy, TResult resultIfExecutionPermitted);

[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(5)]
public void Ratelimiter_specifies_correct_wait_until_next_execution_by_custom_factory(int onePerSeconds)
{
FixClock();

// Arrange
TimeSpan onePer = TimeSpan.FromSeconds(onePerSeconds);
Func<TimeSpan, Context, ResultClassWithRetryAfter> retryAfterFactory = (t, ctx) => new ResultClassWithRetryAfter(t);
var rateLimiter = GetPolicyViaSyntax<ResultClassWithRetryAfter>(1, onePer, 1, retryAfterFactory);

// Assert - first execution after initialising should always be permitted.
ShouldPermitAnExecution(rateLimiter);

// Arrange
// (do nothing - time not advanced)

// Act - try another execution.
var resultExpectedBlocked = TryExecuteThroughPolicy(rateLimiter, new ResultClassWithRetryAfter(ResultPrimitive.Good));

// Assert - should be blocked - time not advanced. Result should be expressed per the retryAfterFactory.
resultExpectedBlocked.ResultCode.Should().NotBe(ResultPrimitive.Good);
resultExpectedBlocked.RetryAfter.Should().Be(onePer);
}
}
}