public void GivenCircuitBreaker_WhenFailureThenSuccess_ThenLastExceptionIsNull()
        {
            // Arrange
            Action protectedCode  = () => { throw new Exception("Message"); };
            var    circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(10, TimeSpan.FromMinutes(5));

            // Act
            circuitBreaker.AttemptCall(protectedCode);
            circuitBreaker.AttemptCall(() => { });

            // Assert
            Assert.Null(circuitBreaker.GetExceptionFromLastAttemptCall());
        }
        public void GivenCircuitBreakerHalfOpen_WhenNoException_ThenFailureCountZero()
        {
            // Arrange
            const int THRESHOLD      = 2;
            Action    protectedCode  = () => { throw new Exception(); };
            var       circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD, TimeSpan.FromMilliseconds(10));

            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);
            Thread.Sleep(25);             //This set is back to HalfOpen
            Assert.True(circuitBreaker.IsHalfOpen);

            // Act
            circuitBreaker.AttemptCall(() => { });

            // Act
            Assert.Equal(0, circuitBreaker.Failures);
        }
        public void GivenCircuitBreakerClose_WhenOpenTwiceAndStateChangeSubscribed_ThenCallEventStateChangeOnce()
        {
            // Arrange
            int       changeStateCount = 0;
            const int THRESHOLD        = 2;
            Action    protectedCode    = () => { throw new Exception(); };
            var       circuitBreaker   = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD, TimeSpan.FromMinutes(5));

            circuitBreaker.OnStateChange += (o, state) => { changeStateCount++; };
            Assert.True(circuitBreaker.IsClosed);

            // Act
            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);
            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);

            // Assert
            Assert.Equal(1, changeStateCount);
        }
        public void GivenCircuitBreakerClose_WhenOpenAndCloseAndStateChangeSubscribed_ThenCallEventStateChangeTwice()
        {
            // Arrange
            int       changeStateCount = 0;
            const int THRESHOLD        = 2;
            Action    protectedCode    = () => { throw new Exception(); };
            var       circuitBreaker   = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD, TimeSpan.FromMilliseconds(10));

            circuitBreaker.OnStateChange += (o, state) => { changeStateCount++; };
            Assert.True(circuitBreaker.IsClosed);

            // Act
            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);
            Thread.Sleep(25); //This set is back to HalfOpen
            circuitBreaker.AttemptCall(() => { });

            // Assert
            Assert.Equal(3, changeStateCount); //Close->Open, Open->Half, Half->Close
        }
        public void GivenCircuitBreaker_WhenFailure_ThenFailureCountIncrease()
        {
            // Arrange
            Action protectedCode  = () => { throw new Exception(); };
            var    circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(10, TimeSpan.FromMinutes(5));

            // Act
            circuitBreaker.AttemptCall(protectedCode);

            // Assert
            Assert.Equal(1, circuitBreaker.Failures);
        }
        public void GivenCircuitBreaker_WhenAttemptCallCallOnCloseCircuit_ThenFailureCountRemainToZero()
        {
            // Arrange
            Action protectedCode  = () => { return; };
            var    circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(10, TimeSpan.FromMinutes(5));

            // Act
            circuitBreaker.AttemptCall(protectedCode);

            // Assert
            Assert.Equal(0, circuitBreaker.Failures);
        }
        public void GivenCircuitBreakerOpen_WhenCallAgain_ThenNotCallNotExecuted()
        {
            // Arrange
            const int THRESHOLD_INVOCATION = 10;
            int       countInvocation      = 0;
            Action    protectedCode        = () =>
            {
                countInvocation++;
                throw new Exception();
            };
            var circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD_INVOCATION, TimeSpan.FromMinutes(5));

            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD_INVOCATION);

            // Act
            Assert.Equal(THRESHOLD_INVOCATION, countInvocation);
            circuitBreaker.AttemptCall(protectedCode);

            // Assert
            Assert.Equal(THRESHOLD_INVOCATION, countInvocation);
        }
        public void GivenCircuitBreaker_WhenAttemptCallCallOnCloseCircuit_ThenCallMethod()
        {
            // Arrange
            bool   protectedCodeWasCalled = false;
            Action protectedCode          = () => protectedCodeWasCalled = true;
            var    circuitBreaker         = new BaseCircuitBreaker.CircuitBreaker(10, TimeSpan.FromMinutes(5));

            // Act
            circuitBreaker.AttemptCall(protectedCode);

            // Assert
            Assert.True(protectedCodeWasCalled);
        }
        public void GivenCircuitBreakerClose_WhenThresholdIsReached_ThenOpen()
        {
            // Arrange
            const int THRESHOLD      = 10;
            Action    protectedCode  = () => { throw new Exception(); };
            var       circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD, TimeSpan.FromMinutes(5));

            // Act
            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);

            // Assert
            Assert.True(circuitBreaker.IsOpen);
        }
        public void GivenCircuitBreakerOpen_WhenTimeIfPassed_ThenHalfOpen()
        {
            // Arrange
            const int THRESHOLD      = 2;
            Action    protectedCode  = () => { throw new Exception(); };
            var       circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD, TimeSpan.FromMilliseconds(10));

            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);

            // Act
            Thread.Sleep(25);

            // Assert
            Assert.True(circuitBreaker.IsHalfOpen);
        }
        public void GivenCircuitBreakerOpen_WhenManuallyClose_ThenClosed()
        {
            // Arrange
            const int THRESHOLD      = 2;
            Action    protectedCode  = () => { throw new Exception(); };
            var       circuitBreaker = new BaseCircuitBreaker.CircuitBreaker(THRESHOLD, TimeSpan.FromMinutes(5));

            CallXAmountOfTimes(() => circuitBreaker.AttemptCall(protectedCode), THRESHOLD);
            Assert.True(circuitBreaker.IsOpen);

            // Act
            circuitBreaker.Close();

            // Assert
            Assert.True(circuitBreaker.IsClosed);
        }