From 84c9f286681138c9a1995539d23907990a76f21a Mon Sep 17 00:00:00 2001
From: reVInotip <grigoriy.novikov220@gmail.com>
Date: Sat, 18 Oct 2025 10:54:27 +0700
Subject: [PATCH 4/4] Add tap tests for cascade sync replication
 This patch contains rewritten tap tests for synchronous replication. These
 tests now take cascading into account.
 
 Also the test infrastructure has been updated to address configuration
 requirements for cascaded synchronous replication. Server configurations
 that were incompatible with cascaded synchronous replication have been
 identified and corrected across the test suite.

---
 src/test/perl/PostgreSQL/Test/Cluster.pm   |  30 ++
 src/test/recovery/t/007_sync_rep.pl        | 571 ++++++++++++++++++++++-------
 src/test/recovery/t/009_twophase.pl        |  18 +-
 src/test/recovery/t/012_subtransactions.pl |   5 +
 4 files changed, 487 insertions(+), 137 deletions(-)

diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index 35413f14019..9c14f9fdad0 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -1409,6 +1409,36 @@ primary_conninfo='$root_connstr'
 	return;
 }
 
+# Internal routine to enable waiting synchronous standbys
+# on primary node
+sub enable_waiting_standbys
+{
+	my ($self) = @_;
+	my $name = $self->name;
+
+	print "### Enabling waiting standbys for node \"$name\"\n";
+	$self->append_conf(
+		'postgresql.conf', qq(
+		synchronous_commit=on
+	));
+	return;
+}
+
+# Internal routine to ignore synchronous_standby_names
+# on standby node
+sub disable_waiting_standbys
+{
+	my ($self) = @_;
+	my $name = $self->name;
+
+	print "### Now ignore synchronous_standby_names for node \"$name\"\n";
+	$self->append_conf(
+		'postgresql.conf', qq(
+		synchronous_commit=local
+	));
+	return;
+}
+
 # Internal routine to enable archive recovery command on a standby node
 sub enable_restoring
 {
diff --git a/src/test/recovery/t/007_sync_rep.pl b/src/test/recovery/t/007_sync_rep.pl
index 602652a7638..ad463287b4d 100644
--- a/src/test/recovery/t/007_sync_rep.pl
+++ b/src/test/recovery/t/007_sync_rep.pl
@@ -50,6 +50,194 @@ sub start_standby_and_wait
 	return;
 }
 
