]> granicus.if.org Git - postgresql/commitdiff
Add TAP tests for client programs
authorPeter Eisentraut <peter_e@gmx.net>
Tue, 15 Apr 2014 01:33:46 +0000 (21:33 -0400)
committerPeter Eisentraut <peter_e@gmx.net>
Tue, 15 Apr 2014 01:33:46 +0000 (21:33 -0400)
Reviewed-by: Pavel Stěhule <pavel.stehule@gmail.com>
Reviewed-by: Erik Rijkers <er@xs4all.nl>
39 files changed:
GNUmakefile.in
configure
configure.in
doc/src/sgml/installation.sgml
doc/src/sgml/regress.sgml
src/Makefile.global.in
src/bin/initdb/.gitignore
src/bin/initdb/Makefile
src/bin/initdb/t/001_initdb.pl [new file with mode: 0644]
src/bin/pg_basebackup/.gitignore
src/bin/pg_basebackup/Makefile
src/bin/pg_basebackup/t/010_pg_basebackup.pl [new file with mode: 0644]
src/bin/pg_basebackup/t/020_pg_receivexlog.pl [new file with mode: 0644]
src/bin/pg_config/.gitignore
src/bin/pg_config/Makefile
src/bin/pg_config/t/001_pg_config.pl [new file with mode: 0644]
src/bin/pg_controldata/.gitignore
src/bin/pg_controldata/Makefile
src/bin/pg_controldata/t/001_pg_controldata.pl [new file with mode: 0644]
src/bin/pg_ctl/.gitignore
src/bin/pg_ctl/Makefile
src/bin/pg_ctl/t/001_start_stop.pl [new file with mode: 0644]
src/bin/pg_ctl/t/002_status.pl [new file with mode: 0644]
src/bin/scripts/.gitignore
src/bin/scripts/Makefile
src/bin/scripts/t/010_clusterdb.pl [new file with mode: 0644]
src/bin/scripts/t/011_clusterdb_all.pl [new file with mode: 0644]
src/bin/scripts/t/020_createdb.pl [new file with mode: 0644]
src/bin/scripts/t/030_createlang.pl [new file with mode: 0644]
src/bin/scripts/t/040_createuser.pl [new file with mode: 0644]
src/bin/scripts/t/050_dropdb.pl [new file with mode: 0644]
src/bin/scripts/t/060_droplang.pl [new file with mode: 0644]
src/bin/scripts/t/070_dropuser.pl [new file with mode: 0644]
src/bin/scripts/t/080_pg_isready.pl [new file with mode: 0644]
src/bin/scripts/t/090_reindexdb.pl [new file with mode: 0644]
src/bin/scripts/t/091_reindexdb_all.pl [new file with mode: 0644]
src/bin/scripts/t/100_vacuumdb.pl [new file with mode: 0644]
src/bin/scripts/t/101_vacuumdb_all.pl [new file with mode: 0644]
src/test/perl/TestLib.pm [new file with mode: 0644]

index a573880d793023da80adcb4fc7758e68536786af..69e08249c1daede9254c4c74a07fb4414fc653a4 100644 (file)
@@ -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 $@
index 122ace7e39776a11c835ba2bc51d369752a0bf26..e0dbdfec1097b263bec64d59916bb6b9a8acc37c 100755 (executable)
--- a/configure
+++ b/configure
@@ -627,6 +627,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 vpath_build
+PROVE
 OSX
 XSLTPROC
 COLLATEINDEX
 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
index 0f3e0ccdd0c2c24f8958e0aa73bdd3a939706b0b..fc9c52f83d2c792a76945712c86883883f7e67cf 100644 (file)
@@ -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
index efaaad80b402fa0657a0b4e4ce3796919c68bb8a..32160bf33f22f9a63f867f8a9b41891f9ab4e945 100644 (file)
@@ -333,7 +333,8 @@ su - postgres
       <application>Perl</> 5.8 or later is needed to build from a Git checkout,
       or if you changed the input files for any of the build steps that
       use Perl scripts.  If building on Windows you will need
-      <application>Perl</> in any case.
+      <application>Perl</> in any case.  <application>Perl</application> is
+      also required to run some test suites.
      </para>
     </listitem>
    </itemizedlist>
index 16b36211f3dc439fc9d8603b524364931f5aad7a..aee049a3d5af73d7138ccf9acd56712219b45ee4 100644 (file)
@@ -204,6 +204,12 @@ make installcheck-world
      located in <filename>src/test/isolation</>.
     </para>
    </listitem>
+   <listitem>
+    <para>
+     Tests of client programs under <filename>src/bin</filename>.  See
+     also <xref linkend="regress-tap">.
+    </para>
+   </listitem>
   </itemizedlist>
 
   <para>
