189 lines
8.5 KiB
Gherkin
189 lines
8.5 KiB
Gherkin
Feature: Retry Patterns Implementation
|
|
As a developer
|
|
I want retry patterns implemented with tenacity
|
|
So that operations can be resilient to transient failures
|
|
|
|
Background:
|
|
Given I have the retry patterns module imported
|
|
|
|
Scenario: Basic exponential backoff retry works
|
|
Given I have a function that fails 2 times then succeeds
|
|
When I apply exponential backoff retry with max 3 attempts
|
|
Then the function should eventually succeed
|
|
And the function should be called 3 times
|
|
|
|
Scenario: Async exponential backoff retry works
|
|
Given I have an async function that fails 2 times then succeeds
|
|
When I apply async exponential backoff retry with max 3 attempts
|
|
Then the async function should eventually succeed
|
|
And the function should be called 3 times
|
|
|
|
Scenario: Network operation retry handles connection errors
|
|
Given I have a function that raises NetworkError twice
|
|
When I apply network retry pattern
|
|
Then the function should retry on NetworkError
|
|
And the function should be called 3 times maximum
|
|
|
|
Scenario: Provider operation retry handles rate limits
|
|
Given I have a function that raises RateLimitError
|
|
When I apply provider retry pattern
|
|
Then the function should retry with exponential jitter
|
|
And the function should respect rate limit backoff
|
|
|
|
Scenario: File operation retry recovers from transient OSError
|
|
Given I have a file operation that fails with OSError once
|
|
When I apply file retry pattern
|
|
Then the file operation should eventually succeed
|
|
And the file operation should be invoked 2 times
|
|
|
|
Scenario: Circuit breaker opens after threshold
|
|
Given I have a circuit breaker with threshold 3
|
|
When a function fails 3 times
|
|
Then the circuit breaker should open
|
|
And subsequent calls should fail immediately
|
|
|
|
Scenario: Circuit breaker resets after timeout
|
|
Given I have an open circuit breaker
|
|
When the recovery timeout expires
|
|
Then the circuit breaker should enter half-open state
|
|
And successful calls should close the circuit
|
|
|
|
Scenario: Retry context tracks attempts
|
|
Given I have a retry context for "test operation"
|
|
When I execute a function that fails twice
|
|
Then the retry context should track 3 attempts
|
|
And the errors should be recorded
|
|
|
|
Scenario: Retry context manager records exceptions raised in block
|
|
Given I have a retry context for "context block"
|
|
When I execute a failing block under the retry context manager
|
|
Then the retry context manager should capture the exception
|
|
|
|
Scenario: Async retry context manager records exceptions raised in block
|
|
Given I have a retry context for "async context block"
|
|
When I execute a failing block under the async retry context manager
|
|
Then the async retry context manager should capture the exception
|
|
|
|
Scenario: Retry context manager leaves errors untouched on success
|
|
Given I have a retry context for "successful context block"
|
|
When I execute a successful block under the retry context manager
|
|
Then the retry context manager should not record errors
|
|
|
|
Scenario: Async retry context manager leaves errors untouched on success
|
|
Given I have a retry context for "async successful context block"
|
|
When I execute a successful block under the async retry context manager
|
|
Then the async retry context manager should not record errors
|
|
|
|
Scenario: Retry context async execute handles transient async failures
|
|
Given I have a retry context for "async execute operation"
|
|
And I have an async function that fails 2 times then succeeds
|
|
When I execute the async function with the retry context
|
|
Then the async retry context execute should succeed after 3 attempts
|
|
|
|
Scenario: Retry with timeout retries transient failures without waiting
|
|
Given I have a function that fails 1 times then succeeds
|
|
When I apply retry with timeout of 3 attempts and 0.01 seconds
|
|
Then the function should eventually succeed
|
|
And the function should be called 2 times
|
|
|
|
Scenario: Retry with jitter prevents thundering herd
|
|
Given I have multiple concurrent operations
|
|
When I apply retry with jitter
|
|
Then the retries should have random delays
|
|
And operations should not retry simultaneously
|
|
|
|
Scenario: Retry on result retries when predicate flags response
|
|
Given I have sequential result payloads requiring a retry
|
|
And I have a retry predicate that checks for retry flag
|
|
When I apply retry on result with max 3 attempts
|
|
Then the decorated function should return the successful payload
|
|
And the function should be called 2 times
|
|
|
|
Scenario: Auto-debug retry pattern works
|
|
Given I have a function that fails with errors
|
|
And I have a debug callback that fixes issues
|
|
When I apply auto-debug retry
|
|
Then the function should retry with debug fixes
|
|
And eventually succeed after debugging
|
|
|
|
Scenario: Retry categories have correct configurations
|
|
Given I have the retry categories defined
|
|
Then network operations should retry 5 times
|
|
And provider operations should retry 3 times
|
|
And database operations should retry 3 times
|
|
And file operations should retry 3 times
|
|
|
|
Scenario: Retry logging handles loggers without keyword support
|
|
Given the retry logger rejects keyword arguments
|
|
When I invoke logging callbacks for failed and successful attempts
|
|
Then the fallback logging messages should be recorded
|
|
|
|
Scenario: Circuit breaker half-open transitions recover and reopen
|
|
Given I have a half-open circuit breaker with threshold 2
|
|
When I record a successful half-open call
|
|
And I record another successful half-open call
|
|
Then the circuit breaker should close after consecutive successes
|
|
When I simulate a half-open failure
|
|
Then the circuit breaker should reopen after half-open failure
|
|
|
|
Scenario: Circuit breaker resets failure counters after closed success
|
|
Given I have a circuit breaker with threshold 2
|
|
And the circuit breaker has recorded failures
|
|
When I execute a successful call while the circuit is closed
|
|
Then the circuit breaker should reset failure tracking after success
|
|
|
|
Scenario: Async circuit breaker enforces open and recovery transitions
|
|
Given I have an async circuit breaker with threshold 1
|
|
When I trigger an async failure on the circuit breaker
|
|
Then the async circuit breaker should raise immediately while open
|
|
When the recovery timeout expires
|
|
And I perform two async successful calls after recovery
|
|
Then the async circuit breaker should close after async successes
|
|
|
|
Scenario: should_retry_result handles error payloads
|
|
Given I have a response payload with error "timeout detected"
|
|
When I evaluate the retry decision
|
|
Then the retry decision should be True
|
|
|
|
Scenario: should_retry_result handles server error status codes
|
|
Given I have a response payload with status code 503
|
|
When I evaluate the retry decision
|
|
Then the retry decision should be True
|
|
|
|
Scenario: should_retry_result returns False for None payloads
|
|
Given I have a result payload set to None
|
|
When I evaluate the retry decision
|
|
Then the retry decision should be False
|
|
|
|
Scenario: should_retry_result returns False for non-error dictionaries
|
|
Given I have a response payload with status code 200
|
|
When I evaluate the retry decision
|
|
Then the retry decision should be False
|
|
|
|
Scenario: should_retry_result returns False for non-dictionary results
|
|
Given I have a result payload set to the string "ok"
|
|
When I evaluate the retry decision
|
|
Then the retry decision should be False
|
|
|
|
Scenario: Unknown retry category falls back to default decorator
|
|
When I request a retry decorator for "unknown-category"
|
|
And I decorate a function returning "decorated result"
|
|
Then the decorated function should execute successfully
|
|
|
|
Scenario: configure_retry_logging sets tenacity logger levels
|
|
When I configure retry logging to warning level
|
|
Then the tenacity loggers should be set to warning
|
|
|
|
Scenario: Auto-debug retry raises the last error message when unresolved
|
|
Given I have a function that returns persistent error payloads
|
|
And I have a debug callback that never fixes issues
|
|
When I apply auto-debug retry expecting failure
|
|
Then the auto-debug retry should raise the last error message
|
|
|
|
Scenario: Auto-debug retry logs debug callback failures
|
|
Given I have a function that returns persistent error payloads
|
|
And I have a debug callback that raises errors
|
|
When I apply auto-debug retry expecting failure
|
|
Then the auto-debug retry should raise the debug callback failure
|
|
And the debug callback failures should be counted
|