+sub check_replication_state
+{
+	my ($source_node, $node_standby_1, $node_standby_2,
+		$node_standby_3, $node_standby_4, $backup_name) = @_;
+
+	my $stdby1_name = $node_standby_1->name;
+	my $stdby2_name = $node_standby_2->name;
+	my $stdby3_name = $node_standby_3->name;
+	my $stdby4_name = $node_standby_4->name;
+
+	# Check that sync_state is determined correctly when
+	# synchronous_standby_names is specified in old syntax.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|sync
+$stdby2_name|2|potential
+$stdby3_name|0|async",
+		'old syntax of synchronous_standby_names',
+		"$stdby1_name,$stdby2_name");
+
+	# Check that all the standbys are considered as either sync or
+	# potential when * is specified in synchronous_standby_names.
+	# Note that standby1 is chosen as sync standby because
+	# it's stored in the head of WalSnd array which manages
+	# all the standbys though they have the same priority.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|sync
+$stdby2_name|1|potential
+$stdby3_name|1|potential",
+		'asterisk in synchronous_standby_names',
+		'*');
+
+	# Stop and start standbys to rearrange the order of standbys
+	# in WalSnd array. Now, if standbys have the same priority,
+	# standby2 is selected preferentially and standby3 is next.
+	$node_standby_1->stop;
+	$node_standby_2->stop;
+	$node_standby_3->stop;
+
+	# Make sure that each standby reports back to the primary in the wanted
+	# order.
+	start_standby_and_wait($source_node, $node_standby_2);
+	start_standby_and_wait($source_node, $node_standby_3);
+
+	# Specify 2 as the number of sync standbys.
+	# Check that two standbys are in 'sync' state.
+	test_sync_state(
+		$source_node,
+"$stdby2_name|2|sync
+$stdby3_name|3|sync",
+		'2 synchronous standbys',
+		"2($stdby1_name,$stdby2_name,$stdby3_name)");
+
+	# Start standby1
+	start_standby_and_wait($source_node, $node_standby_1);
+
+	$node_standby_4->init_from_backup($source_node, $backup_name,
+		has_streaming => 1);
+	$node_standby_4->start;
+
+	# Check that standby1 and standby2 whose names appear earlier in
+	# synchronous_standby_names are considered as sync. Also check that
+	# standby3 appearing later represents potential, and standby4 is
+	# in 'async' state because it's not in the list.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|sync
+$stdby2_name|2|sync
+$stdby3_name|3|potential
+$stdby4_name|0|async",
+		'2 sync, 1 potential, and 1 async');
+
+	# Check that sync_state of each standby is determined correctly
+	# when num_sync exceeds the number of names of potential sync standbys
+	# specified in synchronous_standby_names.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|0|async
+$stdby2_name|4|sync
+$stdby3_name|3|sync
+$stdby4_name|1|sync",
+		'num_sync exceeds the num of potential sync standbys',
+		"6($stdby4_name,standby,$stdby3_name,$stdby2_name)");
+
+	# The setting that * comes before another standby name is acceptable
+	# but does not make sense in most cases. Check that sync_state is
+	# chosen properly even in case of that setting. standby1 is selected
+	# as synchronous as it has the highest priority, and is followed by a
+	# second standby listed first in the WAL sender array, which is
+	# standby2 in this case.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|sync
+$stdby2_name|2|sync
+$stdby3_name|2|potential
+$stdby4_name|2|potential",
+		'asterisk before another standby name',
+		"2($stdby1_name,*,$stdby2_name)");
+
+	# Check that the setting of '2(*)' chooses standby2 and standby3 that are stored
+	# earlier in WalSnd array as sync standbys.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|potential
+$stdby2_name|1|sync
+$stdby3_name|1|sync
+$stdby4_name|1|potential",
+		'multiple standbys having the same priority are chosen as sync',
+		'2(*)');
+
+	# Stop Standby3 which is considered in 'sync' state.
+	$node_standby_3->stop;
+
+	# Check that the state of standby1 stored earlier in WalSnd array than
+	# standby4 is transited from potential to sync.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|sync
+$stdby2_name|1|sync
+$stdby4_name|1|potential",
+		'potential standby found earlier in array is promoted to sync');
+
+	# Check that standby1 and standby2 are chosen as sync standbys
+	# based on their priorities.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|sync
+$stdby2_name|2|sync
+$stdby4_name|0|async",
+		'priority-based sync replication specified by FIRST keyword',
+		"FIRST 2($stdby1_name, $stdby2_name)");
+
+	# Check that all the listed standbys are considered as candidates
+	# for sync standbys in a quorum-based sync replication.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|quorum
+$stdby2_name|1|quorum
+$stdby4_name|0|async",
+		'2 quorum and 1 async',
+		"ANY 2($stdby1_name, $stdby2_name)");
+
+	# Start Standby3 which will be considered in 'quorum' state.
+	$node_standby_3->start;
+
+	# Check that the setting of 'ANY 2(*)' chooses all standbys as
+	# candidates for quorum sync standbys.
+	test_sync_state(
+		$source_node,
+"$stdby1_name|1|quorum
+$stdby2_name|1|quorum
+$stdby3_name|1|quorum
+$stdby4_name|1|quorum",
+		'all standbys are considered as candidates for quorum sync standbys',
+		'ANY 2(*)');
+
+	return;
+}
+
+# Cluster topology (the arrow shows the direction of replication)
+#
+#							 		  |-> cascade_standby10 |-> standby
+#							 		  |
+# 							 		  |-> cascade_standby11
+# 			 |-> cascade_standby00 -> |
+#			 |				 		  |-> cascade_standby12
+#			 |				 		  |
+#			 |				 		  |-> cascade_standby13
+# 			 |
+#			 |				 		  |-> standby00
+#			 |				 		  |
+# 			 |				 		  |-> standby01
+# 			 |-> cascade_standby01 -> |
+#			 |				 		  |-> standby02
+#			 |				 		  |
+# primary -> |				 		  |-> standby03
+# 			 |
+#			 |				 		  |-> standby10
+#			 |				 		  |
+# 			 |				 		  |-> standby11
+# 			 |-> cascade_standby02 -> |
+#			 |				 		  |-> standby12
+#			 |				 		  |
+#			 |				 		  |-> standby13
+#			 |
+#			 |-> cascade_standby03
+
 # Initialize primary node
 my $node_primary = PostgreSQL::Test::Cluster->new('primary');
 $node_primary->init(allows_streaming => 1);
