From da7b9ae191f50a13fecd9837d5b9a650e78769f2 Mon Sep 17 00:00:00 2001
From: Zhijie Hou <houzj.fnst@fujitsu.com>
Date: Thu, 29 Jan 2026 15:13:07 +0800
Subject: [PATCH v1 2/2] Add a taptest

---
 .../t/040_standby_failover_slots_sync.pl      | 77 +++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/src/test/recovery/t/040_standby_failover_slots_sync.pl b/src/test/recovery/t/040_standby_failover_slots_sync.pl
index 47d64d05ad1..1f41a5236e4 100644
--- a/src/test/recovery/t/040_standby_failover_slots_sync.pl
+++ b/src/test/recovery/t/040_standby_failover_slots_sync.pl
@@ -1102,4 +1102,81 @@ $standby2->wait_for_log(
 
 $h->quit;
 
+##################################################
+# Test that when physical replication lags behind logical replication,
+# pg_sync_replication_slots() on the standby skips and retries until physical
+# replication catches up. Also verify that slotsync skip statistics are
+# correctly updated when the slotsync operation is skipped.
+##################################################
+
+# Remove the standby from the synchronized_standby_slots list and reload the
+# configuration.
+$primary->adjust_conf('postgresql.conf', 'synchronized_standby_slots', "''");
+$primary->reload;
+
+# Remove the standby from the synchronized_standby_slots and reduce the maximum
+# walsender number.
+$primary->append_conf(
+	'postgresql.conf', qq(
+max_wal_senders = 2
+synchronized_standby_slots = ''
+));
+$primary->restart;
+
+# Stop the standby and initiate a new replication connection to occupy a
+# walsender slot, blocking physical replication.
+$standby2->stop;
+my $repl = $primary->background_psql('postgres', on_error_stop => 0,
+	replication => 'database');
+
+# Advance the logical slot
+$primary->safe_psql('postgres', "INSERT INTO push_wal VALUES(1);");
+$primary->wait_for_catchup('regress_mysub1');
+
+$standby2->start;
+
+# Attempt to synchronize slots using API. The API will continue retrying
+# synchronization until the standby catches up.
+# The API will not return until this happens, to be able to make
+# further calls, call the API in a background process.
+$h = $standby2->background_psql('postgres', on_error_stop => 0);
+
+$log_offset = -s $standby2->logfile;
+
+$h->query_until(qr/start/, q(
+	\echo start
+	SELECT pg_sync_replication_slots();
+	));
+
+# Confirm that slot synchronization is skipped because physical replication is
+# lagging behind logical replication.
+$standby2->wait_for_log(
+	qr/skipping slot synchronization because the received slot sync LSN .* for slot \"lsub1_slot\" is ahead of the standby position/, $log_offset);
+
+# Confirm that the slotsync skip reason is updated
+$result = $standby2->safe_psql('postgres',
+	"SELECT slotsync_skip_reason FROM pg_replication_slots WHERE slot_name = 'lsub1_slot'"
+);
+is($result, 'wal_not_flushed', "check slot sync skip reason");
+
+# Terminate the replication connection, enabling physical replication to resume
+$repl->quit;
+
+# Configure primary to disallow any logical slots that have enabled failover
+# from getting ahead of the specified physical replication slot (sb2_slot).
+$primary->append_conf(
+	'postgresql.conf', qq(
+synchronized_standby_slots = 'sb2_slot'
+));
+$primary->reload;
+
+# Verify that the slot sync finishes
+ok( $standby2->poll_query_until(
+		'postgres',
+		"SELECT slotsync_skip_reason IS NULL FROM pg_replication_slots WHERE slot_name = 'lsub1_slot';"
+	),
+	'slot sync is not skipped anymore');
+
+$h->quit;
+
 done_testing();
-- 
2.51.1.windows.1

