mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-10-06 04:38:22 +00:00
Closes 29 of 30 open Dependabot alerts (all 3 critical, all 17 high): Python (uv.lock): - litellm 1.83.0 -> 1.84.10 (CVE-2026-49468, CVE-2026-42208 criticals + 8 more high/med/low) - starlette 0.46.2 -> 1.6.0 (CVE-2026-54283, CVE-2026-48818, CVE-2026-48817, CVE-2026-48710, CVE-2025-62727, CVE-2025-54121) - cryptography 43.0.3 -> 50.0.1 (CVE-2026-69249, CVE-2026-26007, CVE-2026-34073, CVE-2024-12797) - h11 0.14.0 -> 0.16.0 (CVE-2025-43859 critical) - fastapi 0.115.14 -> 0.141.1 (starlette 1.x support) - httpx 0.25.2 -> 0.28.1, setuptools 75.9.1 -> 84.0.0, wheel 0.41.3 -> 0.48.0 cashu 0.20.x pins conservative upper bounds (httpx<0.26, h11<0.15, fastapi<0.116, cryptography<44, setuptools<76, wheel<0.42, importlib-metadata<7) that conflict with every patched version, so the gated packages are lifted via [tool.uv] override-dependencies. routstr only imports cashu's wallet-side modules, not its mint/fastapi server paths. starlette is forced via constraint-dependencies since fastapi 0.141 permits the old in-range 0.46.2. Code changes required by the bumps: - httpx 0.28 removed `proxies=`: use `proxy=` in routstr/nostr/discovery.py (Tor .onion health fetches) and examples/tor.py. The discovery.py path was untested and would have raised TypeError at runtime on any .onion provider check. - tests/integration/test_admin_pricing_rate_validation.py: httpx 0.28 refuses to encode NaN/Inf client-side (allow_nan=False); send raw JSON bytes so the bare NaN/Infinity literals still reach the server, which is the behavior under test. UI (pnpm-lock.yaml): - browserslist 4.28.1 -> 4.28.9 (CVE-2026-73089, CVE-2026-73088) - @humanfs/node 0.16.7 -> 0.16.8 Remaining alert: ecdsa (GHSA-wj6h-64fc-37mp, Minerva timing attack) is already at the latest release 0.19.2 with no fix available upstream; cashu pins ecdsa<0.20. Deferred until cashu migrates off python-ecdsa. Verified: 1336 unit + 439 integration tests pass, mypy, ruff, UI lint / format-check / build all clean. 2 unit test failures (test_provider_slugs) are pre-existing environment leaks (python-dotenv loads the parent checkout's .env containing TINFOIL_API_KEY and fail identically on main. EOF )
Integration Tests
End-to-end tests for API endpoints, Cashu wallet operations, and database interactions.
Quick Start
# 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)
# 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)
# 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
# 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 testingauthenticated_client- Pre-authenticated client with API keytestmint_wallet- Mock/real Cashu wallet for token generationdb_snapshot- Database state tracking for verificationtest_mode- Reports current execution mode (mock/docker)
Utility Classes
ResponseValidator- Validates API response formatsPerformanceValidator- Tracks and validates performance metricsConcurrencyTester- Tests concurrent request handlingCashuTokenGenerator- 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
@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
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
@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:
# 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
- Use Mock Mode for Development - It's fast and catches most issues
- Run Docker Mode Before PRs - Ensures realistic testing
- Add Appropriate Markers - Help others run relevant test subsets
- Use
@pytest.mark.slowfor tests that take significant time (e.g., memory/load tests) - Use
@pytest.mark.requires_dockerfor tests needing Docker services
- Use
- Verify Database State - Use
db_snapshotfor state verification - Test Edge Cases - Invalid inputs, network failures, race conditions
- Monitor Performance - Add performance tests for critical paths