3 # Test driver for pg_rewind. Each test consists of a cycle where a new cluster
4 # is first created with initdb, and a streaming replication standby is set up
5 # to follow the master. Then the master is shut down and the standby is
6 # promoted, and finally pg_rewind is used to rewind the old master, using the
7 # standby as the source.
9 # To run a test, the test script (in t/ subdirectory) calls the functions
10 # in this module. These functions should be called in this sequence:
12 # 1. setup_cluster - creates a PostgreSQL cluster that runs as the master
14 # 2. start_master - starts the master server
16 # 3. create_standby - runs pg_basebackup to initialize a standby server, and
17 # sets it up to follow the master.
19 # 4. promote_standby - runs "pg_ctl promote" to promote the standby server.
20 # The old master keeps running.
22 # 5. run_pg_rewind - stops the old master (if it's still running) and runs
23 # pg_rewind to synchronize it with the now-promoted standby server.
25 # 6. clean_rewind_test - stops both servers used in the test, if they're
28 # The test script can use the helper functions master_psql and standby_psql
29 # to run psql against the master and standby servers, respectively. The
30 # test script can also use the $connstr_master and $connstr_standby global
31 # variables, which contain libpq connection strings for connecting to the
32 # master and standby servers. The data directories are also available
33 # in paths $test_master_datadir and $test_standby_datadir
40 use Exporter 'import';
42 use File::Path qw(rmtree);
72 system_or_bail 'psql', '-q', '--no-psqlrc', '-d',
73 $node_master->connstr('postgres'), '-c', "$cmd";
80 system_or_bail 'psql', '-q', '--no-psqlrc', '-d',
81 $node_standby->connstr('postgres'), '-c', "$cmd";
84 # Run a query against the master, and check that the output matches what's
88 my ($query, $expected_stdout, $test_name) = @_;
89 my ($stdout, $stderr);
91 # we want just the output, no formatting
93 'psql', '-q', '-A', '-t', '--no-psqlrc', '-d',
94 $node_master->connstr('postgres'),
97 '>', \$stdout, '2>', \$stderr;
99 # We don't use ok() for the exit code and stderr, because we want this
100 # check to be just a single test.
103 fail("$test_name: psql exit code");
105 elsif ($stderr ne '')
108 fail("$test_name: psql no stderr");
112 $stdout =~ s/\r//g if $Config{osname} eq 'msys';
113 is($stdout, $expected_stdout, "$test_name: query result matches");
119 my $extra_name = shift; # Used to differentiate clusters
120 my $extra = shift; # Extra params for initdb
122 # Initialize master, data checksums are mandatory
124 get_new_node('master' . ($extra_name ? "_${extra_name}" : ''));
125 $node_master->init(allows_streaming => 1, extra => $extra);
127 # Set wal_keep_segments to prevent WAL segment recycling after enforced
128 # checkpoints in the tests.
129 $node_master->append_conf(
130 'postgresql.conf', qq(
131 wal_keep_segments = 20
139 #### Now run the test-specific parts to initialize the master before setting
145 my $extra_name = shift;
148 get_new_node('standby' . ($extra_name ? "_${extra_name}" : ''));
149 $node_master->backup('my_backup');
150 $node_standby->init_from_backup($node_master, 'my_backup');
151 my $connstr_master = $node_master->connstr();
153 $node_standby->append_conf(
155 primary_conninfo='$connstr_master application_name=rewind_standby'
157 recovery_target_timeline='latest'
161 $node_standby->start;
163 # The standby may have WAL to apply before it matches the primary. That
164 # is fine, because no test examines the standby before promotion.
169 #### Now run the test-specific parts to run after standby has been started
172 # Wait for the standby to receive and write all WAL.
173 $node_master->wait_for_catchup('rewind_standby', 'write');
175 # Now promote standby and insert some new data on master, this will put
176 # the master out-of-sync with the standby.
177 $node_standby->promote;
179 # Force a checkpoint after the promotion. pg_rewind looks at the control
180 # file to determine what timeline the server is on, and that isn't updated
181 # immediately at promotion, but only at the next checkpoint. When running
182 # pg_rewind in remote mode, it's possible that we complete the test steps
183 # after promotion so quickly that when pg_rewind runs, the standby has not
184 # performed a checkpoint after promotion yet.
185 standby_psql("checkpoint");
190 my $test_mode = shift;
191 my $master_pgdata = $node_master->data_dir;
192 my $standby_pgdata = $node_standby->data_dir;
193 my $standby_connstr = $node_standby->connstr('postgres');
194 my $tmp_folder = TestLib::tempdir;
196 # Stop the master and be ready to perform the rewind
199 # At this point, the rewind processing is ready to run.
200 # We now have a very simple scenario with a few diverged WAL record.
201 # The real testing begins really now with a bifurcation of the possible
202 # scenarios that pg_rewind supports.
204 # Keep a temporary postgresql.conf for master node or it would be
205 # overwritten during the rewind.
207 "$master_pgdata/postgresql.conf",
208 "$tmp_folder/master-postgresql.conf.tmp");
211 if ($test_mode eq "local")
214 # Do rewind using a local pgdata as source
215 # Stop the master and be ready to perform the rewind
221 "--source-pgdata=$standby_pgdata",
222 "--target-pgdata=$master_pgdata"
226 elsif ($test_mode eq "remote")
229 # Do rewind using a remote connection as source
232 'pg_rewind', "--debug",
233 "--source-server", $standby_connstr,
234 "--target-pgdata=$master_pgdata"
241 # Cannot come here normally
242 croak("Incorrect test mode specified");
245 # Now move back postgresql.conf with old settings
247 "$tmp_folder/master-postgresql.conf.tmp",
248 "$master_pgdata/postgresql.conf");
251 $node_master->group_access() ? 0640 : 0600,
252 "$master_pgdata/postgresql.conf")
254 "unable to set permissions for $master_pgdata/postgresql.conf");
256 # Plug-in rewound node to the now-promoted standby node
257 my $port_standby = $node_standby->port;
258 $node_master->append_conf(
260 primary_conninfo='port=$port_standby'
262 recovery_target_timeline='latest'
265 # Restart the master to check that rewind went correctly
268 #### Now run the test-specific parts to check the result
271 # Clean up after the test. Stop both servers, if they're still running.
272 sub clean_rewind_test
274 $node_master->teardown_node if defined $node_master;
275 $node_standby->teardown_node if defined $node_standby;