@@ -660,6 +666,28 @@ float8:out:i.86-.*-openbsd=float8-small-is-zero.out
 
   </sect1>
 
+  <sect1 id="regress-tap">
+   <title>TAP Tests</title>
+
+   <para>
+    The client program tests under <filename>src/bin</filename> use the Perl
+    TAP tools and are run by <command>prove</command>.  You can pass
+    command-line options to <command>prove</command> by setting
+    the <command>make</command> variable <varname>PROVE_FLAGS</>, for example:
+<programlisting>
+make -C src/bin check PROVE_FLAGS='--reverse'
+</programlisting>
+    The default is <literal>--verbose</literal>.  See the manual page
+    of <command>prove</command> for more information.
+   </para>
+
+   <para>
+    The tests written in Perl require the Perl
+    module <literal>IPC::Run</literal>, otherwise most tests will be skipped.
+    This module is available from CPAN or an operating system package.
+   </para>
+  </sect1>
+
   <sect1 id="regress-coverage">
    <title>Test Coverage Examination</title>
 
index cdddf492f459e7dc7dfcd9a4823bf4d2c1fc39bc..7a7b0899fd30a8bc29d3c40b7e56d272ca06c2dc 100644 (file)
@@ -292,6 +292,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@
index 0f74727d8f6732d20333a2f13cea1f4d9c0e16a3..71a899ffb8a68eb2a710286dc62e7e41468370c4 100644 (file)
@@ -2,3 +2,5 @@
 /localtime.c
 
 /initdb
+
+/tmp_check/
index 1ece7acf44a06ae436e767e878d7267edecb7447..fb7d1424874e199194d3bde5f0df084917e4d1ee 100644 (file)
@@ -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 (file)
index 0000000..ad6d74c
--- /dev/null
@@ -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');
index 7abea15a3f9a08908c7308dc5a6fa7aaed18272a..36a2f12d61571a8d099d49fb0f3e41d5a4ec6d76 100644 (file)
@@ -1,3 +1,5 @@
 /pg_basebackup
 /pg_receivexlog
 /pg_recvlogical
+
+/tmp_check/
index 346560eeab1cca5f2e66b2921e952013393c6d5f..37ee6b0288aafcba1fc835bb7db32ffe0d0c1fbc 100644 (file)
@@ -48,3 +48,9 @@ clean distclean maintainer-clean:
        rm -f pg_basebackup$(X) pg_receivexlog$(X) pg_recvlogical$(X) \
                pg_basebackup.o pg_receivexlog.o pg_recvlogical.o \
                $(OBJS)
+
+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 (file)
index 0000000..38f4692
--- /dev/null
@@ -0,0 +1,90 @@
+use strict;
+use warnings;
+use Cwd;
+use TestLib;
+use Test::More tests => 28;
+
+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";
+is(scalar(@tblspc_tars), 1, 'one tablespace tar was created');
+
+command_fails(['pg_basebackup', '-D', "$tempdir/backup1", '-Fp'],
+                         'plain format with tablespaces fails without tablespace mapping');
+
+command_ok(['pg_basebackup', '-D', "$tempdir/backup1", '-Fp',
+                       "-T$tempdir/tblspc1=$tempdir/tbackup/tblspc1"],
+                  'plain format with tablespaces succeeds with tablespace mapping');
+ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+opendir(my $dh, "$tempdir/pgdata/pg_tblspc") or die;
+ok((grep { -l "$tempdir/backup1/pg_tblspc/$_" and readlink "$tempdir/backup1/pg_tblspc/$_" eq "$tempdir/tbackup/tblspc1" } readdir($dh)),
+   "tablespace symlink was updated");
+closedir $dh;
+
+mkdir "$tempdir/tbl=spc2";
+psql 'postgres', "DROP TABLE test1;";
+psql 'postgres', "DROP TABLESPACE tblspc1;";
+psql 'postgres', "CREATE TABLESPACE tblspc2 LOCATION '$tempdir/tbl=spc2';";
+command_ok(['pg_basebackup', '-D', "$tempdir/backup3", '-Fp',
+                       "-T$tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"],
+                  'mapping tablespace with = sign in path');
+ok(-d "$tempdir/tbackup/tbl=spc2", 'tablespace with = sign was relocated');
+
+psql 'postgres', "DROP TABLESPACE tblspc2;";
+
+command_fails(['pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
+                          "-T=/foo"],
+                         '-T with empty old directory fails');
+command_fails(['pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
+                          "-T/foo="],
+                         '-T with empty new directory fails');
+command_fails(['pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
+                          "-T/foo=/bar=/baz"],
+                         '-T with multiple = fails');
+command_fails(['pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
+                          "-Tfoo=/bar"],
+                         '-T with old directory not absolute fails');
+command_fails(['pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
+                          "-T/foo=bar"],
+                         '-T with new directory not absolute fails');
+command_fails(['pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp',
+                          "-Tfoo"],
+                         '-T with invalid format fails');
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 (file)
index 0000000..700ae04
--- /dev/null
@@ -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');
index 169bc766de4209d3b6c20ed7474692462e1ad4ed..cc422470d931abac3a21da037e98a2a02d7f97c5 100644 (file)
@@ -1 +1,2 @@
 /pg_config