@@ -62,160 +250,275 @@ $node_primary->backup($backup_name);
 # Create all the standbys.  Their status on the primary is checked to ensure
 # the ordering of each one of them in the WAL sender array of the primary.
 
-# Create standby1 linking to primary
-my $node_standby_1 = PostgreSQL::Test::Cluster->new('standby1');
-$node_standby_1->init_from_backup($node_primary, $backup_name,
-	has_streaming => 1);
-start_standby_and_wait($node_primary, $node_standby_1);
+my @cascade_standbys0;
+my @cascade_standby0_names;
 
-# Create standby2 linking to primary
-my $node_standby_2 = PostgreSQL::Test::Cluster->new('standby2');
-$node_standby_2->init_from_backup($node_primary, $backup_name,
-	has_streaming => 1);
-start_standby_and_wait($node_primary, $node_standby_2);
+my $node;
+my $i = 0;
+for (; $i < 3; $i++) {
+	push @cascade_standby0_names, "cascade_standby0$i";
+
+	$node = PostgreSQL::Test::Cluster->new($cascade_standby0_names[$i]);
+	$node->init_from_backup($node_primary, $backup_name,
+		has_streaming => 1);
+	start_standby_and_wait($node_primary, $node);
+
+	push @cascade_standbys0, $node;
+}
+
+# This cascade standby will be initted in check_replication_state function
+push @cascade_standby0_names, "cascade_standby0$i";
+
+$node = PostgreSQL::Test::Cluster->new($cascade_standby0_names[$i]);
+push @cascade_standbys0, $node;
+$i = 0;
+
+# Create cascade standby and it`s last standbys.
+$backup_name = 'cascade_standby00_backup';
+
+# Take backup of cascade_standby00
+$cascade_standbys0[0]->backup($backup_name);
+
+my @cascade_standbys1;
+my @cascade_standby1_names;
+for (; $i < 3; $i++) {
+	push @cascade_standby1_names, "cascade_standby1$i";
+
+	$node = PostgreSQL::Test::Cluster->new($cascade_standby1_names[$i]);
+	$node->init_from_backup($cascade_standbys0[0], $backup_name,
+		has_streaming => 1);
+	start_standby_and_wait($cascade_standbys0[0], $node);
 
-# Create standby3 linking to primary
-my $node_standby_3 = PostgreSQL::Test::Cluster->new('standby3');
-$node_standby_3->init_from_backup($node_primary, $backup_name,
+	push @cascade_standbys1, $node;
+}
+
+# This cascade standby will be initted in check_replication_state function
+push @cascade_standby1_names, "cascade_standby1$i";
+
+$node = PostgreSQL::Test::Cluster->new($cascade_standby1_names[$i]);
+push @cascade_standbys1, $node;
+$i = 0;
+
+# Take backup
+$backup_name = 'cascade_standby10_backup';
+$cascade_standbys1[0]->backup($backup_name);
+
+# Create standby5 linking to cascade standby
+my $standby = PostgreSQL::Test::Cluster->new('standby');
+$standby->init_from_backup($cascade_standbys1[0], $backup_name,
 	has_streaming => 1);
-start_standby_and_wait($node_primary, $node_standby_3);
+start_standby_and_wait($cascade_standbys1[0], $standby);
+
+my $standby_name = $standby->name;
+
+# Take backup of cascade_standby01
+$backup_name = 'cascade_standby01_backup';
+$cascade_standbys0[1]->backup($backup_name);
+
+my @standbys0;
+for (; $i < 3; $i++) {
+	$node = PostgreSQL::Test::Cluster->new("standby0$i");
+	$node->init_from_backup($cascade_standbys0[1], $backup_name,
+		has_streaming => 1);
+	start_standby_and_wait($cascade_standbys0[1], $node);
+
+	push @standbys0, $node;
+}
+
+# This cascade_standby will be initted in check_replication_state function
+$node = PostgreSQL::Test::Cluster->new("standby0$i");
+push @standbys0, $node;
+$i = 0;
+
+# Take backup of cascade_standby02
+$backup_name = 'cascade_standby02_backup';
+$cascade_standbys0[2]->backup($backup_name);
+
+my @standbys1;
+for ($i = 0; $i < 3; $i++) {
+	$node = PostgreSQL::Test::Cluster->new("standby1$i");
+	$node->init_from_backup($cascade_standbys0[2], $backup_name,
+		has_streaming => 1);
+	start_standby_and_wait($cascade_standbys0[2], $node);
+
+	push @standbys1, $node;
+}
+
+# This cascade standby will be initted in check_replication_state function
+$node = PostgreSQL::Test::Cluster->new("standby1$i");
+push @standbys1, $node;
+
+# Set up initial topology
 
-# Check that sync_state is determined correctly when
-# synchronous_standby_names is specified in old syntax.
 test_sync_state(
-	$node_primary, qq(standby1|1|sync
-standby2|2|potential
-standby3|0|async),
-	'old syntax of synchronous_standby_names',
-	'standby1,standby2');
-
-# Check that all the standbys are considered as either sync or
-# potential when * is specified in synchronous_standby_names.
-# Note that standby1 is chosen as sync standby because
-# it's stored in the head of WalSnd array which manages
-# all the standbys though they have the same priority.
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|sync",
+	'set up initial topology for primary server and it`s standbys',
+	"FIRST 3 (${cascade_standby0_names[0]}, ${cascade_standby0_names[1]}, ${cascade_standby0_names[2]})");
+
 test_sync_state(
-	$node_primary, qq(standby1|1|sync
-standby2|1|potential
-standby3|1|potential),
-	'asterisk in synchronous_standby_names',
-	'*');
-
-# Stop and start standbys to rearrange the order of standbys
-# in WalSnd array. Now, if standbys have the same priority,
-# standby2 is selected preferentially and standby3 is next.
-$node_standby_1->stop;
-$node_standby_2->stop;
-$node_standby_3->stop;
-
-# Make sure that each standby reports back to the primary in the wanted
-# order.
-start_standby_and_wait($node_primary, $node_standby_2);
-start_standby_and_wait($node_primary, $node_standby_3);
-
-# Specify 2 as the number of sync standbys.
-# Check that two standbys are in 'sync' state.
+	$cascade_standbys0[0],
+"${cascade_standby1_names[0]}|1|quorum
+${cascade_standby1_names[1]}|1|quorum
+${cascade_standby1_names[2]}|0|async",
+	'set up initial topology for cascade standby server and it`s standbys',
+	"ANY 2 (${cascade_standby1_names[0]}, ${cascade_standby1_names[1]})");
+
 test_sync_state(
-	$node_primary, qq(standby2|2|sync
-standby3|3|sync),
-	'2 synchronous standbys',
-	'2(standby1,standby2,standby3)');
+	$cascade_standbys1[0],
+"$standby_name|1|sync",
+	'make sync standby 5',
+	"$standby_name");
 
