Er, the patch is attached this time.

On 22 February 2016 at 18:54, Craig Ringer <cr...@2ndquadrant.com> wrote:

> On 22 February 2016 at 15:41, Michael Paquier <michael.paqu...@gmail.com>
> wrote:
>
>
>>
>> >> > Sound about right? I can tidy that up a bit and turn it into a README
>> >> > and
>> >> > add a reference to that to the public tap docs to tell users where
>> to go
>> >> > if
>> >> > they want to write more tests.
>> >>
>> >> Yes, please.
>> >
>> > Will do that now.
>>
>> This is definitely independent from the efforts of the other patches.
>>
>
> Done.
>
> I got a bit carried away and added:
>
> - src/test/perl/README
> - src/test/README
> - src/test/modules/README
> - POD for src/test/perl/PostgresNode.pm
> - $node->info() function (that just returns what dump_info() printed, but
> as a string
> - $node->backup(...) support for passing -R to pg_basebackup
> - $node->backup(...) support for passing -X stream to pg_basebackup
> -  src/test/example_suite/ with some simple demo tests
>
> I found that I was writing documentation for how to write tests that'd
> bitrot quickly and landed up writing a demo/sample test that can be run as
> part of 'make check' with --enable-tap-tests instead. Hopefully it's not
> overkill.
>
> LMK if you think it's too much and I can trim out what's unwanted.
>
> In the process I noticed a few helpers I think should be added to
> PostgresNode. I haven't added them since I didn't want this to turn into a
> big patch when it was meant to just be 'add a README', but the main things
> are:
>
> - promote (you've done this)
>
> - Facilities to make it easier to set a master up as replication-enabled
> (your patch does this, but it should use wal_level = 'logical' by default
> IMO; also I think setting autovacuum=off is very wrong and will mask
> problems)
>
> - wait_for_recovery_lsn($lsn) to wait until a hot standby passes a given
> LSN
>
> - wait_for_replication_lsn($lsn, $col, $appname) - wait until standby with
> name $appname (or any standby, if unspecified) passes $lsn for $col, where
> $col can be 'sent', 'write', 'flush' or 'replay'
>
>
>
>> > Not committed yet, I see. That's
>> https://commitfest.postgresql.org/9/438/
>> > right?
>>
>> Yeah... That's life.
>>
>>
> I'll comment separately on that thread.
>
> --
>  Craig Ringer                   http://www.2ndQuadrant.com/
>  PostgreSQL Development, 24x7 Support, Training & Services
>



-- 
 Craig Ringer                   http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services
From 0271314446293a61457f0b8e6a77d784804bae43 Mon Sep 17 00:00:00 2001
From: Craig Ringer <cr...@2ndquadrant.com>
Date: Mon, 22 Feb 2016 18:54:24 +0800
Subject: [PATCH] Add README and example to document how to create TAP tests

---
 src/test/Makefile                       |   2 +-
 src/test/README                         |  37 ++++
 src/test/example_suite/.gitignore       |   1 +
 src/test/example_suite/Makefile         |   9 +
 src/test/example_suite/t/001_minimal.pl | 157 ++++++++++++++
 src/test/mb/.gitignore                  |   1 +
 src/test/modules/README                 |  10 +
 src/test/perl/PostgresNode.pm           | 374 +++++++++++++++++++++++++++++---
 src/test/perl/README                    |  37 ++++
 9 files changed, 596 insertions(+), 32 deletions(-)
 create mode 100644 src/test/README
 create mode 100644 src/test/example_suite/.gitignore
 create mode 100644 src/test/example_suite/Makefile
 create mode 100644 src/test/example_suite/t/001_minimal.pl
 create mode 100644 src/test/mb/.gitignore
 create mode 100644 src/test/modules/README
 create mode 100644 src/test/perl/README

diff --git a/src/test/Makefile b/src/test/Makefile
index b713c2c..e9b0136 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -12,7 +12,7 @@ subdir = src/test
 top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS = regress isolation modules
+SUBDIRS = regress isolation modules example_suite
 
 # We don't build or execute examples/, locale/, or thread/ by default,
 # but we do want "make clean" etc to recurse into them.  Likewise for ssl/,
diff --git a/src/test/README b/src/test/README
new file mode 100644
index 0000000..485f20b
--- /dev/null
+++ b/src/test/README
@@ -0,0 +1,37 @@
+This directory contains a variety of test infrastructure as well as some of the
+tests in PostgreSQL. Not all tests are here - in particular, there are more in
+individual contrib/ modules and in src/bin.
+
+Not all these tests get run by "make check". Check src/test/Makefile to see
+which tests get run automatically.
+
+examples/
+  demo programs for libpq that double as regression tests via "make check"
+
+isolation/
+  tests for concurrent behaviours at the SQL level
+
+locale/
+  sanity checks for locale data, encodings, etc
+
+mb/
+  tests for multibyte encoding (UTF-8) support
+
+modules/
+  extensions used only or mainly for test purposes, generally not useful
+  or suitable for installing in production databases. Some of these have
+  their own tests, some are used by tests elsewhere.
+
+perl/
+  infrastructure for Perl-based Test::More tests. There are no actual tests
+  here, the code is used by other tests in src/bin/, contrib/ and in the
+  subdirectories of src/test.
+
+regress/
+  PostgreSQL's main regression test suite, pg_regress
+
+ssl/
+  Tests to exercise and verify SSL certificate handling
+
+thread/
+  A thread-safety-testing utility used by configure, see its README
diff --git a/src/test/example_suite/.gitignore b/src/test/example_suite/.gitignore
new file mode 100644
index 0000000..b6a2a01
--- /dev/null
+++ b/src/test/example_suite/.gitignore
@@ -0,0 +1 @@
+/tmp_check/
diff --git a/src/test/example_suite/Makefile b/src/test/example_suite/Makefile
new file mode 100644
index 0000000..f557c7d
--- /dev/null
+++ b/src/test/example_suite/Makefile
@@ -0,0 +1,9 @@
+subdir = src/test/example_suite
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+check:
+	$(prove_check)
+
+clean:
+	rm -rf ./tmp_check
diff --git a/src/test/example_suite/t/001_minimal.pl b/src/test/example_suite/t/001_minimal.pl
new file mode 100644
index 0000000..7fe489a
--- /dev/null
+++ b/src/test/example_suite/t/001_minimal.pl
@@ -0,0 +1,157 @@
+=pod
+
+=head1 Demo tests
+
+This is a minimal example showing how to use the Perl-based test framework for
+writing tests that are more complicated than pg_regress or the isolation tester
+can handle.
+
+Test scripts should all begin with:
+
+    use strict;
+    use warnings;
+    use 5.8.8;
+    use PostgresNode;
+    use TestLib;
+
+The script must include:
+
+    use Test::More tests => 1;
+
+where the number of tests expected to run is the value of 'tests'.
+
+All tests must support running under Perl 5.8.8. "use 5_008_008" does NOT
+ensure that.
+
+=cut
+
+use strict;
+use warnings;
+use 5.8.8;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 5;
+
+my $verbose = 0;
+
+=pod
+
+=head2 Set up a node
+
+Unlike pg_regress tests, Perl-based tests must create their own PostgreSQL
+node (s). The nodes are managed with the PostgresNode module; see that module
+for methods available for the node.
+
+=cut
+
+diag 'Setting up node "master"' if $verbose;
+my $node = get_new_node('master');
+$node->init;
+$node->start;
+
+diag $node->info() if $verbose;
+
+=pod
+
+=head2 Trivial SELECT test
+
+A very simple test that just runs a SELECT and checks the result.
+
+Obviously you should write tests like this with pg_regress, but this
+serves to demonstrate the minimal setup required.
+
+=cut
+
+my $ret = $node->psql('postgres', 'SELECT 1;');
+is($ret, '1', 'simple SELECT');
+
+=pod
+
+=head2 Create a read-replica
+
+One of the reasons to write Perl tests is to do work that touches
+multiple nodes, so lets set up a second node.
+
+=cut
+
+diag 'Reconfiguring master for replication' if $verbose;
+$node->append_conf('postgresql.conf', "max_wal_senders = 2\n");
+$node->append_conf('postgresql.conf', "wal_level = logical\n");
+$node->append_conf('postgresql.conf', "hot_standby = on\n");
+$node->restart('fast');
+
+diag 'Making base backup of current node' if $verbose;
+$ret = $node->backup('makereplica',
+	write_recovery_conf => 1,
+	xlog_stream => 1);
+ok($ret, 'base backup of master');
+
+diag 'Setting up node "replica"' if $verbose;
+my $replica = get_new_node('replica');
+$replica->init_from_backup($node, 'makereplica');
+$replica->start;
+
+diag $replica->info() if $verbose;
+
+=pod
+
+=head2 Wait for replica to catch up
+
+A simple example of the sort of tests that can be written with this
+toolset: write to a master server then wait until the replica server
+replays the change.
+
+=cut
+
+diag 'Setting up for catchup tests' if $verbose;
+
+$node->psql('postgres', q|
+	CREATE TABLE replica_test(blah text);
+	INSERT INTO replica_test(blah) VALUES ('fruit bat');
+	|);
+
+# method one: poll until the new row becomes visible on the replica
+diag 'Waiting for replica to catch up - polling' if $verbose;
+$ret = $replica->poll_query_until('postgres',
+	q|SELECT 't' FROM replica_test WHERE blah = 'fruit bat';|);
+
+ok($ret, 'caught up - polling for row');
+
+# Method two: wait for the replica replay position to overtake the master
+# by querying the replica.
+$node->psql('postgres', q|INSERT INTO replica_test(blah) VALUES ('donkey');|);
+
+my $lsn = $node->psql('postgres', 'SELECT pg_current_xlog_location()');
+
+diag "Waiting for replica to catch up to $lsn - replica xlog location" if $verbose;
+$ret = $replica->poll_query_until('postgres',
+	qq|SELECT pg_xlog_location_diff('$lsn', pg_last_xlog_replay_location()) <= 0;|);
+
+ok($ret, 'caught up - polling for replay on replica');
+
+# Method three: wait for the replica to catch up according to
+# pg_stat_replication on the master.
+$node->psql('postgres', q|INSERT INTO replica_test(blah) VALUES ('turkey');|);
+
+$lsn = $node->psql('postgres', 'SELECT pg_current_xlog_location()');
+
+# This assumes only one replica...
+diag "Waiting for replica to catch up to $lsn - pg_stat_replication" if $verbose;
+$ret = $node->poll_query_until('postgres',
+	qq|SELECT pg_xlog_location_diff('$lsn', replay_location) <= 0
+	   FROM pg_stat_replication|);
+
+ok($ret, 'caught up - polling pg_stat_replication on master');
+
+=pod
+
+=head2 Test teardown
+
+Every test should end by explicitly tearing down the node (s) it created.
+
+=cut
+
+$node->teardown_node;
+$replica->teardown_node;
+
+1;
diff --git a/src/test/mb/.gitignore b/src/test/mb/.gitignore
new file mode 100644
index 0000000..6628455
--- /dev/null
+++ b/src/test/mb/.gitignore
@@ -0,0 +1 @@
+/results/
diff --git a/src/test/modules/README b/src/test/modules/README
new file mode 100644
index 0000000..290268d
--- /dev/null
+++ b/src/test/modules/README
@@ -0,0 +1,10 @@
+src/test/modules contains PostgreSQL extensions that are primarily or entirely
+intended for testing PostgreSQL and/or to serve as example code. The extensions
+here aren't intended to be installed in a production server and aren't useful
+for "real work".
+
+Most extensions have their own pg_regress tests. Some are also used by tests
+elsewhere in the test tree.
+
+If you're adding new hooks or other functionality exposed as C-level API this
+is where to add the tests for it.
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 2ab9aee..08109a7 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -1,8 +1,15 @@
-# PostgresNode, class representing a data directory and postmaster.
-#
-# This contains a basic set of routines able to work on a PostgreSQL node,
-# allowing to start, stop, backup and initialize it with various options.
-# The set of nodes managed by a given test is also managed by this module.
+=pod
+
+=head1 PostgresNode - class representing a data directory and postmaster
+
+This contains a basic set of routines able to work on a PostgreSQL node,
+allowing to start, stop, backup and initialize it with various options.
+The set of nodes managed by a given test is also managed by this module.
+
+It requires IPC::Run - install libperl-ipc-run (Debian/Ubuntu) or perl-IPC-Run
+(Fedora/RHEL).
+
+=cut
 
 package PostgresNode;
 
@@ -40,6 +47,21 @@ INIT
 	$last_port_assigned = int(rand() * 16384) + 49152;
 }
 
+=pod
+
+=head2 Methods
+
+=over
+
+=item PostgresNode::new($class, $name, $pghost, $pgport)
+
+Create a new PostgresNode instance. Does not initdb or start it.
+
+You should generally prefer to use get_new_node() instead since it takes care
+of finding port numbers, registering instances for cleanup, etc.
+
+=cut
+
 sub new
 {
 	my $class  = shift;
@@ -61,36 +83,91 @@ sub new
 	return $self;
 }
 
+=pod
+
+=item $node->port()
+
+Get the port number assigned to the host. This won't necessarily be a TCP port
+open on the local host since we prefer to use unix sockets if possible.
+
+Use $node->connstr() if you want a connection string.
+
+=cut
+
 sub port
 {
 	my ($self) = @_;
 	return $self->{_port};
 }
 
+=pod
+
+=item $node->host()
+
+Return the host (like PGHOST) for this instance. May be a UNIX socket path.
+
+Use $node->connstr() if you want a connection string.
+
+=cut
+
 sub host
 {
 	my ($self) = @_;
 	return $self->{_host};
 }
 
+=pod
+
+=item $node->basedir()
+
+The directory all the node's files will be within - datadir, archive directory,
+backups, etc.
+
+=cut
+
 sub basedir
 {
 	my ($self) = @_;
 	return $self->{_basedir};
 }
 
+=pod
+
+=item $node->name()
+
+The name assigned to the node at creation time.
+
+=cut
+
 sub name
 {
 	my ($self) = @_;
 	return $self->{_name};
 }
 
+=pod
+
+=item $node->logfile()
+
+Path to the PostgreSQL log file for this instance.
+
+=cut
+
 sub logfile
 {
 	my ($self) = @_;
 	return $self->{_logfile};
 }
 
+=pod
+
+=item $node->connstr()
+
+Get a libpq connection string that will establish a connection to
+this node. Suitable for passing to psql, DBD::Pg, etc.
+
+=cut
+
 sub connstr
 {
 	my ($self, $dbname) = @_;
@@ -103,6 +180,15 @@ sub connstr
 	return "port=$pgport host=$pghost dbname=$dbname";
 }
 
+=pod
+
+=item $node->data_dir()
+
+Returns the path to the data directory. postgresql.conf and pg_hba.conf are
+always here.
+
+=cut
+
 sub data_dir
 {
 	my ($self) = @_;
@@ -110,6 +196,14 @@ sub data_dir
 	return "$res/pgdata";
 }
 
+=pod
+
+=item $node->archive_dir()
+
+If archiving is enabled, WAL files go here.
+
+=cut
+
 sub archive_dir
 {
 	my ($self) = @_;
@@ -117,6 +211,14 @@ sub archive_dir
 	return "$basedir/archives";
 }
 
+=pod
+
+=item $node->backup_dir()
+
+The output path for backups taken with $node->backup()
+
+=cut
+
 sub backup_dir
 {
 	my ($self) = @_;
@@ -124,23 +226,55 @@ sub backup_dir
 	return "$basedir/backup";
 }
 
-# Dump node information
+=pod
+
+=item $node->info()
+
+Return a string containing human-readable diagnostic information (paths, etc)
+about this node.
+
+=cut
+
+sub info
+{
+	my ($self) = @_;
+	my $_info = '';
+	open my $fh, '>', \$_info or die;
+	print $fh "Name: " . $self->name . "\n";
+	print $fh "Data directory: " . $self->data_dir . "\n";
+	print $fh "Backup directory: " . $self->backup_dir . "\n";
+	print $fh "Archive directory: " . $self->archive_dir . "\n";
+	print $fh "Connection string: " . $self->connstr . "\n";
+	print $fh "Log file: " . $self->logfile . "\n";
+	close $fh or die;
+	return $_info;
+}
+
+=pod
+
+=item $node->dump_info()
+
+Print $node->info()
+
+=cut
+
 sub dump_info
 {
 	my ($self) = @_;
-	print "Name: " . $self->name . "\n";
-	print "Data directory: " . $self->data_dir . "\n";
-	print "Backup directory: " . $self->backup_dir . "\n";
-	print "Archive directory: " . $self->archive_dir . "\n";
-	print "Connection string: " . $self->connstr . "\n";
-	print "Log file: " . $self->logfile . "\n";
+	print $self->info;
 }
 
+
+# Internal method to set up trusted pg_hba.conf for replication.  Not
+# documented because you shouldn't use it, it's called automatically if needed.
 sub set_replication_conf
 {
 	my ($self) = @_;
 	my $pgdata = $self->data_dir;
 
+	$self->host eq $test_pghost
+	  or die "set_replication_conf only works with the default host";
+
 	open my $hba, ">>$pgdata/pg_hba.conf";
 	print $hba "\n# Allow replication (set up by PostgresNode.pm)\n";
 	if (!$TestLib::windows_os)
@@ -155,13 +289,26 @@ sub set_replication_conf
 	close $hba;
 }
 
-# Initialize a new cluster for testing.
-#
-# Authentication is set up so that only the current OS user can access the
-# cluster. On Unix, we use Unix domain socket connections, with the socket in
-# a directory that's only accessible to the current user to ensure that.
-# On Windows, we use SSPI authentication to ensure the same (by pg_regress
-# --config-auth).
+=pod
+
+=item $node->init(...)
+
+Initialize a new cluster for testing.
+
+Authentication is set up so that only the current OS user can access the
+cluster. On Unix, we use Unix domain socket connections, with the socket in
+a directory that's only accessible to the current user to ensure that.
+On Windows, we use SSPI authentication to ensure the same (by pg_regress
+--config-auth).
+
+pg_hba.conf is configured to allow replication connections. Pass the keyword
+parameter hba_permit_replication => 0 to disable this.
+
+The new node is set up in a fast but unsafe configuration where fsync is
+disabled.
+
+=cut
+
 sub init
 {
 	my ($self, %params) = @_;
@@ -197,6 +344,19 @@ sub init
 	$self->set_replication_conf if ($params{hba_permit_replication});
 }
 
+=pod
+
+=item $node->append_conf(filename, str)
+
+A shortcut method to append to files like pg_hba.conf and postgresql.conf.
+
+Does no validation or sanity checking. Does not reload the configuration
+after writing.
+
+A newline is NOT automatically appended to the string.
+
+=cut
+
 sub append_conf
 {
 	my ($self, $filename, $str) = @_;
@@ -206,18 +366,66 @@ sub append_conf
 	TestLib::append_to_file($conffile, $str);
 }
 
+=pod
+
+=item $node->backup(backup_name, ...)
+
+Create a hot backup with pg_basebackup in $node->backup_dir,
+including the transaction logs. xlogs are fetched at the
+end of the backup, not streamed.
+
+You'll have to configure a suitable max_wal_senders on the
+target server since it isn't done by default.
+
+Additional options may be passed as a hash:
+
+=over
+
+=item write_recovery_conf => 1
+
+use pg_basebackup -R to write a recovery.conf
+
+=item xlog_stream => 1
+
+Stream WAL archives during backup instead of copying them at the end.
+
+=back
+
+=cut
+
 sub backup
 {
-	my ($self, $backup_name) = @_;
+	my ($self, $backup_name, %params) = @_;
 	my $backup_path = $self->backup_dir . '/' . $backup_name;
 	my $port        = $self->port;
 	my $name        = $self->name;
 
+	my $recovery_opt = '';
+	$recovery_opt = '-R' if ($params{write_recovery_conf});
+
+	my $xlog_opt = '-x';
+	$xlog_opt = '-X stream' if ($params{xlog_stream});
+
 	print "# Taking backup $backup_name from node \"$name\"\n";
-	TestLib::system_or_bail("pg_basebackup -D $backup_path -p $port -x");
+	TestLib::system_or_bail("pg_basebackup -D $backup_path -p $port $xlog_opt $recovery_opt");
 	print "# Backup finished\n";
 }
 
+=pod
+
+=item $node->init_from_backup(root_node, backup_name)
+
+Initialize a node from a backup, which may come from this node or a different
+node. root_node must be a PostgresNode reference, backup_name the string name
+of a backup previously created on that node with $node->backup.
+
+Does not start the node after init.
+
+The backup is copied, leaving the original unmodified. pg_hba.conf is
+unconditionally set to enable replication connections.
+
+=cut
+
 sub init_from_backup
 {
 	my ($self, $root_node, $backup_name) = @_;
@@ -248,6 +456,16 @@ port = $port
 	$self->set_replication_conf;
 }
 
+=pod
+
+=item $node->start()
+
+Wrapper for pg_ctl -w start
+
+Start the node and wait until it is ready to accept connections.
+
+=cut
+
 sub start
 {
 	my ($self) = @_;
@@ -268,6 +486,14 @@ sub start
 	$self->_update_pid;
 }
 
+=pod
+
+=item $node->stop(mode)
+
+Stop the node using pg_ctl -m $mode and wait for it to stop.
+
+=cut
+
 sub stop
 {
 	my ($self, $mode) = @_;
@@ -281,6 +507,14 @@ sub stop
 	$self->_update_pid;
 }
 
+=pod
+
+=item $node->restart()
+
+wrapper for pg_ctl -w restart
+
+=cut
+
 sub restart
 {
 	my ($self)  = @_;
@@ -294,6 +528,8 @@ sub restart
 	$self->_update_pid;
 }
 
+
+# Internal method
 sub _update_pid
 {
 	my $self = shift;
@@ -314,14 +550,20 @@ sub _update_pid
 	print "# No postmaster PID\n";
 }
 
-#
-# Cluster management functions
-#
+=pod
+
+=item get_new_node(node_name)
+
+Build a new PostgresNode object, assigning a free port number. Standalone
+function that's automatically imported.
+
+We also register the node, to avoid the port number from being reused
+for another node even when this one is not active.
+
+You should generally use this instead of PostgresNode::new(...).
+
+=cut
 
-# Build a new PostgresNode object, assigning a free port number.
-#
-# We also register the node, to avoid the port number from being reused
-# for another node even when this one is not active.
 sub get_new_node
 {
 	my $name  = shift;
@@ -360,6 +602,7 @@ sub get_new_node
 	return $node;
 }
 
+# Attempt automatic cleanup
 sub DESTROY
 {
 	my $self = shift;
@@ -369,6 +612,14 @@ sub DESTROY
 	TestLib::system_log('pg_ctl', 'kill', 'QUIT', $self->{_pid});
 }
 
+=pod
+
+=item $node->teardown_node()
+
+Do an immediate stop of the node
+
+=cut
+
 sub teardown_node
 {
 	my $self = shift;
@@ -376,6 +627,18 @@ sub teardown_node
 	$self->stop('immediate');
 }
 
+=pod
+
+=item $node->psql(dbname, sql)
+
+Run a query with psql and return stdout, or on error print stderr.
+
+Executes a query/script with psql and returns psql's standard output.  psql is
+run in unaligned tuples-only quiet mode with psqlrc disabled so simple queries
+will just return the result row(s) with fields separated by commas.
+
+=cut
+
 sub psql
 {
 	my ($self, $dbname, $sql) = @_;
@@ -399,7 +662,15 @@ sub psql
 	return $stdout;
 }
 
-# Run a query once a second, until it returns 't' (i.e. SQL boolean true).
+=pod
+
+=item $node->poll_query_until(dbname, query)
+
+Run a query once a second, until it returns 't' (i.e. SQL boolean true).
+Continues polling if psql returns an error result. Times out after 90 seconds.
+
+=cut
+
 sub poll_query_until
 {
 	my ($self, $dbname, $query) = @_;
@@ -432,6 +703,16 @@ sub poll_query_until
 	return 0;
 }
 
+=pod
+
+=item $node->command_ok(...)
+
+Runs a shell command like TestLib::command_ok, but with PGPORT
+set so that the command will default to connecting to this
+PostgresNode.
+
+=cut
+
 sub command_ok
 {
 	my $self = shift;
@@ -441,6 +722,14 @@ sub command_ok
 	TestLib::command_ok(@_);
 }
 
+=pod
+
+=item $node->command_fails(...) - TestLib::command_fails with our PGPORT
+
+See command_ok(...)
+
+=cut
+
 sub command_fails
 {
 	my $self = shift;
@@ -450,6 +739,14 @@ sub command_fails
 	TestLib::command_fails(@_);
 }
 
+=pod
+
+=item $node->command_like(...)
+
+TestLib::command_like with our PGPORT. See command_ok(...)
+
+=cut
+
 sub command_like
 {
 	my $self = shift;
@@ -459,8 +756,17 @@ sub command_like
 	TestLib::command_like(@_);
 }
 
-# Run a command on the node, then verify that $expected_sql appears in the
-# server log file.
+=pod
+
+=item $node->issues_sql_like(cmd, expected_sql, test_name)
+
+Run a command on the node, then verify that $expected_sql appears in the
+server log file.
+
+Reads the whole log file so be careful when working with large log outputs.
+
+=cut
+
 sub issues_sql_like
 {
 	my ($self, $cmd, $expected_sql, $test_name) = @_;
@@ -474,4 +780,10 @@ sub issues_sql_like
 	like($log, $expected_sql, "$test_name: SQL found in server log");
 }
 
+=pod
+
+=back
+
+=cut
+
 1;
diff --git a/src/test/perl/README b/src/test/perl/README
new file mode 100644
index 0000000..d635a18
--- /dev/null
+++ b/src/test/perl/README
@@ -0,0 +1,37 @@
+Perl-based (Test::More) 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.
+
+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
+
+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.
+
+src/test/sample_suite/t contains some sample tests that describe the structure
+of tests, test compatibility requirements, etc. There are tests there with
+sample usage of the node management support. Start with
+
+    perldoc src/test/example_suite/t/001_minimal.pl
+
+Adding a suite
+===
+
+If your tests don't make sense under any of the existing test suites you can
+add a new suite in src/test/ . There's an example suite in src/test/sample_suite
+that can be copied and modified to suit. Try to avoid creating lots of new
+test suites - it's better to add new tests to an existing suite if they can
+reasonably fit there.
+
+You should add the new suite to src/test/Makefile . See the comments there.
-- 
2.1.0

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to