pg_automergev0.1.0

Testing and CI

Testing the image#

mise run docker-test runs everything against throwaway containers of the image (labelled pg-automerge-test, removed afterwards with their volumes): the init script and its variable, SQL through the container's own psql (casts, merges, jsonb operators with a GIN expression index and a generated column, the history functions, a real LISTEN session for automerge_notify(), the settings and their privileges), pg_dump -Fc in one container restored into a second, a restart on the same volume, the regress examples and the concurrency, notify, dump, extension and memory suites, the load memory limit against a container started with --memory=1g, a 60-second smoke run of the soak test (see Operations; mise run soak is the full hour), and that no server log shows an assertion failure, panic or crashed backend. The suites need Postgres 18 client tools and cargo: those of the pgrx Postgres by default (mise run pgrx-init), or PGDG's postgresql-client-18 with PG_CONFIG=/usr/lib/postgresql/18/bin/pg_config (what CI uses; the soak run also needs its pgbench and python3); DOCKER_TEST_SUITES=0 skips them. It also runs tests/cnpg_smoke.sh against the CloudNativePG extension image (DOCKER_TEST_CNPG=0 skips it; see CloudNativePG). It also checks the release scripts: scripts/docker-archive.sh and a --dry-run of scripts/docker-push.sh (see Releasing).

mise run cnpg-e2e (not part of docker-test; the CI cnpg-e2e job runs it, see below) tests the CNPG extension image with the real operator in a kind cluster; see CloudNativePG.

mise run docker-upgrade-test (not part of docker-test) upgrades a deployment of the previous release to the current version the way the Updating section describes (while 0.1.0, the first release, is the current version, it has nothing to upgrade from and says so): a container of the previous release's image (PG_AUTOMERGE_OLD_IMAGE=<tag or image ID>, or by default built from its release tag v<version> in the git history) with tables, a generated doc::jsonb column, GIN and B-tree expression indexes, a view, an automerge_notify() trigger and documents; then the new image on the same volume, ALTER EXTENSION pg_automerge UPDATE, and checks of the data, indexes, trigger, automerge_spans, the memory counters and the catalog against a fresh install.

The multi-session suites run against any server of yours, too (it needs the extension available, a superuser, and room for scratch databases):

PG_AUTOMERGE_TEST_HOST=127.0.0.1 PG_AUTOMERGE_TEST_PORT=5432 \
PG_AUTOMERGE_TEST_USER=postgres PG_AUTOMERGE_TEST_PASSWORD=... \
  bash tests/concurrency.sh   # or notify.sh, dump.sh, extension.sh, memory.sh, bench_sql.sh

mise run docker-bench-sql times the everyday SQL paths against the image; see Performance for how it compares.

CI#

.github/workflows/ci.yml has a docker job next to the ci job, on every push and pull request: it builds the image with BuildKit, caching its layers in the GitHub Actions cache (so the Rust toolchain and cargo-pgrx are built once, not on every run), and runs tests/docker.sh in full against it, with PGDG's client tools. It does not need pgrx.

Both images go through the same steps: the docker job builds the full image first (exporting the layer cache) and then the CloudNativePG extension image from that cache, so the extension is compiled once per architecture and both images hold the same pg_automerge.so. tests/docker.sh tests both, including tests/cnpg_smoke.sh in CNPG's own PostgreSQL image, on every push and pull request.

The cnpg-e2e job runs tests/cnpg_e2e.sh (a kind cluster with the CloudNativePG operator, a few minutes) after the docker job, on the amd64 CNPG image that job built and saved as a short-lived artifact. It runs for releases, on the nightly schedule and on manual runs (Actions > CI > Run workflow), not on every push or pull request. Set the repository variable PG_AUTOMERGE_CNPG_E2E to always to run it on every event.

ci.yml never publishes anything, and its token is read-only (contents: read). For a release, .github/workflows/release.yml calls it on the release's commit with release: true, which adds what a release needs: the docker job runs twice, on an amd64 and on GitHub's native arm64 runner (ubuntu-24.04-arm; no QEMU or cross-compilation, why), each building and testing its own images and saving them as archives (pg-automerge-<version>-linux-<arch>.tar.gz and pg-automerge-cnpg-<version>-18-trixie-linux-<arch>.tar.gz); the ci job builds and installs the package tarball; cnpg-e2e always runs. Then the release workflow pushes and attaches exactly those files; see Releasing. tests/check_ci.sh (part of mise run lint) fails if ci.yml gets a tag trigger, a write permission, a registry login or a push, or if the release workflow's publish job stops depending on every test job.

To use an archive from a release:

docker load -i pg-automerge-0.1.0-linux-arm64.tar.gz   # loads pg-automerge:0.1.0

docker load moves your local pg-automerge:0.1.0 tag to the loaded image, so loading the other architecture's archive leaves that tag on an image your host cannot run (exec format error) until you mise run docker-build again. scripts/docker-push.sh loads archives too, but puts the tags back as they were.