On Wed, 2014-01-15 at 20:56 +0100, Erik Rijkers wrote:
> 2 tests stumbled:
> 
> 1. One test  ( pg_ctl/t/001_start_stop.pl )  failed because I had PGDATA set. 
>  I unset all PG+ vars after that.  No a big
> problem but nonetheless it might be better if the test suite removes 
> /controls the variables before running.
> 
> 2. The pg_isready test failed command_fails()  ('fails with no server 
> running') because it defaults to the compiled-in
> server-port (and that server was running).  I added the test-designated port 
> (65432, as defined in TestLib.pm).  This
> simple change is in the attached patch.
> 
> 
> With these two changes the whole test suite passed.

Fixed those two things by unsetting environment variables and picking a
different port.

New patch attached.
>From 5af8f6849506b993ab7cb3fc8bb167d2f93424fc Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Sat, 8 Feb 2014 22:05:09 -0500
Subject: [PATCH v2] Add TAP tests for client programs

---
 GNUmakefile.in                                 |   4 +-
 configure                                      |  47 +++++++
 configure.in                                   |   5 +
 src/Makefile.global.in                         |  19 ++-
 src/bin/initdb/.gitignore                      |   2 +
 src/bin/initdb/Makefile                        |   7 +
 src/bin/initdb/t/001_initdb.pl                 |  37 +++++
 src/bin/pg_basebackup/.gitignore               |   2 +
 src/bin/pg_basebackup/Makefile                 |   6 +
 src/bin/pg_basebackup/t/010_pg_basebackup.pl   |  67 ++++++++++
 src/bin/pg_basebackup/t/020_pg_receivexlog.pl  |   8 ++
 src/bin/pg_config/.gitignore                   |   1 +
 src/bin/pg_config/Makefile                     |   6 +
 src/bin/pg_config/t/001_pg_config.pl           |  12 ++
 src/bin/pg_controldata/.gitignore              |   1 +
 src/bin/pg_controldata/Makefile                |   6 +
 src/bin/pg_controldata/t/001_pg_controldata.pl |  14 ++
 src/bin/pg_ctl/.gitignore                      |   1 +
 src/bin/pg_ctl/Makefile                        |   6 +
 src/bin/pg_ctl/t/001_start_stop.pl             |  21 +++
 src/bin/pg_ctl/t/002_status.pl                 |  14 ++
 src/bin/scripts/.gitignore                     |   2 +
 src/bin/scripts/Makefile                       |   7 +
 src/bin/scripts/t/010_clusterdb.pl             |  18 +++
 src/bin/scripts/t/011_clusterdb_all.pl         |   9 ++
 src/bin/scripts/t/020_createdb.pl              |  16 +++
 src/bin/scripts/t/030_createlang.pl            |  18 +++
 src/bin/scripts/t/040_createuser.pl            |  26 ++++
 src/bin/scripts/t/050_dropdb.pl                |  16 +++
 src/bin/scripts/t/060_droplang.pl              |  15 +++
 src/bin/scripts/t/070_dropuser.pl              |  16 +++
 src/bin/scripts/t/080_pg_isready.pl            |  15 +++
 src/bin/scripts/t/090_reindexdb.pl             |  21 +++
 src/bin/scripts/t/091_reindexdb_all.pl         |  11 ++
 src/bin/scripts/t/100_vacuumdb.pl              |  17 +++
 src/bin/scripts/t/101_vacuumdb_all.pl          |   9 ++
 src/test/perl/TestLib.pm                       | 178 +++++++++++++++++++++++++
 37 files changed, 677 insertions(+), 3 deletions(-)
 create mode 100644 src/bin/initdb/t/001_initdb.pl
 create mode 100644 src/bin/pg_basebackup/t/010_pg_basebackup.pl
 create mode 100644 src/bin/pg_basebackup/t/020_pg_receivexlog.pl
 create mode 100644 src/bin/pg_config/t/001_pg_config.pl
 create mode 100644 src/bin/pg_controldata/t/001_pg_controldata.pl
 create mode 100644 src/bin/pg_ctl/t/001_start_stop.pl
 create mode 100644 src/bin/pg_ctl/t/002_status.pl
 create mode 100644 src/bin/scripts/t/010_clusterdb.pl
 create mode 100644 src/bin/scripts/t/011_clusterdb_all.pl
 create mode 100644 src/bin/scripts/t/020_createdb.pl
 create mode 100644 src/bin/scripts/t/030_createlang.pl
 create mode 100644 src/bin/scripts/t/040_createuser.pl
 create mode 100644 src/bin/scripts/t/050_dropdb.pl
 create mode 100644 src/bin/scripts/t/060_droplang.pl
 create mode 100644 src/bin/scripts/t/070_dropuser.pl
 create mode 100644 src/bin/scripts/t/080_pg_isready.pl
 create mode 100644 src/bin/scripts/t/090_reindexdb.pl
 create mode 100644 src/bin/scripts/t/091_reindexdb_all.pl
 create mode 100644 src/bin/scripts/t/100_vacuumdb.pl
 create mode 100644 src/bin/scripts/t/101_vacuumdb_all.pl
 create mode 100644 src/test/perl/TestLib.pm

diff --git a/GNUmakefile.in b/GNUmakefile.in
index 40ab280..3910abb 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -66,9 +66,9 @@ check check-tests: all
 check check-tests installcheck installcheck-parallel installcheck-tests:
 	$(MAKE) -C src/test/regress $@
 
-$(call recurse,check-world,src/test src/pl src/interfaces/ecpg contrib,check)
+$(call recurse,check-world,src/test src/pl src/interfaces/ecpg contrib src/bin,check)
 
-$(call recurse,installcheck-world,src/test src/pl src/interfaces/ecpg contrib,installcheck)
+$(call recurse,installcheck-world,src/test src/pl src/interfaces/ecpg contrib src/bin,installcheck)
 
 GNUmakefile: GNUmakefile.in $(top_builddir)/config.status
 	./config.status $@
diff --git a/configure b/configure
index 6ad165f..368545f 100755
--- a/configure
+++ b/configure
@@ -627,6 +627,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 vpath_build
+PROVE
 OSX
 XSLTPROC
 COLLATEINDEX
@@ -14354,6 +14355,52 @@ fi
 done
 
 
+#
+# Check for test tools
+#
+for ac_prog in prove
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PROVE+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PROVE"; then
+  ac_cv_prog_PROVE="$PROVE" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PROVE="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+PROVE=$ac_cv_prog_PROVE
+if test -n "$PROVE"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROVE" >&5
+$as_echo "$PROVE" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$PROVE" && break
+done
+
+
 # Thread testing
 
 # We have to run the thread test near the end so we have all our symbols
diff --git a/configure.in b/configure.in
index aa23f9b..f06857e 100644
--- a/configure.in
+++ b/configure.in
@@ -1817,6 +1817,11 @@ PGAC_PATH_COLLATEINDEX
 AC_CHECK_PROGS(XSLTPROC, xsltproc)
 AC_CHECK_PROGS(OSX, [osx sgml2xml sx])
 
+#
+# Check for test tools
+#
+AC_CHECK_PROGS(PROVE, prove)
+
 # Thread testing
 
 # We have to run the thread test near the end so we have all our symbols
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index e0e9b79..cd7f4db 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -1,5 +1,6 @@
 # -*-makefile-*-
 # src/Makefile.global.in
+# @configure_input@
 
 #------------------------------------------------------------------------------
 # All PostgreSQL makefiles include this file and use the variables it sets,
@@ -292,6 +293,22 @@ XGETTEXT = @XGETTEXT@
 GZIP	= gzip
 BZIP2	= bzip2
 
+# Testing
+
+PROVE = @PROVE@
+PG_PROVE_FLAGS = --ext='.pl' -I $(top_srcdir)/src/test/perl/
+PROVE_FLAGS = --verbose
+
+define prove_installcheck
+PATH="$(bindir):$$PATH" PGPORT='6$(DEF_PGPORT)' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS)
+endef
+
+define prove_check
+$(MKDIR_P) tmp_check/log
+$(MAKE) -C $(top_builddir) DESTDIR=$(CURDIR)/tmp_check/install install >$(CURDIR)/tmp_check/log/install.log 2>&1
+PATH="$(CURDIR)/tmp_check/install$(bindir):$$PATH" PGPORT='6$(DEF_PGPORT)' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS)
+endef
+
 # Installation.
 
 install_bin = @install_bin@
