# Configuration and Testing

Global configuration functions for controlling retry behavior system-wide and enabling test mode with modified retry parameters for faster test execution and predictable behavior.

## Capabilities

### Global Activation Control

Control whether retry behavior is active across the entire application. When deactivated, all retry decorators and contexts will execute only once without retries.

```python { .api }
def is_active() -> bool:
    """
    Check whether retrying is globally active.
    
    Returns:
    bool: True if retrying is active, False otherwise
    """

def set_active(active: bool) -> None:
    """
    Globally activate or deactivate retrying.
    
    When deactivated, all retry decorators and retry contexts will 
    execute only once regardless of configured attempts.
    
    Parameters:
    - active: bool - Whether to activate retrying
    
    This function is idempotent and can be called repeatedly.
    """
```

**Usage Examples:**

```python
import stamina

# Check current state
print(f"Retries active: {stamina.is_active()}")  # True by default

# Temporarily disable retries
stamina.set_active(False)

@stamina.retry(on=Exception, attempts=5)  
def unreliable_function():
    raise ValueError("This will not retry")

try:
    unreliable_function()  # Fails immediately, no retries
except ValueError:
    print("Function failed without retries")

# Re-enable retries
stamina.set_active(True)

# Emergency circuit breaker pattern
def emergency_disable_retries():
    """Disable retries when system is under stress."""
    stamina.set_active(False)
    logger.warning("Retries disabled due to system overload")

def restore_retries():
    """Re-enable retries when system recovers."""
    stamina.set_active(True)
    logger.info("Retries re-enabled")
```

### Test Mode Configuration

Test mode provides predictable retry behavior for testing scenarios by disabling backoff delays and controlling attempt counts.

```python { .api }
def is_testing() -> bool:
    """
    Check whether test mode is enabled.
    
    Returns:
    bool: True if test mode is active, False otherwise
    """

def set_testing(
    testing: bool, 
    *, 
    attempts: int = 1, 
    cap: bool = False
) -> _RestoreTestingCM:
    """
    Activate or deactivate test mode.
    
    In test mode:
    - All backoff delays are set to 0 (no waiting)
    - Attempt counts are controlled by the attempts parameter
    
    Parameters:
    - testing: bool - Whether to enable test mode
    - attempts: int - Number of attempts in test mode (default: 1)
    - cap: bool - If True, cap attempts rather than override (default: False)
    
    Returns:
    Context manager that restores previous testing state when exited
    
    When cap=True:
    - If attempts=3 and user specifies 5 attempts, use 3 (capped)
    - If attempts=3 and user specifies 2 attempts, use 2 (user's value)
    
    This function can be used as a context manager and is idempotent.
    """
```

**Usage Examples:**

```python
import stamina

# Basic test mode usage
def test_retry_behavior():
    # Enable test mode with single attempt
    stamina.set_testing(True, attempts=1)
    
    @stamina.retry(on=ValueError, attempts=5)  # Will only try once
    def failing_function():
        raise ValueError("Test failure")
    
    try:
        failing_function()
        assert False, "Should have failed"
    except ValueError:
        pass  # Expected
    
    # Disable test mode
    stamina.set_testing(False)

# Test mode with multiple attempts
def test_eventual_success():
    stamina.set_testing(True, attempts=3)  # Allow 3 attempts in test
    
    call_count = 0
    
    @stamina.retry(on=ValueError, attempts=10)  # Normally 10, but test caps at 3
    def eventually_succeeds():
        nonlocal call_count
        call_count += 1
        if call_count < 3:
            raise ValueError("Not yet")
        return "success"
    
    result = eventually_succeeds()
    assert result == "success"
    assert call_count == 3
    
    stamina.set_testing(False)

# Context manager usage
def test_with_context_manager():
    with stamina.set_testing(True, attempts=2):
        # Test code here runs with test mode
        @stamina.retry(on=Exception, attempts=5)
        def test_function():
            raise Exception("Test")
        
        try:
            test_function()  # Will try 2 times, not 5
        except Exception:
            pass
    
    # Test mode automatically restored after context

# Capped attempts mode
def test_capped_attempts():
    with stamina.set_testing(True, attempts=3, cap=True):
        # User specifies 2 attempts, test allows up to 3, so use 2
        @stamina.retry(on=ValueError, attempts=2)
        def function_a():
            raise ValueError("Test")
        
        # User specifies 5 attempts, test caps at 3, so use 3  
        @stamina.retry(on=ValueError, attempts=5)
        def function_b():
            raise ValueError("Test")
```

