Skip to content

Commit 8df1a25

Browse files
committed
Improve unit test coverage
1 parent 540e308 commit 8df1a25

File tree

6 files changed

+247
-24
lines changed

6 files changed

+247
-24
lines changed

Diff for: src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerSyntax.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,14 @@ public static AsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(this PolicyB
215215
/// <exception cref="ArgumentNullException">onBreak</exception>
216216
/// <exception cref="ArgumentNullException">onReset</exception>
217217
/// <exception cref="ArgumentNullException">onHalfOpen</exception>
218-
public static AsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(this PolicyBuilder policyBuilder, double failureThreshold, TimeSpan samplingDuration, int minimumThroughput, TimeSpan durationOfBreak, Action<Exception, CircuitState, TimeSpan, Context> onBreak, Action<Context> onReset, Action onHalfOpen)
218+
public static AsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(
219+
this PolicyBuilder policyBuilder,
220+
double failureThreshold,
221+
TimeSpan samplingDuration,
222+
int minimumThroughput,
223+
TimeSpan durationOfBreak,
224+
Action<Exception, CircuitState, TimeSpan, Context> onBreak,
225+
Action<Context> onReset, Action onHalfOpen)
219226
{
220227
var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController<EmptyStruct>.ResolutionOfCircuitTimer);
221228

Diff for: test/Polly.Specs/CircuitBreaker/AdvancedCircuitBreakerAsyncSpecs.cs

+154
Original file line numberDiff line numberDiff line change
@@ -2484,6 +2484,160 @@ public void Should_open_circuit_with_timespan_maxvalue_if_manual_override_open()
24842484
passedBreakTimespan.Should().Be(TimeSpan.MaxValue);
24852485
}
24862486

