Testing¶
tests/test_resilience.py has 120 tests: classification across SDK shapes (real botocore errors included), Retry-After parsing, token buckets and AIMD on a fake clock, the limiter's levels and overrides, the bulkhead, the breaker state machine and its per-operation scope, unknown config keys, retries, budgets and deadlines, the decorator, the live guard, the config models, and integration tests for each provider. The AWS ones use moto with a before-send handler that answers one operation with RequestLimitExceeded, and check the attempt count, the coverage status and the stats.
The governor is process-wide state, so tests/conftest.py has an autouse fixture, fresh_resilience_governor, that calls reset_governor() before and after every test. It also raises every built-in rate, burst and account limit to 1,000,000 by swapping limiter.DEFAULT_LIMITS for a fast profile. moto never throttles, and its fixtures (hundreds of default AMIs and snapshots) would otherwise make the production per-service rates the bottleneck of the suite. The hooks, limiter, breakers and telemetry still run on every call. tests/test_resilience.py has its own autouse fixture that puts limiter.BUILTIN_LIMITS back, so the resilience tests see the real defaults.
When you write a test that depends on throttling behaviour, either live in tests/test_resilience.py or restore BUILTIN_LIMITS the same way, inject a clock (RateLimiter(clock=...), CircuitBreaker(clock=...), LiveOperationGuard(clock=...), Governor(clock=...)) and pass sleep= to call_with_resilience so nothing waits for real. For moto, patch botocore's ExponentialBackoff.delay_amount to return 0, as the integration tests do.