Refactor the pg_rewind regression tests to use TAP
authorHeikki Linnakangas <[email protected]>
Wed, 7 Jan 2015 13:22:07 +0000 (15:22 +0200)
committerHeikki Linnakangas <[email protected]>
Fri, 16 Jan 2015 11:37:06 +0000 (13:37 +0200)
15 files changed:
contrib/pg_rewind/Makefile
contrib/pg_rewind/RewindTest.pm [new file with mode: 0644]
contrib/pg_rewind/expected/basictest.out [deleted file]
contrib/pg_rewind/expected/databases.out [deleted file]
contrib/pg_rewind/expected/extrafiles.out [deleted file]
contrib/pg_rewind/launcher [deleted file]
contrib/pg_rewind/sql/basictest.sql [deleted file]
contrib/pg_rewind/sql/config_test.sh [deleted file]
contrib/pg_rewind/sql/databases.sql [deleted file]
contrib/pg_rewind/sql/extrafiles.sql [deleted file]
contrib/pg_rewind/sql/run_test.sh [deleted file]
contrib/pg_rewind/t/001_basic.pl [new file with mode: 0644]
contrib/pg_rewind/t/002_databases.pl [new file with mode: 0644]
contrib/pg_rewind/t/003_extrafiles.pl [new file with mode: 0644]
src/test/perl/TestLib.pm

index 241c775bf56c82be5314c67ad7d198ab4c14ba52..ab778002d05e733e7f41df5fab4ba2ef0b76b2b0 100644 (file)
@@ -10,8 +10,8 @@ PROGRAM = pg_rewind
 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)
@@ -36,16 +36,5 @@ endif
 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)
diff --git a/contrib/pg_rewind/RewindTest.pm b/contrib/pg_rewind/RewindTest.pm
new file mode 100644 (file)
index 0000000..2578464
--- /dev/null
@@ -0,0 +1,238 @@
+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';
+       }
+}
diff --git a/contrib/pg_rewind/expected/basictest.out b/contrib/pg_rewind/expected/basictest.out
deleted file mode 100644 (file)
index b67ead5..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-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)
-
diff --git a/contrib/pg_rewind/expected/databases.out b/contrib/pg_rewind/expected/databases.out
deleted file mode 100644 (file)
index e486107..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-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)
-
diff --git a/contrib/pg_rewind/expected/extrafiles.out b/contrib/pg_rewind/expected/extrafiles.out
deleted file mode 100644 (file)
index 8e3f3f1..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-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
diff --git a/contrib/pg_rewind/launcher b/contrib/pg_rewind/launcher
deleted file mode 100755 (executable)
index 56f8cc0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-#
-# Normally, psql feeds the files in sql/ directory to psql, but we want to
-# run them as shell scripts instead.
-
-bash
diff --git a/contrib/pg_rewind/sql/basictest.sql b/contrib/pg_rewind/sql/basictest.sql
deleted file mode 100644 (file)
index cee59c2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/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
diff --git a/contrib/pg_rewind/sql/config_test.sh b/contrib/pg_rewind/sql/config_test.sh
deleted file mode 100755 (executable)
index 0baa468..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/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"
diff --git a/contrib/pg_rewind/sql/databases.sql b/contrib/pg_rewind/sql/databases.sql
deleted file mode 100644 (file)
index 60520d2..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/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
diff --git a/contrib/pg_rewind/sql/extrafiles.sql b/contrib/pg_rewind/sql/extrafiles.sql
deleted file mode 100644 (file)
index 8512369..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/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
diff --git a/contrib/pg_rewind/sql/run_test.sh b/contrib/pg_rewind/sql/run_test.sh
deleted file mode 100755 (executable)
index a6b934c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-#!/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
diff --git a/contrib/pg_rewind/t/001_basic.pl b/contrib/pg_rewind/t/001_basic.pl
new file mode 100644 (file)
index 0000000..8786cf6
--- /dev/null
@@ -0,0 +1,50 @@
+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);
diff --git a/contrib/pg_rewind/t/002_databases.pl b/contrib/pg_rewind/t/002_databases.pl
new file mode 100644 (file)
index 0000000..d90c90f
--- /dev/null
@@ -0,0 +1,42 @@
+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);
diff --git a/contrib/pg_rewind/t/003_extrafiles.pl b/contrib/pg_rewind/t/003_extrafiles.pl
new file mode 100644 (file)
index 0000000..01751ae
--- /dev/null
@@ -0,0 +1,61 @@
+# 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);
index 003cd9a2cca9d56ad2ecdd4cf2a9b192939a6bba..a035472d83b3bd98d9fec31a5443aab5b288d305 100644 (file)
@@ -20,6 +20,7 @@ our @EXPORT = qw(
   program_version_ok
   program_options_handling_ok
   command_like
+  command_is
   issues_sql_like
 );
 
@@ -200,6 +201,16 @@ sub command_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) = @_;