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 TheTokenConsumptionRateDoesNotBurstAboveCapacityInAnInterval()
        {
            // 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);

            // Do not burst above average rate
            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 another token is consumed
            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 - 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);
        }