Skip to content
Snippets Groups Projects
Commit 1caef31d authored by Alvaro Herrera's avatar Alvaro Herrera
Browse files

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
parent c7485a82
No related branches found
No related tags found
No related merge requests found
Showing
with 319 additions and 298 deletions
......@@ -4,6 +4,7 @@
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 14;
......
......@@ -2,6 +2,7 @@ use strict;
use warnings;
use Cwd;
use Config;
use PostgresNode;
use TestLib;
use Test::More tests => 51;
......@@ -9,12 +10,18 @@ program_help_ok('pg_basebackup');
program_version_ok('pg_basebackup');
program_options_handling_ok('pg_basebackup');
my $tempdir = tempdir;
start_test_server $tempdir;
my $tempdir = TestLib::tempdir;
command_fails(['pg_basebackup'],
my $node = get_new_node();
# Initialize node without replication settings
$node->init(hba_permit_replication => 0);
$node->start;
my $pgdata = $node->data_dir;
$node->command_fails(['pg_basebackup'],
'pg_basebackup needs target directory specified');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup" ],
'pg_basebackup fails because of hba');
......@@ -26,160 +33,191 @@ if (open BADCHARS, ">>$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
close BADCHARS;
}
configure_hba_for_replication "$tempdir/pgdata";
system_or_bail 'pg_ctl', '-D', "$tempdir/pgdata", 'reload';
$node->set_replication_conf();
system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup" ],
'pg_basebackup fails because of WAL configuration');
open CONF, ">>$tempdir/pgdata/postgresql.conf";
open CONF, ">>$pgdata/postgresql.conf";
print CONF "max_replication_slots = 10\n";
print CONF "max_wal_senders = 10\n";
print CONF "wal_level = archive\n";
close CONF;
restart_test_server;
$node->restart;
command_ok([ 'pg_basebackup', '-D', "$tempdir/backup" ],
$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup" ],
'pg_basebackup runs');
ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
is_deeply([sort(slurp_dir("$tempdir/backup/pg_xlog/"))],
[sort qw(. .. archive_status)],
'no WAL files copied');
is_deeply(
[ sort(slurp_dir("$tempdir/backup/pg_xlog/")) ],
[ sort qw(. .. archive_status) ],
'no WAL files copied');
command_ok(
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backup2", '--xlogdir',
"$tempdir/xlog2" ],
'separate xlog directory');
ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
ok(-d "$tempdir/xlog2/", 'xlog directory was created');
command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft' ],
$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft' ],
'tar format');
ok(-f "$tempdir/tarbackup/base.tar", 'backup tar was created');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-T=/foo" ],
'-T with empty old directory fails');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-T/foo=" ],
'-T with empty new directory fails');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
"-T/foo=/bar=/baz" ],
'-T with multiple = fails');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-Tfoo=/bar" ],
'-T with old directory not absolute fails');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-T/foo=bar" ],
'-T with new directory not absolute fails');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-Tfoo" ],
'-T with invalid format fails');
# Tar format doesn't support filenames longer than 100 bytes.
my $superlongname = "superlongname_" . ("x" x 100);
my $superlongpath = "$tempdir/pgdata/$superlongname";
my $superlongpath = "$pgdata/$superlongname";
open FILE, ">$superlongpath" or die "unable to create file $superlongpath";
close FILE;
command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft' ],
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft' ],
'pg_basebackup tar with long name fails');
unlink "$tempdir/pgdata/$superlongname";
unlink "$pgdata/$superlongname";
# The following tests test symlinks. Windows doesn't have symlinks, so
# skip on Windows.
SKIP: {
skip "symlinks not supported on Windows", 10 if ($windows_os);
SKIP:
{
skip "symlinks not supported on Windows", 10 if ($windows_os);
# Create a temporary directory in the system location and symlink it
# to our physical temp location. That way we can use shorter names
# for the tablespace directories, which hopefully won't run afoul of
# the 99 character length limit.
my $shorter_tempdir = tempdir_short . "/tempdir";
my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
symlink "$tempdir", $shorter_tempdir;
mkdir "$tempdir/tblspc1";
psql 'postgres',
"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';";
psql 'postgres', "CREATE TABLE test1 (a int) TABLESPACE tblspc1;";
command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft' ],
'tar format with tablespaces');
$node->psql('postgres',
"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
$node->psql('postgres', "CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft' ],
'tar format with tablespaces');
ok(-f "$tempdir/tarbackup2/base.tar", 'backup tar was created');
my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
is(scalar(@tblspc_tars), 1, 'one tablespace tar was created');
command_fails(
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp' ],
'plain format with tablespaces fails without tablespace mapping');
command_ok(
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp',
"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1" ],
'plain format with tablespaces succeeds with tablespace mapping');
ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
opendir(my $dh, "$tempdir/pgdata/pg_tblspc") or die;
opendir(my $dh, "$pgdata/pg_tblspc") or die;
ok( ( grep {
-l "$tempdir/backup1/pg_tblspc/$_"
and readlink "$tempdir/backup1/pg_tblspc/$_" eq
"$tempdir/tbackup/tblspc1"
} readdir($dh)),
-l "$tempdir/backup1/pg_tblspc/$_"
and readlink "$tempdir/backup1/pg_tblspc/$_" eq
"$tempdir/tbackup/tblspc1"
} readdir($dh)),
"tablespace symlink was updated");
closedir $dh;
mkdir "$tempdir/tbl=spc2";
psql 'postgres', "DROP TABLE test1;";
psql 'postgres', "DROP TABLESPACE tblspc1;";
psql 'postgres',
"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';";
command_ok(
$node->psql('postgres', "DROP TABLE test1;");
$node->psql('postgres', "DROP TABLESPACE tblspc1;");
$node->psql('postgres',
"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backup3", '-Fp',
"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2" ],
'mapping tablespace with = sign in path');
ok(-d "$tempdir/tbackup/tbl=spc2", 'tablespace with = sign was relocated');
psql 'postgres', "DROP TABLESPACE tblspc2;";
ok(-d "$tempdir/tbackup/tbl=spc2",
'tablespace with = sign was relocated');
$node->psql('postgres', "DROP TABLESPACE tblspc2;");
mkdir "$tempdir/$superlongname";
psql 'postgres',
"CREATE TABLESPACE tblspc3 LOCATION '$tempdir/$superlongname';";
command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup_l3", '-Ft' ],
'pg_basebackup tar with long symlink target');
psql 'postgres', "DROP TABLESPACE tblspc3;";
$node->psql('postgres',
"CREATE TABLESPACE tblspc3 LOCATION '$tempdir/$superlongname';");
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l3", '-Ft' ],
'pg_basebackup tar with long symlink target');
$node->psql('postgres', "DROP TABLESPACE tblspc3;");
}
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' ],
$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' ],
'pg_basebackup -R runs');
ok(-f "$tempdir/backupR/recovery.conf", 'recovery.conf was created');
my $recovery_conf = slurp_file "$tempdir/backupR/recovery.conf";
# using a character class for the final "'" here works around an apparent
# bug in several version of the Msys DTK perl
like($recovery_conf, qr/^standby_mode = 'on[']$/m, 'recovery.conf sets standby_mode');
like($recovery_conf, qr/^primary_conninfo = '.*port=$ENV{PGPORT}.*'$/m, 'recovery.conf sets primary_conninfo');
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' ],
like(
$recovery_conf,
qr/^standby_mode = 'on[']$/m,
'recovery.conf sets standby_mode');
like(
$recovery_conf,
qr/^primary_conninfo = '.*port=$ENV{PGPORT}.*'$/m,
'recovery.conf sets primary_conninfo');
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' ],
'pg_basebackup -X fetch runs');
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), 'WAL files copied');
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' ],
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")),
'WAL files copied');
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' ],
'pg_basebackup -X stream runs');
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), 'WAL files copied');
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")),
'WAL files copied');
command_fails([ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1' ],
$node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1' ],
'pg_basebackup with replication slot fails without -X stream');
command_fails([ 'pg_basebackup', '-D', "$tempdir/backupxs_sl_fail", '-X', 'stream', '-S', 'slot1' ],
$node->command_fails(
[ 'pg_basebackup', '-D',
"$tempdir/backupxs_sl_fail", '-X',
'stream', '-S',
'slot1' ],
'pg_basebackup fails with nonexistent replication slot');
psql 'postgres', q{SELECT * FROM pg_create_physical_replication_slot('slot1')};
my $lsn = psql 'postgres', q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'};
$node->psql('postgres',
q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
my $lsn = $node->psql('postgres',
q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
);
is($lsn, '', 'restart LSN of new slot is null');
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X', 'stream', '-S', 'slot1' ],
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
'stream', '-S', 'slot1' ],
'pg_basebackup -X stream with replication slot runs');
$lsn = psql 'postgres', q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'};
$lsn = $node->psql('postgres',
q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
);
like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X', 'stream', '-S', 'slot1', '-R' ],
$node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
'stream', '-S', 'slot1', '-R' ],
'pg_basebackup with replication slot and -R runs');
like(slurp_file("$tempdir/backupxs_sl_R/recovery.conf"),
qr/^primary_slot_name = 'slot1'$/m,
'recovery.conf sets primary_slot_name');
like(
slurp_file("$tempdir/backupxs_sl_R/recovery.conf"),
qr/^primary_slot_name = 'slot1'$/m,
'recovery.conf sets primary_slot_name');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 13;
my $tempdir = TestLib::tempdir;
program_help_ok('pg_controldata');
program_version_ok('pg_controldata');
program_options_handling_ok('pg_controldata');
command_fails(['pg_controldata'], 'pg_controldata without arguments fails');
command_fails([ 'pg_controldata', 'nonexistent' ],
'pg_controldata with nonexistent directory fails');
standard_initdb "$tempdir/data";
command_like([ 'pg_controldata', "$tempdir/data" ],
my $node = get_new_node();
$node->init;
$node->start;
command_like([ 'pg_controldata', $node->data_dir ],
qr/checkpoint/, 'pg_controldata produces output');
use strict;
use warnings;
use Config;
use PostgresNode;
use TestLib;
use Test::More tests => 17;
......@@ -16,13 +18,11 @@ command_exit_is([ 'pg_ctl', 'start', '-D', "$tempdir/nonexistent" ],
command_ok([ 'pg_ctl', 'initdb', '-D', "$tempdir/data", '-o', '-N' ],
'pg_ctl initdb');
command_ok(
[ $ENV{PG_REGRESS}, '--config-auth',
"$tempdir/data" ],
command_ok([ $ENV{PG_REGRESS}, '--config-auth', "$tempdir/data" ],
'configure authentication');
open CONF, ">>$tempdir/data/postgresql.conf";
print CONF "fsync = off\n";
if (! $windows_os)
if (!$windows_os)
{
print CONF "listen_addresses = ''\n";
print CONF "unix_socket_directories = '$tempdir_short'\n";
......@@ -34,6 +34,7 @@ else
close CONF;
command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data", '-w' ],
'pg_ctl start -w');
# sleep here is because Windows builds can't check postmaster.pid exactly,
# so they may mistake a pre-existing postmaster.pid for one created by the
# postmaster they start. Waiting more than the 2 seconds slop time allowed
......
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 3;
......@@ -9,14 +11,15 @@ my $tempdir_short = TestLib::tempdir_short;
command_exit_is([ 'pg_ctl', 'status', '-D', "$tempdir/nonexistent" ],
4, 'pg_ctl status with nonexistent directory');
standard_initdb "$tempdir/data";
my $node = get_new_node();
$node->init;
command_exit_is([ 'pg_ctl', 'status', '-D', "$tempdir/data" ],
command_exit_is([ 'pg_ctl', 'status', '-D', $node->data_dir ],
3, 'pg_ctl status with server not running');
system_or_bail 'pg_ctl', '-l', "$tempdir/logfile", '-D',
"$tempdir/data", '-w', 'start';
command_exit_is([ 'pg_ctl', 'status', '-D', "$tempdir/data" ],
$node->data_dir, '-w', 'start';
command_exit_is([ 'pg_ctl', 'status', '-D', $node->data_dir ],
0, 'pg_ctl status with server running');
system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data", '-m', 'fast';
system_or_bail 'pg_ctl', 'stop', '-D', $node->data_dir, '-m', 'fast';
......@@ -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;
......@@ -17,7 +17,7 @@ sub run_test
RewindTest::setup_cluster();
RewindTest::start_master();
my $test_master_datadir = $RewindTest::test_master_datadir;
my $test_master_datadir = $node_master->data_dir;
# Create a subdir and files that will be present in both
mkdir "$test_master_datadir/tst_both_dir";
......@@ -30,6 +30,7 @@ sub run_test
RewindTest::create_standby();
# Create different subdirs and files in master and standby
my $test_standby_datadir = $node_standby->data_dir;
mkdir "$test_standby_datadir/tst_standby_dir";
append_to_file "$test_standby_datadir/tst_standby_dir/standby_file1",
......
......@@ -23,11 +23,13 @@ sub run_test
{
my $test_mode = shift;
my $master_xlogdir = "$tmp_check/xlog_master";
my $master_xlogdir = "${TestLib::tmp_check}/xlog_master";
rmtree($master_xlogdir);
RewindTest::setup_cluster();
my $test_master_datadir = $node_master->data_dir;
# turn pg_xlog into a symlink
print("moving $test_master_datadir/pg_xlog to $master_xlogdir\n");
move("$test_master_datadir/pg_xlog", $master_xlogdir) or die;
......
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 13;
......@@ -7,20 +9,22 @@ program_help_ok('clusterdb');
program_version_ok('clusterdb');
program_options_handling_ok('clusterdb');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
issues_sql_like(
[ 'clusterdb', 'postgres' ],
$node->issues_sql_like(
['clusterdb'],
qr/statement: CLUSTER;/,
'SQL CLUSTER run');
command_fails([ 'clusterdb', '-t', 'nonexistent', 'postgres' ],
$node->command_fails([ 'clusterdb', '-t', 'nonexistent' ],
'fails with nonexistent table');
psql 'postgres',
'CREATE TABLE test1 (a int); CREATE INDEX test1x ON test1 (a); CLUSTER test1 USING test1x';
issues_sql_like(
[ 'clusterdb', '-t', 'test1', 'postgres' ],
$node->psql('postgres',
'CREATE TABLE test1 (a int); CREATE INDEX test1x ON test1 (a); CLUSTER test1 USING test1x'
);
$node->issues_sql_like(
[ 'clusterdb', '-t', 'test1' ],
qr/statement: CLUSTER test1;/,
'cluster specific table');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 2;
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
# clusterdb -a is not compatible with -d, hence enforce environment variable
# correctly.
$ENV{PGDATABASE} = 'postgres';
issues_sql_like(
$node->issues_sql_like(
[ 'clusterdb', '-a' ],
qr/statement: CLUSTER.*statement: CLUSTER/s,
'cluster all databases');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 13;
......@@ -7,16 +9,18 @@ program_help_ok('createdb');
program_version_ok('createdb');
program_options_handling_ok('createdb');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
issues_sql_like(
$node->issues_sql_like(
[ 'createdb', 'foobar1' ],
qr/statement: CREATE DATABASE foobar1/,
'SQL CREATE DATABASE run');
issues_sql_like(
$node->issues_sql_like(
[ 'createdb', '-l', 'C', '-E', 'LATIN1', '-T', 'template0', 'foobar2' ],
qr/statement: CREATE DATABASE foobar2 ENCODING 'LATIN1'/,
'create database with encoding');
command_fails([ 'createdb', 'foobar1' ], 'fails if database already exists');
$node->command_fails([ 'createdb', 'foobar1' ],
'fails if database already exists');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 14;
......@@ -7,18 +9,17 @@ program_help_ok('createlang');
program_version_ok('createlang');
program_options_handling_ok('createlang');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
command_fails(
[ 'createlang', 'plpgsql', 'postgres' ],
$node->command_fails([ 'createlang', 'plpgsql' ],
'fails if language already exists');
psql 'postgres', 'DROP EXTENSION plpgsql';
issues_sql_like(
[ 'createlang', 'plpgsql', 'postgres' ],
$node->psql('postgres', 'DROP EXTENSION plpgsql');
$node->issues_sql_like(
[ 'createlang', 'plpgsql' ],
qr/statement: CREATE EXTENSION "plpgsql"/,
'SQL CREATE EXTENSION run');
command_like([ 'createlang', '--list', 'postgres' ],
qr/plpgsql/, 'list output');
$node->command_like([ 'createlang', '--list' ], qr/plpgsql/, 'list output');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 17;
......@@ -7,24 +9,26 @@ program_help_ok('createuser');
program_version_ok('createuser');
program_options_handling_ok('createuser');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
issues_sql_like(
$node->issues_sql_like(
[ 'createuser', 'user1' ],
qr/statement: CREATE ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;/,
'SQL CREATE USER run');
issues_sql_like(
$node->issues_sql_like(
[ 'createuser', '-L', 'role1' ],
qr/statement: CREATE ROLE role1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN;/,
'create a non-login role');
issues_sql_like(
$node->issues_sql_like(
[ 'createuser', '-r', 'user2' ],
qr/statement: CREATE ROLE user2 NOSUPERUSER NOCREATEDB CREATEROLE INHERIT LOGIN;/,
'create a CREATEROLE user');
issues_sql_like(
$node->issues_sql_like(
[ 'createuser', '-s', 'user3' ],
qr/statement: CREATE ROLE user3 SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;/,
'create a superuser');
command_fails([ 'createuser', 'user1' ], 'fails if role already exists');
$node->command_fails([ 'createuser', 'user1' ],
'fails if role already exists');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 11;
......@@ -7,13 +9,15 @@ program_help_ok('dropdb');
program_version_ok('dropdb');
program_options_handling_ok('dropdb');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
psql 'postgres', 'CREATE DATABASE foobar1';
issues_sql_like(
$node->psql('postgres', 'CREATE DATABASE foobar1');
$node->issues_sql_like(
[ 'dropdb', 'foobar1' ],
qr/statement: DROP DATABASE foobar1/,
'SQL DROP DATABASE run');
command_fails([ 'dropdb', 'nonexistent' ], 'fails with nonexistent database');
$node->command_fails([ 'dropdb', 'nonexistent' ],
'fails with nonexistent database');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 11;
......@@ -7,14 +9,15 @@ program_help_ok('droplang');
program_version_ok('droplang');
program_options_handling_ok('droplang');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
issues_sql_like(
$node->issues_sql_like(
[ 'droplang', 'plpgsql', 'postgres' ],
qr/statement: DROP EXTENSION "plpgsql"/,
'SQL DROP EXTENSION run');
command_fails(
$node->command_fails(
[ 'droplang', 'nonexistent', 'postgres' ],
'fails with nonexistent language');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 11;
......@@ -7,13 +9,15 @@ program_help_ok('dropuser');
program_version_ok('dropuser');
program_options_handling_ok('dropuser');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
psql 'postgres', 'CREATE ROLE foobar1';
issues_sql_like(
$node->psql('postgres', 'CREATE ROLE foobar1');
$node->issues_sql_like(
[ 'dropuser', 'foobar1' ],
qr/statement: DROP ROLE foobar1/,
'SQL DROP ROLE run');
command_fails([ 'dropuser', 'nonexistent' ], 'fails with nonexistent user');
$node->command_fails([ 'dropuser', 'nonexistent' ],
'fails with nonexistent user');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 10;
......@@ -9,7 +11,8 @@ program_options_handling_ok('pg_isready');
command_fails(['pg_isready'], 'fails with no server running');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
command_ok(['pg_isready'], 'succeeds with server running');
$node->command_ok(['pg_isready'], 'succeeds with server running');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 20;
......@@ -7,35 +9,36 @@ program_help_ok('reindexdb');
program_version_ok('reindexdb');
program_options_handling_ok('reindexdb');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
$ENV{PGOPTIONS} = '--client-min-messages=WARNING';
issues_sql_like(
$node->issues_sql_like(
[ 'reindexdb', 'postgres' ],
qr/statement: REINDEX DATABASE postgres;/,
'SQL REINDEX run');
psql 'postgres',
'CREATE TABLE test1 (a int); CREATE INDEX test1x ON test1 (a);';
issues_sql_like(
$node->psql('postgres',
'CREATE TABLE test1 (a int); CREATE INDEX test1x ON test1 (a);');
$node->issues_sql_like(
[ 'reindexdb', '-t', 'test1', 'postgres' ],
qr/statement: REINDEX TABLE test1;/,
'reindex specific table');
issues_sql_like(
$node->issues_sql_like(
[ 'reindexdb', '-i', 'test1x', 'postgres' ],
qr/statement: REINDEX INDEX test1x;/,
'reindex specific index');
issues_sql_like(
$node->issues_sql_like(
[ 'reindexdb', '-S', 'pg_catalog', 'postgres' ],
qr/statement: REINDEX SCHEMA pg_catalog;/,
'reindex specific schema');
issues_sql_like(
$node->issues_sql_like(
[ 'reindexdb', '-s', 'postgres' ],
qr/statement: REINDEX SYSTEM postgres;/,
'reindex system tables');
issues_sql_like(
$node->issues_sql_like(
[ 'reindexdb', '-v', '-t', 'test1', 'postgres' ],
qr/statement: REINDEX \(VERBOSE\) TABLE test1;/,
'reindex with verbose output');
use strict;
use warnings;
use TestLib;
use PostgresNode;
use Test::More tests => 2;
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
$ENV{PGOPTIONS} = '--client-min-messages=WARNING';
issues_sql_like(
$node->issues_sql_like(
[ 'reindexdb', '-a' ],
qr/statement: REINDEX.*statement: REINDEX/s,
'reindex all databases');
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 18;
......@@ -7,26 +9,27 @@ program_help_ok('vacuumdb');
program_version_ok('vacuumdb');
program_options_handling_ok('vacuumdb');
my $tempdir = tempdir;
start_test_server $tempdir;
my $node = get_new_node();
$node->init;
$node->start;
issues_sql_like(
$node->issues_sql_like(
[ 'vacuumdb', 'postgres' ],
qr/statement: VACUUM;/,
'SQL VACUUM run');
issues_sql_like(
$node->issues_sql_like(
[ 'vacuumdb', '-f', 'postgres' ],
qr/statement: VACUUM \(FULL\);/,
'vacuumdb -f');
issues_sql_like(
$node->issues_sql_like(
[ 'vacuumdb', '-F', 'postgres' ],
qr/statement: VACUUM \(FREEZE\);/,
'vacuumdb -F');
issues_sql_like(
$node->issues_sql_like(
[ 'vacuumdb', '-z', 'postgres' ],
qr/statement: VACUUM \(ANALYZE\);/,
'vacuumdb -z');
issues_sql_like(
$node->issues_sql_like(
[ 'vacuumdb', '-Z', 'postgres' ],
qr/statement: ANALYZE;/,
'vacuumdb -Z');
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment