mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-08-09 02:54:37 +00:00
234 lines
5.1 KiB
Markdown
234 lines
5.1 KiB
Markdown
# Testing Guide
|
|
|
|
This guide covers testing practices, patterns, and tools used in Routstr Core development.
|
|
|
|
## Testing Philosophy
|
|
|
|
We follow these principles:
|
|
|
|
- Test behavior, not implementation
|
|
- Fast feedback
|
|
- Reliable tests
|
|
- Clear failures
|
|
|
|
## Test Structure
|
|
|
|
```
|
|
tests/
|
|
├── integration/
|
|
│ ├── conftest.py
|
|
│ ├── utils.py
|
|
│ ├── test_wallet_topup.py
|
|
│ ├── test_wallet_refund.py
|
|
│ ├── test_wallet_information.py
|
|
│ ├── test_proxy_get_endpoints.py
|
|
│ ├── test_proxy_post_endpoints.py
|
|
│ └── ... more integration tests
|
|
├── unit/
|
|
│ ├── test_algorithm.py
|
|
│ ├── test_fee_consistency.py
|
|
│ ├── test_image_tokens.py
|
|
│ ├── test_logging_securityfilter.py
|
|
│ ├── test_payment_helpers.py
|
|
│ ├── test_settings.py
|
|
│ ├── test_wallet.py
|
|
│ └── ... more unit tests
|
|
└── run_integration.py
|
|
```
|
|
|
|
## Running Tests
|
|
|
|
### Make Targets
|
|
|
|
```bash
|
|
# Run all tests (unit + integration with mocks)
|
|
make test
|
|
|
|
# Unit tests only
|
|
make test-unit
|
|
|
|
# Integration tests with mocks (fast)
|
|
make test-integration
|
|
|
|
# Integration tests with Docker services
|
|
make test-integration-docker
|
|
|
|
# Fast tests only (skip slow and Docker tests)
|
|
make test-fast
|
|
|
|
# Performance tests
|
|
make test-performance
|
|
|
|
# Coverage
|
|
make test-coverage
|
|
```
|
|
|
|
### Direct pytest Commands
|
|
|
|
```bash
|
|
# Run all tests
|
|
pytest
|
|
|
|
# Run a specific test file
|
|
pytest tests/unit/test_wallet.py -v
|
|
|
|
# Run a specific test
|
|
pytest tests/unit/test_wallet.py::test_get_balance -v
|
|
|
|
# Run tests matching a pattern
|
|
pytest -k "wallet" -v
|
|
```
|
|
|
|
## Test Modes (Integration)
|
|
|
|
Integration tests support two execution modes:
|
|
|
|
- Mock mode (default): uses in-memory mocks, no Docker required
|
|
- Docker mode: uses real Docker services (Cashu mint, mock OpenAI, Nostr relay)
|
|
|
|
Use the runner script for Docker mode:
|
|
|
|
```bash
|
|
./tests/run_integration.py
|
|
```
|
|
|
|
Or manually:
|
|
|
|
```bash
|
|
docker-compose -f compose.testing.yml up -d
|
|
USE_LOCAL_SERVICES=1 pytest tests/integration/ -v
|
|
docker-compose -f compose.testing.yml down -v
|
|
```
|
|
|
|
## Test Markers
|
|
|
|
Markers are defined in `pyproject.toml`:
|
|
|
|
- `integration`
|
|
- `unit`
|
|
- `slow`
|
|
- `requires_docker`
|
|
- `requires_real_mint`
|
|
- `performance`
|
|
- `asyncio`
|
|
|
|
Examples:
|
|
|
|
```bash
|
|
# Skip slow tests
|
|
pytest -m "not slow" -v
|
|
|
|
# Run only integration tests
|
|
pytest -m "integration" -v
|
|
|
|
# Run performance tests
|
|
pytest -m "performance" -v
|
|
```
|
|
|
|
## Fixtures and Utilities
|
|
|
|
### Core Integration Fixtures
|
|
|
|
Defined in `tests/integration/conftest.py`:
|
|
|
|
- `integration_client` - Async HTTP client for the FastAPI app
|
|
- `authenticated_client` - Client with a pre-created API key
|
|
- `testmint_wallet` - Test wallet for generating Cashu tokens
|
|
- `db_snapshot` - Database state snapshot/diff helper
|
|
- `create_api_key` - Helper to create API keys for tests
|
|
- `integration_engine`, `integration_session` - Async DB engine/session
|
|
- `background_tasks_controller` - Control background tasks in tests
|
|
- `mock_upstream_server` - Mock upstream API responses
|
|
|
|
### Integration Utilities
|
|
|
|
Defined in `tests/integration/utils.py`:
|
|
|
|
- `CashuTokenGenerator`
|
|
- `ResponseValidator`
|
|
- `PerformanceValidator`
|
|
- `ConcurrencyTester`
|
|
- `DatabaseStateValidator`
|
|
- `MockServiceBuilder`
|
|
- `TestDataBuilder`
|
|
|
|
## Writing Tests
|
|
|
|
### Unit Test Example
|
|
|
|
```python
|
|
from routstr.algorithm import calculate_model_cost_score
|
|
from routstr.payment.models import Architecture, Model, Pricing
|
|
|
|
|
|
def test_calculate_model_cost_score_basic() -> None:
|
|
model = Model(
|
|
id="test-model",
|
|
name="Test test-model",
|
|
created=1234567890,
|
|
description="Test model",
|
|
context_length=8192,
|
|
architecture=Architecture(
|
|
modality="text",
|
|
input_modalities=["text"],
|
|
output_modalities=["text"],
|
|
tokenizer="gpt",
|
|
instruct_type=None,
|
|
),
|
|
pricing=Pricing(
|
|
prompt=0.001,
|
|
completion=0.002,
|
|
request=0.0,
|
|
image=0.0,
|
|
web_search=0.0,
|
|
internal_reasoning=0.0,
|
|
),
|
|
)
|
|
assert calculate_model_cost_score(model) == 0.002
|
|
```
|
|
|
|
### Integration Test Example
|
|
|
|
```python
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.asyncio
|
|
async def test_wallet_topup(
|
|
authenticated_client: AsyncClient,
|
|
testmint_wallet: object,
|
|
db_snapshot: object,
|
|
) -> None:
|
|
await db_snapshot.capture()
|
|
token = await testmint_wallet.mint_tokens(1000)
|
|
response = await authenticated_client.post(
|
|
"/v1/wallet/topup", params={"cashu_token": token}
|
|
)
|
|
assert response.status_code == 200
|
|
diff = await db_snapshot.diff()
|
|
assert len(diff["api_keys"]["modified"]) == 1
|
|
```
|
|
|
|
## Debugging Tips
|
|
|
|
```bash
|
|
# Show print output
|
|
pytest -s tests/unit/test_wallet.py
|
|
|
|
# Drop into debugger on failure
|
|
pytest --pdb
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
- Docker mode failures: check `docker ps` and `docker-compose -f compose.testing.yml logs`
|
|
- Connection errors: make sure ports 3338, 3000, 8000, and 8088 are free
|
|
- Slow tests: use `pytest -m "not slow"` or `make test-fast`
|
|
|
|
## Next Steps
|
|
|
|
- See [Architecture](architecture.md)
|
|
- Read [Setup Guide](setup.md)
|