# Tests Standalone scripts — no pytest, no fixtures. Each one runs against a throwaway data directory (`VELLICHOR_DATA`, set by the script) and prints one line per check, exiting non-zero on any failure. They cover the account layer, which is the part where a mistake is a privacy bug rather than a bad audiobook. ```bash python3 tests/test_accounts.py # 72 checks python3 tests/test_api.py # 73 checks python3 tests/test_ratelimit.py # 29 checks python3 tests/test_export_guard.py # 9 checks ``` | Script | Covers | | --- | --- | | `test_accounts.py` | the single-user → per-user migration (and that re-running it is a no-op), account CRUD, scrypt password checks, session tokens, per-user isolation of every store, job ownership, account deletion, and passwordless (no-sign-in) mode | | `test_api.py` | the real FastAPI app via `TestClient` with real cookies: anonymous 401/redirect, login, cross-user 404s, admin-only 403s, password change/reset session semantics, account deletion | | `test_ratelimit.py` | login lockout escalation, and resolving the real client IP behind a proxy — including that a spoofed `X-Forwarded-For` can't buy a fresh bucket | | `test_export_guard.py` | the collision guard on the shared Audiobookshelf library | They run **outside the container**, where the TTS/GPU stack isn't installed, so the heavy modules (`tts`, `convert`, `ambience`, `smartcast`, `numpy`, `soundfile`, `extract`) are stubbed. Everything about accounts, sessions and per-user scoping is the real code. `test_export_guard.py` can't import `convert.py` at all without numpy, so it lifts the function under test out of the file with `ast`. Only `test_api.py` needs anything installed: ```bash pip install fastapi httpx python-multipart itsdangerous ``` Because the heavy modules are stubbed by name, a rename there will break these scripts before it breaks the app — adjust the `stub(...)` calls at the top.