-# Start standby1
-start_standby_and_wait($node_primary, $node_standby_1);
+my ($stdout, $stderr, $timed_out);
 
-# Create standby4 linking to primary
-my $node_standby_4 = PostgreSQL::Test::Cluster->new('standby4');
-$node_standby_4->init_from_backup($node_primary, $backup_name,
-	has_streaming => 1);
-$node_standby_4->start;
+# Check that queries working
+my $cmdret = $node_primary->psql('postgres', 'CREATE TABLE test (id integer, data text);',
+	stdout => \$stdout, stderr => \$stderr,
+	timeout => $PostgreSQL::Test::Utils::timeout_default,
+	timed_out => \$timed_out,
+	on_error_die => 1,
+	extra_params => ['--single-transaction']);
+
+ok($cmdret == 0 && $timed_out == 0, "Query works");
+
+# Try to stop standby 5
+$standby->stop;
+
+# This query needs only for status of sync replicas can be changed
+$cmdret = $node_primary->psql('postgres', 'INSERT INTO test VALUES (1, \'first insertion\')',
+	stdout => \$stdout, stderr => \$stderr,
+	timeout => $PostgreSQL::Test::Utils::timeout_default,
+	timed_out => \$timed_out,
+	on_error_die => 1,
+	extra_params => ['--single-transaction']);
+
+ok($timed_out == 1, "Query fails with time out");
 
