From b7e98f170d48e2081fe07821e0be14c8daaf43e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Tue, 24 Feb 2026 17:32:28 +0100 Subject: [PATCH] feat: add new TAP group infra for PostgreSQL replication testing --- test/tap/groups/pgsql-repl/Dockerfile | 3 + test/tap/groups/pgsql-repl/README.md | 29 ++++++++ .../pgsql-repl/bin/docker-pgsql-post.bash | 35 ++++++++++ .../pgsql-repl/bin/docker-proxy-post.bash | 35 ++++++++++ .../pgsql-repl/conf/postgres/00_init.sql | 9 +++ .../pgsql-repl/conf/proxysql/config.sql | 36 ++++++++++ test/tap/groups/pgsql-repl/constants | 12 ++++ .../pgsql-repl/docker-compose-destroy.bash | 3 + .../pgsql-repl/docker-compose-init.bash | 10 +++ .../tap/groups/pgsql-repl/docker-compose.yaml | 70 +++++++++++++++++++ test/tap/groups/pgsql-repl/post-proxysql.bash | 8 +++ test/tap/groups/pgsql-repl/pre-proxysql.bash | 11 +++ .../pgsql-repl/scripts/create_test_tables.sql | 13 ++++ 13 files changed, 274 insertions(+) create mode 100644 test/tap/groups/pgsql-repl/Dockerfile create mode 100644 test/tap/groups/pgsql-repl/README.md create mode 100755 test/tap/groups/pgsql-repl/bin/docker-pgsql-post.bash create mode 100755 test/tap/groups/pgsql-repl/bin/docker-proxy-post.bash create mode 100644 test/tap/groups/pgsql-repl/conf/postgres/00_init.sql create mode 100644 test/tap/groups/pgsql-repl/conf/proxysql/config.sql create mode 100644 test/tap/groups/pgsql-repl/constants create mode 100755 test/tap/groups/pgsql-repl/docker-compose-destroy.bash create mode 100755 test/tap/groups/pgsql-repl/docker-compose-init.bash create mode 100644 test/tap/groups/pgsql-repl/docker-compose.yaml create mode 100755 test/tap/groups/pgsql-repl/post-proxysql.bash create mode 100755 test/tap/groups/pgsql-repl/pre-proxysql.bash create mode 100644 test/tap/groups/pgsql-repl/scripts/create_test_tables.sql diff --git a/test/tap/groups/pgsql-repl/Dockerfile b/test/tap/groups/pgsql-repl/Dockerfile new file mode 100644 index 000000000..935358e24 --- /dev/null +++ b/test/tap/groups/pgsql-repl/Dockerfile @@ -0,0 +1,3 @@ +FROM postgres:17 + +RUN apt-get update && apt-get install -y iproute2 diff --git a/test/tap/groups/pgsql-repl/README.md b/test/tap/groups/pgsql-repl/README.md new file mode 100644 index 000000000..4735d1ca3 --- /dev/null +++ b/test/tap/groups/pgsql-repl/README.md @@ -0,0 +1,29 @@ +# PostgreSQL Primary-Replica Infra + +## Images build + +```bash +docker build -t postgres-tc:17 . +``` + +This step is automatically performed by `docker-compose-init.bash`. Images should be reused between +executions. + +## Start / Stop + +To start the infra just execute the group startup script: + +```bash +pre-proxysql.bash +``` + +To stop the infra just execute the group shutdown script: + +```bash +post-proxysql.bash +``` + +## Folder structure + +* `conf`: Config files for both infra and `ProxySQL`. +* `scripts`: Collection of scripts used to prepare the infra. diff --git a/test/tap/groups/pgsql-repl/bin/docker-pgsql-post.bash b/test/tap/groups/pgsql-repl/bin/docker-pgsql-post.bash new file mode 100755 index 000000000..8781a8e69 --- /dev/null +++ b/test/tap/groups/pgsql-repl/bin/docker-pgsql-post.bash @@ -0,0 +1,35 @@ +#!/bin/bash + +set -e + +. constants + +POSTGRE_SETUP_DIR=$(dirname $(realpath $0))/../scripts/ + +WAITED=0 +TIMEOUT=300 +RC=1 + +set +e + +printf "[$(date)] Waiting for PostgreSQL service to initialize" +while [ $RC -ne 0 ]; do + if [ $WAITED -gt $TIMEOUT ]; then + echo "[ERROR] Timeout of $TIMEOUT seconds reached while connecting to MySQL" + exit 1 + else + printf "." + PGPASSWORD=$PGSQL_PWD ON_ERROR_STOP=1 psql -h$PGSQL_HOST -p$PGSQL_PORT -U$PGSQL_DB -c"SELECT" > /dev/null 2>&1 + RC=$? + WAITED=$((WAITED+1)) + sleep 1 + fi +done +printf "\n" + +set -e + +echo "[$(date)] Creating table structures for testing ..." +set -x +PGPASSWORD=$PGSQL_PWD ON_ERROR_STOP=1 psql -h$PGSQL_HOST -p$PGSQL_PORT -U$PGSQL_DB < $POSTGRE_SETUP_DIR/create_test_tables.sql +set +x diff --git a/test/tap/groups/pgsql-repl/bin/docker-proxy-post.bash b/test/tap/groups/pgsql-repl/bin/docker-proxy-post.bash new file mode 100755 index 000000000..60766cd81 --- /dev/null +++ b/test/tap/groups/pgsql-repl/bin/docker-proxy-post.bash @@ -0,0 +1,35 @@ +#!/bin/bash + +set -e + +. constants + +PROXY_CONF_DIR=$(dirname $(realpath $0))/../conf/proxysql + +WAITED=0 +TIMEOUT=300 +RC=1 + +set +e + +printf "[$(date)] Waiting for ProxySQL service to initialize" +while [ $RC -eq 1 ]; do + if [ $WAITED -gt $TIMEOUT ]; then + echo "[ERROR] Timeout of $TIMEOUT seconds reached while connecting to ProxySQL" + exit 1 + else + printf "." + mysql -h$ADMIN_HOST -P$ADMIN_PORT -u$ADMIN_USER -p$ADMIN_PWD -e"\s" > /dev/null 2>&1 + RC=$? + WAITED=$((WAITED+1)) + sleep 1 + fi +done +printf "\n" + +set -e + +echo "[$(date)] Applying initial config for ProxySQL ..." +set -x +mysql --prompt="admin> " -u$ADMIN_USER -p$ADMIN_PWD --table -h$ADMIN_HOST -P$ADMIN_PORT < $PROXY_CONF_DIR/config.sql +set +x diff --git a/test/tap/groups/pgsql-repl/conf/postgres/00_init.sql b/test/tap/groups/pgsql-repl/conf/postgres/00_init.sql new file mode 100644 index 000000000..1ae32a559 --- /dev/null +++ b/test/tap/groups/pgsql-repl/conf/postgres/00_init.sql @@ -0,0 +1,9 @@ +CREATE USER repluser WITH replication encrypted password 'replpass'; +SELECT pg_create_physical_replication_slot('replication_slot'); + +CREATE USER proxymon WITH encrypted password 'proxymon'; + +GRANT pg_monitor TO proxymon; + +-- For testing 'pgsql-monitor_dbname' +CREATE DATABASE proxymondb; diff --git a/test/tap/groups/pgsql-repl/conf/proxysql/config.sql b/test/tap/groups/pgsql-repl/conf/proxysql/config.sql new file mode 100644 index 000000000..5c4fe1a0f --- /dev/null +++ b/test/tap/groups/pgsql-repl/conf/proxysql/config.sql @@ -0,0 +1,36 @@ +SET pgsql-monitor_password='proxymon'; +SET pgsql-monitor_username='proxymon'; + +LOAD PGSQL VARIABLES TO RUNTIME; +SAVE PGSQL VARIABLES TO DISK; + +DELETE FROM pgsql_users; +INSERT INTO pgsql_users (username,password,default_hostgroup) VALUES ('postgres','postgres',0); + +LOAD PGSQL USERS TO RUNTIME; +SAVE PGSQL USERS TO DISK; + +SET pgsql-monitor_replication_lag_interval=1000; + +LOAD PGSQL VARIABLES TO RUNTIME; +SAVE PGSQL VARIABLES TO DISK; + +DELETE FROM pgsql_replication_hostgroups; +INSERT INTO + pgsql_replication_hostgroups (writer_hostgroup, reader_hostgroup, check_type, comment) +VALUES + (0, 1, 'read_only', 'pg-replication'); + +LOAD PGSQL SERVERS TO RUNTIME; +SAVE PGSQL SERVERS TO DISK; + +DELETE FROM pgsql_servers; + +INSERT INTO + pgsql_servers (hostgroup_id, hostname, port, max_replication_lag, comment) +VALUES + (0, '127.0.0.1', 15432, 3, 'pg-primary'), + (1, '127.0.0.1', 15433, 3, 'pg-replica'); + +LOAD PGSQL SERVERS TO RUNTIME; +SAVE PGSQL SERVERS TO DISK; diff --git a/test/tap/groups/pgsql-repl/constants b/test/tap/groups/pgsql-repl/constants new file mode 100644 index 000000000..caf5afe2c --- /dev/null +++ b/test/tap/groups/pgsql-repl/constants @@ -0,0 +1,12 @@ +#!/bin/bash + +export PGSQL_USER=${TAP_PGSQLROOT_USERNAME:=postgres} +export PGSQL_PWD=${TAP_PGSQLROOT_PASSWORD:=postgres} +export PGSQL_DB=${TAP_PGSQLROOT_DATABASE:=postgres} +export PGSQL_HOST=${TAP_PGSQLSERVER_HOST:=127.0.0.1} +export PGSQL_PORT=${TAP_PGSQLSERVER_PORT:=15432} + +export ADMIN_HOST=${TAP_ADMINHOST:=127.0.0.1} +export ADMIN_PORT=${TAP_ADMINPORT:=6032} +export ADMIN_USER=${TAP_ADMINUSERNAME:=radmin} +export ADMIN_PWD=${TAP_ADMINPASSWORD:=radmin} diff --git a/test/tap/groups/pgsql-repl/docker-compose-destroy.bash b/test/tap/groups/pgsql-repl/docker-compose-destroy.bash new file mode 100755 index 000000000..0ec548cf8 --- /dev/null +++ b/test/tap/groups/pgsql-repl/docker-compose-destroy.bash @@ -0,0 +1,3 @@ +#!/bin/bash + +docker compose down -v diff --git a/test/tap/groups/pgsql-repl/docker-compose-init.bash b/test/tap/groups/pgsql-repl/docker-compose-init.bash new file mode 100755 index 000000000..d509b2e2f --- /dev/null +++ b/test/tap/groups/pgsql-repl/docker-compose-init.bash @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e + +. constants + +docker build -t postgres-tc:17 . +docker compose up -d + +./bin/docker-pgsql-post.bash && ./bin/docker-proxy-post.bash diff --git a/test/tap/groups/pgsql-repl/docker-compose.yaml b/test/tap/groups/pgsql-repl/docker-compose.yaml new file mode 100644 index 000000000..988a1a53c --- /dev/null +++ b/test/tap/groups/pgsql-repl/docker-compose.yaml @@ -0,0 +1,70 @@ +x-pg-common: + &pg-common + image: postgres-tc:17 + user: postgres + restart: always + healthcheck: + test: 'pg_isready -U postgres --dbname=postgres' + interval: 10s + timeout: 5s + retries: 5 + +services: + pg_primary: + <<: *pg-common + ports: + - 15432:5432 + environment: + POSTGRES_USER: postgres + POSTGRES_DB: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_HOST_AUTH_METHOD: "scram-sha-256\nhost replication all 0.0.0.0/0 md5" + POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256" + networks: + default: {} + pg_backend: + aliases: + - pg_primary_int + cap_add: + - NET_ADMIN + command: | + postgres + -c wal_level=replica + -c hot_standby=on + -c max_wal_senders=10 + -c max_connections=500 + -c max_replication_slots=10 + -c hot_standby_feedback=on + volumes: + - ./conf/postgres/00_init.sql:/docker-entrypoint-initdb.d/00_init.sql + + pg_replica: + <<: *pg-common + ports: + - 15433:5432 + environment: + PGUSER: repluser + PGPASSWORD: replpass + networks: + - default + - pg_backend + cap_add: + - NET_ADMIN + command: | + bash -c " + until pg_basebackup --pgdata=/var/lib/postgresql/data -R --slot=replication_slot --host=pg_primary_int --port=5432 + do + echo 'Waiting for primary to connect...' + sleep 1s + done + echo 'Backup done, starting replica...' + chmod 0700 /var/lib/postgresql/data + postgres -c max_connections=500 + " + depends_on: + - pg_primary + +networks: + pg_backend: + driver: bridge + internal: true diff --git a/test/tap/groups/pgsql-repl/post-proxysql.bash b/test/tap/groups/pgsql-repl/post-proxysql.bash new file mode 100755 index 000000000..6b78b7daf --- /dev/null +++ b/test/tap/groups/pgsql-repl/post-proxysql.bash @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e + +. constants + +echo "[$(date)] Shutting down PGSQL_REPL testing infra ..." +./docker-compose-destroy.bash diff --git a/test/tap/groups/pgsql-repl/pre-proxysql.bash b/test/tap/groups/pgsql-repl/pre-proxysql.bash new file mode 100755 index 000000000..e8ab606ff --- /dev/null +++ b/test/tap/groups/pgsql-repl/pre-proxysql.bash @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +. constants + +echo "[$(date)] Cleaning infra prior to PGSQL_REPL group testing" +./docker-compose-destroy.bash + +echo "[$(date)] Starting infra required for PGSQL_REPL group testing" +./docker-compose-init.bash diff --git a/test/tap/groups/pgsql-repl/scripts/create_test_tables.sql b/test/tap/groups/pgsql-repl/scripts/create_test_tables.sql new file mode 100644 index 000000000..1e52bfe4d --- /dev/null +++ b/test/tap/groups/pgsql-repl/scripts/create_test_tables.sql @@ -0,0 +1,13 @@ +\set ON_ERROR_STOP on + +DROP DATABASE IF EXISTS sysbench; +CREATE DATABASE sysbench; + +\connect sysbench; + +CREATE TABLE sbtest1 ( + id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + k integer DEFAULT 0 NOT NULL, + c character(120) DEFAULT ''::bpchar NOT NULL, + pad character(60) DEFAULT ''::bpchar NOT NULL +);