diff options
Diffstat (limited to 'src/bin/pg_rewind/t/001_basic.pl')
-rw-r--r-- | src/bin/pg_rewind/t/001_basic.pl | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/bin/pg_rewind/t/001_basic.pl b/src/bin/pg_rewind/t/001_basic.pl new file mode 100644 index 0000000..db9201f --- /dev/null +++ b/src/bin/pg_rewind/t/001_basic.pl @@ -0,0 +1,194 @@ + +# Copyright (c) 2021-2022, PostgreSQL Global Development Group + +use strict; +use warnings; +use PostgreSQL::Test::Utils; +use Test::More; + +use FindBin; +use lib $FindBin::RealBin; + +use RewindTest; + +sub run_test +{ + my $test_mode = shift; + + RewindTest::setup_cluster($test_mode); + RewindTest::start_primary(); + + # Create a test table and insert a row in primary. + primary_psql("CREATE TABLE tbl1 (d text)"); + primary_psql("INSERT INTO tbl1 VALUES ('in primary')"); + + # This test table will be used to test truncation, i.e. the table + # is extended in the old primary after promotion + primary_psql("CREATE TABLE trunc_tbl (d text)"); + primary_psql("INSERT INTO trunc_tbl VALUES ('in primary')"); + + # This test table will be used to test the "copy-tail" case, i.e. the + # table is truncated in the old primary after promotion + primary_psql("CREATE TABLE tail_tbl (id integer, d text)"); + primary_psql("INSERT INTO tail_tbl VALUES (0, 'in primary')"); + + # This test table is dropped in the old primary after promotion. + primary_psql("CREATE TABLE drop_tbl (d text)"); + primary_psql("INSERT INTO drop_tbl VALUES ('in primary')"); + + primary_psql("CHECKPOINT"); + + RewindTest::create_standby($test_mode); + + # Insert additional data on primary that will be replicated to standby + primary_psql("INSERT INTO tbl1 values ('in primary, before promotion')"); + primary_psql( + "INSERT INTO trunc_tbl values ('in primary, before promotion')"); + primary_psql( + "INSERT INTO tail_tbl SELECT g, 'in primary, before promotion: ' || g FROM generate_series(1, 10000) g" + ); + + primary_psql('CHECKPOINT'); + + RewindTest::promote_standby(); + + # Insert a row in the old primary. This causes the primary and standby + # to have "diverged", it's no longer possible to just apply the + # standy's logs over primary directory - you need to rewind. + primary_psql("INSERT INTO tbl1 VALUES ('in primary, after promotion')"); + + # Also insert a new row in the standby, which won't be present in the + # old primary. + standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')"); + + # Insert enough rows to trunc_tbl to extend the file. pg_rewind should + # truncate it back to the old size. + primary_psql( + "INSERT INTO trunc_tbl SELECT 'in primary, after promotion: ' || g FROM generate_series(1, 10000) g" + ); + + # Truncate tail_tbl. pg_rewind should copy back the truncated part + # (We cannot use an actual TRUNCATE command here, as that creates a + # whole new relfilenode) + primary_psql("DELETE FROM tail_tbl WHERE id > 10"); + primary_psql("VACUUM tail_tbl"); + + # Drop drop_tbl. pg_rewind should copy it back. + primary_psql( + "insert into drop_tbl values ('in primary, after promotion')"); + primary_psql("DROP TABLE drop_tbl"); + + # Before running pg_rewind, do a couple of extra tests with several + # option combinations. As the code paths taken by those tests + # do not change for the "local" and "remote" modes, just run them + # in "local" mode for simplicity's sake. + if ($test_mode eq 'local') + { + my $primary_pgdata = $node_primary->data_dir; + my $standby_pgdata = $node_standby->data_dir; + + # First check that pg_rewind fails if the target cluster is + # not stopped as it fails to start up for the forced recovery + # step. + command_fails( + [ + 'pg_rewind', '--debug', + '--source-pgdata', $standby_pgdata, + '--target-pgdata', $primary_pgdata, + '--no-sync' + ], + 'pg_rewind with running target'); + + # Again with --no-ensure-shutdown, which should equally fail. + # This time pg_rewind complains without attempting to perform + # recovery once. + command_fails( + [ + 'pg_rewind', '--debug', + '--source-pgdata', $standby_pgdata, + '--target-pgdata', $primary_pgdata, + '--no-sync', '--no-ensure-shutdown' + ], + 'pg_rewind --no-ensure-shutdown with running target'); + + # Stop the target, and attempt to run with a local source + # still running. This fails as pg_rewind requires to have + # a source cleanly stopped. + $node_primary->stop; + command_fails( + [ + 'pg_rewind', '--debug', + '--source-pgdata', $standby_pgdata, + '--target-pgdata', $primary_pgdata, + '--no-sync', '--no-ensure-shutdown' + ], + 'pg_rewind with unexpected running source'); + + # Stop the target cluster cleanly, and run again pg_rewind + # with --dry-run mode. If anything gets generated in the data + # folder, the follow-up run of pg_rewind will most likely fail, + # so keep this test as the last one of this subset. + $node_standby->stop; + command_ok( + [ + 'pg_rewind', '--debug', + '--source-pgdata', $standby_pgdata, + '--target-pgdata', $primary_pgdata, + '--no-sync', '--dry-run' + ], + 'pg_rewind --dry-run'); + + # Both clusters need to be alive moving forward. + $node_standby->start; + $node_primary->start; + } + + RewindTest::run_pg_rewind($test_mode); + + check_query( + 'SELECT * FROM tbl1', + qq(in primary +in primary, before promotion +in standby, after promotion +), + 'table content'); + + check_query( + 'SELECT * FROM trunc_tbl', + qq(in primary +in primary, before promotion +), + 'truncation'); + + check_query( + 'SELECT count(*) FROM tail_tbl', + qq(10001 +), + 'tail-copy'); + + check_query( + 'SELECT * FROM drop_tbl', + qq(in primary +), + 'drop'); + + # Permissions on PGDATA should be default + SKIP: + { + skip "unix-style permissions not supported on Windows", 1 + if ($windows_os); + + ok(check_mode_recursive($node_primary->data_dir(), 0700, 0600), + 'check PGDATA permissions'); + } + + RewindTest::clean_rewind_test(); + return; +} + +# Run the test in both modes +run_test('local'); +run_test('remote'); +run_test('archive'); + +done_testing(); |