postgresql/src/test/perl
Tom Lane d09f765b9d Harden TAP tests that intentionally corrupt page checksums.
The previous method for doing that was to write zeroes into a
predetermined set of page locations.  However, there's a roughly
1-in-64K chance that the existing checksum will match by chance,
and yesterday several buildfarm animals started to reproducibly
see that, resulting in test failures because no checksum mismatch
was reported.

Since the checksum includes the page LSN, test success depends on
the length of the installation's WAL history, which is affected by
(at least) the initial catalog contents, the set of locales installed
on the system, and the length of the pathname of the test directory.
Sooner or later we were going to hit a chance match, and today is
that day.

Harden these tests by specifically inverting the checksum field and
leaving all else alone, thereby guaranteeing that the checksum is
incorrect.

In passing, fix places that were using seek() to set up for syswrite(),
a combination that the Perl docs very explicitly warn against.  We've
probably escaped problems because no regular buffered I/O is done on
these filehandles; but if it ever breaks, we wouldn't deserve or get
much sympathy.

Although we've only seen problems in HEAD, now that we recognize the
environmental dependencies it seems like it might be just a matter
of time until someone manages to hit this in back-branch testing.
Hence, back-patch to v11 where we started doing this kind of test.

Discussion: https://postgr.es/m/3192026.1648185780@sss.pgh.pa.us
2022-03-25 14:23:26 -04:00
..
Makefile Update copyright for 2019 2019-01-02 12:44:25 -05:00
PostgresNode.pm Harden TAP tests that intentionally corrupt page checksums. 2022-03-25 14:23:26 -04:00
README Add more $Test::Builder::Level in the TAP tests 2021-10-12 11:16:30 +09:00
RecursiveCopy.pm Reindent Perl files with perltidy version 20170521. 2018-04-25 14:00:19 -04:00
SimpleTee.pm Don't fall off the end of perl functions 2018-05-27 09:08:42 -04:00
TestLib.pm Introduce PG_TEST_TIMEOUT_DEFAULT for TAP suite non-elapsing timeouts. 2022-03-04 18:53:17 -08:00

Perl-based TAP tests
====================

src/test/perl/ contains shared infrastructure that's used by Perl-based tests
across the source tree, particularly tests in src/bin and src/test. It's used
to drive tests for backup and restore, replication, etc - anything that can't
really be expressed using pg_regress or the isolation test framework.

The tests are invoked via perl's 'prove' command, wrapped in PostgreSQL
makefiles to handle instance setup etc. See the $(prove_check) and
$(prove_installcheck) targets in Makefile.global. By default every test in the
t/ subdirectory is run. Individual test(s) can be run instead by passing
something like PROVE_TESTS="t/001_testname.pl t/002_othertestname.pl" to make.

You should prefer to write tests using pg_regress in src/test/regress, or
isolation tester specs in src/test/isolation, if possible. If not, check to
see if your new tests make sense under an existing tree in src/test, like
src/test/ssl, or should be added to one of the suites for an existing utility.

Note that all tests and test tools should have perltidy run on them before
patches are submitted, using perltidy --profile=src/tools/pgindent/perltidyrc

By default, to keep the noise low during runs, we do not set any flags via
PROVE_FLAGS, but this can be done on the 'make' command line if desired, eg:

make check-world PROVE_FLAGS='--verbose'

Writing tests
-------------

Tests are written using Perl's Test::More with some PostgreSQL-specific
infrastructure from src/test/perl providing node management, support for
invoking 'psql' to run queries and get results, etc. You should read the
documentation for Test::More before trying to write tests.

Test scripts in the t/ subdirectory of a suite are executed in alphabetical
order.

Each test script should begin with:

    use strict;
    use warnings;
    use PostgresNode;
    use TestLib;
    # Replace with the number of tests to execute:
    use Test::More tests => 1;

then it will generally need to set up one or more nodes, run commands
against them and evaluate the results. For example:

    my $node = PostgresNode->get_new_node('master');
    $node->init;
    $node->start;

    my $ret = $node->safe_psql('postgres', 'SELECT 1');
    is($ret, '1', 'SELECT 1 returns 1');

    $node->stop('fast');

Test::More::like entails use of the qr// operator.  Avoid Perl 5.8.8 bug
#39185 by not using the "$" regular expression metacharacter in qr// when also
using the "/m" modifier.  Instead of "$", use "\n" or "(?=\n|\z)".

Test::Builder::Level controls how far up in the call stack a test will look
at when reporting a failure.  This should be incremented by any subroutine
which directly or indirectly calls test routines from Test::More, such as
ok() or is():

    local $Test::Builder::Level = $Test::Builder::Level + 1;

Read the documentation for more on how to write tests:

    perldoc Test::More
    perldoc Test::Builder

For available PostgreSQL-specific test methods and some example tests read the
perldoc for the test modules, e.g.:

    perldoc src/test/perl/PostgresNode.pm

Required Perl
-------------

Tests must run on perl 5.8.0 and newer. perlbrew is a good way to obtain such
a Perl; see http://perlbrew.pl .

Just install and

    perlbrew --force install 5.8.0
    perlbrew use 5.8.0
    perlbrew install-cpanm
    cpanm install IPC::Run

then re-run configure to ensure the correct Perl is used when running
tests. To verify that the right Perl was found:

    grep ^PERL= config.log