@ -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,101 +33,104 @@ 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 ) ] ,
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:
{
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' ] ,
$ 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
@ -130,56 +140,84 @@ SKIP: {
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' ] ,
$ 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' ) ;
psql 'postgres' , "DROP TABLESPACE tblspc3;" ;
$ 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" ) ,
like (
slurp_file ( "$tempdir/backupxs_sl_R/recovery.conf" ) ,
qr/^primary_slot_name = 'slot1'$/ m ,
'recovery.conf sets primary_slot_name' ) ;