Skip to content

Commit 027fa0f

Browse files
committed
basebackup_to_shell: Add TAP test.
Per gripe from Andres Freund. Thanks to Andres Freund, Thomas Munro, and Andrew Dunstan for advice on how to make this test work even on Windows. Discussion: https://postgr.es/m/CA+Tgmoat+zbzzZQJ7poXyUwiqxQxTaUid=auB4FejZ15VvDh4Q@mail.gmail.com
1 parent 26a0c02 commit 027fa0f

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

contrib/basebackup_to_shell/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ OBJS = \
77

88
PGFILEDESC = "basebackup_to_shell - target basebackup to shell command"
99

10+
TAP_TESTS = 1
11+
12+
export GZIP_PROGRAM=$(GZIP)
13+
export TAR
14+
1015
ifdef USE_PGXS
1116
PG_CONFIG = pg_config
1217
PGXS := $(shell $(PG_CONFIG) --pgxs)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright (c) 2021-2022, PostgreSQL Global Development Group
2+
3+
use strict;
4+
use warnings;
5+
6+
use PostgreSQL::Test::Cluster;
7+
use PostgreSQL::Test::Utils;
8+
use Test::More;
9+
10+
# For testing purposes, we just want basebackup_to_shell to write standard
11+
# input to a file. However, Windows doesn't have "cat" or any equivalent, so
12+
# we use "gzip" for this purpose.
13+
my $gzip = $ENV{'GZIP_PROGRAM'};
14+
if (!defined $gzip || $gzip eq '')
15+
{
16+
plan skip_all => 'gzip not available';
17+
}
18+
19+
my $node = PostgreSQL::Test::Cluster->new('primary');
20+
$node->init('allows_streaming' => 1);
21+
$node->append_conf('postgresql.conf',
22+
"shared_preload_libraries = 'basebackup_to_shell'");
23+
$node->start;
24+
$node->safe_psql('postgres', 'CREATE USER backupuser REPLICATION');
25+
$node->safe_psql('postgres', 'CREATE ROLE trustworthy');
26+
27+
# For nearly all pg_basebackup invocations some options should be specified,
28+
# to keep test times reasonable. Using @pg_basebackup_defs as the first
29+
# element of the array passed to IPC::Run interpolate the array (as it is
30+
# not a reference to an array)...
31+
my @pg_basebackup_defs = ('pg_basebackup', '--no-sync', '-cfast');
32+
33+
# This particular test module generally wants to run with -Xfetch, because
34+
# -Xstream is not supported with a backup target, and with -U backupuser.
35+
my @pg_basebackup_cmd = (@pg_basebackup_defs, '-U', 'backupuser', '-Xfetch');
36+
37+
# Can't use this module without setting basebackup_to_shell.command.
38+
$node->command_fails_like(
39+
[ @pg_basebackup_cmd, '--target', 'shell' ],
40+
qr/shell command for backup is not configured/,
41+
'fails if basebackup_to_shell.command is not set');
42+
43+
# Configure basebackup_to_shell.command and reload the configuation file.
44+
my $backup_path = PostgreSQL::Test::Utils::tempdir;
45+
my $escaped_backup_path = $backup_path;
46+
$escaped_backup_path =~ s{\\}{\\\\}g if ($PostgreSQL::Test::Utils::windows_os);
47+
my $shell_command =
48+
$PostgreSQL::Test::Utils::windows_os
49+
? qq{$gzip --fast > "$escaped_backup_path\\\\%f.gz"}
50+
: qq{$gzip --fast > "$escaped_backup_path/%f.gz"};
51+
$node->append_conf('postgresql.conf',
52+
"basebackup_to_shell.command='$shell_command'");
53+
$node->reload();
54+
55+
# Should work now.
56+
$node->command_ok(
57+
[ @pg_basebackup_cmd, '--target', 'shell' ],
58+
'backup with no detail: pg_basebackup');
59+
verify_backup('', $backup_path, "backup with no detail");
60+
61+
# Should fail with a detail.
62+
$node->command_fails_like(
63+
[ @pg_basebackup_cmd, '--target', 'shell:foo' ],
64+
qr/a target detail is not permitted because the configured command does not include %d/,
65+
'fails if detail provided without %d');
66+
67+
# Reconfigure to restrict access and require a detail.
68+
$shell_command =
69+
$PostgreSQL::Test::Utils::windows_os
70+
? qq{$gzip --fast > "$escaped_backup_path\\\\%d.%f.gz"}
71+
: qq{$gzip --fast > "$escaped_backup_path/%d.%f.gz"};
72+
$node->append_conf('postgresql.conf',
73+
"basebackup_to_shell.command='$shell_command'");
74+
$node->append_conf('postgresql.conf',
75+
"basebackup_to_shell.required_role='trustworthy'");
76+
$node->reload();
77+
78+
# Should fail due to lack of permission.
79+
$node->command_fails_like(
80+
[ @pg_basebackup_cmd, '--target', 'shell' ],
81+
qr/permission denied to use basebackup_to_shell/,
82+
'fails if required_role not granted');
83+
84+
# Should fail due to lack of a detail.
85+
$node->safe_psql('postgres', 'GRANT trustworthy TO backupuser');
86+
$node->command_fails_like(
87+
[ @pg_basebackup_cmd, '--target', 'shell' ],
88+
qr/a target detail is required because the configured command includes %d/,
89+
'fails if %d is present and detail not given');
90+
91+
# Should work.
92+
$node->command_ok(
93+
[ @pg_basebackup_cmd, '--target', 'shell:bar' ],
94+
'backup with detail: pg_basebackup');
95+
verify_backup('bar.', $backup_path, "backup with detail");
96+
97+
done_testing();
98+
99+
sub verify_backup
100+
{
101+
my ($prefix, $backup_dir, $test_name) = @_;
102+
103+
ok(-f "$backup_dir/${prefix}backup_manifest.gz",
104+
"$test_name: backup_manifest.gz was created");
105+
ok(-f "$backup_dir/${prefix}base.tar.gz",
106+
"$test_name: base.tar.gz was created");
107+
108+
SKIP: {
109+
my $tar = $ENV{TAR};
110+
skip "no tar program available", 1 if (!defined $tar || $tar eq '');
111+
112+
# Decompress.
113+
system_or_bail($gzip, '-d',
114+
$backup_dir . '/' . $prefix . 'backup_manifest.gz');
115+
system_or_bail($gzip, '-d',
116+
$backup_dir . '/' . $prefix . 'base.tar.gz');
117+
118+
# Untar.
119+
my $extract_path = PostgreSQL::Test::Utils::tempdir;
120+
system_or_bail($tar, 'xf', $backup_dir . '/' . $prefix . 'base.tar',
121+
'-C', $extract_path);
122+
123+
# Verify.
124+
$node->command_ok([ 'pg_verifybackup', '-n',
125+
'-m', "${backup_dir}/${prefix}backup_manifest",
126+
'-e', $extract_path ],
127+
"$test_name: backup verifies ok");
128+
}
129+
}

0 commit comments

Comments
 (0)