Files
routstr-core/tests/integration/README.md
T

229 lines
6.1 KiB
Markdown

# Integration Tests
End-to-end tests for API endpoints, Cashu wallet operations, and database interactions.
## Quick Start
```bash
# First-time setup (installs uv if needed)
make setup
# Check if all dependencies are installed
make check-deps
# Run tests
make test
```
## Test Modes
The integration tests support two execution modes:
### 🎭 Mock Mode (Default - Fast)
- Uses in-memory mocks for external services
- No Docker required
- Runs quickly, ideal for CI/CD
- Good for rapid development iteration
### 🐳 Docker Mode (Realistic)
- Uses real Docker services (Cashu mint, mock OpenAI, Nostr relay)
- More accurate testing environment
- Slower but catches more edge cases
- Recommended before releases
## Running Tests
### Quick Mode (Mocked Services)
```bash
# All integration tests with mocks
pytest tests/integration/ -v
# Specific test file
pytest tests/integration/test_wallet_topup.py -v
# Skip slow tests
pytest tests/integration/ -m "not slow" -v
# Run only unit-style integration tests
pytest tests/integration/ -m "not requires_docker" -v
```
### Full Integration Mode (Docker Services)
```bash
# Using the automated script (recommended)
./tests/run_integration.py
# Or manually:
docker-compose -f compose.testing.yml up -d
USE_LOCAL_SERVICES=1 pytest tests/integration/ -v
docker-compose -f compose.testing.yml down -v
```
### CI/CD Mode
```bash
# Fast tests only for continuous integration
pytest tests/integration/ -m "not slow and not requires_docker" -v
# Performance tests
pytest tests/integration/ -m "performance" -v
```
## Test Infrastructure
### Core Fixtures
- **`integration_client`** - Async HTTP client configured for testing
- **`authenticated_client`** - Pre-authenticated client with API key
- **`testmint_wallet`** - Mock/real Cashu wallet for token generation
- **`db_snapshot`** - Database state tracking for verification
- **`test_mode`** - Reports current execution mode (mock/docker)
### Utility Classes
- **`ResponseValidator`** - Validates API response formats
- **`PerformanceValidator`** - Tracks and validates performance metrics
- **`ConcurrencyTester`** - Tests concurrent request handling
- **`CashuTokenGenerator`** - Generates valid/invalid test tokens
## Environment Configuration
Test environment configuration is handled directly in `conftest.py`. The configuration automatically switches between:
- **Mock mode**: Fast, uses mocked services (default)
- **Docker mode**: Uses real Docker services when `USE_LOCAL_SERVICES=1`
This keeps all test configuration in one place and avoids file duplication.
## Writing Tests
### Basic Test Structure
```python
@pytest.mark.integration
@pytest.mark.asyncio
async def test_wallet_topup(
authenticated_client: AsyncClient,
testmint_wallet: Any,
db_snapshot: Any
):
# Capture initial state
await db_snapshot.capture()
# Generate test token
token = await testmint_wallet.mint_tokens(1000)
# Make API request
response = await authenticated_client.post(
"/v1/wallet/topup",
params={"cashu_token": token}
)
# Validate response
assert response.status_code == 200
# Verify database changes
diff = await db_snapshot.diff()
assert len(diff["api_keys"]["modified"]) == 1
```
### Testing Concurrent Operations
```python
async def test_concurrent_topups(
integration_client: AsyncClient,
testmint_wallet: Any,
create_api_key: Callable
):
# Create multiple API keys
keys = []
for i in range(5):
key, _ = await create_api_key(integration_client, testmint_wallet)
keys.append(key)
# Test concurrent requests
tester = ConcurrencyTester()
responses = await tester.run_concurrent_requests(
integration_client,
[{"method": "GET", "url": "/v1/wallet/",
"headers": {"Authorization": f"Bearer {key}"}}
for key in keys],
max_concurrent=5
)
# All should succeed
assert all(r.status_code == 200 for r in responses)
```
### Performance Testing
```python
@pytest.mark.performance
async def test_endpoint_performance(
authenticated_client: AsyncClient,
performance_validator: PerformanceValidator
):
# Run multiple requests
for i in range(100):
start = performance_validator.start_timing("wallet_info")
response = await authenticated_client.get("/v1/wallet/")
performance_validator.end_timing("wallet_info", start)
# Validate 95th percentile < 100ms
result = performance_validator.validate_response_time(
"wallet_info", max_duration=0.1, percentile=0.95
)
assert result["valid"], f"P95: {result['percentile_time']:.3f}s"
```
## Troubleshooting
### Tests Failing with Connection Errors
- Ensure Docker services are running: `docker ps`
- Check service logs: `docker-compose -f compose.testing.yml logs`
- Verify ports aren't in use: `lsof -i :3338,3000,8000,8088`
### Mock vs Docker Mode Confusion
- Check current mode: Look for 🎭 or 🐳 emoji in test output
- Force mock mode: Unset `USE_LOCAL_SERVICES`
- Force Docker mode: `export USE_LOCAL_SERVICES=1`
### Slow Test Execution
- Use mock mode for development: `pytest tests/integration/`
- Skip slow tests: `pytest -m "not slow"`
- Run specific test files only
- Use pytest-xdist for parallel execution: `pytest -n auto`
### Installing uv Manually
If `make dev-setup` fails to install uv automatically:
```bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or with pip
pip install uv
# Or with Homebrew
brew install uv
```
## Best Practices
1. **Use Mock Mode for Development** - It's fast and catches most issues
2. **Run Docker Mode Before PRs** - Ensures realistic testing
3. **Add Appropriate Markers** - Help others run relevant test subsets
- Use `@pytest.mark.slow` for tests that take significant time (e.g., memory/load tests)
- Use `@pytest.mark.requires_docker` for tests needing Docker services
4. **Verify Database State** - Use `db_snapshot` for state verification
5. **Test Edge Cases** - Invalid inputs, network failures, race conditions
6. **Monitor Performance** - Add performance tests for critical paths