aboutsummaryrefslogtreecommitdiff
path: root/src/test/perl
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/perl')
-rw-r--r--src/test/perl/PostgresNode.pm470
-rw-r--r--src/test/perl/RecursiveCopy.pm42
-rw-r--r--src/test/perl/TestLib.pm319
3 files changed, 620 insertions, 211 deletions
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
new file mode 100644
index 00000000000..aa7a00c9fa4
--- /dev/null
+++ b/src/test/perl/PostgresNode.pm
@@ -0,0 +1,470 @@
+# 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.
+
+package PostgresNode;
+
+use strict;
+use warnings;
+
+use Config;
+use Cwd;
+use Exporter 'import';
+use File::Basename;
+use File::Spec;
+use File::Temp ();
+use IPC::Run;
+use PostgresNode;
+use RecursiveCopy;
+use Test::More;
+use TestLib ();
+
+our @EXPORT = qw(
+ get_new_node
+);
+
+our ($test_pghost, $last_port_assigned, @all_nodes);
+
+BEGIN
+{
+
+ # PGHOST is set once and for all through a single series of tests when
+ # this module is loaded.
+ $test_pghost =
+ $TestLib::windows_os ? "127.0.0.1" : TestLib::tempdir_short;
+ $ENV{PGHOST} = $test_pghost;
+ $ENV{PGDATABASE} = 'postgres';
+
+ # Tracking of last port value assigned to accelerate free port lookup.
+ # XXX: Should this use PG_VERSION_NUM?
+ $last_port_assigned = 90600 % 16384 + 49152;
+
+ # Node tracking
+ @all_nodes = ();
+}
+
+sub new
+{
+ my $class = shift;
+ my $pghost = shift;
+ my $pgport = shift;
+ my $self = {
+ _port => $pgport,
+ _host => $pghost,
+ _basedir => TestLib::tempdir,
+ _applname => "node_$pgport",
+ _logfile => "$TestLib::log_path/node_$pgport.log" };
+
+ bless $self, $class;
+ $self->dump_info;
+
+ return $self;
+}
+
+sub port
+{
+ my ($self) = @_;
+ return $self->{_port};
+}
+
+sub host
+{
+ my ($self) = @_;
+ return $self->{_host};
+}
+
+sub basedir
+{
+ my ($self) = @_;
+ return $self->{_basedir};
+}
+
+sub applname
+{
+ my ($self) = @_;
+ return $self->{_applname};
+}
+
+sub logfile
+{
+ my ($self) = @_;
+ return $self->{_logfile};
+}
+
+sub connstr
+{
+ my ($self, $dbname) = @_;
+ my $pgport = $self->port;
+ my $pghost = $self->host;
+ if (!defined($dbname))
+ {
+ return "port=$pgport host=$pghost";
+ }
+ return "port=$pgport host=$pghost dbname=$dbname";
+}
+
+sub data_dir
+{
+ my ($self) = @_;
+ my $res = $self->basedir;
+ return "$res/pgdata";
+}
+
+sub archive_dir
+{
+ my ($self) = @_;
+ my $basedir = $self->basedir;
+ return "$basedir/archives";
+}
+
+sub backup_dir
+{
+ my ($self) = @_;
+ my $basedir = $self->basedir;
+ return "$basedir/backup";
+}
+
+# Dump node information
+sub dump_info
+{
+ my ($self) = @_;
+ 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 "Application name: " . $self->applname . "\n";
+ print "Log file: " . $self->logfile . "\n";
+}
+
+sub set_replication_conf
+{
+ my ($self) = @_;
+ my $pgdata = $self->data_dir;
+
+ open my $hba, ">>$pgdata/pg_hba.conf";
+ print $hba "\n# Allow replication (set up by PostgresNode.pm)\n";
+ if (!$TestLib::windows_os)
+ {
+ print $hba "local replication all trust\n";
+ }
+ else
+ {
+ print $hba
+"host replication all 127.0.0.1/32 sspi include_realm=1 map=regress\n";
+ }
+ 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).
+sub init
+{
+ my ($self, %params) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $host = $self->host;
+
+ $params{hba_permit_replication} = 1
+ if (!defined($params{hba_permit_replication}));
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N');
+ TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata);
+
+ open my $conf, ">>$pgdata/postgresql.conf";
+ print $conf "\n# Added by PostgresNode.pm)\n";
+ print $conf "fsync = off\n";
+ print $conf "log_statement = all\n";
+ print $conf "port = $port\n";
+ if ($TestLib::windows_os)
+ {
+ print $conf "listen_addresses = '$host'\n";
+ }
+ else
+ {
+ print $conf "unix_socket_directories = '$host'\n";
+ print $conf "listen_addresses = ''\n";
+ }
+ close $conf;
+
+ $self->set_replication_conf if ($params{hba_permit_replication});
+}
+
+sub append_conf
+{
+ my ($self, $filename, $str) = @_;
+
+ my $conffile = $self->data_dir . '/' . $filename;
+
+ TestLib::append_to_file($conffile, $str);
+}
+
+sub backup
+{
+ my ($self, $backup_name) = @_;
+ my $backup_path = $self->backup_dir . '/' . $backup_name;
+ my $port = $self->port;
+
+ print "# Taking backup $backup_name from node with port $port\n";
+ TestLib::system_or_bail("pg_basebackup -D $backup_path -p $port -x");
+ print "# Backup finished\n";
+}
+
+sub init_from_backup
+{
+ my ($self, $root_node, $backup_name) = @_;
+ my $backup_path = $root_node->backup_dir . '/' . $backup_name;
+ my $port = $self->port;
+ my $root_port = $root_node->port;
+
+ print
+"Initializing node $port from backup \"$backup_name\" of node $root_port\n";
+ die "Backup $backup_path does not exist" unless -d $backup_path;
+
+ mkdir $self->backup_dir;
+ mkdir $self->archive_dir;
+
+ my $data_path = $self->data_dir;
+ rmdir($data_path);
+ RecursiveCopy::copypath($backup_path, $data_path);
+ chmod(0700, $data_path);
+
+ # Base configuration for this node
+ $self->append_conf(
+ 'postgresql.conf',
+ qq(
+port = $port
+));
+ $self->set_replication_conf;
+}
+
+sub start
+{
+ my ($self) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ print("### Starting test server in $pgdata\n");
+ my $ret = TestLib::system_log('pg_ctl', '-w', '-D', $self->data_dir, '-l',
+ $self->logfile, 'start');
+
+ if ($ret != 0)
+ {
+ print "# pg_ctl failed; logfile:\n";
+ print TestLib::slurp_file($self->logfile);
+ BAIL_OUT("pg_ctl failed");
+ }
+
+ $self->_update_pid;
+
+}
+
+sub stop
+{
+ my ($self, $mode) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ $mode = 'fast' if (!defined($mode));
+ print "### Stopping node in $pgdata with port $port using mode $mode\n";
+ TestLib::system_log('pg_ctl', '-D', $pgdata, '-m', $mode, 'stop');
+ $self->{_pid} = undef;
+ $self->_update_pid;
+}
+
+sub restart
+{
+ my ($self) = @_;
+ my $port = $self->port;
+ my $pgdata = $self->data_dir;
+ my $logfile = $self->logfile;
+ TestLib::system_log('pg_ctl', '-D', $pgdata, '-w', '-l', $logfile,
+ 'restart');
+ $self->_update_pid;
+}
+
+sub _update_pid
+{
+ my $self = shift;
+
+ # If we can open the PID file, read its first line and that's the PID we
+ # want. If the file cannot be opened, presumably the server is not
+ # running; don't be noisy in that case.
+ open my $pidfile, $self->data_dir . "/postmaster.pid";
+ if (not defined $pidfile)
+ {
+ $self->{_pid} = undef;
+ print "# No postmaster PID\n";
+ return;
+ }
+
+ $self->{_pid} = <$pidfile>;
+ print "# Postmaster PID is $self->{_pid}\n";
+ close $pidfile;
+}
+
+#
+# Cluster management functions
+#
+
+# 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 $found = 0;
+ my $port = $last_port_assigned;
+
+ while ($found == 0)
+ {
+ $port++;
+ print "# Checking for port $port\n";
+ my $devnull = $TestLib::windows_os ? "nul" : "/dev/null";
+ if (!TestLib::run_log([ 'pg_isready', '-p', $port ]))
+ {
+ $found = 1;
+
+ # Found a potential candidate port number. Check first that it is
+ # not included in the list of registered nodes.
+ foreach my $node (@all_nodes)
+ {
+ $found = 0 if ($node->port == $port);
+ }
+ }
+ }
+
+ print "# Found free port $port\n";
+
+ # Lock port number found by creating a new node
+ my $node = new PostgresNode($test_pghost, $port);
+
+ # Add node to list of nodes
+ push(@all_nodes, $node);
+
+ # And update port for next time
+ $last_port_assigned = $port;
+
+ return $node;
+}
+
+sub DESTROY
+{
+ my $self = shift;
+ return if not defined $self->{_pid};
+ print "# signalling QUIT to $self->{_pid}\n";
+ kill 'QUIT', $self->{_pid};
+}
+
+sub teardown_node
+{
+ my $self = shift;
+
+ $self->stop('immediate');
+}
+
+sub psql
+{
+ my ($self, $dbname, $sql) = @_;
+
+ my ($stdout, $stderr);
+ print("# Running SQL command: $sql\n");
+
+ IPC::Run::run [ 'psql', '-XAtq', '-d', $self->connstr($dbname), '-f',
+ '-' ], '<', \$sql, '>', \$stdout, '2>', \$stderr
+ or die;
+
+ if ($stderr ne "")
+ {
+ print "#### Begin standard error\n";
+ print $stderr;
+ print "#### End standard error\n";
+ }
+ chomp $stdout;
+ $stdout =~ s/\r//g if $Config{osname} eq 'msys';
+ return $stdout;
+}
+
+# Run a query once a second, until it returns 't' (i.e. SQL boolean true).
+sub poll_query_until
+{
+ my ($self, $dbname, $query) = @_;
+
+ my $max_attempts = 30;
+ my $attempts = 0;
+ my ($stdout, $stderr);
+
+ while ($attempts < $max_attempts)
+ {
+ my $cmd =
+ [ 'psql', '-At', '-c', $query, '-d', $self->connstr($dbname) ];
+ my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr;
+
+ chomp($stdout);
+ $stdout =~ s/\r//g if $Config{osname} eq 'msys';
+ if ($stdout eq "t")
+ {
+ return 1;
+ }
+
+ # Wait a second before retrying.
+ sleep 1;
+ $attempts++;
+ }
+
+ # The query result didn't change in 30 seconds. Give up. Print the stderr
+ # from the last attempt, hopefully that's useful for debugging.
+ diag $stderr;
+ return 0;
+}
+
+sub command_ok
+{
+ my $self = shift;
+
+ local $ENV{PGPORT} = $self->port;
+
+ TestLib::command_ok(@_);
+}
+
+sub command_fails
+{
+ my $self = shift;
+
+ local $ENV{PGPORT} = $self->port;
+
+ TestLib::command_fails(@_);
+}
+
+sub command_like
+{
+ my $self = shift;
+
+ local $ENV{PGPORT} = $self->port;
+
+ TestLib::command_like(@_);
+}
+
+# Run a command on the node, then verify that $expected_sql appears in the
+# server log file.
+sub issues_sql_like
+{
+ my ($self, $cmd, $expected_sql, $test_name) = @_;
+
+ local $ENV{PGPORT} = $self->port;
+
+ truncate $self->logfile, 0;
+ my $result = TestLib::run_log($cmd);
+ ok($result, "@$cmd exit code 0");
+ my $log = TestLib::slurp_file($self->logfile);
+ like($log, $expected_sql, "$test_name: SQL found in server log");
+}
+
+1;
diff --git a/src/test/perl/RecursiveCopy.pm b/src/test/perl/RecursiveCopy.pm
new file mode 100644
index 00000000000..9362aa89590
--- /dev/null
+++ b/src/test/perl/RecursiveCopy.pm
@@ -0,0 +1,42 @@
+# RecursiveCopy, a simple recursive copy implementation
+package RecursiveCopy;
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Copy;
+
+sub copypath
+{
+ my $srcpath = shift;
+ my $destpath = shift;
+
+ die "Cannot operate on symlinks" if -l $srcpath or -l $destpath;
+
+ # This source path is a file, simply copy it to destination with the
+ # same name.
+ die "Destination path $destpath exists as file" if -f $destpath;
+ if (-f $srcpath)
+ {
+ copy($srcpath, $destpath)
+ or die "copy $srcpath -> $destpath failed: $!";
+ return 1;
+ }
+
+ die "Destination needs to be a directory" unless -d $srcpath;
+ mkdir($destpath) or die "mkdir($destpath) failed: $!";
+
+ # Scan existing source directory and recursively copy everything.
+ opendir(my $directory, $srcpath) or die "could not opendir($srcpath): $!";
+ while (my $entry = readdir($directory))
+ {
+ next if ($entry eq '.' || $entry eq '..');
+ RecursiveCopy::copypath("$srcpath/$entry", "$destpath/$entry")
+ or die "copypath $srcpath/$entry -> $destpath/$entry failed";
+ }
+ closedir($directory);
+ return 1;
+}
+
+1;
diff --git a/src/test/perl/TestLib.pm b/src/test/perl/TestLib.pm
index 02533ebde53..af46dc8c7a2 100644
--- a/src/test/perl/TestLib.pm
+++ b/src/test/perl/TestLib.pm
@@ -1,3 +1,10 @@
+# TestLib, low-level routines and actions regression tests.
+#
+# This module contains a set of routines dedicated to environment setup for
+# a PostgreSQL regression test tun, and includes some low-level routines
+# aimed at controlling command execution, logging and test functions. This
+# module should never depend on any other PostgreSQL regression test modules.
+
package TestLib;
use strict;
@@ -5,16 +12,17 @@ use warnings;
use Config;
use Exporter 'import';
+use File::Basename;
+use File::Spec;
+use File::Temp ();
+use IPC::Run;
+use SimpleTee;
+use Test::More;
+
our @EXPORT = qw(
- tempdir
- tempdir_short
- standard_initdb
- configure_hba_for_replication
- start_test_server
- restart_test_server
- psql
slurp_dir
slurp_file
+ append_to_file
system_or_bail
system_log
run_log
@@ -26,88 +34,82 @@ our @EXPORT = qw(
program_version_ok
program_options_handling_ok
command_like
- issues_sql_like
- $tmp_check
- $log_path
$windows_os
);
-use Cwd;
-use File::Basename;
-use File::Spec;
-use File::Temp ();
-use IPC::Run qw(run start);
+our ($windows_os, $tmp_check, $log_path, $test_logfile);
-use SimpleTee;
-
-use Test::More;
-
-our $windows_os = $Config{osname} eq 'MSWin32' || $Config{osname} eq 'msys';
-
-# Open log file. For each test, the log file name uses the name of the
-# file launching this module, without the .pl suffix.
-our ($tmp_check, $log_path);
-$tmp_check = $ENV{TESTDIR} ? "$ENV{TESTDIR}/tmp_check" : "tmp_check";
-$log_path = "$tmp_check/log";
-mkdir $tmp_check;
-mkdir $log_path;
-my $test_logfile = basename($0);
-$test_logfile =~ s/\.[^.]+$//;
-$test_logfile = "$log_path/regress_log_$test_logfile";
-open TESTLOG, '>', $test_logfile or die "Cannot open STDOUT to logfile: $!";
-
-# Hijack STDOUT and STDERR to the log file
-open(ORIG_STDOUT, ">&STDOUT");
-open(ORIG_STDERR, ">&STDERR");
-open(STDOUT, ">&TESTLOG");
-open(STDERR, ">&TESTLOG");
-
-# The test output (ok ...) needs to be printed to the original STDOUT so
-# that the 'prove' program can parse it, and display it to the user in
-# real time. But also copy it to the log file, to provide more context
-# in the log.
-my $builder = Test::More->builder;
-my $fh = $builder->output;
-tie *$fh, "SimpleTee", *ORIG_STDOUT, *TESTLOG;
-$fh = $builder->failure_output;
-tie *$fh, "SimpleTee", *ORIG_STDERR, *TESTLOG;
-
-# Enable auto-flushing for all the file handles. Stderr and stdout are
-# redirected to the same file, and buffering causes the lines to appear
-# in the log in confusing order.
-autoflush STDOUT 1;
-autoflush STDERR 1;
-autoflush TESTLOG 1;
-
-# Set to untranslated messages, to be able to compare program output
-# with expected strings.
-delete $ENV{LANGUAGE};
-delete $ENV{LC_ALL};
-$ENV{LC_MESSAGES} = 'C';
-
-delete $ENV{PGCONNECT_TIMEOUT};
-delete $ENV{PGDATA};
-delete $ENV{PGDATABASE};
-delete $ENV{PGHOSTADDR};
-delete $ENV{PGREQUIRESSL};
-delete $ENV{PGSERVICE};
-delete $ENV{PGSSLMODE};
-delete $ENV{PGUSER};
-
-if (!$ENV{PGPORT})
+BEGIN
{
- $ENV{PGPORT} = 65432;
+
+ # Set to untranslated messages, to be able to compare program output
+ # with expected strings.
+ delete $ENV{LANGUAGE};
+ delete $ENV{LC_ALL};
+ $ENV{LC_MESSAGES} = 'C';
+
+ delete $ENV{PGCONNECT_TIMEOUT};
+ delete $ENV{PGDATA};
+ delete $ENV{PGDATABASE};
+ delete $ENV{PGHOSTADDR};
+ delete $ENV{PGREQUIRESSL};
+ delete $ENV{PGSERVICE};
+ delete $ENV{PGSSLMODE};
+ delete $ENV{PGUSER};
+ delete $ENV{PGPORT};
+ delete $ENV{PGHOST};
+
+ # Must be set early
+ $windows_os = $Config{osname} eq 'MSWin32' || $Config{osname} eq 'msys';
}
-$ENV{PGPORT} = int($ENV{PGPORT}) % 65536;
+INIT
+{
+ # Determine output directories, and create them. The base path is the
+ # TESTDIR environment variable, which is normally set by the invoking
+ # Makefile.
+ $tmp_check = $ENV{TESTDIR} ? "$ENV{TESTDIR}/tmp_check" : "tmp_check";
+ $log_path = "$tmp_check/log";
+
+ mkdir $tmp_check;
+ mkdir $log_path;
+
+ # Open the test log file, whose name depends on the test name.
+ $test_logfile = basename($0);
+ $test_logfile =~ s/\.[^.]+$//;
+ $test_logfile = "$log_path/regress_log_$test_logfile";
+ open TESTLOG, '>', $test_logfile
+ or die "could not open STDOUT to logfile \"$test_logfile\": $!";
+
+ # Hijack STDOUT and STDERR to the log file
+ open(ORIG_STDOUT, ">&STDOUT");
+ open(ORIG_STDERR, ">&STDERR");
+ open(STDOUT, ">&TESTLOG");
+ open(STDERR, ">&TESTLOG");
+
+ # The test output (ok ...) needs to be printed to the original STDOUT so
+ # that the 'prove' program can parse it, and display it to the user in
+ # real time. But also copy it to the log file, to provide more context
+ # in the log.
+ my $builder = Test::More->builder;
+ my $fh = $builder->output;
+ tie *$fh, "SimpleTee", *ORIG_STDOUT, *TESTLOG;
+ $fh = $builder->failure_output;
+ tie *$fh, "SimpleTee", *ORIG_STDERR, *TESTLOG;
+
+ # Enable auto-flushing for all the file handles. Stderr and stdout are
+ # redirected to the same file, and buffering causes the lines to appear
+ # in the log in confusing order.
+ autoflush STDOUT 1;
+ autoflush STDERR 1;
+ autoflush TESTLOG 1;
+}
#
# Helper functions
#
-
-
sub tempdir
{
return File::Temp::tempdir(
@@ -124,117 +126,31 @@ sub tempdir_short
return File::Temp::tempdir(CLEANUP => 1);
}
-# Initialize a new cluster for testing.
-#
-# The PGHOST environment variable is set to connect to the new cluster.
-#
-# 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).
-sub standard_initdb
-{
- my $pgdata = shift;
- system_or_bail('initdb', '-D', "$pgdata", '-A' , 'trust', '-N');
- system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata);
-
- my $tempdir_short = tempdir_short;
-
- open CONF, ">>$pgdata/postgresql.conf";
- print CONF "\n# Added by TestLib.pm)\n";
- print CONF "fsync = off\n";
- if ($windows_os)
- {
- print CONF "listen_addresses = '127.0.0.1'\n";
- }
- else
- {
- print CONF "unix_socket_directories = '$tempdir_short'\n";
- print CONF "listen_addresses = ''\n";
- }
- close CONF;
-
- $ENV{PGHOST} = $windows_os ? "127.0.0.1" : $tempdir_short;
-}
-
-# Set up the cluster to allow replication connections, in the same way that
-# standard_initdb does for normal connections.
-sub configure_hba_for_replication
-{
- my $pgdata = shift;
-
- open HBA, ">>$pgdata/pg_hba.conf";
- print HBA "\n# Allow replication (set up by TestLib.pm)\n";
- if (! $windows_os)
- {
- print HBA "local replication all trust\n";
- }
- else
- {
- print HBA "host replication all 127.0.0.1/32 sspi include_realm=1 map=regress\n";
- }
- close HBA;
-}
-
-my ($test_server_datadir, $test_server_logfile);
-
-
-# Initialize a new cluster for testing in given directory, and start it.
-sub start_test_server
-{
- my ($tempdir) = @_;
- my $ret;
-
- print("### Starting test server in $tempdir\n");
- standard_initdb "$tempdir/pgdata";
-
- $ret = system_log('pg_ctl', '-D', "$tempdir/pgdata", '-w', '-l',
- "$log_path/postmaster.log", '-o', "--log-statement=all",
- 'start');
-
- if ($ret != 0)
- {
- print "# pg_ctl failed; logfile:\n";
- system('cat', "$log_path/postmaster.log");
- BAIL_OUT("pg_ctl failed");
- }
-
- $test_server_datadir = "$tempdir/pgdata";
- $test_server_logfile = "$log_path/postmaster.log";
-}
-
-sub restart_test_server
+sub system_log
{
- print("### Restarting test server\n");
- system_log('pg_ctl', '-D', $test_server_datadir, '-w', '-l',
- $test_server_logfile, 'restart');
+ print("# Running: " . join(" ", @_) . "\n");
+ return system(@_);
}
-END
+sub system_or_bail
{
- if ($test_server_datadir)
+ if (system_log(@_) != 0)
{
- system_log('pg_ctl', '-D', $test_server_datadir, '-m',
- 'immediate', 'stop');
+ BAIL_OUT("system $_[0] failed");
}
}
-sub psql
+sub run_log
{
- my ($dbname, $sql) = @_;
- my ($stdout, $stderr);
- print("# Running SQL command: $sql\n");
- run [ 'psql', '-X', '-A', '-t', '-q', '-d', $dbname, '-f', '-' ], '<', \$sql, '>', \$stdout, '2>', \$stderr or die;
- chomp $stdout;
- $stdout =~ s/\r//g if $Config{osname} eq 'msys';
- return $stdout;
+ print("# Running: " . join(" ", @{ $_[0] }) . "\n");
+ return run(@_);
}
sub slurp_dir
{
my ($dir) = @_;
- opendir(my $dh, $dir) or die;
+ opendir(my $dh, $dir)
+ or die "could not opendir \"$dir\": $!";
my @direntries = readdir $dh;
closedir $dh;
return @direntries;
@@ -249,32 +165,18 @@ sub slurp_file
return $contents;
}
-sub system_or_bail
-{
- if (system_log(@_) != 0)
- {
- BAIL_OUT("system $_[0] failed: $?");
- }
-}
-
-sub system_log
+sub append_to_file
{
- print("# Running: " . join(" ", @_) ."\n");
- return system(@_);
-}
+ my ($filename, $str) = @_;
-sub run_log
-{
- print("# Running: " . join(" ", @{$_[0]}) ."\n");
- return run (@_);
+ open my $fh, ">>", $filename or die "could not open \"$filename\": $!";
+ print $fh $str;
+ close $fh;
}
-
#
# Test functions
#
-
-
sub command_ok
{
my ($cmd, $test_name) = @_;
@@ -292,8 +194,8 @@ sub command_fails
sub command_exit_is
{
my ($cmd, $expected, $test_name) = @_;
- print("# Running: " . join(" ", @{$cmd}) ."\n");
- my $h = start $cmd;
+ print("# Running: " . join(" ", @{$cmd}) . "\n");
+ my $h = IPC::Run::start $cmd;
$h->finish();
# On Windows, the exit status of the process is returned directly as the
@@ -303,8 +205,10 @@ sub command_exit_is
# assuming the Unix convention, which will always return 0 on Windows as
# long as the process was not terminated by an exception. To work around
# that, use $h->full_result on Windows instead.
- my $result = ($Config{osname} eq "MSWin32") ?
- ($h->full_results)[0] : $h->result(0);
+ my $result =
+ ($Config{osname} eq "MSWin32")
+ ? ($h->full_results)[0]
+ : $h->result(0);
is($result, $expected, $test_name);
}
@@ -313,7 +217,8 @@ sub program_help_ok
my ($cmd) = @_;
my ($stdout, $stderr);
print("# Running: $cmd --help\n");
- my $result = run [ $cmd, '--help' ], '>', \$stdout, '2>', \$stderr;
+ my $result = IPC::Run::run [ $cmd, '--help' ], '>', \$stdout, '2>',
+ \$stderr;
ok($result, "$cmd --help exit code 0");
isnt($stdout, '', "$cmd --help goes to stdout");
is($stderr, '', "$cmd --help nothing to stderr");
@@ -324,7 +229,8 @@ sub program_version_ok
my ($cmd) = @_;
my ($stdout, $stderr);
print("# Running: $cmd --version\n");
- my $result = run [ $cmd, '--version' ], '>', \$stdout, '2>', \$stderr;
+ my $result = IPC::Run::run [ $cmd, '--version' ], '>', \$stdout, '2>',
+ \$stderr;
ok($result, "$cmd --version exit code 0");
isnt($stdout, '', "$cmd --version goes to stdout");
is($stderr, '', "$cmd --version nothing to stderr");
@@ -335,8 +241,9 @@ sub program_options_handling_ok
my ($cmd) = @_;
my ($stdout, $stderr);
print("# Running: $cmd --not-a-valid-option\n");
- my $result = run [ $cmd, '--not-a-valid-option' ], '>', \$stdout, '2>',
- \$stderr;
+ my $result = IPC::Run::run [ $cmd, '--not-a-valid-option' ], '>',
+ \$stdout,
+ '2>', \$stderr;
ok(!$result, "$cmd with invalid option nonzero exit code");
isnt($stderr, '', "$cmd with invalid option prints error message");
}
@@ -346,20 +253,10 @@ sub command_like
my ($cmd, $expected_stdout, $test_name) = @_;
my ($stdout, $stderr);
print("# Running: " . join(" ", @{$cmd}) . "\n");
- my $result = run $cmd, '>', \$stdout, '2>', \$stderr;
+ my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr;
ok($result, "@$cmd exit code 0");
is($stderr, '', "@$cmd no stderr");
like($stdout, $expected_stdout, "$test_name: matches");
}
-sub issues_sql_like
-{
- my ($cmd, $expected_sql, $test_name) = @_;
- truncate $test_server_logfile, 0;
- my $result = run_log($cmd);
- ok($result, "@$cmd exit code 0");
- my $log = slurp_file($test_server_logfile);
- like($log, $expected_sql, "$test_name: SQL found in server log");
-}
-
1;