Merge pull request 'Update test_inventory.md to reflect PC1 checkpoint reality' (#40) from agent/398bf1a22a2d into main
This commit was merged in pull request #40.
This commit is contained in:
@@ -7,72 +7,88 @@ 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 (parametrized valid/invalid date rejection). 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 | **Integration tests** for `POST /api/auth/register` and `POST /api/auth/login` against the real FastAPI app + real Postgres. Covers: successful register (201), duplicate username (409), duplicate email (409), underage rejection (400), invalid date format (422), exact-18 registration, successful login with correct credentials (200), wrong password (401), nonexistent user (401), form-encoded login (OAuth2), and JWT validity of returned tokens. |
|
||||
| `test_refresh_endpoint.py` | 8 | **Integration tests** for `POST /api/auth/refresh`. Covers: successful refresh (200, new access token, same refresh token returned), refresh produces different access tokens on repeated calls, invalid refresh token (401), empty body (422), missing field (422), refresh token from login also works, returned access token is valid JWT decodable with public key, `access_token_expires_minutes` in response. |
|
||||
| `test_refresh_token_jti.py` | 6 | Unit tests for refresh token uniqueness (jti claim) and model column length. Covers: two calls with same sub produce different tokens (jti uniqueness), jti is valid UUID, rapid repeated calls all produce unique jtis, jti survives decode, `RefreshToken.token` column is `String(512)`, column type is `String`. |
|
||||
| `test_auth_expired_token.py` | 5 | **Integration tests** for expired-token rejection across auth endpoints. Covers: expired access JWT rejected by `GET /api/auth/me` (401), garbage access token rejected by `/me` (401), missing bearer token returns 401, expired refresh token (DB `expires_at` in past) rejected by `/refresh` (401), expired refresh JWT (past `exp` claim) rejected before DB lookup (401). |
|
||||
|
||||
**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 these are, honestly:** a mix of pure unit tests (`test_auth_age_gate.py`,
|
||||
`test_gltf_metadata.py`, `test_refresh_token_jti.py`) and real integration tests
|
||||
(`test_auth_endpoints.py`, `test_refresh_endpoint.py`, `test_auth_expired_token.py`)
|
||||
that hit the FastAPI app against a real Postgres database via `TestClient`.
|
||||
The integration tests exercise the full stack: Pydantic validation → DB →
|
||||
JWT → response. The suite is also re-runnable without manual cleanup —
|
||||
`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."
|
||||
- No endpoint tests for `GET /api/worlds`, `GET /api/assets/*`, or any
|
||||
world/asset CRUD routes — only auth endpoints have integration coverage
|
||||
(`GET /api/worlds` is covered indirectly via the Godot smoke tests below).
|
||||
- No tests for the moderation schema/migration beyond "the migration runs."
|
||||
- No tests for the `GET /api/auth/me` endpoint's response body (only its
|
||||
auth-header validation is covered via expired-token tests).
|
||||
- No tests for session management (create/validate/revoke sessions).
|
||||
|
||||
## 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 smoke tests merged into `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.
|
||||
| File | What it covers |
|
||||
|---|---|
|
||||
| `smoke_test_api.gd` | Exercises `ApiClient.health_check()` against a live backend. Verifies the real HTTP request path (`HTTPRequest` node lifecycle, JSON parse, result-dictionary contract). Exits 1 on failure. |
|
||||
| `smoke_test_auth.gd` | Tests the full auth flow via `ApiClient` autoload: register unique user (201), duplicate username (409), under-18 registration (400), correct login (200), wrong password (401), nonexistent user (401). |
|
||||
| `smoke_test_e2e.gd` | End-to-end flow: health check → register → login → worlds list. Verifies the full request chain with a fresh user, including token storage and `get_worlds()` with auth header. |
|
||||
| `smoke_test_world_list.gd` | Instantiates `world_list.tscn` as a real scene, adds to tree (catches `@onready` node-path bugs), waits for `_refresh_worlds()` to complete, confirms the screen reaches a real end state (world cards, empty-list message, or error label — not stuck loading). |
|
||||
|
||||
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`
|
||||
Run (once, to build the class cache): `godot --headless --path . --import`,
|
||||
then for each smoke test: `godot --headless --path . --script
|
||||
res://scripts/smoke_test_<name>.gd` — **no `--quit`**, it kills these before
|
||||
their awaited HTTP calls finish.
|
||||
|
||||
**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 gaps:**
|
||||
- No smoke tests for the main menu scene (`main_menu.tscn`).
|
||||
- No smoke tests for chunk loading/streaming (`chunk.gd`, `chunk_scene.gd`).
|
||||
- No smoke tests for dynamic/static object nodes.
|
||||
- All smoke tests require a live backend; no offline/unit smoke tests exist.
|
||||
- `smoke_test_world_list.gd` is the only one that exercises a real `.tscn`
|
||||
scene instantiation — others only test the `ApiClient` autoload.
|
||||
- `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 `docs/checkpoints/PC1.md` for 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 as of 2026-08-20 is
|
||||
"integration tests for every endpoint + smoke tests for every major scene."
|
||||
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