@@ -755,7 +772,7 @@ gcda_files := $(wildcard *.gcda)
 
 lcov.info: $(gcda_files)
 	rm -f *.gcov
-	$(if $^,$(LCOV) -d . -c -o $@ $(LCOVFLAGS))
+	$(if $^,$(LCOV) -d . -c -o $@ $(LCOVFLAGS) --gcov-tool $(GCOV))
 
 %.c.gcov: %.gcda | lcov.info
 	$(GCOV) -b -f -p -o . $(GCOVFLAGS) $*.c >$*.c.gcov.out
diff --git a/src/bin/initdb/.gitignore b/src/bin/initdb/.gitignore
index 0f74727..71a899f 100644
--- a/src/bin/initdb/.gitignore
+++ b/src/bin/initdb/.gitignore
@@ -2,3 +2,5 @@
 /localtime.c
 
 /initdb
+
+/tmp_check/
diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile
index 1ece7ac..fb7d142 100644
--- a/src/bin/initdb/Makefile
+++ b/src/bin/initdb/Makefile
@@ -57,3 +57,10 @@ clean distclean maintainer-clean:
 
 # ensure that changes in datadir propagate into object file
 initdb.o: initdb.c $(top_builddir)/src/Makefile.global
+
+
+check: all
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/bin/initdb/t/001_initdb.pl b/src/bin/initdb/t/001_initdb.pl
new file mode 100644
index 0000000..ad6d74c
--- /dev/null
+++ b/src/bin/initdb/t/001_initdb.pl
@@ -0,0 +1,37 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 14;
+
+my $tempdir = TestLib::tempdir;
+
+program_help_ok('initdb');
+program_version_ok('initdb');
+program_options_handling_ok('initdb');
+
+command_ok(['initdb', "$tempdir/data"], 'basic initdb');
+command_fails(['initdb', "$tempdir/data"], 'existing data directory');
+command_ok(['initdb', '-N', "$tempdir/data2"], 'nosync');
+command_ok(['initdb', '-S', "$tempdir/data2"], 'sync only');
+command_fails(['initdb', '-S', "$tempdir/data3"], 'sync missing data directory');
+mkdir "$tempdir/data4" or BAIL_OUT($!);
+command_ok(['initdb', "$tempdir/data4"], 'existing empty data directory');
+
+system_or_bail "rm -rf $tempdir/*";
+
+command_ok(['initdb', "$tempdir/data", '-X', "$tempdir/pgxlog"], 'separate xlog directory');
+
+system_or_bail "rm -rf $tempdir/*";
+command_fails(['initdb', "$tempdir/data", '-X', 'pgxlog'], 'relative xlog directory not allowed');
+
+system_or_bail "rm -rf $tempdir/*";
+mkdir "$tempdir/pgxlog";
+command_ok(['initdb', "$tempdir/data", '-X', "$tempdir/pgxlog"], 'existing empty xlog directory');
+
+system_or_bail "rm -rf $tempdir/*";
+mkdir "$tempdir/pgxlog";
+mkdir "$tempdir/pgxlog/lost+found";
+command_fails(['initdb', "$tempdir/data", '-X', "$tempdir/pgxlog"], 'existing nonempty xlog directory');
+
+system_or_bail "rm -rf $tempdir/*";
+command_ok(['initdb', "$tempdir/data", '-T', 'german'], 'select default dictionary');
diff --git a/src/bin/pg_basebackup/.gitignore b/src/bin/pg_basebackup/.gitignore
index 1334a1f..17c1731 100644
--- a/src/bin/pg_basebackup/.gitignore
+++ b/src/bin/pg_basebackup/.gitignore
@@ -1,2 +1,4 @@
 /pg_basebackup
 /pg_receivexlog
