public void TheRequestedNumberOfTokensDepletesTheTokenBucket()
        {
            // Given
            const int Interval    = 10;
            const int AverageRate = 2;
            const int Bursting    = 2;
            const int Requested   = 4;
            const int Capacity    = AverageRate * Bursting;

            var tokenBucket = new TokenBucket.TokenBucket(
                interval: Interval,
                averageRate: AverageRate,
                bursting: Bursting);

            // When the number of tokens requested depletes the token bucket
            var response = tokenBucket.Consume(Requested);

            // Then it should allow token consumption
            response.IsAllowed.Should().BeTrue();
            response.Limit.Should().Be(Capacity);
            response.Remaining.Should().Be(Capacity - Requested);

            // And it should return the expected number of available tokens
            response.Remaining.Should().Be(AverageRate * Bursting - Requested);
        }
        public void TheTokenConsumptionRateBurstsAboveCapacityInAnInterval()
        {
            // Given
            const int Interval    = 1;
            const int AverageRate = 2;
            const int Bursting    = 2;
            const int Requested   = 1;

            var response = new List <ConsumeResult>();

            var tokenBucket = new TokenBucket.TokenBucket(
                interval: Interval,
                averageRate: AverageRate,
                bursting: Bursting);

            // Burst above average rate by 3 requests
            response.Add(tokenBucket.Consume(Requested));
            response.Add(tokenBucket.Consume(Requested));
            response.Add(tokenBucket.Consume(Requested));
            response.Add(tokenBucket.Consume(Requested));
            response.Add(tokenBucket.Consume(Requested));

            var lastConsumedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

            // Wait for interval to lapse
            Thread.Sleep(Interval * 1000);

            // When 1 more token is consumed in new interval
            response.Add(tokenBucket.Consume(Requested));

            var availableTokensAfterBurst = (DateTimeOffset.UtcNow.ToUnixTimeSeconds() - lastConsumedAt) / Interval * AverageRate;

            // Then it should return the expected sequence of responses
            var capacityAtBurst = AverageRate * Bursting;

            response[0].IsAllowed.Should().BeTrue();
            response[0].Limit.Should().Be(capacityAtBurst);
            response[0].Remaining.Should().Be(capacityAtBurst - 1);

            response[1].IsAllowed.Should().BeTrue();
            response[1].Limit.Should().Be(capacityAtBurst);
            response[1].Remaining.Should().Be(capacityAtBurst - 2);

            response[2].IsAllowed.Should().BeTrue();
            response[2].Limit.Should().Be(capacityAtBurst);
            response[2].Remaining.Should().Be(capacityAtBurst - 3);

            response[3].IsAllowed.Should().BeTrue();
            response[3].Limit.Should().Be(capacityAtBurst);
            response[3].Remaining.Should().Be(capacityAtBurst - 4);

            response[4].IsAllowed.Should().BeFalse();
            response[4].Limit.Should().Be(capacityAtBurst);
            response[4].Remaining.Should().Be(0);

            response[5].IsAllowed.Should().BeTrue();
            response[5].Limit.Should().Be(capacityAtBurst);
            response[5].Remaining.Should().Be((int)availableTokensAfterBurst - 1);
        }
        public void TheRequestedNumberOfTokensExceedsAvailableTokens()
        {
            // Given
            const int Interval    = 10;
            const int AverageRate = 2;
            const int Bursting    = 2;
            const int Requested   = 10;
            const int Capacity    = AverageRate * Bursting;

            var tokenBucket = new TokenBucket.TokenBucket(
                interval: Interval,
                averageRate: AverageRate,
                bursting: Bursting);

            // When a token is consumed exceeding available capacity
            var response = tokenBucket.Consume(Requested);

            // Then it should not allow token consumption
            response.IsAllowed.Should().BeFalse();
            response.Limit.Should().Be(Capacity);
            response.Remaining.Should().Be(Capacity);
        }