public void ConsumeBlocksUntilTokensAreAvailable()
        {
            var time         = new DateTime(2000, 01, 01);
            var timeProvider = new ManualTimeProvider(time);

            const int refillAmount   = 1;
            var       refillInterval = TimeSpan.FromMinutes(1);
            var       refillStrategy = new FixedIntervalRefillStrategy(timeProvider, refillAmount, refillInterval);

            // using spin wait strategy to ensure we update AvailableTokens as quickly as possible
            var sleepStrategy = new BusyWaitSleepStrategy();

            const int capacity = 10;
            var       bucket   = new LeakyBucket(capacity, sleepStrategy, refillStrategy, timeProvider);

            // first remove half the capacity
            bucket.Consume(capacity / 2);

            // we've consumed half of the available tokens
            Assert.AreEqual(capacity / 2, bucket.AvailableTokens);

            var taskStarted            = new ManualResetEvent(false);
            var bucketConsumeCompleted = new ManualResetEvent(false);

            Task.Run(() =>
            {
                taskStarted.Set();

                // this will block until time advances
                bucket.Consume(capacity);
                bucketConsumeCompleted.Set();
            });

            taskStarted.WaitOne();

            // each loop we'll advance one refill increment and when the loop finishes
            // the bucket's consume operation will succeed
            var initialAmount = bucket.AvailableTokens;

            for (int i = 0; i < 5; i++)
            {
                timeProvider.Advance(refillInterval);
                Thread.Sleep(1);

                // on the last loop, the bucket will consume all ten
                if (i != 4)
                {
                    // each time we advance the number of available tokens will increment by the refill amount
                    Assert.AreEqual(initialAmount + (1 + i) * refillAmount, bucket.AvailableTokens,
                                    $"CurrentTime: {timeProvider.GetUtcNow():O}: Iteration: {i}"
                                    );
                }
            }

            // now that we've advanced, bucket consumption should have completed
            // we provide for a small timeout to support non-multi-threaded machines
            Assert.IsTrue(bucketConsumeCompleted.WaitOne(10));
            Assert.AreEqual(0, bucket.AvailableTokens);
        }