OBJS = pg_rewind.o parsexlog.o xlogreader.o util.o datapagemap.o timeline.o \
fetch.o copy_fetch.o libpq_fetch.o filemap.o
-REGRESS = basictest extrafiles databases
-REGRESS_OPTS=--use-existing --launcher=./launcher
+#REGRESS = basictest extrafiles databases
+#REGRESS_OPTS=--use-existing --launcher=./launcher
PG_CPPFLAGS = -I$(libpq_srcdir)
PG_LIBS = $(libpq_pgport)
xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
rm -f $@ && $(LN_S) $< .
-# The regression tests can be run separately against, using the libpq or local
-# method to copy the files. For local mode, the makefile target is
-# "check-local", and for libpq mode, "check-remote". The target check-both
-# runs the tests in both modes.
-check-local:
- echo "Running tests against local data directory, in copy-mode"
- bindir=$(bindir) TEST_SUITE="local" $(MAKE) installcheck
-
-check-remote:
- echo "Running tests against a running standby, via libpq"
- bindir=$(bindir) TEST_SUITE="remote" $(MAKE) installcheck
-
-check-both: check-local check-remote
+check: all
+ $(prove_check)
--- /dev/null
+package RewindTest;
+
+# Test driver for pg_rewind. Each test consists of a cycle where a new cluster
+# is first created with initdb, and a streaming replication standby is set up
+# to follow the master. Then the master is shut down and the standby is
+# promoted, and finally pg_rewind is used to rewind the old master, using the
+# standby as the source. Between the steps, test-specific actions are
+# performed.
+#
+# To run a test, the test script (in t/ subdirectory) calls run_rewind_test
+# function. All the test-specific actions that are run in different stages
+# are defined as callback functions:
+#
+# before_standby - runs after initializing the master, before creating the
+# standby
+# standby_following_master - runs after standby has been created and started
+# after_promotion - runs after standby has been promoted, but old master is
+# still running
+# after_rewind - runs after pg_rewind and after restarting the rewound
+# old master
+#
+# The test script can use the helper functions master_psql and standby_psql
+# to run psql against the master and standby servers, respectively. The
+# test script can also use the $connstr_master and $connstr_standby global
+# variables, which contain libpq connection strings for connecting to the
+# master and standby servers. The data directories are also available
+# in paths $test_master_datadir and $test_standby_datadir
+
+use TestLib;
+use Test::More;
+
+use File::Copy;
+use File::Path qw(remove_tree);
+use IPC::Run qw(run start);
+
+use Exporter 'import';
+our @EXPORT = qw(
+ $connstr_master
+ $connstr_standby
+ $test_master_datadir
+ $test_standby_datadir
+
+ append_to_file
+ master_psql
+ standby_psql
+ run_rewind_test
+);
+
+
+# Adjust these paths for your environment
+my $testroot = "./tmp_check";
+$test_master_datadir="$testroot/data_master";
+$test_standby_datadir="$testroot/data_standby";
+
+mkdir $testroot;
+
+# Log files are created here
+mkdir "regress_log";
+
+# Define non-conflicting ports for both nodes.
+my $port_master=$ENV{PGPORT};
+my $port_standby=$port_master + 1;
+
+$connstr_master="port=$port_master";
+$connstr_standby="port=$port_standby";
+
+$ENV{PGDATABASE} = "postgres";
+
+sub master_psql
+{
+ my $cmd = shift;
+
+ system_or_bail("psql -a --no-psqlrc -d $connstr_master -c \"$cmd\"");
+}
+
+sub standby_psql
+{
+ my $cmd = shift;
+
+ system_or_bail("psql -a --no-psqlrc -p$port_standby -c \"$cmd\"");
+}
+
+sub append_to_file
+{
+ my($filename, $str) = @_;
+
+ open my $fh, ">>", $filename or die "could not open file $filename";
+ print $fh $str;
+ close $fh;
+}
+
+sub run_rewind_test
+{
+ my($testname, $test_mode, %callbacks) = @_;
+
+ my $log_path="regress_log/pg_rewind_log_${testname}_${test_mode}";
+
+ remove_tree $log_path;
+ diag "Running rewind test in $test_mode mode...\n";
+
+ # Initialize master, data checksums are mandatory
+ remove_tree($test_master_datadir);
+ system_or_bail("initdb -N -A trust -D $test_master_datadir >>$log_path");
+
+ # Custom parameters for master's postgresql.conf
+ append_to_file("$test_master_datadir/postgresql.conf", qq(
+wal_level = hot_standby
+max_wal_senders = 2
+wal_keep_segments = 20
+checkpoint_segments = 50
+shared_buffers = 1MB
+wal_log_hints = on
+log_line_prefix = 'M %m %p '
+hot_standby = on
+autovacuum = off
+max_connections = 50
+listen_addresses = '$LISTEN_ADDRESSES'
+));
+
+ # Accept replication connections on master
+ append_to_file("$test_master_datadir/pg_hba.conf", qq(
+local replication all trust
+host replication all 127.0.0.1/32 trust
+host replication all ::1/128 trust
+));
+
+ system_or_bail("pg_ctl -w -D $test_master_datadir -o \"-p $port_master\" start >>$log_path 2>&1");
+
+ #### Now run the test-specific parts to initialize the master before setting
+ # up standby
+ diag "Master initialized and running.\n";
+
+ $callbacks{before_standby}();
+
+ # Set up standby with necessary parameter
+ remove_tree $test_standby_datadir;
+
+ # Base backup is taken with xlog files included
+ system_or_bail("pg_basebackup -D $test_standby_datadir -p $port_master -x >>$log_path 2>&1");
+ append_to_file("$test_standby_datadir/recovery.conf", qq(
+primary_conninfo='$connstr_master'
+standby_mode=on
+recovery_target_timeline='latest'
+));
+
+ # Start standby
+ system_or_bail("pg_ctl -w -D $test_standby_datadir start -o \"-p $port_standby\" >>$log_path 2>&1");
+
+ #### Now run the test-specific parts to run after standby has been started
+ # up standby
+ diag "Standby initialized and running.\n";
+ $callbacks{standby_following_master}();
+
+ # sleep a bit to make sure the standby has caught up.
+ sleep 1;
+
+ # Now promote slave and insert some new data on master, this will put
+ # the master out-of-sync with the standby.
+ system_or_bail("pg_ctl -w -D $test_standby_datadir promote >>$log_path 2>&1");
+ sleep 1;
+
+ #### Now run the test-specific parts to run after promotion
+ diag "Standby promoted.\n";
+ $callbacks{after_promotion}();
+
+ # Stop the master and be ready to perform the rewind
+ system_or_bail("pg_ctl -w -D $test_master_datadir stop -m fast >>$log_path 2>&1");
+
+ # At this point, the rewind processing is ready to run.
+ # We now have a very simple scenario with a few diverged WAL record.
+ # The real testing begins really now with a bifurcation of the possible
+ # scenarios that pg_rewind supports.
+
+ # Keep a temporary postgresql.conf for master node or it would be
+ # overwritten during the rewind.
+ copy("$test_master_datadir/postgresql.conf", "$testroot/master-postgresql.conf.tmp");
+ # Now run pg_rewind
+ diag "Running pg_rewind...\n";
+ if ($test_mode == "local")
+ {
+ # Do rewind using a local pgdata as source
+ my $result =
+ run(['./pg_rewind',
+ "--source-pgdata=$test_standby_datadir",
+ "--target-pgdata=$test_master_datadir"],
+ '>>', $log_path, '2>&1');
+ ok ($result, 'pg_rewind local');
+ }
+ elsif ($test_mode == "remote")
+ {
+ # Do rewind using a remote connection as source
+ my $result =
+ run(['./pg_rewind',
+ "--source-server=\"port=$port_standby dbname=postgres\"",
+ "--target-pgdata=$test_master_datadir"],
+ '>>', $log_path, '2>&1');
+ ok ($result, 'pg_rewind remote');
+ } else {
+ # Cannot come here normally
+ die("Incorrect test suite specified");
+ }
+
+ # Now move back postgresql.conf with old settings
+ move("$testroot/master-postgresql.conf.tmp", "$test_master_datadir/postgresql.conf");
+
+ # Plug-in rewound node to the now-promoted standby node
+ append_to_file("$test_master_datadir/recovery.conf", qq(
+primary_conninfo='port=$port_standby'
+standby_mode=on
+recovery_target_timeline='latest'
+));
+
+ # Restart the master to check that rewind went correctly
+ system_or_bail("pg_ctl -w -D $test_master_datadir start -o \"-p $port_master\" >>$log_path 2>&1");
+
+ #### Now run the test-specific parts to check the result
+ diag "Old master restarted after rewind.\n";
+ $callbacks{after_rewind}();
+
+ # Stop remaining servers
+ system "pg_ctl stop -D $test_master_datadir -m fast -w >>$log_path 2>&1";
+ system "pg_ctl stop -D $test_standby_datadir -m fast -w >>$log_path 2>&1";
+}
+
+# Clean up after the test. Stop both servers, if they're still running.
+END
+{
+ if ($test_master_datadir)
+ {
+ system 'pg_ctl', '-D', $test_master_datadir, '-s', '-w', '-m',
+ 'immediate', 'stop';
+ }
+ if ($test_standby_datadir)
+ {
+ system 'pg_ctl', '-D', $test_standby_datadir, '-s', '-w', '-m',
+ 'immediate', 'stop';
+ }
+}
+++ /dev/null
-Master initialized and running.
-CREATE TABLE tbl1 (d text);
-CREATE TABLE
-INSERT INTO tbl1 VALUES ('in master');
-INSERT 0 1
-CHECKPOINT;
-CHECKPOINT
-Standby initialized and running.
-INSERT INTO tbl1 values ('in master, before promotion');
-INSERT 0 1
-CHECKPOINT;
-CHECKPOINT
-Standby promoted.
-INSERT INTO tbl1 VALUES ('in master, after promotion');
-INSERT 0 1
-INSERT INTO tbl1 VALUES ('in standby, after promotion');
-INSERT 0 1
-Running pg_rewind...
-Old master restarted after rewind.
-SELECT * from tbl1
- d
------------------------------
- in master
- in master, before promotion
- in standby, after promotion
-(3 rows)
-
+++ /dev/null
-Master initialized and running.
-CREATE DATABASE inmaster;
-CREATE DATABASE
-Standby initialized and running.
-CREATE DATABASE beforepromotion
-CREATE DATABASE
-Standby promoted.
-CREATE DATABASE master_afterpromotion
-CREATE DATABASE
-CREATE DATABASE standby_afterpromotion
-CREATE DATABASE
-Running pg_rewind...
-Old master restarted after rewind.
-SELECT datname from pg_database
- datname
-------------------------
- template1
- template0
- postgres
- inmaster
- beforepromotion
- standby_afterpromotion
-(6 rows)
-
+++ /dev/null
-Master initialized and running.
-Standby initialized and running.
-Standby promoted.
-Running pg_rewind...
-Old master restarted after rewind.
-tst_both_dir
-tst_both_dir/both_file1
-tst_both_dir/both_file2
-tst_both_dir/both_subdir
-tst_both_dir/both_subdir/both_file3
-tst_standby_dir
-tst_standby_dir/standby_file1
-tst_standby_dir/standby_file2
-tst_standby_dir/standby_subdir
-tst_standby_dir/standby_subdir/standby_file3
+++ /dev/null
-#!/bin/bash
-#
-# Normally, psql feeds the files in sql/ directory to psql, but we want to
-# run them as shell scripts instead.
-
-bash
+++ /dev/null
-#!/bin/bash
-
-# This file has the .sql extension, but it is actually launched as a shell
-# script. This contortion is necessary because pg_regress normally uses
-# psql to run the input scripts, and requires them to have the .sql
-# extension, but we use a custom launcher script that runs the scripts using
-# a shell instead.
-
-TESTNAME=basictest
-
-. sql/config_test.sh
-
-# Do an insert in master.
-function before_standby
-{
-$MASTER_PSQL <<EOF
-CREATE TABLE tbl1 (d text);
-INSERT INTO tbl1 VALUES ('in master');
-CHECKPOINT;
-EOF
-}
-
-function standby_following_master
-{
-# Insert additional data on master that will be replicated to standby
-$MASTER_PSQL -c "INSERT INTO tbl1 values ('in master, before promotion');"
-
-# Launch checkpoint after standby has been started
-$MASTER_PSQL -c "CHECKPOINT;"
-}
-
-# This script runs after the standby has been promoted. Old Master is still
-# running.
-function after_promotion
-{
-# Insert a row in the old master. This causes the master and standby to have
-# "diverged", it's no longer possible to just apply the standy's logs over
-# master directory - you need to rewind.
-$MASTER_PSQL -c "INSERT INTO tbl1 VALUES ('in master, after promotion');"
-
-# Also insert a new row in the standby, which won't be present in the old
-# master.
-$STANDBY_PSQL -c "INSERT INTO tbl1 VALUES ('in standby, after promotion');"
-}
-
-# Compare results generated by querying new master after rewind
-function after_rewind
-{
-$MASTER_PSQL -c "SELECT * from tbl1"
-}
-
-# Run the test
-. sql/run_test.sh
+++ /dev/null
-#!/bin/bash
-#
-# Initialize some variables, before running pg_rewind.sh.
-
-set -e
-
-mkdir -p "regress_log"
-log_path="regress_log/pg_rewind_log_${TESTNAME}_${TEST_SUITE}"
-: ${MAKE=make}
-
-rm -f $log_path
-
-# Guard against parallel make issues (see comments in pg_regress.c)
-unset MAKEFLAGS
-unset MAKELEVEL
-
-# Check at least that the option given is suited
-if [ "$TEST_SUITE" = 'remote' ]; then
- echo "Running tests with libpq connection as source" >>$log_path 2>&1
- TEST_SUITE="remote"
-elif [ "$TEST_SUITE" = 'local' ]; then
- echo "Running tests with local data folder as source" >>$log_path 2>&1
- TEST_SUITE="local"
-else
- echo "TEST_SUITE environment variable must be set to either \"local\" or \"remote\""
- exit 1
-fi
-
-# Set listen_addresses desirably
-testhost=`uname -s`
-case $testhost in
- MINGW*) LISTEN_ADDRESSES="localhost" ;;
- *) LISTEN_ADDRESSES="" ;;
-esac
-
-# Indicate of binaries
-PATH=$bindir:$PATH
-export PATH
-
-# Adjust these paths for your environment
-TESTROOT=$PWD/tmp_check
-TEST_MASTER=$TESTROOT/data_master
-TEST_STANDBY=$TESTROOT/data_standby
-
-# Create the root folder for test data
-mkdir -p $TESTROOT
-
-# Clear out any environment vars that might cause libpq to connect to
-# the wrong postmaster (cf pg_regress.c)
-#
-# Some shells, such as NetBSD's, return non-zero from unset if the variable
-# is already unset. Since we are operating under 'set -e', this causes the
-# script to fail. To guard against this, set them all to an empty string first.
-PGDATABASE=""; unset PGDATABASE
-PGUSER=""; unset PGUSER
-PGSERVICE=""; unset PGSERVICE
-PGSSLMODE=""; unset PGSSLMODE
-PGREQUIRESSL=""; unset PGREQUIRESSL
-PGCONNECT_TIMEOUT=""; unset PGCONNECT_TIMEOUT
-PGHOST=""; unset PGHOST
-PGHOSTADDR=""; unset PGHOSTADDR
-
-export PGDATABASE="postgres"
-
-# Define non conflicting ports for both nodes, this could be a bit
-# smarter with for example dynamic port recognition using psql but
-# this will make it for now.
-PG_VERSION_NUM=90401
-PORT_MASTER=`expr $PG_VERSION_NUM % 16384 + 49152`
-PORT_STANDBY=`expr $PORT_MASTER + 1`
-
-MASTER_PSQL="psql -a --no-psqlrc -p $PORT_MASTER"
-STANDBY_PSQL="psql -a --no-psqlrc -p $PORT_STANDBY"
+++ /dev/null
-#!/bin/bash
-
-# This file has the .sql extension, but it is actually launched as a shell
-# script. This contortion is necessary because pg_regress normally uses
-# psql to run the input scripts, and requires them to have the .sql
-# extension, but we use a custom launcher script that runs the scripts using
-# a shell instead.
-
-TESTNAME=databases
-
-. sql/config_test.sh
-
-# Create a database in master.
-function before_standby
-{
-$MASTER_PSQL <<EOF
-CREATE DATABASE inmaster;
-EOF
-}
-
-function standby_following_master
-{
-# Create another database after promotion
-$MASTER_PSQL -c "CREATE DATABASE beforepromotion"
-}
-
-# This script runs after the standby has been promoted. Old Master is still
-# running.
-function after_promotion
-{
-$MASTER_PSQL -c "CREATE DATABASE master_afterpromotion"
-
-$STANDBY_PSQL -c "CREATE DATABASE standby_afterpromotion"
-}
-
-# Compare results generated by querying new master after rewind
-function after_rewind
-{
-$MASTER_PSQL -c "SELECT datname from pg_database"
-}
-
-# Run the test
-. sql/run_test.sh
+++ /dev/null
-#!/bin/bash
-
-# This file has the .sql extension, but it is actually launched as a shell
-# script. This contortion is necessary because pg_regress normally uses
-# psql to run the input scripts, and requires them to have the .sql
-# extension, but we use a custom launcher script that runs the scripts using
-# a shell instead.
-
-# Test how pg_rewind reacts to extra files and directories in the data dirs.
-
-TESTNAME=extrafiles
-
-. sql/config_test.sh
-
-# Create a subdir that will be present in both
-function before_standby
-{
- mkdir $TEST_MASTER/tst_both_dir
- echo "in both1" > $TEST_MASTER/tst_both_dir/both_file1
- echo "in both2" > $TEST_MASTER/tst_both_dir/both_file2
- mkdir $TEST_MASTER/tst_both_dir/both_subdir/
- echo "in both3" > $TEST_MASTER/tst_both_dir/both_subdir/both_file3
-}
-
-# Create subdirs that will be present only in one data dir.
-function standby_following_master
-{
- mkdir $TEST_STANDBY/tst_standby_dir
- echo "in standby1" > $TEST_STANDBY/tst_standby_dir/standby_file1
- echo "in standby2" > $TEST_STANDBY/tst_standby_dir/standby_file2
- mkdir $TEST_STANDBY/tst_standby_dir/standby_subdir/
- echo "in standby3" > $TEST_STANDBY/tst_standby_dir/standby_subdir/standby_file3
- mkdir $TEST_MASTER/tst_master_dir
- echo "in master1" > $TEST_MASTER/tst_master_dir/master_file1
- echo "in master2" > $TEST_MASTER/tst_master_dir/master_file2
- mkdir $TEST_MASTER/tst_master_dir/master_subdir/
- echo "in master3" > $TEST_MASTER/tst_master_dir/master_subdir/master_file3
-}
-
-function after_promotion
-{
- :
-}
-
-# See what files and directories are present after rewind.
-function after_rewind
-{
- (cd $TEST_MASTER; find tst_* | sort)
-}
-
-# Run the test
-. sql/run_test.sh
+++ /dev/null
-#!/bin/bash
-#
-# pg_rewind.sh
-#
-# Test driver for pg_rewind. This test script initdb's and configures a
-# cluster and creates a table with some data in it. Then, it makes a
-# standby of it with pg_basebackup, and promotes the standby.
-#
-# The result is two clusters, so that the old "master" cluster can be
-# resynchronized with pg_rewind to catch up with the new "standby" cluster.
-# This test can be run with either a local data folder or a remote
-# connection as source.
-#
-# Before running this script, the calling script should've included
-# config_test.sh, and defined four functions to define the test case:
-#
-# before_standby - runs after initializing the master, before creating the
-# standby
-# standby_following_master - runs after standby has been created and started
-# after_promotion - runs after standby has been promoted, but old master is
-# still running
-# after_rewind - runs after pg_rewind and after restarting the rewound
-# old master
-#
-# In those functions, the test script can use $MASTER_PSQL and $STANDBY_PSQL
-# to run psql against the master and standby servers, to cause the servers
-# to diverge.
-
-PATH=$bindir:$PATH
-export PATH
-
-# Initialize master, data checksums are mandatory
-rm -rf $TEST_MASTER
-initdb -N -A trust -D $TEST_MASTER >>$log_path
-
-# Custom parameters for master's postgresql.conf
-cat >> $TEST_MASTER/postgresql.conf <<EOF
-wal_level = hot_standby
-max_wal_senders = 2
-wal_keep_segments = 20
-checkpoint_segments = 50
-shared_buffers = 1MB
-wal_log_hints = on
-log_line_prefix = 'M %m %p '
-hot_standby = on
-autovacuum = off
-max_connections = 50
-listen_addresses = '$LISTEN_ADDRESSES'
-port = $PORT_MASTER
-EOF
-
-# Accept replication connections on master
-cat >> $TEST_MASTER/pg_hba.conf <<EOF
-local replication all trust
-host replication all 127.0.0.1/32 trust
-host replication all ::1/128 trust
-EOF
-
-pg_ctl -w -D $TEST_MASTER start >>$log_path 2>&1
-
-#### Now run the test-specific parts to initialize the master before setting
-# up standby
-echo "Master initialized and running."
-before_standby
-
-# Set up standby with necessary parameter
-rm -rf $TEST_STANDBY
-
-# Base backup is taken with xlog files included
-pg_basebackup -D $TEST_STANDBY -p $PORT_MASTER -x >>$log_path 2>&1
-echo "port = $PORT_STANDBY" >> $TEST_STANDBY/postgresql.conf
-
-cat > $TEST_STANDBY/recovery.conf <<EOF
-primary_conninfo='port=$PORT_MASTER'
-standby_mode=on
-recovery_target_timeline='latest'
-EOF
-
-# Start standby
-pg_ctl -w -D $TEST_STANDBY start >>$log_path 2>&1
-
-#### Now run the test-specific parts to run after standby has been started
-# up standby
-echo "Standby initialized and running."
-standby_following_master
-
-# sleep a bit to make sure the standby has caught up.
-sleep 1
-
-# Now promote slave and insert some new data on master, this will put
-# the master out-of-sync with the standby.
-pg_ctl -w -D $TEST_STANDBY promote >>$log_path 2>&1
-sleep 1
-
-#### Now run the test-specific parts to run after promotion
-echo "Standby promoted."
-after_promotion
-
-# Stop the master and be ready to perform the rewind
-pg_ctl -w -D $TEST_MASTER stop -m fast >>$log_path 2>&1
-
-# At this point, the rewind processing is ready to run.
-# We now have a very simple scenario with a few diverged WAL record.
-# The real testing begins really now with a bifurcation of the possible
-# scenarios that pg_rewind supports.
-
-# Keep a temporary postgresql.conf for master node or it would be
-# overwritten during the rewind.
-cp $TEST_MASTER/postgresql.conf $TESTROOT/master-postgresql.conf.tmp
-
-# Now run pg_rewind
-echo "Running pg_rewind..."
-echo "Running pg_rewind..." >> $log_path
-if [ $TEST_SUITE == "local" ]; then
- # Do rewind using a local pgdata as source
- pg_rewind \
- --source-pgdata=$TEST_STANDBY \
- --target-pgdata=$TEST_MASTER >>$log_path 2>&1
-elif [ $TEST_SUITE == "remote" ]; then
- # Do rewind using a remote connection as source
- pg_rewind \
- --source-server="port=$PORT_STANDBY dbname=postgres" \
- --target-pgdata=$TEST_MASTER >>$log_path 2>&1
-else
- # Cannot come here normally
- echo "Incorrect test suite specified"
- exit 1
-fi
-
-# Now move back postgresql.conf with old settings
-mv $TESTROOT/master-postgresql.conf.tmp $TEST_MASTER/postgresql.conf
-
-# Plug-in rewound node to the now-promoted standby node
-cat > $TEST_MASTER/recovery.conf <<EOF
-primary_conninfo='port=$PORT_STANDBY'
-standby_mode=on
-recovery_target_timeline='latest'
-EOF
-
-# Restart the master to check that rewind went correctly
-pg_ctl -w -D $TEST_MASTER start >>$log_path 2>&1
-
-#### Now run the test-specific parts to check the result
-echo "Old master restarted after rewind."
-after_rewind
-
-# Stop remaining servers
-pg_ctl stop -D $TEST_MASTER -m fast -w >>$log_path 2>&1
-pg_ctl stop -D $TEST_STANDBY -m fast -w >>$log_path 2>&1
--- /dev/null
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 8;
+
+use RewindTest;
+
+my %rewind_test_callbacks = (
+ # Create a test table and insert a row in master.
+ 'before_standby' => sub {
+ master_psql("CREATE TABLE tbl1 (d text)");
+ master_psql("INSERT INTO tbl1 VALUES ('in master')");
+ master_psql("CHECKPOINT");
+ },
+
+ # Create another database after promotion
+ standby_following_master => sub {
+ # Insert additional data on master that will be replicated to standby
+ master_psql("INSERT INTO tbl1 values ('in master, before promotion')");
+ # Launch checkpoint after standby has been started
+ master_psql('CHECKPOINT');
+ },
+
+ # This function runs after the standby has been promoted. Old Master is
+ # still running.
+ after_promotion => sub {
+ # Insert a row in the old master. This causes the master and standby
+ # to have "diverged", it's no longer possible to just apply the
+ # standy's logs over master directory - you need to rewind.
+ master_psql("INSERT INTO tbl1 VALUES ('in master, after promotion')");
+
+ # Also insert a new row in the standby, which won't be present in the
+ # old master.
+ standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
+ },
+
+ # Compare results generated by querying new master after rewind
+ after_rewind => sub {
+ command_is(['psql', '-A', '-t', '--no-psqlrc', "-d $connstr_master",
+ '-c' , 'SELECT * FROM tbl1'],
+ qq(in master
+in master, before promotion
+in standby, after promotion
+),
+ 'check_table_content');
+ }
+);
+
+RewindTest::run_rewind_test('basic', 'local', %rewind_test_callbacks);
+RewindTest::run_rewind_test('basic', 'remote', %rewind_test_callbacks);
--- /dev/null
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 8;
+
+use RewindTest;
+
+my %rewind_test_callbacks = (
+ # Create a database in master.
+ 'before_standby' => sub {
+ master_psql('CREATE DATABASE inmaster');
+ },
+
+ # Create another database after promotion
+ standby_following_master => sub {
+ master_psql('CREATE DATABASE beforepromotion');
+ },
+
+ # This function runs after the standby has been promoted. Old Master is
+ # still running.
+ after_promotion => sub {
+ master_psql('CREATE DATABASE master_afterpromotion');
+ standby_psql('CREATE DATABASE standby_afterpromotion');
+ },
+
+ # Compare results generated by querying new master after rewind
+ after_rewind => sub {
+ command_is(['psql', '-A', '-t', '--no-psqlrc', "-c $connstr_master",
+ '-c' , 'SELECT datname FROM pg_database'],
+ qq(template1
+template0
+postgres
+inmaster
+beforepromotion
+standby_afterpromotion
+),
+ 'check_database_names');
+ }
+);
+
+RewindTest::run_rewind_test('databases', 'local', %rewind_test_callbacks);
+RewindTest::run_rewind_test('databases', 'remote', %rewind_test_callbacks);
--- /dev/null
+# Test how pg_rewind reacts to extra files and directories in the data dirs.
+
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 4;
+
+use File::Find;
+
+use RewindTest;
+
+my %rewind_test_callbacks = (
+ # Create a subdir that will be present in both
+ 'before_standby' => sub {
+ mkdir "$test_master_datadir/tst_both_dir";
+ append_to_file "$test_master_datadir/tst_both_dir/both_file1", "in both1";
+ append_to_file "$test_master_datadir/tst_both_dir/both_file2", "in both2";
+ mkdir "$test_master_datadir/tst_both_dir/both_subdir/";
+ append_to_file "$test_master_datadir/tst_both_dir/both_subdir/both_file3", "in both3";
+ },
+
+ # Create subdirs that will be present only in one data dir.
+ standby_following_master => sub {
+ mkdir "$test_standby_datadir/tst_standby_dir";
+ append_to_file "$test_standby_datadir/tst_standby_dir/standby_file1", "in standby1";
+ append_to_file "$test_standby_datadir/tst_standby_dir/standby_file2", "in standby2";
+ mkdir "$test_standby_datadir/tst_standby_dir/standby_subdir/";
+ append_to_file "$test_standby_datadir/tst_standby_dir/standby_subdir/standby_file3", "in standby3";
+
+ mkdir "$test_master_datadir/tst_master_dir";
+ append_to_file "$test_master_datadir/tst_master_dir/master_file1", "in master1";
+ append_to_file "$test_master_datadir/tst_master_dir/master_file2", "in master2";
+ mkdir "$test_master_datadir/tst_master_dir/master_subdir/";
+ append_to_file "$test_master_datadir/tst_master_dir/master_subdir/master_file3", "in master3";
+ },
+
+ after_promotion => sub { },
+
+ # List files in the data directory after rewind.
+ after_rewind => sub {
+ my @paths;
+ find(sub {push @paths, $File::Find::name if $File::Find::name =~ m/.*tst_.*/},
+ $test_master_datadir);
+ @paths = sort @paths;
+ is_deeply(\@paths,
+ ["$test_master_datadir/tst_both_dir",
+ "$test_master_datadir/tst_both_dir/both_file1",
+ "$test_master_datadir/tst_both_dir/both_file2",
+ "$test_master_datadir/tst_both_dir/both_subdir",
+ "$test_master_datadir/tst_both_dir/both_subdir/both_file3",
+ "$test_master_datadir/tst_standby_dir",
+ "$test_master_datadir/tst_standby_dir/standby_file1",
+ "$test_master_datadir/tst_standby_dir/standby_file2",
+ "$test_master_datadir/tst_standby_dir/standby_subdir",
+ "$test_master_datadir/tst_standby_dir/standby_subdir/standby_file3"],
+ "file lists match");
+ },
+);
+
+RewindTest::run_rewind_test('extrafiles', 'local', %rewind_test_callbacks);
+RewindTest::run_rewind_test('extrafiles', 'remote', %rewind_test_callbacks);
program_version_ok
program_options_handling_ok
command_like
+ command_is
issues_sql_like
);
like($stdout, $expected_stdout, "$test_name: matches");
}
+sub command_is
+{
+ my ($cmd, $expected_stdout, $test_name) = @_;
+ my ($stdout, $stderr);
+ my $result = run $cmd, '>', \$stdout, '2>', \$stderr;
+ ok($result, "@$cmd exit code 0");
+ is($stderr, '', "@$cmd no stderr");
+ is($stdout, $expected_stdout, "$test_name: matches");
+}
+
sub issues_sql_like
{
my ($cmd, $expected_sql, $test_name) = @_;