| """TokenBucket / CompoundLimiter unit tests.""" |
| from __future__ import annotations |
|
|
| from app.rate_limit import CompoundLimiter, TokenBucket |
|
|
|
|
| def test_token_bucket_consumes_then_rejects_with_retry(): |
| bucket = TokenBucket(capacity=2, refill_per_minute=1) |
| assert bucket.try_consume("k") == (True, 0) |
| assert bucket.try_consume("k") == (True, 0) |
| allowed, retry = bucket.try_consume("k") |
| assert allowed is False |
| assert retry >= 1 |
|
|
|
|
| def test_compound_rejection_refunds_buckets_that_allowed(): |
| burst = TokenBucket(capacity=3, refill_per_minute=1) |
| sustained = TokenBucket(capacity=1, refill_per_minute=1) |
| limiter = CompoundLimiter(burst, sustained) |
|
|
| assert limiter.try_consume("k") == (True, 0) |
|
|
| |
| |
| for _ in range(10): |
| allowed, retry = limiter.try_consume("k") |
| assert allowed is False |
| assert retry >= 1 |
|
|
| |
| |
| assert burst.try_consume("k")[0] is True |
| assert burst.try_consume("k")[0] is True |
|
|
|
|
| def test_compound_keys_are_independent(): |
| limiter = CompoundLimiter( |
| TokenBucket(capacity=1, refill_per_minute=1), |
| TokenBucket(capacity=1, refill_per_minute=1), |
| ) |
| assert limiter.try_consume("a")[0] is True |
| assert limiter.try_consume("a")[0] is False |
| assert limiter.try_consume("b")[0] is True |
|
|