diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/Makefile | 3 | ||||
-rw-r--r-- | src/test/checksum/.gitignore | 2 | ||||
-rw-r--r-- | src/test/checksum/Makefile | 24 | ||||
-rw-r--r-- | src/test/checksum/README | 22 | ||||
-rw-r--r-- | src/test/checksum/t/001_standby_checksum.pl | 101 | ||||
-rw-r--r-- | src/test/isolation/expected/checksum_cancel.out | 27 | ||||
-rw-r--r-- | src/test/isolation/expected/checksum_enable.out | 27 | ||||
-rw-r--r-- | src/test/isolation/isolation_schedule | 4 | ||||
-rw-r--r-- | src/test/isolation/specs/checksum_cancel.spec | 47 | ||||
-rw-r--r-- | src/test/isolation/specs/checksum_enable.spec | 70 |
10 files changed, 326 insertions, 1 deletions
diff --git a/src/test/Makefile b/src/test/Makefile index efb206aa750..6469ac94a47 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -12,7 +12,8 @@ subdir = src/test top_builddir = ../.. include $(top_builddir)/src/Makefile.global -SUBDIRS = perl regress isolation modules authentication recovery subscription +SUBDIRS = perl regress isolation modules authentication recovery subscription \ + checksum # Test suites that are not safe by default but can be run if selected # by the user via the whitespace-separated list in variable diff --git a/src/test/checksum/.gitignore b/src/test/checksum/.gitignore new file mode 100644 index 00000000000..871e943d50e --- /dev/null +++ b/src/test/checksum/.gitignore @@ -0,0 +1,2 @@ +# Generated by test suite +/tmp_check/ diff --git a/src/test/checksum/Makefile b/src/test/checksum/Makefile new file mode 100644 index 00000000000..f3ad9dfae16 --- /dev/null +++ b/src/test/checksum/Makefile @@ -0,0 +1,24 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/test/checksum +# +# Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/test/checksum/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/test/checksum +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +check: + $(prove_check) + +installcheck: + $(prove_installcheck) + +clean distclean maintainer-clean: + rm -rf tmp_check + diff --git a/src/test/checksum/README b/src/test/checksum/README new file mode 100644 index 00000000000..e3fbd2bdb54 --- /dev/null +++ b/src/test/checksum/README @@ -0,0 +1,22 @@ +src/test/checksum/README + +Regression tests for data checksums +=================================== + +This directory contains a test suite for enabling data checksums +in a running cluster with streaming replication. + +Running the tests +================= + + make check + +or + + make installcheck + +NOTE: This creates a temporary installation (in the case of "check"), +with multiple nodes, be they master or standby(s) for the purpose of +the tests. + +NOTE: This requires the --enable-tap-tests argument to configure. diff --git a/src/test/checksum/t/001_standby_checksum.pl b/src/test/checksum/t/001_standby_checksum.pl new file mode 100644 index 00000000000..6a45356b6b1 --- /dev/null +++ b/src/test/checksum/t/001_standby_checksum.pl @@ -0,0 +1,101 @@ +# Test suite for testing enabling data checksums with streaming replication +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 10; + +my $MAX_TRIES = 30; + +# Initialize master node +my $node_master = get_new_node('master'); +$node_master->init(allows_streaming => 1); +$node_master->start; +my $backup_name = 'my_backup'; + +# Take backup +$node_master->backup($backup_name); + +# Create streaming standby linking to master +my $node_standby_1 = get_new_node('standby_1'); +$node_standby_1->init_from_backup($node_master, $backup_name, + has_streaming => 1); +$node_standby_1->start; + +# Create some content on master to have un-checksummed data in the cluster +$node_master->safe_psql('postgres', + "CREATE TABLE t AS SELECT generate_series(1,10000) AS a;"); + +# Wait for standbys to catch up +$node_master->wait_for_catchup($node_standby_1, 'replay', + $node_master->lsn('insert')); + +# Check that checksums are turned off +my $result = $node_master->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); +is($result, "off", 'ensure checksums are turned off on master'); + +$result = $node_standby_1->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); +is($result, "off", 'ensure checksums are turned off on standby_1'); + +# Enable checksums for the cluster +$node_master->safe_psql('postgres', "SELECT pg_enable_data_checksums();"); + +# Ensure that the master has switched to inprogress immediately +$result = $node_master->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); +is($result, "inprogress", 'ensure checksums are in progress on master'); + +# Wait for checksum enable to be replayed +$node_master->wait_for_catchup($node_standby_1, 'replay'); + +# Ensure that the standby has switched to inprogress +$result = $node_standby_1->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); +is($result, "inprogress", 'ensure checksums are in progress on standby_1'); + +# Insert some more data which should be checksummed on INSERT +$node_master->safe_psql('postgres', + "INSERT INTO t VALUES (generate_series(1,10000));"); + +# Wait for checksums enabled on the master +for (my $i = 0; $i < $MAX_TRIES; $i++) +{ + $result = $node_master->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); + last if ($result eq 'on'); + sleep(1); +} +is ($result, "on", 'ensure checksums are enabled on master'); + +# Wait for checksums enabled on the standby +for (my $i = 0; $i < $MAX_TRIES; $i++) +{ + $result = $node_standby_1->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); + last if ($result eq 'on'); + sleep(1); +} +is ($result, "on", 'ensure checksums are enabled on standby'); + +$result = $node_master->safe_psql('postgres', "SELECT count(a) FROM t"); +is ($result, "20000", 'ensure we can safely read all data with checksums'); + +# Disable checksums and ensure it's propagated to standby and that we can +# still read all data +$node_master->safe_psql('postgres', "SELECT pg_disable_data_checksums();"); +$result = $node_master->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); +is($result, "off", 'ensure checksums are in progress on master'); + +# Wait for checksum disable to be replayed +$node_master->wait_for_catchup($node_standby_1, 'replay'); + +# Ensure that the standby has switched to off +$result = $node_standby_1->safe_psql('postgres', + "SELECT setting FROM pg_catalog.pg_settings WHERE name = 'data_checksums';"); +is($result, "off", 'ensure checksums are in progress on standby_1'); + +$result = $node_master->safe_psql('postgres', "SELECT count(a) FROM t"); +is ($result, "20000", 'ensure we can safely read all data without checksums'); diff --git a/src/test/isolation/expected/checksum_cancel.out b/src/test/isolation/expected/checksum_cancel.out new file mode 100644 index 00000000000..c449e7b6ccd --- /dev/null +++ b/src/test/isolation/expected/checksum_cancel.out @@ -0,0 +1,27 @@ +Parsed test spec with 2 sessions + +starting permutation: c_verify_checksums_off r_seqread c_enable_checksums c_verify_checksums_inprogress c_disable_checksums c_wait_checksums_off +step c_verify_checksums_off: SELECT setting = 'off' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; +?column? + +t +step r_seqread: SELECT * FROM reader_loop(); +reader_loop + +t +step c_enable_checksums: SELECT pg_enable_data_checksums(1000); +pg_enable_data_checksums + + +step c_verify_checksums_inprogress: SELECT setting = 'inprogress' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; +?column? + +t +step c_disable_checksums: SELECT pg_disable_data_checksums(); +pg_disable_data_checksums + + +step c_wait_checksums_off: SELECT test_checksums_off(); +test_checksums_off + +t diff --git a/src/test/isolation/expected/checksum_enable.out b/src/test/isolation/expected/checksum_enable.out new file mode 100644 index 00000000000..0a68f470233 --- /dev/null +++ b/src/test/isolation/expected/checksum_enable.out @@ -0,0 +1,27 @@ +Parsed test spec with 3 sessions + +starting permutation: c_verify_checksums_off w_insert100k r_seqread c_enable_checksums c_wait_for_checksums c_verify_checksums_on +step c_verify_checksums_off: SELECT setting = 'off' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; +?column? + +t +step w_insert100k: SELECT insert_1k(100); +insert_1k + +t +step r_seqread: SELECT * FROM reader_loop(); +reader_loop + +t +step c_enable_checksums: SELECT pg_enable_data_checksums(); +pg_enable_data_checksums + + +step c_wait_for_checksums: SELECT test_checksums_on(); +test_checksums_on + +t +step c_verify_checksums_on: SELECT setting = 'on' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; +?column? + +t diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index 99dd7c6bdbf..31900cb920b 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -72,3 +72,7 @@ test: timeouts test: vacuum-concurrent-drop test: predicate-gist test: predicate-gin +# The checksum_enable suite will enable checksums for the cluster so should +# not run before anything expecting the cluster to have checksums turned off +test: checksum_cancel +test: checksum_enable diff --git a/src/test/isolation/specs/checksum_cancel.spec b/src/test/isolation/specs/checksum_cancel.spec new file mode 100644 index 00000000000..3466a749d2e --- /dev/null +++ b/src/test/isolation/specs/checksum_cancel.spec @@ -0,0 +1,47 @@ +setup +{ + CREATE TABLE t1 (a serial, b integer, c text); + INSERT INTO t1 (b, c) VALUES (generate_series(1,10000), 'starting values'); + + CREATE OR REPLACE FUNCTION test_checksums_off() RETURNS boolean AS $$ + DECLARE + enabled boolean; + BEGIN + PERFORM pg_sleep(1); + SELECT setting = 'off' INTO enabled FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; + RETURN enabled; + END; + $$ LANGUAGE plpgsql; + + CREATE OR REPLACE FUNCTION reader_loop() RETURNS boolean AS $$ + DECLARE + counter integer; + enabled boolean; + BEGIN + FOR counter IN 1..100 LOOP + PERFORM count(a) FROM t1; + END LOOP; + RETURN True; + END; + $$ LANGUAGE plpgsql; +} + +teardown +{ + DROP FUNCTION reader_loop(); + DROP FUNCTION test_checksums_off(); + + DROP TABLE t1; +} + +session "reader" +step "r_seqread" { SELECT * FROM reader_loop(); } + +session "checksums" +step "c_verify_checksums_off" { SELECT setting = 'off' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; } +step "c_enable_checksums" { SELECT pg_enable_data_checksums(1000); } +step "c_disable_checksums" { SELECT pg_disable_data_checksums(); } +step "c_verify_checksums_inprogress" { SELECT setting = 'inprogress' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; } +step "c_wait_checksums_off" { SELECT test_checksums_off(); } + +permutation "c_verify_checksums_off" "r_seqread" "c_enable_checksums" "c_verify_checksums_inprogress" "c_disable_checksums" "c_wait_checksums_off" diff --git a/src/test/isolation/specs/checksum_enable.spec b/src/test/isolation/specs/checksum_enable.spec new file mode 100644 index 00000000000..ba85dd6176f --- /dev/null +++ b/src/test/isolation/specs/checksum_enable.spec @@ -0,0 +1,70 @@ +setup +{ + CREATE TABLE t1 (a serial, b integer, c text); + INSERT INTO t1 (b, c) VALUES (generate_series(1,10000), 'starting values'); + + CREATE OR REPLACE FUNCTION insert_1k(iterations int) RETURNS boolean AS $$ + DECLARE + counter integer; + BEGIN + FOR counter IN 1..$1 LOOP + INSERT INTO t1 (b, c) VALUES ( + generate_series(1, 1000), + array_to_string(array(select chr(97 + (random() * 25)::int) from generate_series(1,250)), '') + ); + PERFORM pg_sleep(0.1); + END LOOP; + RETURN True; + END; + $$ LANGUAGE plpgsql; + + CREATE OR REPLACE FUNCTION test_checksums_on() RETURNS boolean AS $$ + DECLARE + enabled boolean; + BEGIN + LOOP + SELECT setting = 'on' INTO enabled FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; + IF enabled THEN + EXIT; + END IF; + PERFORM pg_sleep(1); + END LOOP; + RETURN enabled; + END; + $$ LANGUAGE plpgsql; + + CREATE OR REPLACE FUNCTION reader_loop() RETURNS boolean AS $$ + DECLARE + counter integer; + BEGIN + FOR counter IN 1..30 LOOP + PERFORM count(a) FROM t1; + PERFORM pg_sleep(0.2); + END LOOP; + RETURN True; + END; + $$ LANGUAGE plpgsql; +} + +teardown +{ + DROP FUNCTION reader_loop(); + DROP FUNCTION test_checksums_on(); + DROP FUNCTION insert_1k(int); + + DROP TABLE t1; +} + +session "writer" +step "w_insert100k" { SELECT insert_1k(100); } + +session "reader" +step "r_seqread" { SELECT * FROM reader_loop(); } + +session "checksums" +step "c_verify_checksums_off" { SELECT setting = 'off' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; } +step "c_enable_checksums" { SELECT pg_enable_data_checksums(); } +step "c_wait_for_checksums" { SELECT test_checksums_on(); } +step "c_verify_checksums_on" { SELECT setting = 'on' FROM pg_catalog.pg_settings WHERE name = 'data_checksums'; } + +permutation "c_verify_checksums_off" "w_insert100k" "r_seqread" "c_enable_checksums" "c_wait_for_checksums" "c_verify_checksums_on" |