-# Check that standby1 and standby2 whose names appear earlier in
-# synchronous_standby_names are considered as sync. Also check that
-# standby3 appearing later represents potential, and standby4 is
-# in 'async' state because it's not in the list.
 test_sync_state(
-	$node_primary, qq(standby1|1|sync
-standby2|2|sync
-standby3|3|potential
-standby4|0|async),
-	'2 sync, 1 potential, and 1 async');
-
-# Check that sync_state of each standby is determined correctly
-# when num_sync exceeds the number of names of potential sync standbys
-# specified in synchronous_standby_names.
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync?
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|sync",
+	"check that ${cascade_standby0_names[0]} in primary marks as invalid");
+
+test_sync_state(
+	$cascade_standbys0[0],
+"${cascade_standby1_names[0]}|1|quorum?
+${cascade_standby1_names[1]}|1|quorum
+${cascade_standby1_names[2]}|0|async",
+	"check that ${cascade_standby1_names[0]} in cascade standby marks as invalid");
+
+$standby->start;
+
+$cmdret = $node_primary->psql('postgres', 'INSERT INTO test VALUES (2, \'second insertion\');',
+	stdout => \$stdout, stderr => \$stderr,
+	timeout => $PostgreSQL::Test::Utils::timeout_default,
+	timed_out => \$timed_out,
+	on_error_die => 1,
+	extra_params => ['--single-transaction']);
+
+ok($cmdret == 0 && $timed_out == 0, 'Query works again');
+
 test_sync_state(
-	$node_primary, qq(standby1|0|async
-standby2|4|sync
-standby3|3|sync
-standby4|1|sync),
-	'num_sync exceeds the num of potential sync standbys',
-	'6(standby4,standby0,standby3,standby2)');
-
-# The setting that * comes before another standby name is acceptable
-# but does not make sense in most cases. Check that sync_state is
-# chosen properly even in case of that setting. standby1 is selected
-# as synchronous as it has the highest priority, and is followed by a
-# second standby listed first in the WAL sender array, which is
-# standby2 in this case.
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|sync",
+	'check that primary state backs to normal');
+
 test_sync_state(
-	$node_primary, qq(standby1|1|sync
-standby2|2|sync
-standby3|2|potential
-standby4|2|potential),
-	'asterisk before another standby name',
-	'2(standby1,*,standby2)');
-
-# Check that the setting of '2(*)' chooses standby2 and standby3 that are stored
-# earlier in WalSnd array as sync standbys.
+	$cascade_standbys0[0],
+"${cascade_standby1_names[0]}|1|quorum
+${cascade_standby1_names[1]}|1|quorum
+${cascade_standby1_names[2]}|0|async",
+	'check that cascade standby state backs to normal');
+
 test_sync_state(
-	$node_primary, qq(standby1|1|potential
-standby2|1|sync
-standby3|1|sync
-standby4|1|potential),
-	'multiple standbys having the same priority are chosen as sync',
-	'2(*)');
-
-# Stop Standby3 which is considered in 'sync' state.
-$node_standby_3->stop;
-
-# Check that the state of standby1 stored earlier in WalSnd array than
-# standby4 is transited from potential to sync.
+	$cascade_standbys1[0],
+"$standby_name|1|sync",
+	'check that standby 5 is sync');
+
+check_replication_state($node_primary, $cascade_standbys0[0], $cascade_standbys0[1],  $cascade_standbys0[2],  $cascade_standbys0[3], 'primary_backup');
+
 test_sync_state(
-	$node_primary, qq(standby1|1|sync
-standby2|1|sync
-standby4|1|potential),
-	'potential standby found earlier in array is promoted to sync');
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|potential
+${cascade_standby0_names[3]}|0|async",
+	'check that primary state backs to normal',
+	"FIRST 2 (${cascade_standby0_names[0]}, ${cascade_standby0_names[1]}, ${cascade_standby0_names[2]})");
+
+# Reorder standbys in WalSnd array after testing
+
+$cascade_standbys1[0]->stop;
+$cascade_standbys1[1]->stop;
+$cascade_standbys1[2]->stop;
+
+$cascade_standbys0[0]->stop;
+
+start_standby_and_wait($node_primary, $cascade_standbys0[0]);
+start_standby_and_wait($cascade_standbys0[0], $cascade_standbys1[0]);
+start_standby_and_wait($cascade_standbys0[0], $cascade_standbys1[1]);
+start_standby_and_wait($cascade_standbys0[0], $cascade_standbys1[2]);
+
+check_replication_state($cascade_standbys0[0], $cascade_standbys1[0], $cascade_standbys1[1], $cascade_standbys1[2], $cascade_standbys1[3], 'cascade_standby00_backup');
 
