Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing

pgevolve's test surface is structured in seven tiers. Each tier catches a different class of bug; together they form the gate for releases.

See ../README.md for the status legend.

Tier matrix

TierWhat it catchesWhere it livesStatusNeeds Docker
1Unit-level invariants — IR equality, parser output for one statement, single function behaviorInline #[cfg(test)] mod tests in every src/ file✅ Implementedno
2Fixture corpora — parsing a real *.sql snippet, comparing IR vs expectedcrates/pgevolve-core/tests/parser_corpus.rs, crates/pgevolve-core/tests/parse_directory.rs✅ Implementedno
3Conformance — fixture-driven regression gate (L1–L9); see belowcrates/pgevolve-conformance/✅ Implementedyes
4Executor + CLI end-to-end — apply a plan against real PG, assert side effects + audit rowscrates/pgevolve/tests/{executor_smoke,cli_e2e,chaos_apply,shadow_validate}.rs✅ Implementedyes
5Property tests — random valid Catalogs exercised across the pipelinecrates/pgevolve-core/tests/property_tests.rs (pure) and crates/pgevolve/tests/pg_property_tests.rs (PG-bound)✅ Implementedpartial
6Mutation tests — flip code, verify a test failsnot implemented🔮 Futuren/a
7Soak — high-case property runs over multiple PG versions, weekly.github/workflows/soak.yml✅ Implementedyes

Tier C (conformance) assertion layers

Tier C is the canonical regression gate. Each fixture drives the full pipeline; assertion layers are evaluated in order. Layers L1–L4 shipped with v0.1; L5–L9 landed in v0.2 readiness.

LayerNameStatusNotes
L1parse✅ ImplementedSource parses cleanly.
L2lint✅ ImplementedNo lint errors.
L3plan✅ ImplementedPlan produces expected steps.
L4apply✅ ImplementedPlan applies cleanly against real PG. Runs in-process via pgevolve::api::build_plan + pgevolve::executor::apply_plan — no subprocesses, no per-fixture binary rebuild.
L5minimality✅ ImplementedRe-plan after L4 apply asserts empty diff and empty plan groups.
L6no-collateral-damage✅ ImplementedOpt-in touches_only allow-list; asserts no unlisted objects were modified.
L7intent-shape✅ ImplementedMandatory-on-destructive; matches [[expect.intent]] against the generated intent.toml.
L8dep-graph golden✅ ImplementedByte-compares rendered DOT against expected/dep-graph.dot.
L9topological-order✅ ImplementedDeclared partial orders respected by step sequence.

Full details and authoring contract: crates/pgevolve-conformance/AUTHORING.md.

Fixture authoring subtrees

Each subtree under crates/pgevolve-conformance/fixtures/ has a specific contract:

SubtreeContract
objects/One fixture per object kind / change kind combination. Exercises L1–L5 at minimum.
scenarios/Multi-object, multi-step scenarios (e.g., rename dance, online rewrite sequences).
intent/Destructive-change fixtures; must include [[expect.intent]] blocks (L7).
failure/Fixtures that must fail at a specific phase (parse error, lint error, plan error). Uses [expect.failure].
regressions/Scaffolded by cargo xtask capture-regression; each fixture is linked to a GitHub issue.

v0.2 view / MV fixture coverage (Tier C)

As of T11, there are 15 conformance fixtures covering views and materialized views:

SubtreeFixtures
objects/views/8 fixtures: create-simple, create-with-aliases, comment-on-view, drop, replace-body-compatible, replace-body-incompatible, security-barrier-toggle, security-invoker-toggle
objects/materialized_views/6 fixtures: create-simple, create-no-unique-index-online, index-on-mv, refresh-concurrently, replace-body, with-no-data-override
intent/1 fixture: drop-view-requires-intent
scenarios/dependency-chains/2 fixtures covering transitive view recreation

Total: 15 fixtures across objects/views/, objects/materialized_views/, intent/, and scenarios/dependency-chains/.

fixture.toml schema additions

KeyStatusNotes
[budget].seconds✅ ImplementedPer-fixture time budget; exceeded fixtures fail in CI.
[pg.expect].<major>✅ ImplementedPer-PG-major expected output overrides.
[expect.plan.per_pg.pgN]✅ ImplementedOverride plan expectations for a specific PG major.
[[expect.intent]]✅ ImplementedL7 intent-shape matching rows.
[expect.dep_graph]✅ ImplementedL8 dep-graph golden reference.
[expect.failure]✅ ImplementedPhase and message for expected-failure fixtures.
expect.plan.touches_only✅ ImplementedL6 collateral-damage allow-list.
expect.plan.order✅ ImplementedL9 partial-order declarations.
expect.plan.minimality✅ ImplementedL5 minimality assertion toggle (on by default).

Full schema in crates/pgevolve-conformance/AUTHORING.md.

TestPgBackend pluggability

MechanismStatusNotes
PGEVOLVE_TEST_PG_MODE env var✅ ImplementedSelects backend: testcontainers (default), compose, or dsn.
dev/docker-compose.pg.yml✅ ImplementedShips for compose mode; pre-warms containers across test runs.

xtask additions

TaskStatusNotes
cargo xtask coverage --check | --gaps✅ Implemented(capability × change-kind × major) coverage matrix gate. --check fails if any cell is uncovered; --gaps prints the gap report.
cargo xtask fixture-cost✅ ImplementedPer-fixture timing report; helps identify slow fixtures.
cargo xtask capture-regression --seed <hex> --issue <n>✅ ImplementedScaffold a regression fixture linked to a GitHub issue.
cargo xtask verify-regression <fixture-dir>✅ ImplementedConfirm a regression fixture exercises a real bug (fails without the fix).
cargo xtask property-status --max-age-days N✅ ImplementedOpen-issue compliance gate; uses gh to check issue status.
cargo xtask diagnose-pg-version <fixture-dir> --pg-major N✅ ImplementedPer-PG-major fixture diagnostic for version-specific failures.

What each property test checks (Tier 5)

PropertyStatusNotes
plan_id_is_deterministic✅ ImplementedTwo PlanId::compute(source, target, ver, ruleset) invocations return the same bytes; different ruleset returns different bytes. Pure; no Docker.
Tests: tier-5: crates/pgevolve-core/tests/property_tests.rs::plan_id_is_deterministic
create_graph_topo_sorts_or_only_fk_cycles✅ ImplementedEither the create-graph topologically sorts cleanly, or every node in the cycle is an FK-bound Table / Constraint. Pure.
Tests: tier-5: crates/pgevolve-core/tests/property_tests.rs
view_canonicalization_closed_under_pg_rewrite✅ Implementedv0.2. For a fixed set of representative view bodies: create the view in an ephemeral PG, query pg_get_viewdef, canonicalize both source and catalog bodies via NormalizedBody::from_sql, assert the canonical texts match. Docker-gated; #[ignore]'d. A divergence indicates a canonicalization bug.
Tests: tier-5: crates/pgevolve/tests/pg_property_tests.rs
round_trip_property✅ ImplementedApply a random catalog to PG; re-introspect; assert structural equality. Needs Docker.
Tests: tier-5: crates/pgevolve/tests/pg_property_tests.rs
idempotency_property✅ ImplementedDiff of (applied catalog, applied catalog) is empty.
Tests: tier-5: crates/pgevolve/tests/pg_property_tests.rs
end_to_end_equivalence_property✅ ImplementedApply initial; apply a random mutation; introspect; assert equal to mutated. Exercises IRMutator.
Tests: tier-5: crates/pgevolve/tests/pg_property_tests.rs
drift_recovery_property✅ ImplementedApply with abort_after_step = N; re-plan from partial state; apply to completion; assert equal to target.
Tests: tier-5: crates/pgevolve/tests/pg_property_tests.rs
arb_view_dependency_graph🔮 DeferredSpec §12 step 12.2. Requires a non-trivial proptest generator for arbitrary view dep graphs. Not load-bearing for the closure invariant; deferred post-v0.2.

PGEVOLVE_PROPERTY_CASES controls the Docker-bound test case count (default 3 locally; CI's pg-matrix uses 50; soak uses 5000).

What lives in pgevolve-testkit

ModuleStatusNotes
EphemeralPostgres (testcontainers wrapper, PG 14-18)✅ ImplementedThe binary has a separate ShadowPostgres for validate --shadow.
PgCatalogQuerier (tokio_postgres-backed CatalogQuerier)✅ ImplementedMirrored in the binary as pgevolve::pg_querier.
catalog_snapshotter (canonical JSON renderer)✅ ImplementedPowers tier-3 goldens.
MigrationFixture (tier-4 fixture loader)✅ ImplementedOne seed fixture under crates/pgevolve-core/tests/fixtures/e2e/.
arbitrary_catalog IR generator✅ ImplementedSchemas + tables (with bigint PK) + indexes + sequences + a curated set of column types. Richer coverage (FKs, CHECK, multi-column UNIQUE, generated columns) lands in v0.2.
arbitrary_mutation IR mutator✅ ImplementedNine mutation kinds with cascade semantics.
assert_canonical_eq✅ ImplementedWraps Catalog::diff; renders failures as an indented diff list.

CI / soak

WorkflowStatusNotes
ci.yml — fmt + clippy + tier 1+2 (no Docker) on every push / PR✅ Implemented
ci.ymlpg-matrix job runs tier 3-5 on PG 14/15/16/17 with PROPTEST_CASES=50✅ ImplementedNeeds Docker on the runner.
ci.yml — auto-capture on flaky property failure + property-status compliance gate✅ ImplementedUses cargo xtask capture-regression and cargo xtask property-status.
property-tests.yml — dedicated property-test workflow with coverage matrix gate✅ ImplementedRuns cargo xtask coverage --check on every push to main and on PRs.
soak.yml — manual workflow_dispatch + weekly cron at PROPTEST_CASES=5000 per PG major✅ Implemented
Mutation testing (cargo-mutants, Stryker-style)🔮 FutureOnce the spec stabilizes; mutation testing flags rules that aren't actually tested.
Code coverage badges🔮 Futurecargo-llvm-cov is the obvious tool.