Files
routstr-core/tests/unit
9qeklajcand9qeklajc 7f44389b59 fix(certification): harden against adversarial inputs found by tester agents
Three independent tester subagents found 12 defects (1 critical, 2 high,
9 medium/low). This commit fixes all of them and adds 56 regression tests.

Critical (CLI dead on arrival):
- certify_upstream_url() called sats_usd_price() which raises ValueError
  in any fresh process (the module global is only set by the app lifespan
  task). Now resolves via _resolve_sats_usd_price(): module global → BTC
  global → exchange feed → None (warn row, not a crash). Adds
  --sats-usd-price CLI flag for explicit override.

High (non-finite tokens crash the billing path):
- parse_token_count() crashed on Infinity/NaN (json.loads accepts both).
  Fixed to reject non-finite values → 0. This was a shared-code bug in
  routstr/payment/usage.py, reachable from the main billing path too.
- usage_capture_row and cost_prompt_completion_row now guard normalize_usage
  in try/except via safe_row(), so a raising check becomes a fail row
  instead of a 500.

Medium:
- certification_row now coerces non-dict evidence to {} (was stored verbatim)
- endpoint_validity_row checks .hostname not .netloc (http://:8080 rejected)
- models_payload_row rejects empty-string ids (agrees with CLI discovery)
- models_payload_row / usage_capture_row guard against non-dict payloads
- _reported_usd_cost uses coerce_rate for parity with the engine
- _expected_token_msats raises ValueError on non-finite rates (not OverflowError)
- get_candidates() call in admin endpoint wrapped in try/except
- Admin timeout clamped to [1, 60] seconds
- Explicit --prompt-price validated via coerce_rate (negatives rejected)
- CLI --json-out flag writes strictly parseable JSON to a file
- CLI logs routed to stderr so stdout is the report's channel

Test plan: 1749 passed, 1 skipped (no regressions); ruff clean; mypy clean.
2026-09-21 22:53:33 +02:00
..
2025-08-03 20:35:59 -03:00
2025-08-09 14:55:26 -03:00
2026-09-04 01:35:43 +02:00
2026-06-13 23:40:39 +02:00
2026-09-07 00:30:05 +02:00
2026-08-03 23:32:06 +02:00
2026-08-06 22:58:44 +02:00
2026-08-03 00:05:36 +02:00
2026-09-07 00:30:05 +02:00
2026-07-01 17:08:28 +02:00
2026-07-01 16:53:52 +02:00
2026-05-14 15:40:49 +02:00
2026-09-16 13:15:32 +02:00
2026-07-29 22:50:33 +02:00
2026-08-14 21:48:29 +02:00
2026-09-04 01:35:43 +02:00
2026-07-22 23:10:27 +02:00
2026-07-22 23:10:27 +02:00

FastAPI Async Unit Tests

This directory contains async unit tests for the Routstr proxy FastAPI application.

Installation

First, ensure you have the development dependencies installed:

uv pip install -e ".[dev]"

Running Tests

To run all tests:

pytest

To run tests with coverage:

pytest --cov=routstr --cov-report=html

To run specific test files:

pytest tests/test_main.py
pytest tests/test_models.py
pytest tests/test_proxy.py

To run only async tests:

pytest -m asyncio

Test Structure

  • conftest.py - Pytest fixtures and configuration
  • test_main.py - Tests for main app endpoints
  • test_account.py - Tests for wallet/account management endpoints
  • test_proxy.py - Tests for the proxy functionality with mocked upstream
  • test_models.py - Tests for model pricing and data structures

Key Fixtures

  • async_client - Async HTTP client for testing FastAPI endpoints
  • test_session - In-memory SQLite database session for tests
  • test_api_key - Pre-configured API key with balance
  • api_key_with_balance - API key with sufficient balance for proxy tests

Environment Variables

The tests automatically set up required environment variables in conftest.py. No manual configuration needed.

Writing New Tests

  1. Use @pytest.mark.asyncio for async tests
  2. Use the provided fixtures for database and client access
  3. Mock external dependencies (like upstream API calls)
  4. Test both success and error cases
  5. Verify database state changes when applicable