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