aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_rewind/RewindTest.pm
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2015-12-02 18:46:16 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2015-12-02 18:46:16 -0300
commit1caef31d9e550408d0cbc5788a422dcb69736df5 (patch)
tree451c4745e315c8dba59415a83eb2c4963fded212 /src/bin/pg_rewind/RewindTest.pm
parentc7485a82c3e29103757db75bb9ff8dac597387dc (diff)
downloadpostgresql-1caef31d9e550408d0cbc5788a422dcb69736df5.tar.gz
postgresql-1caef31d9e550408d0cbc5788a422dcb69736df5.zip
Refactor Perl test code
The original code was a bit clunky; make it more amenable for further reuse by creating a new Perl package PostgresNode, which is an object-oriented representation of a single server, with some support routines such as init, start, stop, psql. This serves as a better basis on which to build further test code, and enables writing tests that use more than one server without too much complication. This commit modifies a lot of the existing test files, mostly to remove explicit calls to system commands (pg_ctl) replacing them with method calls of a PostgresNode object. The result is quite a bit more straightforward. Also move some initialization code to BEGIN and INIT blocks instead of having it straight in as top-level code. This commit also introduces package RecursiveCopy so that we can copy whole directories without having to depend on packages that may not be present on vanilla Perl 5.8 installations. I also ran perltidy on the modified files, which changes some code sites that are not otherwise touched by this patch. I tried to avoid this, but it ended up being more trouble than it's worth. Authors: Michael Paquier, Álvaro Herrera Review: Noah Misch
Diffstat (limited to 'src/bin/pg_rewind/RewindTest.pm')
-rw-r--r--src/bin/pg_rewind/RewindTest.pm216
1 files changed, 73 insertions, 143 deletions
diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm
index a4c17371dcf..c1c7d1fa19f 100644
--- a/src/bin/pg_rewind/RewindTest.pm
+++ b/src/bin/pg_rewind/RewindTest.pm
@@ -9,22 +9,20 @@ package RewindTest;
# To run a test, the test script (in t/ subdirectory) calls the functions
# in this module. These functions should be called in this sequence:
#
-# 1. init_rewind_test - sets up log file etc.
+# 1. setup_cluster - creates a PostgreSQL cluster that runs as the master
#
-# 2. setup_cluster - creates a PostgreSQL cluster that runs as the master
+# 2. start_master - starts the master server
#
-# 3. start_master - starts the master server
-#
-# 4. create_standby - runs pg_basebackup to initialize a standby server, and
+# 3. create_standby - runs pg_basebackup to initialize a standby server, and
# sets it up to follow the master.
#
-# 5. promote_standby - runs "pg_ctl promote" to promote the standby server.
+# 4. promote_standby - runs "pg_ctl promote" to promote the standby server.
# The old master keeps running.
#
-# 6. run_pg_rewind - stops the old master (if it's still running) and runs
+# 5. run_pg_rewind - stops the old master (if it's still running) and runs
# pg_rewind to synchronize it with the now-promoted standby server.
#
-# 7. clean_rewind_test - stops both servers used in the test, if they're
+# 6. clean_rewind_test - stops both servers used in the test, if they're
# still running.
#
# The test script can use the helper functions master_psql and standby_psql
@@ -37,27 +35,23 @@ package RewindTest;
use strict;
use warnings;
-use TestLib;
-use Test::More;
-
use Config;
+use Exporter 'import';
use File::Copy;
use File::Path qw(rmtree);
-use IPC::Run qw(run start);
+use IPC::Run qw(run);
+use PostgresNode;
+use TestLib;
+use Test::More;
-use Exporter 'import';
our @EXPORT = qw(
- $connstr_master
- $connstr_standby
- $test_master_datadir
- $test_standby_datadir
+ $node_master
+ $node_standby
- append_to_file
master_psql
standby_psql
check_query
- init_rewind_test
setup_cluster
start_master
create_standby
@@ -66,32 +60,24 @@ our @EXPORT = qw(
clean_rewind_test
);
-our $test_master_datadir = "$tmp_check/data_master";
-our $test_standby_datadir = "$tmp_check/data_standby";
-
-# Define non-conflicting ports for both nodes.
-my $port_master = $ENV{PGPORT};
-my $port_standby = $port_master + 1;
-
-my $connstr_master = "port=$port_master";
-my $connstr_standby = "port=$port_standby";
-
-$ENV{PGDATABASE} = "postgres";
+# Our nodes.
+our $node_master;
+our $node_standby;
sub master_psql
{
my $cmd = shift;
- system_or_bail 'psql', '-q', '--no-psqlrc', '-d', $connstr_master,
- '-c', "$cmd";
+ system_or_bail 'psql', '-q', '--no-psqlrc', '-d',
+ $node_master->connstr('postgres'), '-c', "$cmd";
}
sub standby_psql
{
my $cmd = shift;
- system_or_bail 'psql', '-q', '--no-psqlrc', '-d', $connstr_standby,
- '-c', "$cmd";
+ system_or_bail 'psql', '-q', '--no-psqlrc', '-d',
+ $node_standby->connstr('postgres'), '-c', "$cmd";
}
# Run a query against the master, and check that the output matches what's
@@ -103,8 +89,9 @@ sub check_query
# we want just the output, no formatting
my $result = run [
- 'psql', '-q', '-A', '-t', '--no-psqlrc', '-d',
- $connstr_master, '-c', $query ],
+ 'psql', '-q', '-A', '-t', '--no-psqlrc', '-d',
+ $node_master->connstr('postgres'),
+ '-c', $query ],
'>', \$stdout, '2>', \$stderr;
# We don't use ok() for the exit code and stderr, because we want this
@@ -125,56 +112,16 @@ sub check_query
}
}
-# Run a query once a second, until it returns 't' (i.e. SQL boolean true).
-sub poll_query_until
-{
- my ($query, $connstr) = @_;
-
- my $max_attempts = 30;
- my $attempts = 0;
- my ($stdout, $stderr);
-
- while ($attempts < $max_attempts)
- {
- my $cmd = [ 'psql', '-At', '-c', "$query", '-d', "$connstr" ];
- my $result = run $cmd, '>', \$stdout, '2>', \$stderr;
-
- chomp($stdout);
- $stdout =~ s/\r//g if $Config{osname} eq 'msys';
- if ($stdout eq "t")
- {
- return 1;
- }
-
- # Wait a second before retrying.
- sleep 1;
- $attempts++;
- }
-
- # The query result didn't change in 30 seconds. Give up. Print the stderr
- # from the last attempt, hopefully that's useful for debugging.
- diag $stderr;
- return 0;
-}
-
-sub append_to_file
-{
- my ($filename, $str) = @_;
-
- open my $fh, ">>", $filename or die "could not open file $filename";
- print $fh $str;
- close $fh;
-}
-
sub setup_cluster
{
+
# Initialize master, data checksums are mandatory
- rmtree($test_master_datadir);
- standard_initdb($test_master_datadir);
+ $node_master = get_new_node();
+ $node_master->init;
# Custom parameters for master's postgresql.conf
- append_to_file(
- "$test_master_datadir/postgresql.conf", qq(
+ $node_master->append_conf(
+ "postgresql.conf", qq(
wal_level = hot_standby
max_wal_senders = 2
wal_keep_segments = 20
@@ -185,17 +132,11 @@ hot_standby = on
autovacuum = off
max_connections = 10
));
-
- # Accept replication connections on master
- configure_hba_for_replication $test_master_datadir;
}
sub start_master
{
- system_or_bail('pg_ctl' , '-w',
- '-D' , $test_master_datadir,
- '-l', "$log_path/master.log",
- "-o", "-p $port_master", 'start');
+ $node_master->start;
#### Now run the test-specific parts to initialize the master before setting
# up standby
@@ -203,24 +144,20 @@ sub start_master
sub create_standby
{
+ $node_standby = get_new_node();
+ $node_master->backup('my_backup');
+ $node_standby->init_from_backup($node_master, 'my_backup');
+ my $connstr_master = $node_master->connstr('postgres');
- # Set up standby with necessary parameter
- rmtree $test_standby_datadir;
-
- # Base backup is taken with xlog files included
- system_or_bail('pg_basebackup', '-D', $test_standby_datadir,
- '-p', $port_master, '-x');
- append_to_file(
- "$test_standby_datadir/recovery.conf", qq(
+ $node_standby->append_conf(
+ "recovery.conf", qq(
primary_conninfo='$connstr_master application_name=rewind_standby'
standby_mode=on
recovery_target_timeline='latest'
));
# Start standby
- system_or_bail('pg_ctl', '-w', '-D', $test_standby_datadir,
- '-l', "$log_path/standby.log",
- '-o', "-p $port_standby", 'start');
+ $node_standby->start;
# The standby may have WAL to apply before it matches the primary. That
# is fine, because no test examines the standby before promotion.
@@ -234,14 +171,15 @@ sub promote_standby
# Wait for the standby to receive and write all WAL.
my $wal_received_query =
"SELECT pg_current_xlog_location() = write_location FROM pg_stat_replication WHERE application_name = 'rewind_standby';";
- poll_query_until($wal_received_query, $connstr_master)
+ $node_master->poll_query_until('postgres', $wal_received_query)
or die "Timed out while waiting for standby to receive and write WAL";
# Now promote slave and insert some new data on master, this will put
# the master out-of-sync with the standby. Wait until the standby is
# out of recovery mode, and is ready to accept read-write connections.
- system_or_bail('pg_ctl', '-w', '-D', $test_standby_datadir, 'promote');
- poll_query_until("SELECT NOT pg_is_in_recovery()", $connstr_standby)
+ system_or_bail('pg_ctl', '-w', '-D', $node_standby->data_dir, 'promote');
+ $node_standby->poll_query_until('postgres',
+ "SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby";
# Force a checkpoint after the promotion. pg_rewind looks at the control
@@ -255,10 +193,14 @@ sub promote_standby
sub run_pg_rewind
{
- my $test_mode = shift;
+ my $test_mode = shift;
+ my $master_pgdata = $node_master->data_dir;
+ my $standby_pgdata = $node_standby->data_dir;
+ my $standby_connstr = $node_standby->connstr('postgres');
+ my $tmp_folder = TestLib::tempdir;
# Stop the master and be ready to perform the rewind
- system_or_bail('pg_ctl', '-D', $test_master_datadir, '-m', 'fast', 'stop');
+ $node_master->stop;
# At this point, the rewind processing is ready to run.
# We now have a very simple scenario with a few diverged WAL record.
@@ -267,31 +209,33 @@ sub run_pg_rewind
# Keep a temporary postgresql.conf for master node or it would be
# overwritten during the rewind.
- copy("$test_master_datadir/postgresql.conf",
- "$tmp_check/master-postgresql.conf.tmp");
+ copy(
+ "$master_pgdata/postgresql.conf",
+ "$tmp_folder/master-postgresql.conf.tmp");
# Now run pg_rewind
if ($test_mode eq "local")
{
+
# Do rewind using a local pgdata as source
# Stop the master and be ready to perform the rewind
- system_or_bail('pg_ctl', '-D', $test_standby_datadir,
- '-m', 'fast', 'stop');
- command_ok(['pg_rewind',
- "--debug",
- "--source-pgdata=$test_standby_datadir",
- "--target-pgdata=$test_master_datadir"],
- 'pg_rewind local');
+ $node_standby->stop;
+ command_ok(
+ [ 'pg_rewind',
+ "--debug",
+ "--source-pgdata=$standby_pgdata",
+ "--target-pgdata=$master_pgdata" ],
+ 'pg_rewind local');
}
elsif ($test_mode eq "remote")
{
+
# Do rewind using a remote connection as source
- command_ok(['pg_rewind',
- "--debug",
- "--source-server",
- "port=$port_standby dbname=postgres",
- "--target-pgdata=$test_master_datadir"],
- 'pg_rewind remote');
+ command_ok(
+ [ 'pg_rewind', "--debug",
+ "--source-server", $standby_connstr,
+ "--target-pgdata=$master_pgdata" ],
+ 'pg_rewind remote');
}
else
{
@@ -301,21 +245,21 @@ sub run_pg_rewind
}
# Now move back postgresql.conf with old settings
- move("$tmp_check/master-postgresql.conf.tmp",
- "$test_master_datadir/postgresql.conf");
+ move(
+ "$tmp_folder/master-postgresql.conf.tmp",
+ "$master_pgdata/postgresql.conf");
# Plug-in rewound node to the now-promoted standby node
- append_to_file(
- "$test_master_datadir/recovery.conf", qq(
+ my $port_standby = $node_standby->port;
+ $node_master->append_conf(
+ '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,
- '-l', "$log_path/master.log",
- '-o', "-p $port_master", 'start');
+ $node_master->start;
#### Now run the test-specific parts to check the result
}
@@ -323,22 +267,8 @@ recovery_target_timeline='latest'
# Clean up after the test. Stop both servers, if they're still running.
sub clean_rewind_test
{
- if ($test_master_datadir)
- {
- system
- 'pg_ctl', '-D', $test_master_datadir, '-m', 'immediate', 'stop';
- }
- if ($test_standby_datadir)
- {
- system
- 'pg_ctl', '-D', $test_standby_datadir, '-m', 'immediate', 'stop';
- }
+ $node_master->teardown_node if defined $node_master;
+ $node_standby->teardown_node if defined $node_standby;
}
-# Stop the test servers, just in case they're still running.
-END
-{
- my $save_rc = $?;
- clean_rewind_test();
- $? = $save_rc;
-}
+1;