feat(2): ghost P4 data-integrity overlay (MySQL ci_marker) + §4.3 create-post round-trip
- ops.py + test_{upgrade,backup,restore}.py: seed ci_marker into the MySQL `ghost` DB (db service)
via the mysql CLI; rides the recipe's mysqldump --tab backup. recipe is MySQL not sqlite (stale
comment fixed). Expect restore RED -> recipe-PR (no backupbot.restore hook; immich/mattermost class).
- functional/_ghost.py: cookie-aware Ghost Admin API client (stdlib http.cookiejar; Origin CSRF hdr).
- functional/test_post_roundtrip.py: §4.3 create published post + read back (unique marker, non-vacuous);
closes the DEFERRED ghost create-post item.
- PARITY.md + recipe_meta.py updated. Authored node-free; full-lifecycle run next, NOT yet claimed.
This commit is contained in:
@ -16,22 +16,35 @@ and a JSON Content/Admin API at `/ghost/api/*`. Defining behaviors exercised:
|
||||
|
||||
Two specific tests + parity health_check = ≥2 floor met.
|
||||
|
||||
## Plan §4.3 prescribed deeper test (deferred to Q4 follow-up)
|
||||
## Plan §4.3 prescribed deeper test — AUTHORED (closes DEFERRED ghost create-post)
|
||||
|
||||
§4.3 named "create-a-post round-trip" for ghost. That requires:
|
||||
1. Setup the Ghost owner (POST `/ghost/api/v3/admin/authentication/setup/`) with a per-run
|
||||
admin email+password.
|
||||
2. Login → JWT bearer token.
|
||||
3. POST `/ghost/api/v3/admin/posts/` to create a post.
|
||||
4. GET `/ghost/api/v3/admin/posts/<id>/` to read it back.
|
||||
§4.3 named "create-a-post round-trip" for ghost. Implemented in
|
||||
`tests/ghost/functional/test_post_roundtrip.py` (helper `functional/_ghost.py`):
|
||||
1. Wait for the Admin API healthcheck (`GET /ghost/api/admin/site/` → 200).
|
||||
2. Setup the Ghost owner (POST `/ghost/api/admin/authentication/setup/`, fresh deploy) + establish
|
||||
an admin **session cookie** (POST `/ghost/api/admin/session/`) — cookie-aware stdlib opener,
|
||||
version-negotiated (no `/v3/` in the path; recipe-versioned).
|
||||
3. POST `/ghost/api/admin/posts/?source=html` to create a published post with a unique marker in
|
||||
title + body.
|
||||
4. GET `/ghost/api/admin/posts/<id>/?formats=html` to read it back; assert title + body marker
|
||||
round-trip intact (unique-per-run → non-vacuous).
|
||||
|
||||
Doable; adds a per-run setup secret + token-management. Tracked for Q4 follow-up.
|
||||
Admin creds are class-B run-scoped (destroyed at teardown with the app).
|
||||
|
||||
## Backup data-integrity (P4)
|
||||
## Backup data-integrity (P4) — AUTHORED
|
||||
|
||||
Lifecycle overlays not authored. The base recipe stores state in SQLite + a content volume;
|
||||
backup-capable is auto-detected from compose. Q5 catch-up if backup data-integrity proves
|
||||
needed for this recipe.
|
||||
`ops.py` + `test_install`-free lifecycle overlays (`test_upgrade.py` / `test_backup.py` /
|
||||
`test_restore.py`) seed a deterministic `ci_marker` row into the **MySQL** `ghost` DB (the recipe's
|
||||
real state store) via the `mysql` CLI in the `db` service. The recipe's backupbot pre-hook
|
||||
(`mysqldump ghost --tab`) dumps that table into the backed-up path, so the marker rides
|
||||
backup→restore the way a real post's row would. pre_restore drops the table (divergence); the
|
||||
restore overlay asserts it returned.
|
||||
|
||||
**Expected RED until a recipe-PR lands:** the ghost recipe has a logical mysqldump backup but **no
|
||||
`backupbot.restore.*` hook** (and the mysql data volume itself isn't backupbot-labelled), so a
|
||||
file-level restore never reimports the dump — same defect class fixed in immich#1 / mattermost-lts#1.
|
||||
If `test_restore_returns_state` goes RED, the durable fix is a recipe-PR adding a mysqldump-reimport
|
||||
restore post-hook. (See `test_restore.py` docstring + DECISIONS.md.)
|
||||
|
||||
## Playwright (P6)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user