pgaftest
pgaftest is the pg_auto_failover integration test runner. It reads
.pgaf spec files that describe a cluster topology and a set of test steps,
spins up the cluster using Docker Compose, and drives the steps to completion.
Two modes of operation are supported:
CI mode (
pgaftest run): headless TAP output, non-zero exit on failure.Interactive mode (
pgaftest setup): cluster stays up, shell or tmux session opened for hands-on exploration.
Synopsis
pgaftest run [options] <spec.pgaf>
pgaftest run --schedule <file> [options]
pgaftest setup [options] <spec.pgaf> [--tmux]
pgaftest step <step-name> [--work-dir <dir>]
pgaftest show <spec.pgaf>
pgaftest prepare <spec.pgaf> [<output-dir>]
pgaftest down [--work-dir <dir>]
Sub-commands
pgaftest run
Run a spec in CI mode. Docker Compose is started, the setup {} block
runs, each step in sequence runs in order, teardown {} always runs,
and the stack is removed. Output is TAP: ok N - step_name / not ok.
pgaftest run tests/tap/specs/basic_operation.pgaf
Options:
--schedule <file>Run every spec listed in the file (one name or path per line).
--expected <dir>Compare TAP output against
.outfiles in the directory.--work-dir <dir>Working directory for compose files and state (default:
$TMPDIR/pgaftest/<spec-name>).--no-cleanupLeave the compose stack running after the run for post-mortem inspection. Use
pgaftest downto clean up manually.
pgaftest setup
Start a cluster interactively. Docker Compose is started and the
setup {} block runs. Control is then handed back to you.
pgaftest setup tests/tap/specs/basic_operation.pgaf
pgaftest setup docs/tutorial/interactive_tutorial.pgaf --tmux
Options:
--tmuxOpen a three-pane tmux session immediately after the cluster is ready. The setup block runs in the bottom pane so you can watch the logs pane while the cluster initialises. The three panes are:
top —
docker compose logs -f(live container output)middle —
pg_autoctl watchon the monitorbottom — interactive
bashin the first data node (once setup completes)
--work-dir <dir>Working directory (default:
$TMPDIR/pgaftest/<spec-name>).
pgaftest step
Run a single named step against a cluster that was started with
pgaftest setup.
pgaftest step stop_primary --work-dir /tmp/pgaftest/basic_operation
The step name must match a step <name> {} block in the spec. The spec
file is read from <work-dir>/spec.pgaf.
pgaftest down
Run the teardown {} block (if any) and then docker compose down
--volumes --remove-orphans.
pgaftest down --work-dir /tmp/pgaftest/basic_operation
pgaftest down tests/tap/specs/basic_operation.pgaf
When called with only --work-dir, the project name is derived from the
last path component of the working directory, matching the name that
pgaftest setup used when creating the stack.
pgaftest show
Print the docker-compose.yml that would be generated from the spec,
without running anything.
pgaftest show tests/tap/specs/basic_operation.pgaf
pgaftest prepare
Write docker-compose.yml, per-node .ini files, and a Makefile
to an output directory for manual inspection or customisation.
pgaftest prepare tests/tap/specs/basic_operation.pgaf ./my-cluster
Spec file format
A .pgaf spec file has four top-level sections. Only cluster {} is
required; the others are optional.
# comments start with #
cluster {
... # topology declaration
}
setup {
... # commands to run after compose up
}
teardown {
... # commands to run on cleanup
}
step <name> {
... # named test step
}
sequence
step1
step2
...
The cluster {} block
Declares the Docker Compose topology. Every cluster must have at least one formation with at least one node.
cluster {
monitor # required for multi-node HA
image "pg_auto_failover:pg17" # optional; default: build from source
ssl self-signed # self-signed | cert | off (default: self-signed)
auth trust # trust | md5 | scram (default: trust)
formation { # optional name; default name: "default"
node1
node2
node3 async candidate-priority 0
}
# Citus: multiple formations
formation workers num-sync 1 {
w1 worker group 1
w2 worker group 1
}
}
Node modifiers:
|
Mark as async standby (no sync quorum) |
|
Failover priority 0–100 (default: 50) |
|
Container starts with |
|
Citus role |
|
Standalone node (no monitor) |
|
Bind all interfaces ( |
|
Per-node auth override |
|
Per-node SSL override |
|
Mount a named Docker volume at |
Commands inside setup, teardown, and step blocks
State waits
wait until <node> state is <state> [timeout <N>s]
wait until primary, secondary [timeout <N>s]
wait until <node> stopped [timeout <N>s]
The multi-node form wait until primary, secondary waits until at least
one node in each named state is present in the formation.
Assertions
assert <node> state is <state>
assert <node> assigned-state is <state>
assert <node> stays <state> while {
# commands that must not trigger a transition
}
Execute commands in a container
exec <service> <command...> # must exit 0
exec-fails <service> <command...> # must exit non-zero
SQL
sql <service> { SELECT ... }
expect { <expected output> }
expect error [<SQLSTATE>]
expect matches the output of the immediately preceding sql command.
Fields are separated by whitespace; rows are wrapped in { }.
Network
network disconnect <node>
network connect <node>
Compose lifecycle
compose stop <service>
compose start <service>
compose kill <service>
compose down
PostgreSQL control
stop postgres <node>
start postgres <node>
Failover
promote <node> [, <node2>, ...]
Monitor targeting (replace-monitor tests)
set monitor <service>
Log grep
logs <service> [not] <pattern>
Sleep
sleep <N>s
Environment variables
PGAF_IMAGEOverride the Docker image used for all node containers. Useful in CI to avoid rebuilding the image on every run:
PGAF_IMAGE=pgaf:run pgaftest run tests/tap/specs/basic_operation.pgaf
PGAFTEST_COMPOSE_SERVICEName of the service inside which
pgaftestitself runs when executing inside a container. Used by the CI workflow to locate the binary.PGAFTEST_HOST_WORK_DIRHost-side working directory when
pgaftestruns inside a container. Bind-mounted so compose files written by the binary are visible to the Docker daemon on the host.TMPDIRBase directory for auto-derived working directories (default:
/tmp). Working directories are placed under$TMPDIR/pgaftest/<spec-name>.
TAP output
In run mode, pgaftest produces TAP version 13 output on standard
output. Each named step in sequence becomes one test point:
TAP version 13
1..4
ok 1 - stop_primary
ok 2 - check_failover
ok 3 - restart_node1
ok 4 - verify_replication
On failure:
not ok 2 - check_failover
# DIAG: wait until node2 state is primary: timed out after 90s
Examples
Run a single spec:
pgaftest run tests/tap/specs/basic_operation.pgaf
Run the full schedule:
pgaftest run --schedule tests/tap/schedule
Bring up an interactive cluster, watch it in tmux:
pgaftest setup docs/tutorial/interactive_tutorial.pgaf --tmux
Run a named step against a live cluster:
pgaftest step stop_primary --work-dir /tmp/pgaftest/basic_operation
Tear down a cluster started with --no-cleanup or setup:
pgaftest down --work-dir /tmp/pgaftest/basic_operation
Print the generated docker-compose.yml without running anything:
pgaftest show tests/tap/specs/basic_operation.pgaf
See also
Tutorial — Docker Compose tutorial with
pgaftestalternativeCitus Tutorial — Citus tutorial with
pgaftestalternative