2487+
[Fact]
2488+
public void Should_throw_when_failureThreshold_is_less_or_equals_than_zero()
2489+
{
2490+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2491+
Action<Context> onReset = _ => { };
2492+
2493+
var time = 1.January(2000);
2494+
SystemClock.UtcNow = () => time;
2495+
2496+
Action action = () => Policy
2497+
.Handle<DivideByZeroException>()
2498+
.AdvancedCircuitBreakerAsync(
2499+
failureThreshold: 0,
2500+
samplingDuration: TimeSpan.FromSeconds(10),
2501+
minimumThroughput: 4,
2502+
durationOfBreak: TimeSpan.FromMinutes(1),
2503+
onBreak: onBreak,
2504+
onReset: onReset);
2505+
2506+
action.Should().Throw<ArgumentOutOfRangeException>().And.ParamName.Should().Be("failureThreshold");
2507+
}
2508+
2509+
[Fact]
2510+
public void Should_throw_when_failureThreshold_is_more_than_one()
2511+
{
2512+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2513+
Action<Context> onReset = _ => { };
2514+
2515+
var time = 1.January(2000);
2516+
SystemClock.UtcNow = () => time;
2517+
2518+
Action action = () => Policy
2519+
.Handle<DivideByZeroException>()
2520+
.AdvancedCircuitBreakerAsync(
2521+
failureThreshold: 1.5,
2522+
samplingDuration: TimeSpan.FromSeconds(10),
2523+
minimumThroughput: 4,
2524+
durationOfBreak: TimeSpan.FromMinutes(1),
2525+
onBreak: onBreak,
2526+
onReset: onReset);
2527+
2528+
action.Should().Throw<ArgumentOutOfRangeException>().And.ParamName.Should().Be("failureThreshold");
2529+
}
2530+
2531+
[Fact]
2532+
public void Should_throw_when_samplingDuration_is_less_than_resolutionOfCircuit()
2533+
{
2534+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2535+
Action<Context> onReset = _ => { };
2536+
2537+
var time = 1.January(2000);
2538+
SystemClock.UtcNow = () => time;
2539+
2540+
Action action = () => Policy
2541+
.Handle<DivideByZeroException>()
2542+
.AdvancedCircuitBreakerAsync(
2543+
failureThreshold: 0.5,
2544+
samplingDuration: TimeSpan.FromMilliseconds(10),
2545+
minimumThroughput: 4,
2546+
durationOfBreak: TimeSpan.FromMinutes(1),
2547+
onBreak: onBreak,
2548+
onReset: onReset);
2549+
2550+
action.Should().Throw<ArgumentOutOfRangeException>().And.ParamName.Should().Be("samplingDuration");
2551+
}
2552+
2553+
[Fact]
2554+
public void Should_throw_when_minimumThroughput_is_less_or_equals_than_one()
2555+
{
2556+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2557+
Action<Context> onReset = _ => { };
2558+
2559+
var time = 1.January(2000);
2560+
SystemClock.UtcNow = () => time;
2561+
2562+
Action action = () => Policy
2563+
.Handle<DivideByZeroException>()
2564+
.AdvancedCircuitBreakerAsync(
2565+
failureThreshold: 0.5,
2566+
samplingDuration: TimeSpan.FromSeconds(10),
2567+
minimumThroughput: 0,
2568+
durationOfBreak: TimeSpan.FromMinutes(1),
2569+
onBreak: onBreak,
2570+
onReset: onReset);
2571+
2572+
action.Should().Throw<ArgumentOutOfRangeException>().And.ParamName.Should().Be("minimumThroughput");
2573+
}
2574+
2575+
[Fact]
2576+
public void Should_throw_when_durationOfBreak_is_negative_timespan()
2577+
{
2578+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2579+
Action<Context> onReset = _ => { };
2580+
2581+
var time = 1.January(2000);
2582+
SystemClock.UtcNow = () => time;
2583+
2584+
Action action = () => Policy
2585+
.Handle<DivideByZeroException>()
2586+
.AdvancedCircuitBreakerAsync(
2587+
failureThreshold: 0.5,
2588+
samplingDuration: TimeSpan.FromSeconds(10),
2589+
minimumThroughput: 4,
2590+
durationOfBreak: TimeSpan.FromMinutes(-1),
2591+
onBreak: onBreak,
2592+
onReset: onReset);
2593+
2594+
action.Should().Throw<ArgumentOutOfRangeException>().And.ParamName.Should().Be("durationOfBreak");
2595+
}
2596+
2597+
[Fact]
2598+
public void Should_throw_when_onReset_is_null()
2599+
{
2600+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2601+
2602+
var time = 1.January(2000);
2603+
SystemClock.UtcNow = () => time;
2604+
2605+
Action action = () => Policy
2606+
.Handle<DivideByZeroException>()
2607+
.AdvancedCircuitBreakerAsync(
2608+
failureThreshold: 0.5,
2609+
samplingDuration: TimeSpan.FromSeconds(10),
2610+
minimumThroughput: 4,
2611+
durationOfBreak: TimeSpan.FromMinutes(1),
2612+
onBreak: onBreak,
2613+
onReset: null);
2614+
2615+
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("onReset");
2616+
}
2617+
2618+
[Fact]
2619+
public void Should_throw_when_onHalfOpen_is_null()
2620+
{
2621+
Action<Exception, TimeSpan, Context> onBreak = (_, timespan, _) => { _ = timespan; };
2622+
Action<Context> onReset = _ => { };
2623+
2624+
var time = 1.January(2000);
2625+
SystemClock.UtcNow = () => time;
2626+
2627+
Action action = () => Policy
2628+
.Handle<DivideByZeroException>()
2629+
.AdvancedCircuitBreakerAsync(
2630+
failureThreshold: 0.5,
2631+
samplingDuration: TimeSpan.FromSeconds(10),
2632+
minimumThroughput: 4,
2633+
durationOfBreak: TimeSpan.FromMinutes(1),
2634+
onBreak: onBreak,
2635+
onReset: onReset,
2636+
onHalfOpen: null);
2637+
2638+
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("onHalfOpen");
2639+
}
2640+
24872641
#endregion
24882642

24892643
#region Tests that supplied context is passed to stage-change delegates

Diff for: test/Polly.Specs/PolicyContextAndKeyAsyncSpecs.cs

+23
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ public void Should_not_be_able_to_configure_the_policy_key_explicitly_more_than_
4343
configure.Should().Throw<ArgumentException>().And.ParamName.Should().Be("policyKey");
4444
}
4545

46+
[Fact]
47+
public void Should_not_be_able_to_configure_the_policy_key_explicitly_more_than_once_via_interface()
48+
{
49+
IAsyncPolicy policyAsInterface = Policy.Handle<Exception>().RetryAsync();
50+
51+
Action configure = () => policyAsInterface.WithPolicyKey(Guid.NewGuid().ToString());
52+
53+
configure.Should().NotThrow();
54+
55+
configure.Should().Throw<ArgumentException>().And.ParamName.Should().Be("policyKey");
56+
}
57+
4658
[Fact]
4759
public void PolicyKey_property_should_be_non_null_or_empty_if_not_explicitly_configured()
4860
{
@@ -227,6 +239,17 @@ public void Should_not_be_able_to_configure_the_policy_key_explicitly_more_than_
227239
configure.Should().Throw<ArgumentException>().And.ParamName.Should().Be("policyKey");
228240
}
229241

