97 lines
5.5 KiB
Markdown
97 lines
5.5 KiB
Markdown
# 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 Core and
|
|
module migration discovery, identity schema drift detection, 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. Identity unit tests cover branded opaque-ID contracts, principal shapes,
|
|
configuration validation (secret, base URL, and trusted-origin rules), the Core identity runtime
|
|
(explicit construction, exact schema mapping, only email/password and rate limiting enabled,
|
|
sanitized failures, and that a database outage during principal resolution is never silently
|
|
reported as anonymous), and Core migration discovery (deterministic ordering, the reserved `core`
|
|
identity, and collision rejection) — all without a live database. `apps/api`'s own unit tests cover
|
|
its pure Hono app factory (route shapes, CORS allow/deny/preflight, deterministic 404 and sanitized
|
|
error responses), its runtime configuration, and that importing any of its modules — including the
|
|
executable server module without calling its exported `main` — never reads the environment,
|
|
connects to PostgreSQL, or starts a server.
|
|
|
|
`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 first builds the workspace through the repository's Turbo build graph, then 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 removes the
|
|
container, network, and volume. A build failure occurs before Docker provisioning. 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.
|
|
|
|
A dedicated set of scenarios exercises the committed Core identity migration against real
|
|
PostgreSQL: read-only planning on a fresh database, applying it and confirming exactly the four
|
|
expected `ekklesia_core_*` tables and their indexes exist, a genuine no-op on a second apply, Core
|
|
executing before a fixture module migration in one batch, previously applied module-only history
|
|
staying byte-for-byte unchanged once Core is introduced, and a later module migration's failure
|
|
rolling back cleanly without damaging the already-committed Core identity migration or leaking the
|
|
advisory lock.
|
|
|
|
A second dedicated suite (`apps/api/tests/api-http.integration.ts`, included in the same
|
|
`pnpm test:migrations:integration` run) starts the real `apps/api` HTTP server against a freshly
|
|
migrated disposable database and exercises it with real HTTP requests: public sign-up (with no
|
|
automatic session, per `autoSignIn: false`), explicit sign-in producing a host-only
|
|
`HttpOnly`/`SameSite=Lax`/secure session cookie, `/api/v1/principal` for both the authenticated and
|
|
anonymous shapes, sign-out actually invalidating the session, a malformed or missing cookie
|
|
resolving as anonymous, duplicate sign-up creating no second identity row, two distinct accounts
|
|
producing identical principal shapes with no elevation and no owner/role/permission data at the
|
|
database level, no plaintext password ever stored, CORS never returning an allow-origin header for
|
|
an untrusted origin, Better Auth's handler being unreachable outside `/api/auth/*`, a database
|
|
outage during principal resolution producing a sanitized `503` rather than a false anonymous `200`,
|
|
starting the API against an unmigrated database creating no tables at all, and a clean listener/pool
|
|
shutdown. See [ADR 0011](../architecture/decisions/0011-identity-http-transport-and-public-enrollment.md)
|
|
for one CSRF/origin guarantee that was verified manually against the real server but could not be
|
|
reproduced reliably inside this test runner, and is documented rather than silently asserted.
|
|
|
|
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.
|