test: add PostgreSQL migration integration coverage
CI / verify (pull_request) Successful in 19s
CI / infrastructure-smoke (pull_request) Successful in 21s
CI / migration-smoke (pull_request) Failing after 16s

This commit is contained in:
ekklesia
2026-07-21 09:37:15 -05:00
parent b38f85f438
commit 831a48187c
16 changed files with 1690 additions and 96 deletions
@@ -122,10 +122,14 @@ messages, machine-specific paths, causes, stacks, or partial execution results.
are reported without hiding the primary failure and without copying underlying exception text.
The developer commands read `DATABASE_URL` from the environment. A local uncommitted `.env` may
supply it, but commands never print it. This slice verifies database behavior through a narrow
in-memory database port and unit tests. A real PostgreSQL integration suite for lock contention,
DDL rollback, history creation, and driver behavior is deliberately deferred rather than claimed
by the current verification gate.
supply it, but commands never print it. This decision's implementation slice verified database
behavior through a narrow in-memory database port and unit tests; it deliberately deferred live
PostgreSQL evidence to a follow-up slice rather than claiming it at acceptance time.
Implementation follow-up (2026-07-21): `pnpm test:migrations:integration` now runs the production
adapter and migration services against disposable PostgreSQL for lock contention, DDL rollback,
history creation, approvals, and sanitized driver failures. The Docker-backed command remains
separate from the code-only `pnpm verify` gate.
The transaction and single-client choices follow node-postgres's
[transaction guidance](https://node-postgres.com/features/transactions). The non-blocking lock and
@@ -162,6 +166,6 @@ that invocation's schema or history changes committed. Destructive migrations ar
a trusted approval provider is composed, by design.
The all-or-nothing batch can hold locks for longer than per-migration transactions and excludes
operations PostgreSQL forbids in a transaction. The current unit-tested database port gives fast,
deterministic coverage but cannot prove real server behavior. The next infrastructure-focused
slice must add live PostgreSQL tests before production operation is considered complete.
operations PostgreSQL forbids in a transaction. The narrow database port continues to provide fast,
deterministic unit coverage; the dated implementation follow-up above records the separate live
PostgreSQL evidence added after this decision was accepted.
+3 -2
View File
@@ -69,8 +69,9 @@ validated metadata, explicit destructive-change declarations, and exact SHA-256
now compare that inventory with its fixed PostgreSQL history table, produce a read-only plan, and
apply the complete pending batch under a session advisory lock and one transaction. Destructive
migrations require an exact externally supplied approval bound to module, identity, and checksum.
Hermetic integration coverage now exercises those contracts through the production adapter against
the pinned PostgreSQL container, including real DDL rollback and advisory-lock concurrency.
Target architecture, not yet implemented: production approval-provider composition, live
PostgreSQL migration-runner integration coverage, Better Auth,
Target architecture, not yet implemented: production approval-provider composition, Better Auth,
permission enforcement, physical storage-bucket provisioning, Surface SDK, richer public resource
and action contracts, API server, dashboard, Builder, and reference feature modules.
+18 -6
View File
@@ -24,6 +24,7 @@ pnpm migrations:plan # read-only comparison with PostgreSQL applied history
pnpm migrations:apply # locked, transactional application of the pending batch
pnpm typecheck # strict TypeScript
pnpm test # Vitest
pnpm test:migrations:integration # production runner against disposable PostgreSQL
pnpm build # Turborepo package build graph
pnpm verify # every code-only gate; never plan or apply
```
@@ -63,13 +64,24 @@ The default command composition supplies no destructive approvals. There is no `
or source-controlled approval escape hatch; deployments must later compose a trusted external
provider that supplies an exact module ID, migration identity, and checksum triple.
The migration runner currently has comprehensive unit coverage through its narrow database port.
Live PostgreSQL tests for real DDL rollback, advisory-lock contention, history-table behavior, and
driver cleanup are deliberately deferred and are not part of `pnpm verify` or CI yet.
Migration-runner unit tests cover orchestration through its narrow database port. Run the separate
live suite when changing migration behavior:
CI runs `pnpm ci:verify`, which adds Compose configuration validation to `pnpm verify`. A separate
CI job runs the live infrastructure smoke test so code-only local verification does not require
Docker. The explicit suffix avoids pnpm's built-in `ci` install command.
```bash
pnpm test:migrations:integration
```
It requires Docker with Compose, starts the pinned PostgreSQL image with a generated throwaway
credential and a Docker-assigned loopback port, creates an isolated database for each scenario,
and removes its containers, network, databases, and volume afterward. It exercises the production
adapter and real PostgreSQL transactions, history, advisory locks, approvals, and sanitized errors.
It remains outside the Docker-free `pnpm verify` command.
CI runs `pnpm ci:verify`, which adds Compose configuration validation to `pnpm verify`. Separate
`infrastructure-smoke` and `migration-smoke` jobs run the live service and migration suites. The
exact pull-request context to add to `main` branch protection after merge is
`CI / migration-smoke (pull_request)`. The explicit `ci:verify` suffix avoids pnpm's built-in `ci`
install command.
## Development infrastructure
+60
View File
@@ -0,0 +1,60 @@
# Testing
Ekklesia separates fast code-level evidence from live infrastructure evidence.
## Unit and repository verification
```bash
pnpm test
pnpm verify
```
These commands exercise package tests, repository boundaries, type checking, offline module and
migration discovery, formatting, linting, and builds. Migration-runner unit tests use a narrow
database/session port to prove deterministic planning, approval, transaction orchestration,
cleanup, and sanitized errors. They do not claim to prove PostgreSQL behavior.
`pnpm verify` is intentionally Docker-free. It never plans or applies migrations against a live
database.
## Live PostgreSQL migration evidence
Docker and the Docker Compose plugin are required for the live suite:
```bash
pnpm test:migrations:integration
```
The command starts the repository's pinned PostgreSQL image in a unique Compose project, waits for
bounded health readiness, runs the production PostgreSQL adapter and migration services, and then
removes the container, network, and volume. Each scenario also receives a safely named disposable
database. Direct host runs use a Docker-assigned random port bound only to `127.0.0.1`; a
containerized Gitea job joins the isolated Compose network and uses the PostgreSQL service name.
The live suite proves fresh read-only planning, initial and incremental application, genuine
no-op behavior, exact applied checksums and history, edited or corrupt history rejection,
whole-batch DDL rollback, Drizzle breakpoint execution, real advisory-lock concurrency and
timeouts, lock release after failure, exact destructive approvals, and public-error sanitization.
It does not make migrations automatic during Core startup.
CI runs the same command in the dedicated `migration-smoke` job. After this change is merged, add
the following pull-request status context to `main` branch protection:
```text
CI / migration-smoke (pull_request)
```
## Safe troubleshooting
Confirm the prerequisites without printing configuration:
```bash
docker info
docker compose version
```
Then rerun `pnpm test:migrations:integration`. The harness emits fixed failure messages and does
not dump PostgreSQL logs, SQL, container inspection output, or the generated database URL. Do not
enable query logging, print the test environment, run `docker compose config` without redaction,
or paste Docker inspection output into an issue. If the Docker daemon itself stopped during
cleanup, restore it before rerunning so the harness can create a fresh uniquely named project.
+5 -3
View File
@@ -275,9 +275,11 @@ ID, exact identity, and exact checksum. Module metadata cannot grant approval, a
wildcard, force, or approve-all option. The default developer command supplies no approvals and
therefore refuses destructive pending migrations.
Runner behavior is unit-tested through a narrow database port. Live PostgreSQL coverage of DDL
rollback, advisory-lock contention, and driver behavior is a deferred infrastructure slice; the
current verification suite does not claim that coverage.
Runner behavior is unit-tested through a narrow database port. The separate
`pnpm test:migrations:integration` command now exercises the production adapter against disposable
PostgreSQL, including DDL rollback, advisory-lock contention, history behavior, approvals, and
sanitized failures. It remains outside the Docker-free `pnpm verify` gate; see the
[testing guide](../development/testing.md).
Core completes discovery before importing any server entrypoint. It then loads and verifies every
runtime definition before running hooks, registers all modules dependency-first into an unpublished