summaryrefslogtreecommitdiffstats
path: root/src/tools/msvc/vcregress.pl
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/msvc/vcregress.pl')
-rw-r--r--src/tools/msvc/vcregress.pl660
1 files changed, 660 insertions, 0 deletions
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
new file mode 100644
index 0000000..74fb735
--- /dev/null
+++ b/src/tools/msvc/vcregress.pl
@@ -0,0 +1,660 @@
+# -*-perl-*- hey - emacs - this is a perl file
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# src/tools/msvc/vcregress.pl
+
+use strict;
+use warnings;
+
+our $config;
+
+use Cwd;
+use File::Basename;
+use File::Copy;
+use File::Find ();
+use File::Path qw(rmtree);
+use File::Spec qw(devnull);
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use Install qw(Install);
+
+my $startdir = getcwd();
+
+chdir "../../.." if (-d "../../../src/tools/msvc");
+
+my $topdir = getcwd();
+my $tmp_installdir = "$topdir/tmp_install";
+
+do './src/tools/msvc/config_default.pl';
+do './src/tools/msvc/config.pl' if (-f 'src/tools/msvc/config.pl');
+
+my $devnull = File::Spec->devnull;
+
+# These values are defaults that can be overridden by the calling environment
+# (see buildenv.pl processing below). We assume that the ones listed here
+# always exist by default. Other values may optionally be set for bincheck
+# or taptest, see set_command_env() below.
+# c.f. src/Makefile.global.in and configure.ac
+$ENV{TAR} ||= 'tar';
+
+# buildenv.pl is for specifying the build environment settings
+# it should contain lines like:
+# $ENV{PATH} = "c:/path/to/bison/bin;$ENV{PATH}";
+
+if (-e "src/tools/msvc/buildenv.pl")
+{
+ do "./src/tools/msvc/buildenv.pl";
+}
+
+my $what = shift || "";
+if ($what =~
+ /^(check|installcheck|plcheck|contribcheck|modulescheck|ecpgcheck|isolationcheck|upgradecheck|bincheck|recoverycheck|taptest)$/i
+ )
+{
+ $what = uc $what;
+}
+else
+{
+ usage();
+}
+
+# use a capital C here because config.pl has $config
+my $Config = -e "release/postgres/postgres.exe" ? "Release" : "Debug";
+
+copy("$Config/refint/refint.dll", "src/test/regress");
+copy("$Config/autoinc/autoinc.dll", "src/test/regress");
+copy("$Config/regress/regress.dll", "src/test/regress");
+copy("$Config/dummy_seclabel/dummy_seclabel.dll", "src/test/regress");
+
+# Configuration settings used by TAP tests
+$ENV{with_ssl} = $config->{openssl} ? 'openssl' : 'no';
+$ENV{with_ldap} = $config->{ldap} ? 'yes' : 'no';
+$ENV{with_icu} = $config->{icu} ? 'yes' : 'no';
+$ENV{with_gssapi} = $config->{gss} ? 'yes' : 'no';
+$ENV{with_krb_srvnam} = $config->{krb_srvnam} || 'postgres';
+$ENV{with_readline} = 'no';
+
+$ENV{PATH} = "$topdir/$Config/libpq;$ENV{PATH}";
+
+if ($ENV{PERL5LIB})
+{
+ $ENV{PERL5LIB} = "$topdir/src/tools/msvc;$ENV{PERL5LIB}";
+}
+else
+{
+ $ENV{PERL5LIB} = "$topdir/src/tools/msvc";
+}
+
+my $maxconn = "";
+$maxconn = "--max-connections=$ENV{MAX_CONNECTIONS}"
+ if $ENV{MAX_CONNECTIONS};
+
+my $temp_config = "";
+$temp_config = "--temp-config=\"$ENV{TEMP_CONFIG}\""
+ if $ENV{TEMP_CONFIG};
+
+chdir "src/test/regress";
+
+my %command = (
+ CHECK => \&check,
+ PLCHECK => \&plcheck,
+ INSTALLCHECK => \&installcheck,
+ ECPGCHECK => \&ecpgcheck,
+ CONTRIBCHECK => \&contribcheck,
+ MODULESCHECK => \&modulescheck,
+ ISOLATIONCHECK => \&isolationcheck,
+ BINCHECK => \&bincheck,
+ RECOVERYCHECK => \&recoverycheck,
+ UPGRADECHECK => \&upgradecheck, # no-op
+ TAPTEST => \&taptest,);
+
+my $proc = $command{$what};
+
+exit 3 unless $proc;
+
+&$proc(@ARGV);
+
+exit 0;
+
+########################################################################
+
+# Helper function for set_command_env, to set one environment command.
+sub set_single_env
+{
+ my $envname = shift;
+ my $envdefault = shift;
+
+ # If a command is defined by the environment, just use it.
+ return if (defined($ENV{$envname}));
+
+ # Nothing is defined, so attempt to assign a default. The command
+ # may not be in the current environment, hence check if it can be
+ # executed.
+ my $rc = system("$envdefault --version >$devnull 2>&1");
+
+ # Set the environment to the default if it exists, else leave it.
+ $ENV{$envname} = $envdefault if $rc == 0;
+ return;
+}
+
+# Set environment values for various command types. These can be used
+# in the TAP tests.
+sub set_command_env
+{
+ set_single_env('GZIP_PROGRAM', 'gzip');
+ set_single_env('LZ4', 'lz4');
+ set_single_env('ZSTD', 'zstd');
+}
+
+sub installcheck_internal
+{
+ my ($schedule, @EXTRA_REGRESS_OPTS) = @_;
+ # for backwards compatibility, "serial" runs the tests in
+ # parallel_schedule one by one.
+ my $maxconn = $maxconn;
+ $maxconn = "--max-connections=1" if $schedule eq 'serial';
+ $schedule = 'parallel' if $schedule eq 'serial';
+
+ my @args = (
+ "../../../$Config/pg_regress/pg_regress",
+ "--dlpath=.",
+ "--bindir=../../../$Config/psql",
+ "--schedule=${schedule}_schedule",
+ "--max-concurrent-tests=20");
+ push(@args, $maxconn) if $maxconn;
+ push(@args, @EXTRA_REGRESS_OPTS);
+ system(@args);
+ my $status = $? >> 8;
+ exit $status if $status;
+ return;
+}
+
+sub installcheck
+{
+ my $schedule = shift || 'serial';
+ installcheck_internal($schedule);
+ return;
+}
+
+sub check
+{
+ my $schedule = shift || 'parallel';
+ # for backwards compatibility, "serial" runs the tests in
+ # parallel_schedule one by one.
+ my $maxconn = $maxconn;
+ $maxconn = "--max-connections=1" if $schedule eq 'serial';
+ $schedule = 'parallel' if $schedule eq 'serial';
+
+ InstallTemp();
+ chdir "${topdir}/src/test/regress";
+ my @args = (
+ "../../../$Config/pg_regress/pg_regress",
+ "--dlpath=.",
+ "--bindir=",
+ "--schedule=${schedule}_schedule",
+ "--max-concurrent-tests=20",
+ "--encoding=SQL_ASCII",
+ "--no-locale",
+ "--temp-instance=./tmp_check");
+ push(@args, $maxconn) if $maxconn;
+ push(@args, $temp_config) if $temp_config;
+ system(@args);
+ my $status = $? >> 8;
+ exit $status if $status;
+ return;
+}
+
+sub ecpgcheck
+{
+ my $msbflags = $ENV{MSBFLAGS} || "";
+ chdir $startdir;
+ system("msbuild ecpg_regression.proj $msbflags /p:config=$Config");
+ my $status = $? >> 8;
+ exit $status if $status;
+ InstallTemp();
+ chdir "$topdir/src/interfaces/ecpg/test";
+ my $schedule = "ecpg";
+ my @args = (
+ "../../../../$Config/pg_regress_ecpg/pg_regress_ecpg",
+ "--bindir=",
+ "--dbname=ecpg1_regression,ecpg2_regression",
+ "--create-role=regress_ecpg_user1,regress_ecpg_user2",
+ "--schedule=${schedule}_schedule",
+ "--encoding=SQL_ASCII",
+ "--no-locale",
+ "--temp-instance=./tmp_chk");
+ push(@args, $maxconn) if $maxconn;
+ system(@args);
+ $status = $? >> 8;
+ exit $status if $status;
+ return;
+}
+
+sub isolationcheck
+{
+ chdir "../isolation";
+ copy("../../../$Config/isolationtester/isolationtester.exe",
+ "../../../$Config/pg_isolation_regress");
+ my @args = (
+ "../../../$Config/pg_isolation_regress/pg_isolation_regress",
+ "--bindir=../../../$Config/psql",
+ "--inputdir=.",
+ "--schedule=./isolation_schedule");
+ push(@args, $maxconn) if $maxconn;
+ system(@args);
+ my $status = $? >> 8;
+ exit $status if $status;
+ return;
+}
+
+sub tap_check
+{
+ die "Tap tests not enabled in configuration"
+ unless $config->{tap_tests};
+
+ my @flags;
+ foreach my $arg (0 .. scalar(@_) - 1)
+ {
+ next unless $_[$arg] =~ /^PROVE_FLAGS=(.*)/;
+ @flags = split(/\s+/, $1);
+ splice(@_, $arg, 1);
+ last;
+ }
+
+ my $dir = shift;
+ chdir $dir;
+
+ # Fetch and adjust PROVE_TESTS, applying glob() to each element
+ # defined to build a list of all the tests matching patterns.
+ my $prove_tests_val = $ENV{PROVE_TESTS} || "t/*.pl";
+ my @prove_tests_array = split(/\s+/, $prove_tests_val);
+ my @prove_tests = ();
+ foreach (@prove_tests_array)
+ {
+ push(@prove_tests, glob($_));
+ }
+
+ # Fetch and adjust PROVE_FLAGS, handling multiple arguments.
+ my $prove_flags_val = $ENV{PROVE_FLAGS} || "";
+ my @prove_flags = split(/\s+/, $prove_flags_val);
+
+ my @args = ("prove", @flags, @prove_tests, @prove_flags);
+
+ # adjust the environment for just this test
+ local %ENV = %ENV;
+ $ENV{PERL5LIB} = "$topdir/src/test/perl;$ENV{PERL5LIB}";
+ $ENV{PG_REGRESS} = "$topdir/$Config/pg_regress/pg_regress";
+ $ENV{REGRESS_SHLIB} = "$topdir/src/test/regress/regress.dll";
+
+ $ENV{TESTDIR} = "$dir";
+ my $module = basename $dir;
+ # add the module build dir as the second element in the PATH
+ $ENV{PATH} =~ s!;!;$topdir/$Config/$module;!;
+
+ rmtree('tmp_check');
+ system(@args);
+ my $status = $? >> 8;
+ return $status;
+}
+
+sub bincheck
+{
+ InstallTemp();
+
+ set_command_env();
+
+ my $mstat = 0;
+
+ # Find out all the existing TAP tests by looking for t/ directories
+ # in the tree.
+ my @bin_dirs = glob("$topdir/src/bin/*");
+
+ # Process each test
+ foreach my $dir (@bin_dirs)
+ {
+ next unless -d "$dir/t";
+
+ my $status = tap_check($dir);
+ $mstat ||= $status;
+ }
+ exit $mstat if $mstat;
+ return;
+}
+
+sub taptest
+{
+ my $dir = shift;
+ my @args;
+
+ if ($dir =~ /^PROVE_FLAGS=/)
+ {
+ push(@args, $dir);
+ $dir = shift;
+ }
+
+ die "no tests found!" unless -d "$topdir/$dir/t";
+
+ push(@args, "$topdir/$dir");
+
+ InstallTemp();
+
+ set_command_env();
+
+ my $status = tap_check(@args);
+ exit $status if $status;
+ return;
+}
+
+sub plcheck
+{
+ chdir "$topdir/src/pl";
+
+ foreach my $dir (glob("*/src *"))
+ {
+ next unless -d "$dir/sql" && -d "$dir/expected";
+ my $lang;
+ if ($dir eq 'plpgsql/src')
+ {
+ $lang = 'plpgsql';
+ }
+ elsif ($dir eq 'tcl')
+ {
+ $lang = 'pltcl';
+ }
+ else
+ {
+ $lang = $dir;
+ }
+ if ($lang eq 'plpython')
+ {
+ next
+ unless -d "$topdir/$Config/plpython3";
+ $lang = 'plpythonu';
+ }
+ else
+ {
+ next unless -d "$topdir/$Config/$lang";
+ }
+ my @lang_args = ("--load-extension=$lang");
+ chdir $dir;
+ my @tests = fetchTests();
+ if ($lang eq 'plperl')
+ {
+
+ # plperl tests will install the extensions themselves
+ @lang_args = ();
+
+ # assume we're using this perl to built postgres
+ # test if we can run two interpreters in one backend, and if so
+ # run the trusted/untrusted interaction tests
+ use Config;
+ if ($Config{usemultiplicity} eq 'define')
+ {
+ push(@tests, 'plperl_plperlu');
+ }
+ }
+ elsif ($lang eq 'plpythonu' && -d "$topdir/$Config/plpython3")
+ {
+ @lang_args = ();
+ }
+
+ # Move on if no tests are listed.
+ next if (scalar @tests == 0);
+
+ print
+ "============================================================\n";
+ print "Checking $lang\n";
+ my @args = (
+ "$topdir/$Config/pg_regress/pg_regress",
+ "--bindir=$topdir/$Config/psql",
+ "--dbname=pl_regression", @lang_args, @tests);
+ system(@args);
+ my $status = $? >> 8;
+ exit $status if $status;
+ chdir "$topdir/src/pl";
+ }
+
+ chdir "$topdir";
+ return;
+}
+
+sub subdircheck
+{
+ my $module = shift;
+
+ if ( !-d "$module/sql"
+ || !-d "$module/expected"
+ || (!-f "$module/GNUmakefile" && !-f "$module/Makefile"))
+ {
+ return;
+ }
+
+ chdir $module;
+ my @tests = fetchTests();
+
+ # Leave if no tests are listed in the module.
+ if (scalar @tests == 0)
+ {
+ chdir "..";
+ return;
+ }
+
+ my @opts = fetchRegressOpts();
+
+ print "============================================================\n";
+ print "Checking $module\n";
+ my @args = (
+ "$topdir/$Config/pg_regress/pg_regress",
+ "--bindir=${topdir}/${Config}/psql",
+ "--dbname=contrib_regression", @opts, @tests);
+ print join(' ', @args), "\n";
+ system(@args);
+ chdir "..";
+ return;
+}
+
+sub contribcheck
+{
+ chdir "../../../contrib";
+ my $mstat = 0;
+ foreach my $module (glob("*"))
+ {
+ # these configuration-based exclusions must match Install.pm
+ next if ($module eq "uuid-ossp" && !defined($config->{uuid}));
+ next if ($module eq "sslinfo" && !defined($config->{openssl}));
+ next if ($module eq "pgcrypto" && !defined($config->{openssl}));
+ next if ($module eq "xml2" && !defined($config->{xml}));
+ next if ($module =~ /_plperl$/ && !defined($config->{perl}));
+ next if ($module =~ /_plpython$/ && !defined($config->{python}));
+ next if ($module eq "sepgsql");
+
+ subdircheck($module);
+ my $status = $? >> 8;
+ $mstat ||= $status;
+ }
+ exit $mstat if $mstat;
+ return;
+}
+
+sub modulescheck
+{
+ chdir "../../../src/test/modules";
+ my $mstat = 0;
+ foreach my $module (glob("*"))
+ {
+ subdircheck($module);
+ my $status = $? >> 8;
+ $mstat ||= $status;
+ }
+ exit $mstat if $mstat;
+ return;
+}
+
+sub recoverycheck
+{
+ InstallTemp();
+
+ my $dir = "$topdir/src/test/recovery";
+ my $status = tap_check($dir);
+ exit $status if $status;
+ return;
+}
+
+# Run "initdb", then reconfigure authentication.
+sub standard_initdb
+{
+ return (
+ system('initdb', '-N') == 0 and system(
+ "$topdir/$Config/pg_regress/pg_regress", '--config-auth',
+ $ENV{PGDATA}) == 0);
+}
+
+# This is similar to appendShellString(). Perl system(@args) bypasses
+# cmd.exe, so omit the caret escape layer.
+sub quote_system_arg
+{
+ my $arg = shift;
+
+ # Change N >= 0 backslashes before a double quote to 2N+1 backslashes.
+ $arg =~ s/(\\*)"/${\($1 . $1)}\\"/gs;
+
+ # Change N >= 1 backslashes at end of argument to 2N backslashes.
+ $arg =~ s/(\\+)$/${\($1 . $1)}/gs;
+
+ # Wrap the whole thing in unescaped double quotes.
+ return "\"$arg\"";
+}
+
+sub upgradecheck
+{
+ # pg_upgrade is now handled by bincheck, but keep this target for
+ # backward compatibility.
+ print "upgradecheck is a no-op, use bincheck instead.\n";
+ return;
+}
+
+sub fetchRegressOpts
+{
+ my $handle;
+ open($handle, '<', "GNUmakefile")
+ || open($handle, '<', "Makefile")
+ || die "Could not open Makefile";
+ local ($/) = undef;
+ my $m = <$handle>;
+ close($handle);
+ my @opts;
+
+ $m =~ s{\\\r?\n}{}g;
+ if ($m =~ /^\s*REGRESS_OPTS\s*\+?=(.*)/m)
+ {
+
+ # Substitute known Makefile variables, then ignore options that retain
+ # an unhandled variable reference. Ignore anything that isn't an
+ # option starting with "--".
+ @opts = grep { !/\$\(/ && /^--/ }
+ map { (my $x = $_) =~ s/\Q$(top_builddir)\E/\"$topdir\"/; $x; }
+ split(/\s+/, $1);
+ }
+ if ($m =~ /^\s*ENCODING\s*=\s*(\S+)/m)
+ {
+ push @opts, "--encoding=$1";
+ }
+ if ($m =~ /^\s*NO_LOCALE\s*=\s*\S+/m)
+ {
+ push @opts, "--no-locale";
+ }
+ return @opts;
+}
+
+# Fetch the list of tests by parsing a module's Makefile. An empty
+# list is returned if the module does not need to run anything.
+sub fetchTests
+{
+ my $handle;
+ open($handle, '<', "GNUmakefile")
+ || open($handle, '<', "Makefile")
+ || die "Could not open Makefile";
+ local ($/) = undef;
+ my $m = <$handle>;
+ close($handle);
+ my $t = "";
+
+ $m =~ s{\\\r?\n}{}g;
+
+ # A module specifying NO_INSTALLCHECK does not support installcheck,
+ # so bypass its run by returning an empty set of tests.
+ if ($m =~ /^\s*NO_INSTALLCHECK\s*=\s*\S+/m)
+ {
+ return ();
+ }
+
+ if ($m =~ /^REGRESS\s*=\s*(.*)$/gm)
+ {
+ $t = $1;
+ $t =~ s/\s+/ /g;
+
+ if ($m =~ /contrib\/pgcrypto/)
+ {
+
+ # pgcrypto is special since some tests depend on the
+ # configuration of the build
+
+ my $pgptests =
+ $config->{zlib}
+ ? GetTests("ZLIB_TST", $m)
+ : GetTests("ZLIB_OFF_TST", $m);
+ $t =~ s/\$\(CF_PGP_TESTS\)/$pgptests/;
+ }
+ }
+
+ return split(/\s+/, $t);
+}
+
+sub GetTests
+{
+ my $testname = shift;
+ my $m = shift;
+ if ($m =~ /^$testname\s*=\s*(.*)$/gm)
+ {
+ return $1;
+ }
+ return "";
+}
+
+sub InstallTemp
+{
+ unless ($ENV{NO_TEMP_INSTALL})
+ {
+ print "Setting up temp install\n\n";
+ Install("$tmp_installdir", "all", $config);
+ }
+ $ENV{PATH} = "$tmp_installdir/bin;$ENV{PATH}";
+ return;
+}
+
+sub usage
+{
+ print STDERR
+ "Usage: vcregress.pl <mode> [<arg>]\n\n",
+ "Options for <mode>:\n",
+ " bincheck run tests of utilities in src/bin/\n",
+ " check deploy instance and run regression tests on it\n",
+ " contribcheck run tests of modules in contrib/\n",
+ " ecpgcheck run regression tests of ECPG\n",
+ " installcheck run regression tests on existing instance\n",
+ " isolationcheck run isolation tests\n",
+ " modulescheck run tests of modules in src/test/modules/\n",
+ " plcheck run tests of PL languages\n",
+ " recoverycheck run recovery test suite\n",
+ " taptest run an arbitrary TAP test set\n",
+ " upgradecheck run tests of pg_upgrade (no-op)\n",
+ "\nOptions for <arg>: (used by check and installcheck)\n",
+ " serial serial mode\n",
+ " parallel parallel mode\n",
+ "\nOption for <arg>: for taptest\n",
+ " TEST_DIR (required) directory where tests reside\n";
+ exit(1);
+}