Update test_inventory.md to reflect PC1 checkpoint reality #40
@@ -7,72 +7,81 @@ to know what "run the tests" actually checked.
|
||||
|
||||
Run everything below in one shot with `scripts/run_checkpoint_tests.py`.
|
||||
|
||||
Last verified against `main`: 2026-08-19 (commit `1c75367`).
|
||||
Last verified against `main`: 2026-08-20 (commit `927f9bd`) — full PC1
|
||||
checkpoint run, fresh clone, migrations + pytest + all 4 Godot smoke tests +
|
||||
both platform exports, all clean.
|
||||
|
||||
## Backend — `backend/tests/` (pytest)
|
||||
|
||||
Run: `cd backend && python -m pytest -v` (needs `DATABASE_URL` pointed at a
|
||||
reachable Postgres — see the runner script; most of these tests don't
|
||||
actually touch the DB, but the app's import chain requires a valid URL to
|
||||
construct).
|
||||
reachable Postgres — see the runner script).
|
||||
|
||||
**Current total: 38 tests, all passing on a clean `main` checkout.**
|
||||
**Current total: 68 tests, all passing on a clean `main` checkout.**
|
||||
|
||||
| File | Tests | What it covers |
|
||||
|---|---|---|
|
||||
| `test_auth_age_gate.py` | 10 | `calculate_age()` date-math correctness (exact boundary, leap years, birthday-not-yet-this-year) + `RegisterRequest` date-of-birth validation (parametrized valid/invalid date rejection). Backs the 18+ registration gate (PR #23). |
|
||||
| `test_auth_age_gate.py` | 17 | `calculate_age()` date-math correctness (exact boundary, leap years, birthday-not-yet-this-year) + `RegisterRequest` date-of-birth validation. Backs the 18+ registration gate (PR #23). |
|
||||
| `test_gltf_metadata.py` | 21 | glTF/GLB binary + JSON parsing: magic-byte detection, chunk-padding handling, mesh/animation/texture-reference metadata extraction, malformed-input rejection. Backs the asset-import pipeline (PR #27). |
|
||||
| `test_auth_endpoints.py` | 11 | Real integration tests against the FastAPI app via `TestClient`: register, login, duplicate username/email, wrong password, JWT shape. Hits a real Postgres, not mocked (PR #35). |
|
||||
| `test_refresh_endpoint.py` | 8 | `POST /auth/refresh` end-to-end: valid token exchange, distinct access tokens per call (jti-based), invalid/missing token rejection, login-issued tokens also work (PR #37). |
|
||||
| `test_refresh_token_jti.py` | 6 | Refresh-token `jti` uniqueness and the `refresh_tokens.token` column length/type (PR #33's RS256 upgrade). |
|
||||
| `test_auth_expired_token.py` | 5 | Expired-token rejection on two distinct paths: an access JWT with a past `exp` claim, and a refresh token whose persisted `expires_at` is in the past (PR #38). |
|
||||
|
||||
**What these are, honestly:** pure unit tests of standalone functions
|
||||
(`calculate_age`, the glTF parser, Pydantic validators). None of them spin
|
||||
up the FastAPI app or hit a real endpoint — they run in ~1s and don't
|
||||
actually need Postgres reachable at all (the import chain just needs a
|
||||
syntactically valid `DATABASE_URL`, nothing connects during collection).
|
||||
**What changed since the last inventory (2026-08-19):** that version said
|
||||
"no integration/endpoint tests at all" — that gap is closed.
|
||||
`test_auth_endpoints.py`, `test_refresh_endpoint.py`,
|
||||
`test_refresh_token_jti.py`, and `test_auth_expired_token.py` all hit the
|
||||
real FastAPI app against a real Postgres, not mocks. The suite is also
|
||||
re-runnable without manual cleanup now — `backend/tests/conftest.py` has a
|
||||
session-scoped autouse fixture that truncates all app tables once before
|
||||
the suite runs.
|
||||
|
||||
**Known coverage gaps** (real gaps, not placeholders — nothing enforces filling
|
||||
these yet):
|
||||
- No integration/endpoint tests at all — `/register`, `/login`, `/refresh`,
|
||||
`/worlds`, `/assets/*` have zero tests that actually call them through
|
||||
the FastAPI app (e.g. via `httpx.AsyncClient` + `ASGITransport`) against a
|
||||
real (or test) database. Everything currently shipped works because it
|
||||
was manually verified at merge time (checkpoint review), not because a
|
||||
test asserts it.
|
||||
- No tests for the RS256 auth upgrade (key generation, refresh-token
|
||||
issuance/persistence) — PR #30, pending review as of this writing,
|
||||
manually verified (correct key usage, all 38 existing tests still pass)
|
||||
but not covered by an automated test of its own yet.
|
||||
- No tests for the moderation schema/migration (in progress as of this
|
||||
writing) beyond "the migration runs."
|
||||
**Known coverage gaps** (real gaps, not placeholders):
|
||||
- `/worlds` (POST) and `/assets/*` have no endpoint tests yet — `GET /worlds`
|
||||
is covered indirectly via the Godot smoke tests below, but there's no
|
||||
pytest coverage for either.
|
||||
- No tests for the moderation schema/migration — it exists
|
||||
(`0003_add_moderation_tables_and_user_roles`) and the migration itself
|
||||
runs clean, but nothing in `backend/tests/` exercises the models or any
|
||||
moderation endpoint (there isn't one yet).
|
||||
|
||||
## Godot client — `scripts/smoke_test_*.gd`
|
||||
|
||||
**Nothing merged into `main` yet as of this writing** — `sandbox_probe/test_script.gd`
|
||||
is the only Godot script on `main` right now, and it's **not a real
|
||||
test** (a leftover manual probe, returns a hardcoded string, asserts
|
||||
nothing). Don't count it toward coverage; delete or repurpose it if anyone
|
||||
actually needs a sandbox probe again.
|
||||
**4 real smoke tests merged on `main`.** Each needs a live backend —
|
||||
`AGP_API_BASE_URL` env var, falling back to the
|
||||
`application/agp/api_base_url` project setting (default
|
||||
`http://127.0.0.1:8000`) if unset.
|
||||
|
||||
`scripts/smoke_test_api.gd` (PC1, PR #29, pending review as of this writing)
|
||||
will be the first real one once merged — `ApiClient` autoload's
|
||||
`health_check()` against a **live backend** (set `AGP_API_BASE_URL` to point
|
||||
at one), verified by hand end-to-end before opening the PR: exercises the
|
||||
real HTTP request path (`HTTPRequest` node lifecycle, JSON parse, the
|
||||
result-dictionary contract), not just that the script compiles. Exits 1 on
|
||||
failure, so it's CI/script-friendly.
|
||||
Run: `godot --headless --path . --import` once (builds the class cache —
|
||||
skip this and every `class_name`-declared class falsely errors as
|
||||
undeclared), then for each file below: `godot --headless --path . --script
|
||||
res://scripts/<name>.gd` — **no `--quit`**, it kills these before their
|
||||
awaited HTTP calls finish.
|
||||
|
||||
Run (once merged): `godot --headless --path . --import` once (builds the
|
||||
class cache — skip this and every `class_name`-declared class falsely
|
||||
errors as undeclared), then for each `scripts/smoke_test_*.gd`:
|
||||
`godot --headless --path . --script res://scripts/<name>.gd`
|
||||
| File | What it covers |
|
||||
|---|---|
|
||||
| `smoke_test_api.gd` | `ApiClient.health_check()` against a live backend — the HTTP request path itself (`HTTPRequest` node lifecycle, JSON parse, result-dictionary contract). |
|
||||
| `smoke_test_auth.gd` | 6 real scenarios end-to-end: register, duplicate username, under-18 rejection, correct login, wrong password, non-existent user. |
|
||||
| `smoke_test_e2e.gd` | Full loop: health check → register → login → fetch worlds list, 4/4 steps. |
|
||||
| `smoke_test_world_list.gd` | Instantiates the real `world_list.tscn` scene (not just the API layer) — registers a user, adds the scene to the tree, confirms it reaches a real end state (cards, empty-list, or error) and actually renders world cards when data exists. |
|
||||
|
||||
**Known gap once it lands:** only `health_check()` is exercised end-to-end.
|
||||
`login`, `register`, `get_worlds`, `get_me` are implemented (see
|
||||
`scripts/api_client.gd`) but have no smoke coverage yet — each would need a
|
||||
real user/world fixture in the target backend to test against meaningfully.
|
||||
**Known gap:** `get_me()` (`GET /auth/me`) is implemented in
|
||||
`scripts/api_client.gd` but has no smoke coverage yet.
|
||||
|
||||
## Client export
|
||||
|
||||
`scripts/build.sh` produces real Linux (`agp-game.x86_64`) and Windows
|
||||
(`agp-game.exe`) binaries via `--export-release`. Verified 2026-08-20: both
|
||||
exports complete clean from a fresh checkout and produce valid binaries
|
||||
(confirmed via `file` — real ELF64/PE32+, not empty or truncated). Neither
|
||||
export is exercised by an automated GUI test (headless Godot can't drive a
|
||||
window) — actually launching and clicking through the exported binary is a
|
||||
manual step, see the checkpoint playtest instructions.
|
||||
|
||||
## What "full coverage" should eventually mean here
|
||||
|
||||
Not defined precisely yet — the honest target as of 2026-08-19 is just
|
||||
"more than pure-function unit tests." As real integration/endpoint tests get
|
||||
added, update the tables above rather than letting this doc drift stale;
|
||||
a wrong inventory is worse than no inventory.
|
||||
Not defined precisely yet — the honest target is "close the /worlds POST
|
||||
and /assets/* gaps next, and add get_me() smoke coverage" rather than a
|
||||
number. As real integration/endpoint tests get added, update the tables
|
||||
above rather than letting this doc drift stale; a wrong inventory is worse
|
||||
than no inventory.
|
||||
|
||||
Reference in New Issue
Block a user