From b34e84f160a47d9070b304bfc1baf17596d71865 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 12 Oct 2018 09:12:31 +0900 Subject: [PATCH] Add TAP tests for pg_verify_checksums All options available in the utility get coverage: - Tests with disabled page checksums. - Tests with enabled test checksums. - Emulation of corruption and broken checksums with a full scan and single relfilenode scan. This patch has been contributed mainly by Michael Banck and Magnus Hagander with things presented on various threads, and I have gathered all the contents into a single patch. Author: Michael Banck, Magnus Hagander, Michael Paquier Reviewed-by: Peter Eisentraut Discussion: https://postgr.es/m/20181005012645.GE1629@paquier.xyz --- src/bin/initdb/t/001_initdb.pl | 14 +++- src/bin/pg_verify_checksums/.gitignore | 2 + src/bin/pg_verify_checksums/Makefile | 6 ++ src/bin/pg_verify_checksums/t/001_basic.pl | 8 +++ src/bin/pg_verify_checksums/t/002_actions.pl | 69 ++++++++++++++++++++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/bin/pg_verify_checksums/t/001_basic.pl create mode 100644 src/bin/pg_verify_checksums/t/002_actions.pl diff --git a/src/bin/initdb/t/001_initdb.pl b/src/bin/initdb/t/001_initdb.pl index 5dc629fd5e..759779adb2 100644 --- a/src/bin/initdb/t/001_initdb.pl +++ b/src/bin/initdb/t/001_initdb.pl @@ -8,7 +8,7 @@ use Fcntl ':mode'; use File::stat qw{lstat}; use PostgresNode; use TestLib; -use Test::More tests => 18; +use Test::More tests => 22; my $tempdir = TestLib::tempdir; my $xlogdir = "$tempdir/pgxlog"; @@ -58,6 +58,18 @@ mkdir $datadir; "check PGDATA permissions"); } } + +# Control file should tell that data checksums are disabled by default. +command_like(['pg_controldata', $datadir], + qr/Data page checksum version:.*0/, + 'checksums are disabled in control file'); +# pg_verify_checksums fails with checksums disabled by default. This is +# not part of the tests included in pg_verify_checksums to save from +# the creation of an extra instance. +command_fails( + [ 'pg_verify_checksums', '-D', $datadir], + "pg_verify_checksums fails with data checksum disabled"); + command_ok([ 'initdb', '-S', $datadir ], 'sync only'); command_fails([ 'initdb', $datadir ], 'existing data directory'); diff --git a/src/bin/pg_verify_checksums/.gitignore b/src/bin/pg_verify_checksums/.gitignore index d1dcdaf0dd..0e5e569a54 100644 --- a/src/bin/pg_verify_checksums/.gitignore +++ b/src/bin/pg_verify_checksums/.gitignore @@ -1 +1,3 @@ /pg_verify_checksums + +/tmp_check/ diff --git a/src/bin/pg_verify_checksums/Makefile b/src/bin/pg_verify_checksums/Makefile index d16261571f..cfe4ab1b8b 100644 --- a/src/bin/pg_verify_checksums/Makefile +++ b/src/bin/pg_verify_checksums/Makefile @@ -34,3 +34,9 @@ uninstall: clean distclean maintainer-clean: rm -f pg_verify_checksums$(X) $(OBJS) rm -rf tmp_check + +check: + $(prove_check) + +installcheck: + $(prove_installcheck) diff --git a/src/bin/pg_verify_checksums/t/001_basic.pl b/src/bin/pg_verify_checksums/t/001_basic.pl new file mode 100644 index 0000000000..1fa2e12db2 --- /dev/null +++ b/src/bin/pg_verify_checksums/t/001_basic.pl @@ -0,0 +1,8 @@ +use strict; +use warnings; +use TestLib; +use Test::More tests => 8; + +program_help_ok('pg_verify_checksums'); +program_version_ok('pg_verify_checksums'); +program_options_handling_ok('pg_verify_checksums'); diff --git a/src/bin/pg_verify_checksums/t/002_actions.pl b/src/bin/pg_verify_checksums/t/002_actions.pl new file mode 100644 index 0000000000..dc29da09af --- /dev/null +++ b/src/bin/pg_verify_checksums/t/002_actions.pl @@ -0,0 +1,69 @@ +# Do basic sanity checks supported by pg_verify_checksums using +# an initialized cluster. + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 12; + +# Initialize node with checksums enabled. +my $node = get_new_node('node_checksum'); +$node->init(extra => ['--data-checksums']); +my $pgdata = $node->data_dir; + +# Control file should know that checksums are enabled. +command_like(['pg_controldata', $pgdata], + qr/Data page checksum version:.*1/, + 'checksums enabled in control file'); + +# Checksums pass on a newly-created cluster +command_ok(['pg_verify_checksums', '-D', $pgdata], + "succeeds with offline cluster"); + +# Checks cannot happen with an online cluster +$node->start; +command_fails(['pg_verify_checksums', '-D', $pgdata], + "fails with online cluster"); + +# Create table to corrupt and get its relfilenode +$node->safe_psql('postgres', + "SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; + ALTER TABLE corrupt1 SET (autovacuum_enabled=false);"); + +my $file_corrupted = $node->safe_psql('postgres', + "SELECT pg_relation_filepath('corrupt1')"); +my $relfilenode_corrupted = $node->safe_psql('postgres', + "SELECT relfilenode FROM pg_class WHERE relname = 'corrupt1';"); + +# Set page header and block size +my $pageheader_size = 24; +my $block_size = $node->safe_psql('postgres', 'SHOW block_size;'); +$node->stop; + +# Checksums are correct for single relfilenode as the table is not +# corrupted yet. +command_ok(['pg_verify_checksums', '-D', $pgdata, + '-r', $relfilenode_corrupted], + "succeeds for single relfilenode with offline cluster"); + +# Time to create some corruption +open my $file, '+<', "$pgdata/$file_corrupted"; +seek($file, $pageheader_size, 0); +syswrite($file, '\0\0\0\0\0\0\0\0\0'); +close $file; + +# Global checksum checks fail +$node->command_checks_all([ 'pg_verify_checksums', '-D', $pgdata], + 1, + [qr/Bad checksums:.*1/], + [qr/checksum verification failed/], + 'fails with corrupted data'); + +# Checksum checks on single relfilenode fail +$node->command_checks_all([ 'pg_verify_checksums', '-D', $pgdata, '-r', + $relfilenode_corrupted], + 1, + [qr/Bad checksums:.*1/], + [qr/checksum verification failed/], + 'fails for corrupted data on single relfilenode');