-# Check that standby1 and standby2 are chosen as sync standbys
-# based on their priorities.
 test_sync_state(
-	$node_primary, qq(standby1|1|sync
-standby2|2|sync
-standby4|0|async),
-	'priority-based sync replication specified by FIRST keyword',
-	'FIRST 2(standby1, standby2)');
-
-# Check that all the listed standbys are considered as candidates
-# for sync standbys in a quorum-based sync replication.
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|potential
+${cascade_standby0_names[3]}|0|async",
+		'check that primary state does not change after testing cascade sync replication on standby 1');
+
+# Reorder standbys in WalSnd array after testing
+
+$standbys0[0]->stop;
+$standbys0[1]->stop;
+$standbys0[2]->stop;
+
+$cascade_standbys0[1]->stop;
+
+start_standby_and_wait($node_primary, $cascade_standbys0[1]);
+start_standby_and_wait($cascade_standbys0[1], $standbys0[0]);
+start_standby_and_wait($cascade_standbys0[1], $standbys0[1]);
+start_standby_and_wait($cascade_standbys0[1], $standbys0[2]);
+
+check_replication_state($cascade_standbys0[1], $standbys0[0], $standbys0[1], $standbys0[2], $standbys0[3], 'cascade_standby01_backup');
+
 test_sync_state(
-	$node_primary, qq(standby1|1|quorum
-standby2|1|quorum
-standby4|0|async),
-	'2 quorum and 1 async',
-	'ANY 2(standby1, standby2)');
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|potential
+${cascade_standby0_names[3]}|0|async",
+		'check that primary state does not change after testing cascade sync replication on standby 2');
+
+# Reorder standbys in WalSnd array after testing
+
+$standbys1[0]->stop;
+$standbys1[1]->stop;
+$standbys1[2]->stop;
+
+$cascade_standbys0[2]->stop;
+
+start_standby_and_wait($node_primary, $cascade_standbys0[2]);
+start_standby_and_wait($cascade_standbys0[2], $standbys1[0]);
+start_standby_and_wait($cascade_standbys0[2], $standbys1[1]);
+start_standby_and_wait($cascade_standbys0[2], $standbys1[2]);
 
-# Start Standby3 which will be considered in 'quorum' state.
-$node_standby_3->start;
+check_replication_state($cascade_standbys0[2], $standbys1[0], $standbys1[1], $standbys1[2], $standbys1[3], 'cascade_standby02_backup');
 
-# Check that the setting of 'ANY 2(*)' chooses all standbys as
-# candidates for quorum sync standbys.
 test_sync_state(
-	$node_primary, qq(standby1|1|quorum
-standby2|1|quorum
-standby3|1|quorum
-standby4|1|quorum),
-	'all standbys are considered as candidates for quorum sync standbys',
-	'ANY 2(*)');
+	$node_primary,
+"${cascade_standby0_names[0]}|1|sync
+${cascade_standby0_names[1]}|2|sync
+${cascade_standby0_names[2]}|3|potential
+${cascade_standby0_names[3]}|0|async",
+		'check that primary state does not change after testing cascade sync replication on standby 2');
 
 done_testing();
diff --git a/src/test/recovery/t/009_twophase.pl b/src/test/recovery/t/009_twophase.pl
index 1a662ebe499..40648a0a016 100644
--- a/src/test/recovery/t/009_twophase.pl
+++ b/src/test/recovery/t/009_twophase.pl
@@ -45,10 +45,12 @@ $node_london->backup('london_backup');
 my $node_paris = PostgreSQL::Test::Cluster->new('paris');
 $node_paris->init_from_backup($node_london, 'london_backup',
 	has_streaming => 1);
