public virtual void testCircuitClosedAfterSuccessAndClearsStatisticalWindow()
        {
            int statisticalWindow = 200;
            int sleepWindow       = 10; // this is set very low so that returning from a retry still ends up having data in the buckets for the statisticalWindow
            var properties        = GetCommandConfig();

            properties.CircuitBreakerSleepWindowInMilliseconds       = sleepWindow;
            properties.MetricsRollingStatisticalWindowInMilliseconds = statisticalWindow;
            ICommandMetrics metrics = GetMetrics(properties);
            var             cb      = new TestCircuitBreaker(properties, metrics);

            // fail
            metrics.MarkFailure();
            metrics.MarkFailure();
            metrics.MarkFailure();
            metrics.MarkFailure();

            // everything has failed in the test window so we should return false now
            Assert.IsFalse(cb.AllowRequest());
            Assert.IsTrue(cb.IsOpen());

            // wait for sleepWindow to pass
            Thread.Sleep(sleepWindow + 50);

            // we should now allow 1 request
            Assert.IsTrue(cb.AllowRequest());
            // but the circuit should still be open
            Assert.IsTrue(cb.IsOpen());
            // and further requests are still blocked
            Assert.IsFalse(cb.AllowRequest());

            // the 'singleTest' succeeds so should cause the circuit to be closed
            metrics.MarkSuccess();
            cb.MarkSuccess();

            // all requests should be open again
            Assert.IsTrue(cb.AllowRequest());
            Assert.IsTrue(cb.AllowRequest());
            Assert.IsTrue(cb.AllowRequest());
            // and the circuit should be closed again
            Assert.IsFalse(cb.IsOpen());
        }
        public void TestMultipleTimeWindowRetriesBeforeClosingCircuit()
        {
            int sleepWindow = 200;
            var properties  = GetCommandConfig();

            properties.CircuitBreakerSleepWindowInMilliseconds = sleepWindow;
            ICommandMetrics metrics = GetMetrics(properties);
            var             cb      = new TestCircuitBreaker(properties, metrics);

            // fail
            metrics.MarkFailure();
            metrics.MarkFailure();
            metrics.MarkFailure();
            metrics.MarkFailure();

            // everything has failed in the test window so we should return false now
            Assert.IsFalse(cb.AllowRequest());
            Assert.IsTrue(cb.IsOpen());

            // wait for sleepWindow to pass
            Thread.Sleep(sleepWindow + 50);

            // we should now allow 1 request
            Assert.IsTrue(cb.AllowRequest());
            // but the circuit should still be open
            Assert.IsTrue(cb.IsOpen());
            // and further requests are still blocked
            Assert.IsFalse(cb.AllowRequest());

            // the 'singleTest' fails so it should go back to sleep and not allow any requests again until another 'singleTest' after the sleep
            metrics.MarkFailure();

            Assert.IsFalse(cb.AllowRequest());
            Assert.IsFalse(cb.AllowRequest());
            Assert.IsFalse(cb.AllowRequest());

            // wait for sleepWindow to pass
            Thread.Sleep(sleepWindow + 50);

            // we should now allow 1 request
            Assert.IsTrue(cb.AllowRequest());
            // but the circuit should still be open
            Assert.IsTrue(cb.IsOpen());
            // and further requests are still blocked
            Assert.IsFalse(cb.AllowRequest());

            // the 'singleTest' fails again so it should go back to sleep and not allow any requests again until another 'singleTest' after the sleep
            metrics.MarkFailure();


            Assert.IsFalse(cb.AllowRequest());
            Assert.IsFalse(cb.AllowRequest());
            Assert.IsFalse(cb.AllowRequest());

            // wait for sleepWindow to pass
            Thread.Sleep(sleepWindow + 50);


            // we should now allow 1 request
            Assert.IsTrue(cb.AllowRequest());
            // but the circuit should still be open
            Assert.IsTrue(cb.IsOpen());
            // and further requests are still blocked
            Assert.IsFalse(cb.AllowRequest());

            // now it finally succeeds
            metrics.MarkSuccess();
            cb.MarkSuccess();

            // all requests should be open again
            Assert.IsTrue(cb.AllowRequest());
            Assert.IsTrue(cb.AllowRequest());
            Assert.IsTrue(cb.AllowRequest());
            // and the circuit should be closed again
            Assert.IsFalse(cb.IsOpen());
        }