From d37bd08133f1515102db21c48b074b39f224e23b Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Fri, 25 Mar 2022 12:19:44 -0400
Subject: [PATCH] Tests.

---
 contrib/basebackup_to_shell/Makefile       |   4 +
 contrib/basebackup_to_shell/t/001_basic.pl | 110 +++++++++++++++++++++
 2 files changed, 114 insertions(+)
 create mode 100644 contrib/basebackup_to_shell/t/001_basic.pl

diff --git a/contrib/basebackup_to_shell/Makefile b/contrib/basebackup_to_shell/Makefile
index f31dfaae9c..bbfebcc9a1 100644
--- a/contrib/basebackup_to_shell/Makefile
+++ b/contrib/basebackup_to_shell/Makefile
@@ -7,6 +7,10 @@ OBJS = \
 
 PGFILEDESC = "basebackup_to_shell - target basebackup to shell command"
 
+TAP_TESTS = 1
+
+export TAR
+
 ifdef USE_PGXS
 PG_CONFIG = pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
diff --git a/contrib/basebackup_to_shell/t/001_basic.pl b/contrib/basebackup_to_shell/t/001_basic.pl
new file mode 100644
index 0000000000..a152fcbc1e
--- /dev/null
+++ b/contrib/basebackup_to_shell/t/001_basic.pl
@@ -0,0 +1,110 @@
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init('allows_streaming' => 1);
+$node->append_conf('postgresql.conf',
+				   "shared_preload_libraries = 'basebackup_to_shell'");
+$node->start;
+$node->safe_psql('postgres', 'CREATE USER backupuser REPLICATION');
+$node->safe_psql('postgres', 'CREATE ROLE trustworthy');
+
+# For nearly all pg_basebackup invocations some options should be specified,
+# to keep test times reasonable. Using @pg_basebackup_defs as the first
+# element of the array passed to IPC::Run interpolate the array (as it is
+# not a reference to an array)...
+my @pg_basebackup_defs = ('pg_basebackup', '--no-sync', '-cfast');
+
+# This particular test module generally wants to run with -Xfetch, because
+# -Xstream is not supported with a backup target, and with -U backupuser.
+my @pg_basebackup_cmd = (@pg_basebackup_defs, '-U', 'backupuser', '-Xfetch');
+
+# Can't use this module without setting basebackup_to_shell.command.
+$node->command_fails_like(
+    [ @pg_basebackup_cmd, '--target', 'shell' ],
+	qr/shell command for backup is not configured/,
+	'fails if basebackup_to_shell.command is not set');
+
+# Configure basebackup_to_shell.command and reload the configuation file.
+my $backup_path = PostgreSQL::Test::Utils::tempdir;
+my $shell_command =
+	$PostgreSQL::Test::Utils::windows_os
+	? qq{type con > "$backup_path\\\\%f"} : qq{cat > "$backup_path/%f"};
+$node->append_conf('postgresql.conf',
+				   "basebackup_to_shell.command='$shell_command'");
+$node->reload();
+
+# Should work now.
+$node->command_ok(
+    [ @pg_basebackup_cmd, '--target', 'shell' ],
+	'backup with no detail: pg_basebackup');
+verify_backup('', $backup_path, "backup with no detail");
+
+# Should fail with a detail.
+$node->command_fails_like(
+    [ @pg_basebackup_cmd, '--target', 'shell:foo' ],
+	qr/a target detail is not permitted because the configured command does not include %d/,
+	'fails if detail provided without %d');
+
+# Reconfigure to restrict access and require a detail.
+$shell_command =
+	$PostgreSQL::Test::Utils::windows_os
+	? qq{type con > "$backup_path\\\\%d.%f"} : qq{cat > "$backup_path/%d.%f"};
+$node->append_conf('postgresql.conf',
+				   "basebackup_to_shell.command='$shell_command'");
+$node->append_conf('postgresql.conf',
+				   "basebackup_to_shell.required_role='trustworthy'");
+$node->reload();
+
+# Should fail due to lack of permission.
+$node->command_fails_like(
+    [ @pg_basebackup_cmd, '--target', 'shell' ],
+	qr/permission denied to use basebackup_to_shell/,
+	'fails if required_role not granted');
+
+# Should fail due to lack of a detail.
+$node->safe_psql('postgres', 'GRANT trustworthy TO backupuser');
+$node->command_fails_like(
+    [ @pg_basebackup_cmd, '--target', 'shell' ],
+	qr/a target detail is required because the configured command includes %d/,
+	'fails if %d is present and detail not given');
+
+# Should work.
+$node->command_ok(
+    [ @pg_basebackup_cmd, '--target', 'shell:bar' ],
+	'backup with detail: pg_basebackup');
+verify_backup('bar.', $backup_path, "backup with detail");
+
+done_testing();
+
+sub verify_backup
+{
+	my ($prefix, $backup_dir, $test_name) = @_;
+
+	ok(-f "$backup_dir/${prefix}backup_manifest",
+	   "$test_name: backup_manifest was created");
+	ok(-f "$backup_dir/${prefix}base.tar",
+	   "$test_name: base.tar was created");
+
+	SKIP: {
+		my $tar = $ENV{TAR};
+		skip "no tar program available", 1 if (!defined $tar || $tar eq '');
+
+		# Untar.
+		my $extract_path = PostgreSQL::Test::Utils::tempdir;
+		system_or_bail($tar, 'xf', $backup_dir . '/' . $prefix . 'base.tar',
+					   '-C', $extract_path);
+
+		# Verify.
+		$node->command_ok([ 'pg_verifybackup', '-n',
+						  '-m', "${backup_dir}/${prefix}backup_manifest",
+						  '-e', $extract_path ],
+						  "$test_name: backup verifies ok");
+	}
+}
-- 
2.24.3 (Apple Git-128)

