Commit 4bb2bd9
Migration upgrade-path subprocess tests (roadmap item ②)
The in-process tests in db_test.go build a fresh DB straight to v9 via
OpenMemory. They cannot exercise the real user upgrade path: a DB built
at an old schema version, opened by the current binary, migrated
incrementally. This commit closes that gap.
Five tests in internal/store/migration_e2e_test.go, each booting a real
`continuity serve` subprocess against a programmatically-built old DB:
TestMigrationE2E_UpgradeFromV5_PreservesData
Covers the longest upgrade chain (v5 → v6 → v7 → v8 → v9). v5 is
pre-moments, pre-tone, pre-retraction; this test touches BOTH
full-table rebuilds (v6 + v9). Seeds one row per v5-valid category
with distinguishable values, then verifies each is reachable via
/api/memories after the binary boots and migrates.
TestMigrationE2E_UpgradeFromV7_PreservesToneAndMoments
The most likely real-world upgrade today: a DB built before
retraction (PR #20). Pins that the v7 tone column and a v6 moments
row both survive the v8 ALTER and v9 rebuild.
TestMigrationE2E_UpgradeFromV8_PreservesTombstones
The load-bearing test. v9's INSERT SELECT * relies on column-order
parity between source (v8 mem_nodes: 16 + 3 retraction columns
appended via ALTER) and destination (v9 mem_nodes_new: same 19
columns declared in the same order). If a future migration moves
or inserts columns and SELECT * silently misaligns, this catches
it: we seed a tombstoned row with distinct values per retraction
column and verify each survives the rebuild byte-identical.
Sanity-checked during development by deliberately corrupting the
expected tombstone_reason; the assertion fired with the actual
surviving value visible in the failure message.
TestMigrationE2E_FreshInstallReachesV9
Cold-start path: no pre-existing DB, the binary creates one and
migrates straight to v9. Covers the new-user install case.
TestMigrationE2E_IdempotentSecondBoot
Boots twice against the same DB. Pins the through-binary
idempotency invariant — in-process db_test.go covers migrate()
in isolation; this covers the same invariant through engine init,
embedder probe, server listen. Includes a marker row that
survives the second boot, so a destructive re-migration would be
visible.
Helpers:
- buildDBAtVersion(t, dir, target) — programmatically applies
migrations [1..target] to a fresh DB. Reuses the production
migrations slice (this file is in package store) so the helper
cannot drift from production behavior. Drift would silently
invalidate every test in the file.
- seedV5Data / seedV6Moment / seedV7Tone / seedV8Tombstone —
realistic per-version inserts. Each row has distinguishable
column values so a column-misalignment bug surfaces as garbled
data, not just a missing column.
- startSubprocessAgainstDB / fetchMemoryByURI / assertSchemaV9 /
envGet — shared scaffold so per-test bodies stay on the contract.
Reuses internal/testharness (BuildContinuityBinary, HermeticEnv,
StartServeProcess, WaitForReady). CI inherits the existing e2e job
that runs `-tags noembed -run 'E2E|Subprocess'`; the migration tests
match the filter without further config.
Runtime: ~4s for all five tests (~700-900ms each — dominated by the
binary build, amortizable via TestMain if needed later).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 9883cdb commit 4bb2bd9
1 file changed
Lines changed: 577 additions & 0 deletions
0 commit comments