242+
[Fact]
243+
public void Should_not_be_able_to_configure_the_policy_key_explicitly_more_than_once_via_interface()
244+
{
245+
IAsyncPolicy<int> policyAsInterface = Policy.HandleResult(0).RetryAsync();
246+
Action configure = () => policyAsInterface.WithPolicyKey(Guid.NewGuid().ToString());
247+
248+
configure.Should().NotThrow();
249+
250+
configure.Should().Throw<ArgumentException>().And.ParamName.Should().Be("policyKey");
251+
}
252+
230253
[Fact]
231254
public void PolicyKey_property_should_be_non_null_or_empty_if_not_explicitly_configured()
232255
{

Diff for: test/Polly.Specs/Retry/RetryAsyncSpecs.cs

+20
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,26 @@ await policy.Awaiting(x => x.RaiseExceptionAsync<ArgumentException>())
155155
.Should().NotThrowAsync();
156156
}
157157

158+
[Fact]
159+
public void Should_throw_when_onRetry_is_null()
160+
{
161+
Action action = () => Policy
162+
.Handle<DivideByZeroException>()
163+
.RetryAsync(3, (Action<Exception, int>)null!);
164+
165+
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("onRetry");
166+
}
167+
168+
[Fact]
169+
public void Should_throw_when_onRetryAsync_is_null()
170+
{
171+
Action action = () => Policy
172+
.Handle<DivideByZeroException>()
173+
.RetryAsync(3, (Func<Exception, int, Task>)null!);
174+
175+
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("onRetryAsync");
176+
}
177+
158178
[Fact]
159179
public async Task Should_call_onretry_on_each_retry_with_the_current_retry_count()
160180
{

Diff for: test/Polly.Specs/Retry/WaitAndRetryTResultAsyncSpecs.cs

+42
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,48 @@ await policy.ExecuteAsync(async () =>
4242
actualRetryWaits.Should().ContainInOrder(expectedRetryWaits.Values);
4343
}
4444

45+
[Fact]
46+
public void Should_throw_when_retry_count_is_less_than_zero()
47+
{
48+
var expectedRetryWaits = new Dictionary<ResultPrimitive, TimeSpan>
49+
{
50+
{ResultPrimitive.Fault, 2.Seconds()},
51+
{ResultPrimitive.FaultAgain, 4.Seconds()},
52+
};
53+
54+
var actualRetryWaits = new List<TimeSpan>();
55+
56+
Action configure = () => Policy
57+
.HandleResult(ResultPrimitive.Fault)
58+
.WaitAndRetryAsync(-1,
59+
(_, outcome, _) => expectedRetryWaits[outcome.Result],
60+
(_, timeSpan, _, _) =>
61+
{
62+
actualRetryWaits.Add(timeSpan);
63+
return TaskHelper.EmptyTask;
64+
});
65+
66+
configure.Should().Throw<ArgumentOutOfRangeException>().And.ParamName.Should().Be("retryCount");
67+
}
68+
69+
[Fact]
70+
public void Should_throw_when_onRetryAsync_is_null()
71+
{
72+
var expectedRetryWaits = new Dictionary<ResultPrimitive, TimeSpan>
73+
{
74+
{ResultPrimitive.Fault, 2.Seconds()},
75+
{ResultPrimitive.FaultAgain, 4.Seconds()},
76+
};
77+
78+
Action configure = () => Policy
79+
.HandleResult(ResultPrimitive.Fault)
80+
.WaitAndRetryAsync(2,
81+
(_, outcome, _) => expectedRetryWaits[outcome.Result],
82+
null);
83+
84+
configure.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("onRetryAsync");
85+
}
86+
4587
public void Dispose() =>
4688
SystemClock.Reset();
4789
}

Diff for: test/Polly.Specs/Utilities/SystemClockSpecs.cs

-23
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,4 @@ await SystemClock.SleepAsync.Invoking(async s =>
3535
cts.Cancel();
3636
await s(TimeSpan.FromMilliseconds(1), cts.Token);
3737
}).Should().ThrowAsync<OperationCanceledException>();
38-
39-
[Fact]
40-
public void Reset_ShouldResetToDefaultImplementations()
41-
{
42-
SystemClock.Sleep = (_, _) => { };
43-
SystemClock.SleepAsync = (_, _) => Task.CompletedTask;
44-
SystemClock.UtcNow = () => new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
45-
SystemClock.DateTimeOffsetUtcNow = () => new DateTimeOffset(new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc));
46-
SystemClock.CancelTokenAfter = (_, _) => { };
47-
48-
SystemClock.Reset();
49-
50-
SystemClock.UtcNow().Should().NotBe(new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc));
51-
SystemClock.DateTimeOffsetUtcNow().Should().NotBe(new DateTimeOffset(new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)));
52-
53-
SystemClock.CancelTokenAfter.Invoking(s =>
54-
{
55-
using var cts = new CancellationTokenSource();
56-
s(cts, TimeSpan.FromMilliseconds(1));
57-
Task.Delay(10).Wait();
58-
cts.Token.IsCancellationRequested.Should().BeTrue();
59-
}).Should().NotThrow();
60-
}
6138
}

0 commit comments

Comments
 (0)