Hi,

We have automated tests for many specific replication and recovery
scenarios, but nothing that tests replay of a wide range of records.
People working on recovery code often use installcheck (presumably
along with other custom tests) to exercise it, sometimes with
wal_consistency_check enabled.  So, why don't we automate that?  Aside
from exercising the WAL decoding machinery (which brought me here),
that'd hopefully provide some decent improvements in coverage of the
various redo routines, many of which are not currently exercised at
all.

I'm not quite sure where it belongs, though.  The attached initial
sketch patch puts it under rc/test/recovery near other similar things,
but I'm not sure if it's really OK to invoke make -C ../regress from
here.  I copied pg_update/test.sh's trick of using a different
outputdir to avoid clobbering a concurrent run under src/test/regress,
and I also needed to invent a way to stop it from running the cursed
tablespace test (deferring startup of the standby also works but eats
way too much space, which I learned after blowing out a smallish
development VM's disk).   Alternatively, we could put it under
src/test/regress, which makes some kind of logical sense, but it would
make a quick "make check" take more than twice as long.  Perhaps it
could use a different target, one that check-world somehow reaches but
not check, and that also doesn't seem great.  Ideas on how to
structure this or improve the perl welcome.
From f7d199cefdec98bcdc5f580e5175ce09cb1299b2 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.mu...@gmail.com>
Date: Fri, 23 Apr 2021 15:37:09 +1200
Subject: [PATCH] Test replay of regression tests.

Add a new TAP test under src/test/recovery that runs the regression
tests with wal_consistency_checking=all.
---
 src/test/recovery/Makefile                    |  3 +
 src/test/recovery/t/025_stream_rep_regress.pl | 67 +++++++++++++++++++
 src/test/regress/pg_regress.c                 | 27 ++++++++
 3 files changed, 97 insertions(+)
 create mode 100644 src/test/recovery/t/025_stream_rep_regress.pl

diff --git a/src/test/recovery/Makefile b/src/test/recovery/Makefile
index 96442ceb4e..7dfcbae4b5 100644
--- a/src/test/recovery/Makefile
+++ b/src/test/recovery/Makefile
@@ -18,6 +18,9 @@ include $(top_builddir)/src/Makefile.global
 check:
 	$(prove_check)
 
+# Tell the TAP tests how to invoke make.
+export MAKE
+
 installcheck:
 	$(prove_installcheck)
 
diff --git a/src/test/recovery/t/025_stream_rep_regress.pl b/src/test/recovery/t/025_stream_rep_regress.pl
new file mode 100644
index 0000000000..a7dbe54322
--- /dev/null
+++ b/src/test/recovery/t/025_stream_rep_regress.pl
@@ -0,0 +1,67 @@
+# Run the standard regression tests with streaming replication
+use strict;
+use warnings;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 3;
+
+# Initialize primary node
+my $node_primary = get_new_node('primary');
+# A specific role is created to perform some tests related to replication,
+# and it needs proper authentication configuration.
+$node_primary->init(
+	allows_streaming => 1,
+	auth_extra       => [ '--create-role', 'repl_role' ]);
+$node_primary->append_conf('postgresql.conf', 'wal_consistency_checking = all');
+$node_primary->start;
+is( $node_primary->psql(
+        'postgres',
+        qq[SELECT pg_create_physical_replication_slot('standby_1');]),
+    0,
+    'physical slot created on primary');
+my $backup_name = 'my_backup';
+
+# Take backup
+$node_primary->backup($backup_name);
+
+# Create streaming standby linking to primary
+my $node_standby_1 = get_new_node('standby_1');
+$node_standby_1->init_from_backup($node_primary, $backup_name,
+	has_streaming => 1);
+$node_standby_1->append_conf('postgresql.conf',
+    "primary_slot_name = standby_1");
+$node_standby_1->start;
+
+# Create some content on primary and check its presence in standby 1
+$node_primary->safe_psql('postgres',
+	"CREATE TABLE tab_int AS SELECT generate_series(1,1002) AS a");
+
+# Wait for standby to catch up
+$node_primary->wait_for_catchup($node_standby_1, 'replay',
+	$node_primary->lsn('insert'));
+
+my $result =
+  $node_standby_1->safe_psql('postgres', "SELECT count(*) FROM tab_int");
+print "standby 1: $result\n";
+is($result, qq(1002), 'check streamed content on standby 1');
+
+# XXX The tablespace tests don't currently work when the standby shares a
+# filesystem with the primary due to colliding absolute paths.  We'll skip
+# that for now.
+
+# Run the regression tests against the primary.
+system_or_bail($ENV{MAKE}, '-C', '../regress', 'installcheck',
+			   'PGPORT=' . $node_primary->port,
+			   'EXTRA_REGRESS_OPTS=--skip-tests=tablespace --outputdir=' . TestLib::tempdir);
+
+# Wait for standby to catch up and do a sanity check
+$node_primary->safe_psql('postgres', "INSERT INTO tab_int VALUES (42)");
+$node_primary->wait_for_catchup($node_standby_1, 'replay',
+	$node_primary->lsn('insert'));
+$result =
+  $node_standby_1->safe_psql('postgres', "SELECT count(*) FROM tab_int");
+print "standby 1: $result\n";
+is($result, qq(1003), 'check streamed content on standby 1');
+
+$node_standby_1->stop;
+$node_primary->stop;
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index b7d80bd9bb..b75eccfa7c 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -83,6 +83,7 @@ static int	max_connections = 0;
 static int	max_concurrent_tests = 0;
 static char *encoding = NULL;
 static _stringlist *schedulelist = NULL;
+static _stringlist *skip_tests = NULL;
 static _stringlist *extra_tests = NULL;
 static char *temp_instance = NULL;
 static _stringlist *temp_configs = NULL;
@@ -203,6 +204,22 @@ split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
 	free(sc);
 }
 
