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.shmise 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.0docker 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.