### Testing Patterns

Common patterns for testing retry behavior:

```python
import pytest
import stamina

class TestRetryBehavior:
    def setup_method(self):
        """Reset retry state before each test."""
        stamina.set_active(True)
        stamina.set_testing(False)
    
    def test_successful_retry(self):
        """Test that retries eventually succeed."""
        with stamina.set_testing(True, attempts=3):
            call_count = 0
            
            @stamina.retry(on=ValueError, attempts=5)
            def flaky_function():
                nonlocal call_count
                call_count += 1
                if call_count < 3:
                    raise ValueError("Not ready")
                return "success"
            
            result = flaky_function()
            assert result == "success"
            assert call_count == 3
    
    def test_exhausted_retries(self):
        """Test behavior when all retries are exhausted."""
        with stamina.set_testing(True, attempts=2):
            call_count = 0
            
            @stamina.retry(on=ValueError, attempts=3)  # Will be capped at 2
            def always_fails():
                nonlocal call_count
                call_count += 1
                raise ValueError(f"Failure {call_count}")
            
            with pytest.raises(ValueError, match="Failure 2"):
                always_fails()
            
            assert call_count == 2
    
    def test_no_retries_when_inactive(self):
        """Test that inactive mode prevents retries.""" 
        stamina.set_active(False)
        
        call_count = 0
        
        @stamina.retry(on=ValueError, attempts=5)
        def should_not_retry():
            nonlocal call_count
            call_count += 1
            raise ValueError("Single failure")
        
        with pytest.raises(ValueError):
            should_not_retry()
        
        assert call_count == 1  # Called only once

    def test_context_manager_cleanup(self):
        """Test that context managers properly restore state."""
        original_testing = stamina.is_testing()
        
        try:
            with stamina.set_testing(True, attempts=2):
                assert stamina.is_testing() == True
                # Test code here
            
            # State should be restored
            assert stamina.is_testing() == original_testing
        finally:
            stamina.set_testing(original_testing)

# Pytest fixtures for common test setups
@pytest.fixture
def no_retries():
    """Fixture to disable retries for fast tests."""
    with stamina.set_testing(True, attempts=1):
        yield

@pytest.fixture  
def fast_retries():
    """Fixture for tests that need some retries but fast execution."""
    with stamina.set_testing(True, attempts=3):
        yield

def test_with_no_retries(no_retries):
    """Test using the no_retries fixture."""
    @stamina.retry(on=ValueError, attempts=10)
    def fails_once():
        raise ValueError("Test failure")
    
    with pytest.raises(ValueError):
        fails_once()  # Fails immediately

def test_with_fast_retries(fast_retries):
    """Test using the fast_retries fixture."""
    call_count = 0
    
    @stamina.retry(on=ValueError, attempts=10)
    def succeeds_on_third():
        nonlocal call_count
        call_count += 1
        if call_count < 3:
            raise ValueError("Not yet")
        return "success"
    
    result = succeeds_on_third()
    assert result == "success"
```

## Configuration Best Practices

### Application Startup

Configure retry behavior during application initialization:

```python
import stamina
import os

def configure_retries():
    """Configure retry behavior based on environment."""
    env = os.getenv("ENVIRONMENT", "production")
    
    if env == "test":
        # Fast, predictable retries for tests
        stamina.set_testing(True, attempts=2)
    elif env == "development":
        # Shorter timeouts for development
        # Use default active behavior but configure individual retries
        pass
    elif env == "production":
        # Full retry behavior (default)
        stamina.set_active(True)
    else:
        raise ValueError(f"Unknown environment: {env}")

# Call during app startup
configure_retries()
```

### Health Check Integration

Integrate with application health checks:

```python
import stamina
from your_app import health_check

def monitor_system_health():
    """Disable retries when system is unhealthy."""
    if not health_check.is_healthy():
        stamina.set_active(False)
        logger.warning("Retries disabled due to system health issues")
    else:
        stamina.set_active(True)

# Run periodically
import threading
import time

def health_monitor_loop():
    while True:
        monitor_system_health()
        time.sleep(30)  # Check every 30 seconds

health_thread = threading.Thread(target=health_monitor_loop, daemon=True)
health_thread.start()
```

## Types

```python { .api }
class _RestoreTestingCM:
    """Context manager that restores previous testing state when exited."""
    def __enter__(self) -> None: ...
    def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...
```