+/*
+ * Test if a string is in a list.
+ */
+static bool
+string_in_stringlist(const char *s, _stringlist *list)
+{
+	while (list)
+	{
+		if (strcmp(list->str, s) == 0)
+			return true;
+		list = list->next;
+	}
+
+	return false;
+}
+
 /*
  * Print a progress banner on stdout.
  */
@@ -1662,7 +1679,11 @@ run_schedule(const char *schedule, test_start_function startfunc,
 		if (scbuf[0] == '\0' || scbuf[0] == '#')
 			continue;
 		if (strncmp(scbuf, "test: ", 6) == 0)
+		{
 			test = scbuf + 6;
+			if (string_in_stringlist(test, skip_tests))
+				continue;
+		}
 		else if (strncmp(scbuf, "ignore: ", 8) == 0)
 		{
 			c = scbuf + 8;
@@ -1860,6 +1881,7 @@ run_schedule(const char *schedule, test_start_function startfunc,
 	}
 
 	free_stringlist(&ignorelist);
+	free_stringlist(&skip_tests);
 
 	fclose(scf);
 }
@@ -2065,6 +2087,7 @@ help(void)
 	printf(_("      --outputdir=DIR           place output files in DIR (default \".\")\n"));
 	printf(_("      --schedule=FILE           use test ordering schedule from FILE\n"));
 	printf(_("                                (can be used multiple times to concatenate)\n"));
+	printf(_("      --skip-tests=LIST         comma-separated list of tests to skip\n"));
 	printf(_("      --temp-instance=DIR       create a temporary instance in DIR\n"));
 	printf(_("      --use-existing            use an existing installation\n"));
 	printf(_("  -V, --version                 output version information, then exit\n"));
@@ -2116,6 +2139,7 @@ regression_main(int argc, char *argv[],
 		{"load-extension", required_argument, NULL, 22},
 		{"config-auth", required_argument, NULL, 24},
 		{"max-concurrent-tests", required_argument, NULL, 25},
+		{"skip-tests", required_argument, NULL, 26},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -2245,6 +2269,9 @@ regression_main(int argc, char *argv[],
 			case 25:
 				max_concurrent_tests = atoi(optarg);
 				break;
+			case 26:
+				split_to_stringlist(optarg, ",", &skip_tests);
+				break;
 			default:
 				/* getopt_long already emitted a complaint */
 				fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
-- 
2.30.2

Reply via email to