public void Should_call_onbreak_when_breaking_circuit_first_time_but_not_for_subsequent_calls_through_open_circuit() { int onBreakCalled = 0; Action <DelegateResult <ResultPrimitive>, TimeSpan> onBreak = (_, __) => { onBreakCalled++; }; Action onReset = () => { }; CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); onBreakCalled.Should().Be(0); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); onBreakCalled.Should().Be(1); // call through circuit when already broken - should not retrigger onBreak breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); onBreakCalled.Should().Be(1); }
public void Should_not_open_circuit_if_result_returned_does_not_match_any_of_the_result_predicates() { CircuitBreakerPolicy <ResultClass> breaker = Policy .Handle <ArgumentException>(e => e.ParamName == "key") .OrResult <ResultClass>(r => r.ResultCode == ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); // non-matched result predicate breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain)) .ResultCode.Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain)) .ResultCode.Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain)) .ResultCode.Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); // non-matched exception predicate breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "value"))) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "value"))) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "value"))) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); }
public void Should_be_able_to_reset_automatically_opened_circuit_without_specified_duration_passing() { var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); // 2 exception raised, circuit is now open breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); // reset circuit, with no time having passed breaker.Reset(); SystemClock.UtcNow().Should().Be(time); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good)).ShouldNotThrow(); }
public void Should_open_circuit_with_the_last_handled_result_after_specified_number_of_exceptions_and_results_have_been_raised__when_configuring_multiple_results_and_exceptions() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .Handle <DivideByZeroException>() .OrResult(ResultPrimitive.Fault) .Or <ArgumentException>() .OrResult(ResultPrimitive.FaultAgain) .CircuitBreaker(4, TimeSpan.FromMinutes(1)); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException())) .ShouldThrow <DivideByZeroException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException())) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Open); // 4 exception raised, circuit is now open breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Good)) .ShouldThrow <BrokenCircuitException <ResultPrimitive> >() .WithMessage("The circuit is now open and is not allowing calls.") .Where(e => e.Result == ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Open); }
public void Should_halfopen_circuit_after_the_specified_duration_has_passed() { var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); // 2 exception raised, circuit is now open breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); SystemClock.UtcNow = () => time.Add(durationOfBreak); // duration has passed, circuit now half open breaker.CircuitState.Should().Be(CircuitState.HalfOpen); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); }
public void Should_call_onreset_with_the_passed_context() { IDictionary <string, object> contextData = null; Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, ___) => { }; Action <Context> onReset = context => { contextData = context; }; var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak, onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); SystemClock.UtcNow = () => time.Add(durationOfBreak); breaker.CircuitState.Should().Be(CircuitState.HalfOpen); // first call after duration should invoke onReset, with context breaker.Execute(() => ResultPrimitive.Good, new { key1 = "value1", key2 = "value2" }.AsDictionary()); contextData.Should() .ContainKeys("key1", "key2").And .ContainValues("value1", "value2"); }
public void Should_reset_circuit_after_the_specified_duration_has_passed_if_the_next_call_does_not_return_a_fault() { var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); // 2 exception raised, circuit is now open breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); SystemClock.UtcNow = () => time.Add(durationOfBreak); // duration has passed, circuit now half open breaker.CircuitState.Should().Be(CircuitState.HalfOpen); // first call after duration is successful, so circuit should reset breaker.Execute(() => ResultPrimitive.Good); breaker.CircuitState.Should().Be(CircuitState.Closed); // circuit has been reset so should once again allow 2 faults to be raised before breaking breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); }
public void Should_call_onhalfopen_when_automatically_transitioning_to_halfopen_due_to_subsequent_execution() { int onBreakCalled = 0; int onResetCalled = 0; int onHalfOpenCalled = 0; Action <DelegateResult <ResultPrimitive>, TimeSpan> onBreak = (_, __) => { onBreakCalled++; }; Action onReset = () => { onResetCalled++; }; Action onHalfOpen = () => { onHalfOpenCalled++; }; var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak, onBreak, onReset, onHalfOpen); onBreakCalled.Should().Be(0); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); onBreakCalled.Should().Be(0); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); onBreakCalled.Should().Be(1); // 2 exception raised, circuit is now open breaker.Invoking(x => x.Execute(() => ResultPrimitive.Good)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); onBreakCalled.Should().Be(1); SystemClock.UtcNow = () => time.Add(durationOfBreak); // duration has passed, circuit now half open onHalfOpenCalled.Should().Be(0); // not yet transitioned to half-open, because we have not queried state // first call after duration is successful, so circuit should reset breaker.Execute(() => ResultPrimitive.Good); onHalfOpenCalled.Should().Be(1); breaker.CircuitState.Should().Be(CircuitState.Closed); onResetCalled.Should().Be(1); }
public void Should_not_open_circuit_if_specified_number_of_specified_handled_result_are_not_raised_consecutively() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Good) .Should().Be(ResultPrimitive.Good); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); }
public void Should_not_open_circuit_if_result_returned_does_not_match_result_predicate() { CircuitBreakerPolicy <ResultClass> breaker = Policy .HandleResult <ResultClass>(r => r.ResultCode == ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain)) .ResultCode.Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain)) .ResultCode.Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.FaultAgain)) .ResultCode.Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); }
public void Should_not_open_circuit_if_result_returned_is_not_the_handled_result() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); }
public void Should_be_able_to_handle_a_duration_of_timespan_maxvalue() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(1, TimeSpan.MaxValue); var result = breaker.RaiseResultSequence(ResultPrimitive.Fault); result.Should().Be(ResultPrimitive.Fault); }
public void Should_not_open_circuit_if_result_returned_is_not_one_of_the_configured_results_or_exceptions() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .Handle <DivideByZeroException>() .OrResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); }
public void Should_open_circuit_with_the_last_handled_result_after_specified_number_of_specified_handled_result_have_been_returned() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault)) .ShouldThrow <BrokenCircuitException <ResultPrimitive> >() .WithMessage("The circuit is now open and is not allowing calls.") .Where(e => e.Result == ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); }
public void Context_should_be_empty_if_execute_not_called_with_any_context_data() { IDictionary <string, object> contextData = new { key1 = "value1", key2 = "value2" }.AsDictionary(); Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, context) => { contextData = context; }; Action <Context> onReset = _ => { }; CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); contextData.Should().BeEmpty(); }
public void Should_call_onbreak_when_breaking_circuit_automatically() { bool onBreakCalled = false; Action <DelegateResult <ResultPrimitive>, TimeSpan> onBreak = (_, __) => { onBreakCalled = true; }; Action onReset = () => { }; CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); onBreakCalled.Should().BeFalse(); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); onBreakCalled.Should().BeTrue(); }
public void Should_open_circuit_again_after_the_specified_duration_has_passed_if_the_next_call_raises_a_fault() { var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .Or <DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException())) .ShouldThrow <DivideByZeroException>(); breaker.CircuitState.Should().Be(CircuitState.Open); // 2 exception raised, circuit is now open breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault)) .ShouldThrow <BrokenCircuitException>(); breaker.CircuitState.Should().Be(CircuitState.Open); SystemClock.UtcNow = () => time.Add(durationOfBreak); // duration has passed, circuit now half open breaker.CircuitState.Should().Be(CircuitState.HalfOpen); // first call after duration returns a fault, so circuit should break again breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Fault)) .ShouldThrow <BrokenCircuitException>(); }
public void Should_not_open_circuit_if_result_raised_or_exception_thrown_is_not_one_of_the_handled_results_or_exceptions() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .Or <DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException())) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(ResultPrimitive.FaultAgain) .Should().Be(ResultPrimitive.FaultAgain); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException())) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); }
public void Should_call_onbreak_with_the_last_handled_result() { ResultPrimitive?handledResult = null; Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (outcome, _, __) => { handledResult = outcome.Result; }; Action <Context> onReset = _ => { }; TimeSpan durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak, onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); handledResult?.Should().Be(ResultPrimitive.Fault); }
public void Should_call_onbreak_with_the_correct_timespan() { TimeSpan?passedBreakTimespan = null; Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, timespan, __) => { passedBreakTimespan = timespan; }; Action <Context> onReset = _ => { }; TimeSpan durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak, onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); passedBreakTimespan.Should().Be(durationOfBreak); }
public void Should_create_new_context_for_each_call_to_execute() { string contextValue = null; Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, context) => { contextValue = context.ContainsKey("key") ? context["key"].ToString() : null; }; Action <Context> onReset = context => { contextValue = context.ContainsKey("key") ? context["key"].ToString() : null; }; CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset); var time = 1.January(2000); SystemClock.UtcNow = () => time; var durationOfBreak = TimeSpan.FromMinutes(1); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); // 2 exception raised, circuit is now open breaker.RaiseResultSequence(new { key = "original_value" }.AsDictionary(), ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); contextValue.Should().Be("original_value"); SystemClock.UtcNow = () => time.Add(durationOfBreak); // duration has passed, circuit now half open breaker.CircuitState.Should().Be(CircuitState.HalfOpen); // but not yet reset // first call after duration is successful, so circuit should reset breaker.Execute(() => ResultPrimitive.Good, new { key = "new_value" }.AsDictionary()); breaker.CircuitState.Should().Be(CircuitState.Closed); contextValue.Should().Be("new_value"); }
public void Should_set_LastHandledResult_on_handling_result_even_when_not_breaking() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .Handle <DivideByZeroException>() .OrResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.LastHandledResult.Should().Be(ResultPrimitive.Fault); breaker.LastException.Should().BeNull(); }
public void Should_call_onbreak_with_the_passed_context() { IDictionary <string, object> contextData = null; Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (_, __, context) => { contextData = context; }; Action <Context> onReset = _ => { }; CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.RaiseResultSequence(new { key1 = "value1", key2 = "value2" }.AsDictionary(), ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); contextData.Should() .ContainKeys("key1", "key2").And .ContainValues("value1", "value2"); }
public void Should_set_LastException_to_last_exception_when_breaking() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .Handle <DivideByZeroException>() .OrResult(ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException())) .ShouldThrow <DivideByZeroException>(); breaker.CircuitState.Should().Be(CircuitState.Open); breaker.LastHandledResult.Should().Be(default(ResultPrimitive)); breaker.LastException.Should().BeOfType <DivideByZeroException>(); }
public void Should_open_circuit_with_the_last_exception_after_specified_number_of_exceptions_and_results_have_been_raised__breaking_on_result__when_configuring_result_first() { CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .HandleResult(ResultPrimitive.Fault) .Or <DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException())) .ShouldThrow <DivideByZeroException>(); breaker.CircuitState.Should().Be(CircuitState.Open); // 2 exception raised, circuit is now open breaker.Invoking(b => b.RaiseResultSequence(ResultPrimitive.Good)) .ShouldThrow <BrokenCircuitException>() .WithMessage("The circuit is now open and is not allowing calls.") .WithInnerException <DivideByZeroException>(); breaker.CircuitState.Should().Be(CircuitState.Open); }
public void Should_open_circuit_if_results_and_exceptions_returned_match_combination_of_the_result_and_exception_predicates() { CircuitBreakerPolicy <ResultClass> breaker = Policy .Handle <ArgumentException>(e => e.ParamName == "key") .OrResult <ResultClass>(r => r.ResultCode == ResultPrimitive.Fault) .CircuitBreaker(2, TimeSpan.FromMinutes(1)); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new ArgumentException("message", "key"))) .ShouldThrow <ArgumentException>(); breaker.CircuitState.Should().Be(CircuitState.Closed); breaker.RaiseResultSequence(new ResultClass(ResultPrimitive.Fault)) .ResultCode.Should().Be(ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); // 2 exception raised, circuit is now open breaker.Invoking(b => b.RaiseResultSequence(new ResultClass(ResultPrimitive.Good))) .ShouldThrow <BrokenCircuitException <ResultClass> >() .WithMessage("The circuit is now open and is not allowing calls.") .Where(e => e.Result.ResultCode == ResultPrimitive.Fault); breaker.CircuitState.Should().Be(CircuitState.Open); }
public void Should_call_onbreak_with_the_last_raised_exception() { Exception lastException = null; Action <DelegateResult <ResultPrimitive>, TimeSpan, Context> onBreak = (outcome, _, __) => { lastException = outcome.Exception; }; Action <Context> onReset = _ => { }; TimeSpan durationOfBreak = TimeSpan.FromMinutes(1); CircuitBreakerPolicy <ResultPrimitive> breaker = Policy .Handle <DivideByZeroException>() .OrResult(ResultPrimitive.Fault) .CircuitBreaker(2, durationOfBreak, onBreak, onReset); breaker.RaiseResultSequence(ResultPrimitive.Fault) .Should().Be(ResultPrimitive.Fault); breaker.Invoking(b => b.RaiseResultAndOrExceptionSequence(new DivideByZeroException())) .ShouldThrow <DivideByZeroException>(); breaker.CircuitState.Should().Be(CircuitState.Open); lastException.Should().BeOfType <DivideByZeroException>(); }