+/tmp_check/
index 578a2a52c806a937d135ca15758ae033f8c81b10..579dce62b750769a605efadaddd16cd816baeb24 100644 (file)
@@ -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 (file)
index 0000000..200f394
--- /dev/null
@@ -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');
index eab0c28a8bb3f3c5524da4be86c53163a44d819f..051d71d8f397e4669b5223171afca77f4cca80e1 100644 (file)
@@ -1 +1,2 @@
 /pg_controldata
+/tmp_check/
index 8b5f340d36fc8b57ecf7ae4776463ddae9007cc2..5abe76cc0d9f88e4b9bf7d13d20f2f340a519e82 100644 (file)
@@ -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 (file)
index 0000000..ca89d87
--- /dev/null
@@ -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 >/dev/null";
+command_like(['pg_controldata', "$tempdir/data"], qr/checkpoint/, 'pg_controldata produces output');
index c90c1030ef463564380d8d78ce04aab9b4a5fcf2..73ab4ed9f5fdc55dbba1ab1c6a9ad4e8d13323e9 100644 (file)
@@ -1 +1,2 @@
 /pg_ctl
+/tmp_check/
index cbc16381183b4bbc5e48e21c6e78b15ca8621725..a9a0366ef50215ea6410cc72340a350d3ab2c8c3 100644 (file)
@@ -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 (file)
index 0000000..49c1b1a
--- /dev/null
@@ -0,0 +1,25 @@
+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');
+open CONF, ">>$tempdir/data/postgresql.conf";
+print CONF "listen_addresses = ''\n";
+print CONF "unix_socket_directories = '$tempdir'\n";
+close CONF;
+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', '-s', '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 (file)
index 0000000..e41c22f
--- /dev/null
@@ -0,0 +1,19 @@
+use strict;
+use warnings;
+use TestLib;
+use Test::More tests => 2;
+
+my $tempdir = TestLib::tempdir;
+
+system_or_bail "initdb -D $tempdir/data -A trust >/dev/null";
+open CONF, ">>$tempdir/data/postgresql.conf";
+print CONF "listen_addresses = ''\n";
+print CONF "unix_socket_directories = '$tempdir'\n";
+close CONF;
+
+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';
index 0b9b786da032722064c3bd35da618145cda30223..1056b2870c0f15f378ace25a0c440bfb34e6e4e5 100644 (file)
@@ -14,3 +14,5 @@
 /kwlookup.c
 /mbprint.c
 /print.c
+
+/tmp_check/
index b5d9207b2935fc1124f3847169f8363e5bacbc02..de0e11f7142e12d034e50dc4176c5285a1ed6d51 100644 (file)
@@ -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 (file)
index 0000000..371b2dd
--- /dev/null
@@ -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 (file)
index 0000000..304c4be
--- /dev/null
@@ -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 (file)
index 0000000..8b82a2b
--- /dev/null
@@ -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 (file)
index 0000000..9a87f4c
--- /dev/null
@@ -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 (file)
index 0000000..922873a
--- /dev/null
@@ -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 (file)
index 0000000..3662dd0
--- /dev/null
@@ -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 (file)
index 0000000..47cb48f
--- /dev/null
@@ -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 (file)
index 0000000..495636a
--- /dev/null
@@ -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 (file)
index 0000000..03c3657
--- /dev/null
@@ -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 (file)
index 0000000..18756e8
--- /dev/null
@@ -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 (file)
index 0000000..eee8ba8
--- /dev/null
@@ -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 (file)
index 0000000..39f1cec
--- /dev/null
@@ -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 (file)
index 0000000..b5779bc
--- /dev/null
@@ -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 (file)
index 0000000..7c378e0
--- /dev/null
@@ -0,0 +1,186 @@
+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 Test::More;
+BEGIN {
+       eval {
+               require IPC::Run;
+               import IPC::Run qw(run start);
+               1;
+       } or do {
+               plan skip_all => "IPC::Run not available";
+       }
+}
+
+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 --listen-addresses='' --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();
+       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;
+               my ($stdout, $stderr);
+               truncate $test_server_logfile, 0;
+               my $result = run $cmd, '>', \$stdout, '2>', \$stderr;
+               ok($result, "@$cmd exit code 0");
+               my $log = `cat $test_server_logfile`;
+               like($log, $expected_sql, "$test_name: SQL found in server log");
+       };
+}
+
+1;