+
+/tmp_check/
diff --git a/src/bin/pg_basebackup/Makefile b/src/bin/pg_basebackup/Makefile
index 17c91af..1b8d411 100644
--- a/src/bin/pg_basebackup/Makefile
+++ b/src/bin/pg_basebackup/Makefile
@@ -41,3 +41,9 @@ uninstall:
 
 clean distclean maintainer-clean:
 	rm -f pg_basebackup$(X) pg_receivexlog$(X) $(OBJS) pg_basebackup.o pg_receivexlog.o
+
+check: all
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
new file mode 100644
index 0000000..b4c0471
--- /dev/null
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -0,0 +1,67 @@
+use strict;
+use warnings;
+use Cwd;
+use TestLib;
+use Test::More tests => 19;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+command_fails(['pg_basebackup'], 'pg_basebackup needs target directory specified');
+command_fails(['pg_basebackup', '-D', "$tempdir/backup"], 'pg_basebackup fails because of hba');
+
+open HBA, ">>$tempdir/pgdata/pg_hba.conf";
+print HBA "local replication all trust\n";
+print HBA "host replication all 127.0.0.1/32 trust\n";
+print HBA "host replication all ::1/128 trust\n";
+close HBA;
+system_or_bail 'pg_ctl', '-s', '-D', "$tempdir/pgdata", 'reload';
+
+command_fails(['pg_basebackup', '-D', "$tempdir/backup"], 'pg_basebackup fails because of WAL configuration');
+
+open CONF, ">>$tempdir/pgdata/postgresql.conf";
+print CONF "max_wal_senders = 10\n";
+print CONF "wal_level = archive\n";
+close CONF;
+restart_test_server;
+
+command_ok(['pg_basebackup', '-D', "$tempdir/backup"], 'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+command_ok(['pg_basebackup', '-D', "$tempdir/backup2", '--xlogdir', "$tempdir/xlog2"], 'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/", 'xlog directory was created');
+
+command_ok(['pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft'], 'tar format');
+ok(-f "$tempdir/tarbackup/base.tar", 'backup tar was created');
+
+mkdir "$tempdir/tblspc1";
+psql 'postgres', "CREATE TABLESPACE tblspc1 LOCATION '$tempdir/tblspc1';";
+psql 'postgres', "CREATE TABLE test1 (a int) TABLESPACE tblspc1;";
+command_ok(['pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft'], 'tar format with tablespaces');
+ok(-f "$tempdir/tarbackup2/base.tar", 'backup tar was created');
+my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
+note("tablespace tars are @tblspc_tars");
+is(scalar(@tblspc_tars), 1, 'one tablespace tar was created');
+
+
+our $TODO = 'https://commitfest.postgresql.org/action/patch_view?id=1303';
+
+command_fails(['pg_basebackup', '-D', "$tempdir/same", '--xlogdir', "$tempdir/same"],
+			  'fails if data and xlog directory are the same');
+
+my $pwd = cwd();
+chdir $tempdir or BAIL_OUT("could not chdir to $tempdir: $!");
+
+command_fails(['pg_basebackup', '-D', "$tempdir/same2", '--xlogdir', "same2"],
+			  'fails if data and xlog directory are the same, relative xlog directory');
+command_fails(['pg_basebackup', '-D', "same3", '--xlogdir', "$tempdir/same3"],
+			  'fails if data and xlog directory are the same, relative data directory');
+
+chdir $pwd or BAIL_OUT("could not chdir to $pwd: $!");;
+
+$TODO = undef;
diff --git a/src/bin/pg_basebackup/t/020_pg_receivexlog.pl b/src/bin/pg_basebackup/t/020_pg_receivexlog.pl
new file mode 100644
index 0000000..700ae04
--- /dev/null
+++ b/src/bin/pg_basebackup/t/020_pg_receivexlog.pl
@@ -0,0 +1,8 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 3;
+
+program_help_ok('pg_receivexlog');
+program_version_ok('pg_receivexlog');
+program_options_handling_ok('pg_receivexlog');
diff --git a/src/bin/pg_config/.gitignore b/src/bin/pg_config/.gitignore
index 169bc76..cc42247 100644
--- a/src/bin/pg_config/.gitignore
+++ b/src/bin/pg_config/.gitignore
@@ -1 +1,2 @@
 /pg_config
+/tmp_check/
diff --git a/src/bin/pg_config/Makefile b/src/bin/pg_config/Makefile
index 578a2a5..579dce6 100644
--- a/src/bin/pg_config/Makefile
+++ b/src/bin/pg_config/Makefile
@@ -47,3 +47,9 @@ uninstall:
 
 clean distclean maintainer-clean:
 	rm -f pg_config$(X) $(OBJS)
+
+check: all
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/bin/pg_config/t/001_pg_config.pl b/src/bin/pg_config/t/001_pg_config.pl
new file mode 100644
index 0000000..200f394
--- /dev/null
+++ b/src/bin/pg_config/t/001_pg_config.pl
@@ -0,0 +1,12 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 7;
+
+program_help_ok('pg_config');
+program_version_ok('pg_config');
+program_options_handling_ok('pg_config');
+command_like(['pg_config', '--bindir'], qr/bin/, 'pg_config single option');  # XXX might be wrong
+command_like(['pg_config', '--bindir', '--libdir'],  qr/bin.*\n.*lib/, 'pg_config two options');
+command_like(['pg_config', '--libdir', '--bindir'],  qr/lib.*\n.*bin/, 'pg_config two options different order');
+command_like(['pg_config'], qr/.*\n.*\n.*/, 'pg_config without options prints many lines');
diff --git a/src/bin/pg_controldata/.gitignore b/src/bin/pg_controldata/.gitignore
index eab0c28..051d71d 100644
--- a/src/bin/pg_controldata/.gitignore
+++ b/src/bin/pg_controldata/.gitignore
@@ -1 +1,2 @@
 /pg_controldata
+/tmp_check/
diff --git a/src/bin/pg_controldata/Makefile b/src/bin/pg_controldata/Makefile
index 8b5f340..5abe76c 100644
--- a/src/bin/pg_controldata/Makefile
+++ b/src/bin/pg_controldata/Makefile
@@ -33,3 +33,9 @@ uninstall:
 
 clean distclean maintainer-clean:
 	rm -f pg_controldata$(X) $(OBJS)
+
+check: all
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/bin/pg_controldata/t/001_pg_controldata.pl b/src/bin/pg_controldata/t/001_pg_controldata.pl
new file mode 100644
index 0000000..3ddab80
--- /dev/null
+++ b/src/bin/pg_controldata/t/001_pg_controldata.pl
@@ -0,0 +1,14 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 6;
+
+my $tempdir = TestLib::tempdir;
+
+program_help_ok('pg_controldata');
+program_version_ok('pg_controldata');
+program_options_handling_ok('pg_controldata');
+command_fails(['pg_controldata'], 'pg_controldata without arguments fails');
+command_fails(['pg_controldata', 'nonexistent'], 'pg_controldata with nonexistent directory fails');
+system_or_bail "initdb -D $tempdir/data -A trust";
+command_like(['pg_controldata', "$tempdir/data"], qr/checkpoint/, 'pg_controldata produces output');
diff --git a/src/bin/pg_ctl/.gitignore b/src/bin/pg_ctl/.gitignore
index c90c103..73ab4ed 100644
--- a/src/bin/pg_ctl/.gitignore
+++ b/src/bin/pg_ctl/.gitignore
@@ -1 +1,2 @@
 /pg_ctl
+/tmp_check/
diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile
index cbc1638..a9a0366 100644
--- a/src/bin/pg_ctl/Makefile
+++ b/src/bin/pg_ctl/Makefile
@@ -36,3 +36,9 @@ uninstall:
 
 clean distclean maintainer-clean:
 	rm -f pg_ctl$(X) $(OBJS)
+
+check: all
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/bin/pg_ctl/t/001_start_stop.pl b/src/bin/pg_ctl/t/001_start_stop.pl
new file mode 100644
index 0000000..6818ba4
--- /dev/null
+++ b/src/bin/pg_ctl/t/001_start_stop.pl
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 10;
+
+my $tempdir = TestLib::tempdir;
+
+program_help_ok('pg_ctl');
+program_version_ok('pg_ctl');
+program_options_handling_ok('pg_ctl');
+
+command_ok(['pg_ctl', 'initdb', '-D', "$tempdir/data"], 'pg_ctl initdb');
+command_ok(['pg_ctl', 'start', '-D', "$tempdir/data", '-w'], 'pg_ctl start -w');
+command_ok(['pg_ctl', 'start', '-D', "$tempdir/data", '-w'], 'second pg_ctl start succeeds');
+command_ok(['pg_ctl', 'stop', '-D', "$tempdir/data", '-w', '-m', 'fast'], 'pg_ctl stop -w');
+command_fails(['pg_ctl', 'stop', '-D', "$tempdir/data", '-w', '-m', 'fast'], 'second pg_ctl stop fails');
+
+command_ok(['pg_ctl', 'restart', '-D', "$tempdir/data", '-w', '-m', 'fast'], 'pg_ctl restart with server not running');
+command_ok(['pg_ctl', 'restart', '-D', "$tempdir/data", '-w', '-m', 'fast'], 'pg_ctl restart with server running');
+
+system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data", '-m', 'fast';
diff --git a/src/bin/pg_ctl/t/002_status.pl b/src/bin/pg_ctl/t/002_status.pl
new file mode 100644
index 0000000..53524eb
--- /dev/null
+++ b/src/bin/pg_ctl/t/002_status.pl
@@ -0,0 +1,14 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 2;
+
+my $tempdir = TestLib::tempdir;
+
+system_or_bail "initdb -D $tempdir/data -A trust";
+command_exit_is(['pg_ctl', 'status', '-D', "$tempdir/data"], 3, 'pg_ctl status with server not running');
+
+system_or_bail 'pg_ctl', '-s', '-l', "$tempdir/logfile", '-D', "$tempdir/data", '-w', 'start';
+command_exit_is(['pg_ctl', 'status', '-D', "$tempdir/data"], 0, 'pg_ctl status with server running');
+
+system_or_bail 'pg_ctl', '-s', 'stop', '-D', "$tempdir/data", '-m', 'fast';
diff --git a/src/bin/scripts/.gitignore b/src/bin/scripts/.gitignore
index 0b9b786..1056b28 100644
--- a/src/bin/scripts/.gitignore
+++ b/src/bin/scripts/.gitignore
@@ -14,3 +14,5 @@
 /kwlookup.c
 /mbprint.c
 /print.c
+
+/tmp_check/
diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile
index b5d9207..de0e11f 100644
--- a/src/bin/scripts/Makefile
+++ b/src/bin/scripts/Makefile
@@ -68,3 +68,10 @@ clean distclean maintainer-clean:
 	rm -f $(addsuffix $(X), $(PROGRAMS)) $(addsuffix .o, $(PROGRAMS))
 	rm -f common.o dumputils.o kwlookup.o keywords.o print.o mbprint.o $(WIN32RES)
 	rm -f dumputils.c print.c mbprint.c kwlookup.c keywords.c
+
+
+check: all
+	$(prove_check)
+
+installcheck:
+	$(prove_installcheck)
diff --git a/src/bin/scripts/t/010_clusterdb.pl b/src/bin/scripts/t/010_clusterdb.pl
new file mode 100644
index 0000000..371b2dd
--- /dev/null
+++ b/src/bin/scripts/t/010_clusterdb.pl
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 6;
+
+program_help_ok('clusterdb');
+program_version_ok('clusterdb');
+program_options_handling_ok('clusterdb');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['clusterdb', 'postgres'], qr/statement: CLUSTER;/, 'SQL CLUSTER run');
+
+command_fails(['clusterdb', '-t', 'nonexistent', 'postgres'], 'fails with nonexistent table');
+
+psql 'postgres', 'CREATE TABLE test1 (a int); CREATE INDEX test1x ON test1 (a); CLUSTER test1 USING test1x';
+issues_sql_like(['clusterdb', 'postgres', '-t', 'test1'], qr/statement: CLUSTER test1;/, 'cluster specific table');
diff --git a/src/bin/scripts/t/011_clusterdb_all.pl b/src/bin/scripts/t/011_clusterdb_all.pl
new file mode 100644
index 0000000..304c4be
--- /dev/null
+++ b/src/bin/scripts/t/011_clusterdb_all.pl
@@ -0,0 +1,9 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 1;
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['clusterdb', '-a'], qr/statement: CLUSTER.*statement: CLUSTER/s, 'cluster all databases');
diff --git a/src/bin/scripts/t/020_createdb.pl b/src/bin/scripts/t/020_createdb.pl
new file mode 100644
index 0000000..8b82a2b
--- /dev/null
+++ b/src/bin/scripts/t/020_createdb.pl
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 6;
+
+program_help_ok('createdb');
+program_version_ok('createdb');
+program_options_handling_ok('createdb');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['createdb', 'foobar1'], qr/statement: CREATE DATABASE foobar1/, 'SQL CREATE DATABASE run');
+issues_sql_like(['createdb', 'foobar2', '-l', 'C', '-E', 'LATIN1', '-T', 'template0'], qr/statement: CREATE DATABASE foobar2 ENCODING 'LATIN1'/, 'create database with encoding');
+
+command_fails(['createdb', 'foobar1'], 'fails if database already exists');
diff --git a/src/bin/scripts/t/030_createlang.pl b/src/bin/scripts/t/030_createlang.pl
new file mode 100644
index 0000000..9a87f4c
--- /dev/null
+++ b/src/bin/scripts/t/030_createlang.pl
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 6;
+
+program_help_ok('createlang');
+program_version_ok('createlang');
+program_options_handling_ok('createlang');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+command_fails(['createlang', 'plpgsql', 'postgres'], 'fails if language already exists');
+
+psql 'postgres', 'DROP EXTENSION plpgsql';
+issues_sql_like(['createlang', 'plpgsql', 'postgres'], qr/statement: CREATE EXTENSION "plpgsql"/, 'SQL CREATE EXTENSION run');
+
+command_like(['createlang', '--list', 'postgres'], qr/plpgsql/, 'list output');
diff --git a/src/bin/scripts/t/040_createuser.pl b/src/bin/scripts/t/040_createuser.pl
new file mode 100644
index 0000000..922873a
--- /dev/null
+++ b/src/bin/scripts/t/040_createuser.pl
@@ -0,0 +1,26 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 8;
+
+program_help_ok('createuser');
+program_version_ok('createuser');
+program_options_handling_ok('createuser');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['createuser', 'user1'],
+				qr/statement: CREATE ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;/,
+				'SQL CREATE USER run');
+issues_sql_like(['createuser', '-L', 'role1'],
+				qr/statement: CREATE ROLE role1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN;/,
+				'create a non-login role');
+issues_sql_like(['createuser', '-r', 'user2'],
+				qr/statement: CREATE ROLE user2 NOSUPERUSER NOCREATEDB CREATEROLE INHERIT LOGIN;/,
+				'create a CREATEROLE user');
+issues_sql_like(['createuser', '-s', 'user3'],
+				qr/statement: CREATE ROLE user3 SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;/,
+				'create a superuser');
+
+command_fails(['createuser', 'user1'], 'fails if role already exists');
diff --git a/src/bin/scripts/t/050_dropdb.pl b/src/bin/scripts/t/050_dropdb.pl
new file mode 100644
index 0000000..3662dd0
--- /dev/null
+++ b/src/bin/scripts/t/050_dropdb.pl
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 5;
+
+program_help_ok('dropdb');
+program_version_ok('dropdb');
+program_options_handling_ok('dropdb');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+psql 'postgres', 'CREATE DATABASE foobar1';
+issues_sql_like(['dropdb', 'foobar1'], qr/statement: DROP DATABASE foobar1/, 'SQL DROP DATABASE run');
+
+command_fails(['dropdb', 'nonexistent'], 'fails with nonexistent database');
diff --git a/src/bin/scripts/t/060_droplang.pl b/src/bin/scripts/t/060_droplang.pl
new file mode 100644
index 0000000..47cb48f
--- /dev/null
+++ b/src/bin/scripts/t/060_droplang.pl
@@ -0,0 +1,15 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 5;
+
+program_help_ok('droplang');
+program_version_ok('droplang');
+program_options_handling_ok('droplang');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['droplang', 'plpgsql', 'postgres'], qr/statement: DROP EXTENSION "plpgsql"/, 'SQL DROP EXTENSION run');
+
+command_fails(['droplang', 'nonexistent', 'postgres'], 'fails with nonexistent language');
diff --git a/src/bin/scripts/t/070_dropuser.pl b/src/bin/scripts/t/070_dropuser.pl
new file mode 100644
index 0000000..495636a
--- /dev/null
+++ b/src/bin/scripts/t/070_dropuser.pl
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 5;
+
+program_help_ok('dropuser');
+program_version_ok('dropuser');
+program_options_handling_ok('dropuser');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+psql 'postgres', 'CREATE ROLE foobar1';
+issues_sql_like(['dropuser', 'foobar1'], qr/statement: DROP ROLE foobar1/, 'SQL DROP ROLE run');
+
+command_fails(['dropuser', 'nonexistent'], 'fails with nonexistent user');
diff --git a/src/bin/scripts/t/080_pg_isready.pl b/src/bin/scripts/t/080_pg_isready.pl
new file mode 100644
index 0000000..03c3657
--- /dev/null
+++ b/src/bin/scripts/t/080_pg_isready.pl
@@ -0,0 +1,15 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 5;
+
+program_help_ok('pg_isready');
+program_version_ok('pg_isready');
+program_options_handling_ok('pg_isready');
+
+command_fails(['pg_isready'], 'fails with no server running');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+command_ok(['pg_isready'], 'succeeds with server running');
diff --git a/src/bin/scripts/t/090_reindexdb.pl b/src/bin/scripts/t/090_reindexdb.pl
new file mode 100644
index 0000000..18756e8
--- /dev/null
+++ b/src/bin/scripts/t/090_reindexdb.pl
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 7;
+
+program_help_ok('reindexdb');
+program_version_ok('reindexdb');
+program_options_handling_ok('reindexdb');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+$ENV{PGOPTIONS} = '--client-min-messages=WARNING';
+
+issues_sql_like(['reindexdb', 'postgres'], qr/statement: REINDEX DATABASE postgres;/, 'SQL REINDEX run');
+
+psql 'postgres', 'CREATE TABLE test1 (a int); CREATE INDEX test1x ON test1 (a);';
+issues_sql_like(['reindexdb', 'postgres', '-t', 'test1'], qr/statement: REINDEX TABLE test1;/, 'reindex specific table');
+issues_sql_like(['reindexdb', 'postgres', '-i', 'test1x'], qr/statement: REINDEX INDEX test1x;/, 'reindex specific index');
+
+issues_sql_like(['reindexdb', 'postgres', '-s'], qr/statement: REINDEX SYSTEM postgres;/, 'reindex system tables');
diff --git a/src/bin/scripts/t/091_reindexdb_all.pl b/src/bin/scripts/t/091_reindexdb_all.pl
new file mode 100644
index 0000000..eee8ba8
--- /dev/null
+++ b/src/bin/scripts/t/091_reindexdb_all.pl
@@ -0,0 +1,11 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 1;
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+$ENV{PGOPTIONS} = '--client-min-messages=WARNING';
+
+issues_sql_like(['reindexdb', '-a'], qr/statement: REINDEX.*statement: REINDEX/s, 'reindex all databases');
diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl
new file mode 100644
index 0000000..39f1cec
--- /dev/null
+++ b/src/bin/scripts/t/100_vacuumdb.pl
@@ -0,0 +1,17 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 8;
+
+program_help_ok('vacuumdb');
+program_version_ok('vacuumdb');
+program_options_handling_ok('vacuumdb');
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['vacuumdb', 'postgres'], qr/statement: VACUUM;/, 'SQL VACUUM run');
+issues_sql_like(['vacuumdb', '-f', 'postgres'], qr/statement: VACUUM \(FULL\);/, 'vacuumdb -f');
+issues_sql_like(['vacuumdb', '-F', 'postgres'], qr/statement: VACUUM \(FREEZE\);/, 'vacuumdb -F');
+issues_sql_like(['vacuumdb', '-z', 'postgres'], qr/statement: VACUUM \(ANALYZE\);/, 'vacuumdb -z');
+issues_sql_like(['vacuumdb', '-Z', 'postgres'], qr/statement: ANALYZE;/, 'vacuumdb -z');
diff --git a/src/bin/scripts/t/101_vacuumdb_all.pl b/src/bin/scripts/t/101_vacuumdb_all.pl
new file mode 100644
index 0000000..b5779bc
--- /dev/null
+++ b/src/bin/scripts/t/101_vacuumdb_all.pl
@@ -0,0 +1,9 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 1;
+
+my $tempdir = tempdir;
+start_test_server $tempdir;
+
+issues_sql_like(['vacuumdb', '-a'], qr/statement: VACUUM.*statement: VACUUM/s, 'vacuum all databases');
diff --git a/src/test/perl/TestLib.pm b/src/test/perl/TestLib.pm
new file mode 100644
index 0000000..574ab78
--- /dev/null
+++ b/src/test/perl/TestLib.pm
@@ -0,0 +1,178 @@
+package TestLib;
+
+use strict;
+use warnings;
+
+use Exporter 'import';
+our @EXPORT = qw(
+	tempdir
+	start_test_server
+	restart_test_server
+	psql
+	system_or_bail
+
+	command_ok
+	command_fails
+	command_exit_is
+	program_help_ok
+	program_version_ok
+	program_options_handling_ok
+	command_like
+	issues_sql_like
+);
+
+use Cwd;
+use File::Spec;
+use File::Temp ();
+use IPC::Run qw(run start);
+use Test::More;
+
+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}) {
+	$ENV{PGPORT} = 65432;
+}
+
+$ENV{PGPORT} = int($ENV{PGPORT}) % 65536;
+
+
+#
+# Helper functions
+#
+
+
+sub tempdir {
+	return File::Temp::tempdir('testXXXX', DIR => cwd(), CLEANUP => 1);
+}
+
+my ($test_server_datadir, $test_server_logfile);
+
+sub start_test_server {
+	my ($tempdir) = @_;
+	my $ret;
+
+	system "initdb -D $tempdir/pgdata -A trust -N >/dev/null";
+	$ret = system 'pg_ctl', '-D', "$tempdir/pgdata", '-s', '-w', '-l', "$tempdir/logfile", '-o', "--fsync=off -k $tempdir --log-statement=all", 'start';
+
+	if ($ret != 0) {
+		system('cat', "$tempdir/logfile");
+		BAIL_OUT("pg_ctl failed");
+	}
+
+	$ENV{PGHOST} = $tempdir;
+	$test_server_datadir = "$tempdir/pgdata";
+	$test_server_logfile = "$tempdir/logfile";
+}
+
+sub restart_test_server {
+	system 'pg_ctl', '-s', '-D', $test_server_datadir, '-w', '-l', $test_server_logfile, 'restart';
+}
+
+END {
+	if ($test_server_datadir) {
+		system 'pg_ctl', '-D', $test_server_datadir, '-s', '-w', '-m', 'immediate', 'stop';
+	}
+}
+
+sub psql {
+	my ($dbname, $sql) = @_;
+	run ['psql', '-X', '-q', '-d', $dbname, '-f', '-'], '<', \$sql or die;
+}
+
+sub system_or_bail {
+	system(@_) == 0 or BAIL_OUT("system @_ failed: $?");
+}
+
+
+#
+# Test functions
+#
+
+
+sub command_ok {
+	my ($cmd, $test_name) = @_;
+	#my $result = run $cmd, '>', File::Spec->devnull(), '2>', File::Spec->devnull();
+	my $result = run $cmd;
+	ok($result, $test_name);
+}
+
+sub command_fails {
+	my ($cmd, $test_name) = @_;
+	my $result = run $cmd, '>', File::Spec->devnull(), '2>', File::Spec->devnull();
+	ok(!$result, $test_name);
+}
+
+sub command_exit_is {
+	my ($cmd, $expected, $test_name) = @_;
+	my $h = start $cmd, '>', File::Spec->devnull(), '2>', File::Spec->devnull();
+	$h->finish();
+	is($h->result(0), $expected, $test_name);
+}
+
+sub program_help_ok {
+	my ($cmd) = @_;
+	subtest "$cmd --help" => sub {
+		plan tests => 3;
+		my ($stdout, $stderr);
+		my $result = 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");
+	};
+}
+
+sub program_version_ok {
+	my ($cmd) = @_;
+	subtest "$cmd --version" => sub {
+		plan tests => 3;
+		my ($stdout, $stderr);
+		my $result = 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");
+	};
+}
+
+sub program_options_handling_ok {
+	my ($cmd) = @_;
+	subtest "$cmd options handling" => sub {
+		plan tests => 2;
+		my ($stdout, $stderr);
+		my $result = 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");
+	};
+}
+
+sub command_like {
+	my ($cmd, $expected_stdout, $test_name) = @_;
+	subtest $test_name => sub {
+		plan tests => 3;
+		my ($stdout, $stderr);
+		my $result = 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) = @_;
+	subtest $test_name => sub {
+		plan tests => 2;
+		truncate $test_server_logfile, 0;
+		my $result = run $cmd;
+		ok($result, "@$cmd exit code 0");
+		my $log = `cat $test_server_logfile`;
+		like($log, $expected_sql, "$test_name: SQL found in server log");
+	};
+}
+
+1;
-- 
1.8.5.1

-- 
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