# Tests The first automated tests for JQC. Kept deliberately small and targeted at the places where a bug is **catastrophic and non-obvious** — the money path (Stripe webhooks), the SLA state machine, and the multi-tenant routing invariant. ## Running ```bash pip install -r requirements-dev.txt pytest ``` No MySQL, Redis, or Stripe account is required. `tests/conftest.py` sets throwaway `SECRET_KEY` / `DATABASE_URL` (in-memory SQLite) at import time so the `app` package imports cleanly, and every test either exercises pure functions or uses the in-memory engine. ## What's covered | File | Scope | Infra needed | |---|---|---| | `test_sla.py` | SLA thresholds + `ok`/`at_risk`/`breached`/`None` boundaries | none | | `test_billing_webhooks.py` | `_ts_to_dt`, status normalization, `handle_event` dispatch + error-swallowing | none | | `test_tenant_routing.py` | Routing is inert with no tenant; resolved `g.tenant_engine` wins | in-memory SQLite | ## Not yet covered (needs a live control DB + ≥2 tenant DBs) These are the highest-value **integration** tests to add next. They require a throwaway MySQL control DB plus two provisioned tenant DBs, so they live outside this fast unit suite for now: 1. **Cross-tenant isolation** — resolve tenant A, write a row, resolve tenant B, assert the row is invisible. Proves `RoutingSession` never leaks across tenants. This is the single most important test the project can have. 2. **Webhook handlers end-to-end** — `_on_payment_failed` sets `past_due_since` and `subscription_status='past_due'`; `_on_payment_succeeded` clears the dunning columns. Assert against a real `Tenant` row. 3. **`bootstrap_tenant` vs `upgrade_tenant`** — a freshly bootstrapped tenant DB ends stamped at chain head with the full schema (the logic `scripts/scratch_bootstrap_test.py` proves manually today). 4. **Billing gate state machine** — trial-expired redirects to `/billing/subscribe`; `cancelled` redirects to `/billing/suspended`.