Add more TAP tests with BASE_BACKUP and pg_backup_start/stop
authorMichael Paquier <michael@paquier.xyz>
Mon, 1 Aug 2022 00:16:11 +0000 (09:16 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 1 Aug 2022 00:16:11 +0000 (09:16 +0900)
This commit adds some test coverage for ee79647 (prevent BASE_BACKUP
from running in the middle of another base backup) and b24b2be
(BASE_BACKUP cancellation followed by pg_backup_start), caused by the
interactions of replication and SQL commands in a logical replication
connection in a WAL sender.

The second test uses a design close to what has been introduced in
0475a97f, where BASE_BACKUP is throttled to give enough room for a
cancellation, though this time we rely on psql with multiple -c
switches to keep a connection around for the second query.

Reviewed-by: Fujii Masao
Discussion: https://postgr.es/m/Ys/NCI4Eo9300GnQ@paquier.xyz

src/test/recovery/t/001_stream_rep.pl

index 86864098f9e27655f64acb41687a947206bdfdf0..b15dd6b29a7ab9fe135e87a4ee482cc055d41550 100644 (file)
@@ -531,4 +531,59 @@ my $primary_data = $node_primary->data_dir;
 ok(!-f "$primary_data/pg_wal/$segment_removed",
    "WAL segment $segment_removed recycled after physical slot advancing");
 
+note "testing pg_backup_start() followed by BASE_BACKUP";
+my $connstr = $node_primary->connstr('postgres') . " replication=database";
+
+# This test requires a replication connection with a database, as it mixes
+# a replication command and a SQL command.
+$node_primary->command_fails_like(
+   [
+       'psql', '-c', "SELECT pg_backup_start('backup', true)",
+       '-c',   'BASE_BACKUP', '-d', $connstr
+   ],
+   qr/a backup is already in progress in this session/,
+   'BASE_BACKUP cannot run in session already running backup');
+
+note "testing BASE_BACKUP cancellation";
+
+my $sigchld_bb_timeout =
+  IPC::Run::timer($PostgreSQL::Test::Utils::timeout_default);
+
+# This test requires a replication connection with a database, as it mixes
+# a replication command and a SQL command.  The first BASE_BACKUP is throttled
+# to give enough room for the cancellation running below.  The second command
+# for pg_backup_stop() should fail.
+my ($sigchld_bb_stdin, $sigchld_bb_stdout, $sigchld_bb_stderr) = ('', '', '');
+my $sigchld_bb = IPC::Run::start(
+   [
+       'psql', '-X', '-c', "BASE_BACKUP (CHECKPOINT 'fast', MAX_RATE 32);",
+       '-c',   'SELECT pg_backup_stop()',
+       '-d',   $connstr
+   ],
+   '<',
+   \$sigchld_bb_stdin,
+   '>',
+   \$sigchld_bb_stdout,
+   '2>',
+   \$sigchld_bb_stderr,
+   $sigchld_bb_timeout);
+
+# The cancellation is issued once the database files are streamed and
+# the checkpoint issued at backup start completes.
+is( $node_primary->poll_query_until(
+       'postgres',
+       "SELECT pg_cancel_backend(a.pid) FROM "
+         . "pg_stat_activity a, pg_stat_progress_basebackup b WHERE "
+         . "a.pid = b.pid AND a.query ~ 'BASE_BACKUP' AND "
+         . "b.phase = 'streaming database files';"),
+   "1",
+   "WAL sender sending base backup killed");
+
+# The psql command should fail on pg_backup_stop().
+ok( pump_until(
+       $sigchld_bb,         $sigchld_bb_timeout,
+       \$sigchld_bb_stderr, qr/backup is not in progress/),
+   'base backup cleanly cancelled');
+$sigchld_bb->finish();
+
 done_testing();