# MNW Server Tests ## Prerequisites - PostgreSQL running locally (default: `postgres://localhost/postgres`) - Set `TEST_DATABASE_URL` if using a non-default admin connection ## Test Types ### Unit Tests (`cargo test --lib`) Pure logic: pricing, validation, formatting, enums, error handling, CSRF, RSS, file scanning, import parsing. No database required. ### Integration Tests (`cargo test --test integration`) Workflow modules under `tests/workflows/`. Each test gets an isolated PostgreSQL database cloned from a shared template (migrations applied once, then reused across runs while migration-current). Run with `--test-threads=8`; full parallelism overwhelms PostgreSQL. **Harness features:** - In-process Axum app (no network, uses `tower::ServiceExt::oneshot`) - Cookie-aware HTTP client with automatic CSRF token management - Mock Stripe (`MockPaymentProvider`), captures checkout sessions, supports webhook signing - Mock email (`MockEmailTransport`), captures all sent emails for assertion - Mock S3 (`InMemoryStorage`), in-memory file storage - Direct SQL helpers for test setup (`grant_creator`, `grant_tier`, `connect_stripe`, etc.) **Harness constructors:** - `TestHarness::new()`: DB only (fastest, for auth/CRUD tests) - `with_storage()`: adds in-memory S3 - `with_mocks()`: mock Stripe + email (for payment flow tests) - `with_stripe()`: real Stripe SDK with test keys - `with_admin()`: pre-created admin user - `with_storage_and_scanner()`: file scanning pipeline - `with_git_repos(path)`: git repository support - `with_admin_storage_and_scanner()`: admin user + in-memory S3 + scanner - `with_synckit_storage()`: SyncKit in-memory bucket (OTA tests) - `with_creator_tier_checkout()`: mock Stripe + a configured Everything-tier price - `with_postmark()`: Postmark webhook tokens configured Anything not covered by a constructor goes through `TestHarness::build(BuildOptions { .. })` directly; add a documented `BuildOptions` field rather than a constructor per calling test. **Seeding:** `harness/seed.rs` provides `seed_user` and `seed_project` for the `db_*_layer.rs` contract tests, which run against a bare `TestDb` with no router and so cannot use `signup`. Prefer the harness methods (`signup`, `create_creator`, `create_creator_with_item`) anywhere a session or HTTP flow is in play. ### Seal Tests Ratchets over the repo itself, each its own binary. No database. - `assumptions.rs`: the business assumptions TOML parses, validates, and still resolves every marker in the site-docs corpus. - `migration_hygiene.rs`: new migrations use `CONCURRENTLY` / `IF NOT EXISTS` and opt out of the per-migration transaction correctly. - `frontend_globals.rs`: the `window.*` global count only goes down. - `test_hygiene.rs`: test-suite conventions: doc headers, `#[ignore]` reasons, and `HIGH_WATER` counts for loose status assertions, `test_` prefixes, and oversized modules. - `workflows/enum_drift.rs`: every domain enum's variants match its Postgres `CHECK` list (needs a DB; runs inside the integration binary). ### Load Tests (`cargo test --test load -- --ignored --nocapture`) Multi-scenario virtual user simulation. Requires `--ignored` flag. Configurable via env vars: - `LOAD_VUS`: virtual users (default: 20) - `LOAD_DURATION_SECS`: duration (default: 30) - `LOAD_RAMP_SECS`: ramp-up (default: 5) - `LOAD_MIX`: scenario shares, e.g. `anon:25,buyer:15,creator:10,dash:50`. Must sum to 100. - `QUASI_SCREENS`: which screens serve from the description layer (`*` for all). - `LOAD_MT_LATENCY_MS`: how long the stub Multithreaded sleeps before answering (default: 0). - `LOAD_MT_MEMBERSHIPS`: rows the stub answers with (default: 8). - `LOAD_PROBE_MS`: blocking-pool probe interval (default: 50). The report carries two things beyond the endpoint table: - **`Rej`**, 4xx other than 429. Read it first. A rejected request is fast, so a route quietly answering 403 or 404 wins a latency comparison it never ran. - **Blocking-pool dispatch delay.** How long a fresh `spawn_blocking` waits to start, sampled through the run. The description layer's whole runtime cost is that quasi's router is sync, so every described request holds a pool thread; this is whether that pool still has headroom. `RuntimeMetrics` would say it directly but is behind `tokio_unstable`, which this tree does not build with. Read it with the `POST /join/step/account` mean, which is argon2 and the same fact from the other end. For comparing the description layer against Askama, use `scripts/load-conversion-ab.sh` rather than driving `QUASI_SCREENS` by hand: it runs the alternating-pairs protocol (Askama / described / described / Askama) at one fixed mix, so the four runs stay comparable. ### Health Tests (`cargo test --test health`) External HTTP tests against a running server at `http://localhost:3000`. Skips gracefully if server is not running. ## Running ```bash # Unit tests only (fast, no DB) cargo test --lib # Integration tests (requires PostgreSQL) cargo test --test integration # Specific workflow cargo test --test integration sandbox # All tests cargo test ``` ## Fixtures Test media files in `tests/fixtures/`: `.mp3`, `.mp4`, `.flac`, `.webm`, `.ogg`, `.wav`, `.m4a`