Skip to content

Testing Guide

OsuRender API includes a comprehensive test suite covering unit tests, integration tests, and chaos engineering scenarios.

Running Tests

bash
# Run all tests (with danser mocked)
MOCK_DANSER=1 pytest -W default

# Run with verbose output
MOCK_DANSER=1 pytest -v

# Run with coverage
MOCK_DANSER=1 pytest --cov=src --cov-report=term-missing

# Run a specific test file
MOCK_DANSER=1 pytest tests/test_render.py -v

# Run a specific test
MOCK_DANSER=1 pytest tests/test_chaos.py::test_a5_outbox_claim_race -v

Test Suite Overview

FileTestsCategoryDescription
test_health.py1UnitHealth endpoint returns healthy
test_render.py3IntegrationRender submission, validation, rejection
test_skins.py3IntegrationSkin listing, upload, validation
test_storage.py4UnitStorage client operations
test_legacy.py4IntegrationLegacy endpoint compatibility
test_chaos.py10ChaosArchitecture reliability guarantees

Chaos Engineering Tests

The chaos test suite (test_chaos.py) proves critical reliability properties:

Phase 1 — Outbox Reliability

TestIDGuarantee
Lost Notification RecoveryA1LISTEN/NOTIFY not required for correctness; safety poll recovers
Dispatcher Crash RecoveryA2No job loss after mid-drain SIGKILL; 500 events all reach terminal state
Notification StormA31000 events batched into < 50 drain calls
Stuck Processing SweeperA45-minute-old PROCESSING events reset to PENDING
Outbox Claim RaceA5FOR UPDATE SKIP LOCKED prevents duplicate claims across 3 concurrent dispatchers

Phase 2 — Operational Hardening

TestIDGuarantee
Duplicate Worker ExecutionB1Atomic UPDATE WHERE status=QUEUED prevents double-processing
Redis Failure RecoveryC1Dispatch failure increments retry and reverts to PENDING
Retry ExhaustionC3Events marked FAILED after 3 retries (not retried forever)
Queue Circuit BreakerD1MAX_QUEUED enforced — API returns 503 when full
Advisory Lock RaceE150 concurrent submissions from same IP yield ≤ 2 successes

Prerequisites for Chaos Tests

The chaos tests require a running infrastructure stack:

bash
docker-compose up -d postgres redis

Some tests (A2, A5) interact directly with PostgreSQL via asyncpg.

Writing New Tests

python
import pytest
from httpx import AsyncClient, ASGITransport
from src.api.app import create_app

@pytest.fixture
async def client():
    app = create_app()
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        yield c

@pytest.mark.asyncio
async def test_my_endpoint(client):
    response = await client.get("/health")
    assert response.status_code == 200
    assert response.json()["status"] == "healthy"

Built with VitePress