+# Configure paris node for non waiting because it initially will be synchronous standby
 $node_paris->append_conf(
 	'postgresql.conf', qq(
 	subtransaction_buffers = 32
 ));
+$node_paris->disable_waiting_standbys();
 $node_paris->start;
 
 # Switch to synchronous replication in both directions
@@ -230,14 +232,15 @@ note "Now paris is primary and london is standby";
 ($cur_primary, $cur_standby) = ($node_paris, $node_london);
 $cur_primary_name = $cur_primary->name;
 
-# because london is not running at this point, we can't use syncrep commit
-# on this command
+# we already configure paris node for non wait, so even if london node
+# isn`t running at this point we can prepare commit
 $psql_rc = $cur_primary->psql('postgres',
-	"SET synchronous_commit = off; COMMIT PREPARED 'xact_009_10'");
+	"COMMIT PREPARED 'xact_009_10'");
 is($psql_rc, '0', "Restore of prepared transaction on promoted standby");
 
 # restart old primary as new standby
 $cur_standby->enable_streaming($cur_primary);
+$cur_standby->disable_waiting_standbys();
 $cur_standby->start;
 
 ###############################################################################
@@ -247,14 +250,20 @@ $cur_standby->start;
 # consistent.
 ###############################################################################
 
+# here we need to enable sycnrep commit because current primary has been configured
+# for non waiting
 $cur_primary->psql(
 	'postgres', "
 	BEGIN;
+	SET synchronous_commit = on;
 	INSERT INTO t_009_tbl VALUES (23, 'issued to ${cur_primary_name}');
 	SAVEPOINT s1;
 	INSERT INTO t_009_tbl VALUES (24, 'issued to ${cur_primary_name}');
 	PREPARE TRANSACTION 'xact_009_11';");
 $cur_primary->stop;
+
+# configure cur standby to be primary
+$cur_standby->enable_waiting_standbys();
 $cur_standby->restart;
 $cur_standby->promote;
 
@@ -297,6 +306,8 @@ $cur_standby->promote;
 # change roles
 note "Now paris is primary and london is standby";
 ($cur_primary, $cur_standby) = ($node_paris, $node_london);
+$cur_primary->enable_waiting_standbys();
+$cur_primary->restart;
 $cur_primary_name = $cur_primary->name;
 
 $cur_primary->psql(
@@ -308,6 +319,7 @@ is($psql_out, '1',
 
 # restart old primary as new standby
 $cur_standby->enable_streaming($cur_primary);
+$cur_standby->disable_waiting_standbys();
 $cur_standby->start;
 
 $cur_primary->psql('postgres', "COMMIT PREPARED 'xact_009_12'");
diff --git a/src/test/recovery/t/012_subtransactions.pl b/src/test/recovery/t/012_subtransactions.pl
index 25df73463b7..74323a7c8b4 100644
--- a/src/test/recovery/t/012_subtransactions.pl
+++ b/src/test/recovery/t/012_subtransactions.pl
@@ -121,6 +121,7 @@ is($psql_out, '8128', "Visible");
 # restore state
 ($node_primary, $node_standby) = ($node_standby, $node_primary);
 $node_standby->enable_streaming($node_primary);
+$node_standby->disable_waiting_standbys();
 $node_standby->start;
 $node_standby->psql(
 	'postgres',
@@ -166,6 +167,9 @@ is($psql_out, '-1', "Not visible");
 
 # restore state
 ($node_primary, $node_standby) = ($node_standby, $node_primary);
+$node_primary->enable_waiting_standbys();
+$node_primary->restart();
+
 $node_standby->enable_streaming($node_primary);
 $node_standby->start;
 $psql_rc = $node_primary->psql('postgres', "COMMIT PREPARED 'xact_012_1'");
@@ -203,6 +207,7 @@ is($psql_out, '-1', "Not visible");
 # restore state
 ($node_primary, $node_standby) = ($node_standby, $node_primary);
 $node_standby->enable_streaming($node_primary);
+$node_standby->disable_waiting_standbys();
 $node_standby->start;
 $psql_rc = $node_primary->psql('postgres', "ROLLBACK PREPARED 'xact_012_1'");
 is($psql_rc, '0',
-- 
2.51.0
