On Thu, Jan 30, 2020 at 7:36 AM Mark Dilger
<[email protected]> wrote:
>
>
>
> > On Jan 29, 2020, at 1:02 PM, Andrew Dunstan
> > <[email protected]> wrote:
> >
> > On Wed, Jan 29, 2020 at 4:32 PM Andrew Dunstan
> > <[email protected]> wrote:
> >>
> >>
> >> On 1/28/20 5:28 PM, Mark Dilger wrote:
> >>>
> >>>
> >>>> +# There doesn't seem to be any easy way to get TestLib to use the
> >>>> binaries from
> >>>> +# our directory, so we hack up a path to our binary and run that
> >>>> directly. This
> >>>> +# seems brittle enough that some other solution should be found, if
> >>>> possible.
> >>>> +
> >>>> +my $test_json = join('/', $ENV{TESTDIR}, 'test_json');
> >>>>
> >>>> I don't know what the right thing to do here is. Perhaps someone more
> >>>> familiar with TAP testing can comment.
> >>> Yeah, I was hoping that might get a comment from Andrew. I think if it
> >>> works as-is on windows, we could just use it this way until it causes a
> >>> problem on some platform or other. It’s not a runtime issue, being only
> >>> a build-time test, and only then when tap tests are enabled *and* running
> >>> check-world, so nobody should really be adversely affected. I’ll likely
> >>> get around to testing this on Windows, but I don’t have any Windows
> >>> environments set up yet, as that is still on my todo list.
> >>>
> >>
> >>
> >> I think using TESTDIR is Ok,
> >
> >
> > I've changed my mind, I don't think that will work for MSVC, the
> > executable gets built elsewhere for that. I'll try to come up with
> > something portable.
>
> I’m just now working on getting my Windows VMs set up with Visual Studio and
> whatnot, per the wiki instructions, so I don’t need to burden you with this
> sort of Windows task in the future. If there are any gotchas not mentioned
> on the wiki, I’d appreciate pointers about how to avoid them. I’ll try to
> help devise a solution, or test what you come up with, once I’m properly set
> up for that.
>
> For no particular reason, I chose Windows Server 2019 and Windows 10 Pro.
>
One VM should be sufficient. Either W10Pro os WS2019 would be fine. I
have buildfarm animals running on both.
Here's what I got working after a lot of trial and error. (This will
require a tiny change in the buildfarm script to make the animals test
it). Note that there is one test that I couldn't get working, so I
skipped it. If you can find out why it fails so much the better ... it
seems to be related to how the command processor handles quotes.
cheers
andrew
--
Andrew Dunstan https://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/src/Makefile b/src/Makefile
index bcdbd9588a..ccd4bab0de 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2,7 +2,8 @@
#
# Makefile for src
#
-# Copyright (c) 1994, Regents of the University of California
+# Portions Copyright (c) 1994, Regents of the University of California
+# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
#
# src/Makefile
#
@@ -27,6 +28,7 @@ SUBDIRS = \
bin \
pl \
makefiles \
+ test/bin \
test/regress \
test/isolation \
test/perl
diff --git a/src/test/Makefile b/src/test/Makefile
index efb206aa75..6c3a1d4c27 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -12,7 +12,7 @@ subdir = src/test
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
-SUBDIRS = perl regress isolation modules authentication recovery subscription
+SUBDIRS = bin perl regress isolation modules authentication recovery subscription
# Test suites that are not safe by default but can be run if selected
# by the user via the whitespace-separated list in variable
@@ -40,10 +40,10 @@ endif
ALWAYS_SUBDIRS = $(filter-out $(SUBDIRS),examples kerberos ldap locale thread ssl)
# We want to recurse to all subdirs for all standard targets, except that
-# installcheck and install should not recurse into the subdirectory "modules".
+# installcheck and install should not recurse into "modules" or "bin"
recurse_alldirs_targets := $(filter-out installcheck install, $(standard_targets))
-installable_dirs := $(filter-out modules, $(SUBDIRS))
+installable_dirs := $(filter-out modules bin, $(SUBDIRS))
$(call recurse,$(recurse_alldirs_targets))
$(call recurse,installcheck, $(installable_dirs))
diff --git a/src/test/bin/.gitignore b/src/test/bin/.gitignore
new file mode 100644
index 0000000000..6709c749d8
--- /dev/null
+++ b/src/test/bin/.gitignore
@@ -0,0 +1 @@
+test_json
diff --git a/src/test/bin/Makefile b/src/test/bin/Makefile
new file mode 100644
index 0000000000..113ce04cba
--- /dev/null
+++ b/src/test/bin/Makefile
@@ -0,0 +1,43 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/test/bin
+#
+# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/bin/bin/Makefile
+#
+#-------------------------------------------------------------------------
+
+PGFILEDESC = "bin - the PostgreSQL standalone code binaries for testing"
+PGAPPICON=win32
+
+subdir = src/test/bin
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+# make this available to TAP test scripts
+export with_readline
+
+REFDOCDIR= $(top_srcdir)/doc/src/sgml/ref
+
+override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
+
+OBJS = \
+ $(WIN32RES) \
+ test_json.o
+
+PROGRAMS = test_json
+
+all: test_json
+
+test_json: test_json.o $(WIN32RES) | submake-libpq submake-libpgport submake-libpgfeutils
+ $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+
+check:
+ PATH="$(abs_top_builddir)/src/test/bin:$$PATH" $(prove_check)
+
+clean distclean maintainer-clean:
+ rm -f test_json$(X) $(OBJS)
+ rm -rf tmp_check
diff --git a/src/test/bin/README b/src/test/bin/README
new file mode 100644
index 0000000000..239bd8456f
--- /dev/null
+++ b/src/test/bin/README
@@ -0,0 +1,11 @@
+src/test/bin/README
+
+Binary executable tests
+=======================
+
+This directory contains programs that are built and executed for testing
+purposes, but never installed. It may be used, for example, to test that code
+in src/common works in frontend environments.
+
+These test programs are part of the tap-test suite. Configure with tap tests
+enabled or these tests will be skipped.
diff --git a/src/test/bin/t/001_test_json.pl b/src/test/bin/t/001_test_json.pl
new file mode 100644
index 0000000000..50b06e0726
--- /dev/null
+++ b/src/test/bin/t/001_test_json.pl
@@ -0,0 +1,72 @@
+# Basic logical replication test
+use strict;
+use warnings;
+use TestLib qw(command_like $windows_os);
+
+use Test::More tests => 83;
+
+my $exe = $windows_os ? ".exe" : "";
+
+# We don't install test_json, so we pick it up from the
+# place it gets built, $ENV{TESTDIR} except for MSVC
+
+my $binloc = ".";
+my $using_msvc = 0;
+
+if (-e "../../../test_json.vcxproj") # MSVC
+{
+ $using_msvc = 1;
+ if (-d "../../../Debug/test_json")
+ {
+ $binloc = "../../../Debug/test_json";
+ }
+ else
+ {
+ $binloc = "../../../Release/test_json";
+ }
+}
+elsif (exists $ENV{TESTDIR})
+{
+ $binloc = $ENV{TESTDIR};
+}
+
+my $test_json = "$binloc/test_json$exe";
+
+ok(-f $test_json, "test_json file exists");
+ok(-x $test_json, "test_json file is executable");
+
+# Verify some valid JSON is accepted by our parser
+command_like( [$test_json, q/null/ ], qr{\bVALID\b}, "null");
+command_like( [$test_json, q/{}/ ], qr{\bVALID\b}, "empty object");
+command_like( [$test_json, q/[]/ ], qr{\bVALID\b}, "empty array");
+command_like( [$test_json, q/-12345/ ], qr{\bVALID\b}, "negative integer");
+command_like( [$test_json, q/-1/ ], qr{\bVALID\b}, "negative integer");
+command_like( [$test_json, q/0/ ], qr{\bVALID\b}, "zero");
+command_like( [$test_json, q/1/ ], qr{\bVALID\b}, "positive integer");
+command_like( [$test_json, q/12345/ ], qr{\bVALID\b}, "positive integer");
+command_like( [$test_json, q/-1.23456789/], qr{\bVALID\b}, "negative float");
+command_like( [$test_json, q/1.23456789/ ], qr{\bVALID\b}, "positive float");
+command_like( [$test_json, q/{"a": "b"}/ ], qr{\bVALID\b}, "object");
+command_like( [$test_json, q/["a", "b"]/ ], qr{\bVALID\b}, "array");
+SKIP:
+{
+ skip "text string test confuses processor on MSVC", 3 if $using_msvc;
+
+ command_like( [$test_json, q/"pigs feet"/], qr{\bVALID\b}, 'text string');
+}
+
+# Verify some invalid JSON is rejected by our parser
+command_like( [$test_json, q/{/ ], qr{^\s*The input string ended unexpectedly\.\s*$}ms, 'unclosed object');
+command_like( [$test_json, q/[/ ], qr{^\s*The input string ended unexpectedly\.\s*$}ms, 'unclosed array');
+command_like( [$test_json, q/(/ ], qr{^\s*Token "\(" is invalid\.\s*$}ms, 'unclosed parenthesis');
+command_like( [$test_json, q/}/ ], qr{^\s*Expected JSON value, but found "\}"\.\s*$}ms, 'unopened object');
+command_like( [$test_json, q/]/ ], qr{^\s*Expected JSON value, but found "\]"\.\s*$}ms, 'unopened array');
+command_like( [$test_json, q/)/ ], qr{^\s*Token "\)" is invalid\.\s*$}ms, 'unopened parenthesis');
+command_like( [$test_json, q/{{{}}/ ], qr{^\s*Expected string or "\}", but found "\{"\.\s*$}ms, 'unbalanced object curlies');
+command_like( [$test_json, q/{{}}}/ ], qr{^\s*Expected string or "\}", but found "\{"\.\s*$}ms, 'unbalanced object curlies');
+command_like( [$test_json, q/[[[]]/ ], qr{^\s*The input string ended unexpectedly\.\s*$}ms, 'unbalanced array braces');
+command_like( [$test_json, q/[[]]]/ ], qr{^\s*Expected end of input, but found "\]"\.\s*$}ms, 'unbalanced array braces');
+command_like( [$test_json, q/((())/ ], qr{^\s*Token "\(" is invalid\.\s*$}ms, 'unbalanced array braces');
+command_like( [$test_json, q/(()))/ ], qr{^\s*Token "\(" is invalid\.\s*$}ms, 'unbalanced array braces');
+command_like( [$test_json, q/1 7 13/ ], qr{^\s*Expected end of input, but found "7"\.\s*$}ms, 'integer sequence');
+command_like( [$test_json, q/{"a", "b"}/ ], qr{^\s*Expected ":", but found ","\.\s*$}ms, 'mixed object and array syntax');
diff --git a/src/test/bin/test_json.c b/src/test/bin/test_json.c
new file mode 100644
index 0000000000..86ad9e7e2b
--- /dev/null
+++ b/src/test/bin/test_json.c
@@ -0,0 +1,62 @@
+/*
+ * pg_test_json.c
+ * tests validity of json strings against parser implementation.
+ */
+
+#include "postgres_fe.h"
+
+#include "common/jsonapi.h"
+#include "libpq-fe.h"
+
+static const char *progname;
+
+static void parse_json(const char *str);
+
+int
+main(int argc, char *argv[])
+{
+ int argidx;
+
+ progname = get_progname(argv[0]);
+
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+ {
+ printf(_("Usage: %s jsonstr [, ...]\n"), progname);
+ exit(0);
+ }
+ if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
+ {
+ puts("pg_test_json (PostgreSQL) " PG_VERSION);
+ exit(0);
+ }
+ }
+
+ for (argidx = 1; argidx < argc; argidx++)
+ parse_json(argv[argidx]);
+
+ return 0;
+}
+
+static void
+parse_json(const char *str)
+{
+ char *json;
+ JsonLexContext *lex;
+ int client_encoding;
+ JsonParseErrorType parse_result;
+
+ client_encoding = PQenv2encoding();
+
+ json = strdup(str);
+ lex = makeJsonLexContextCstringLen(json, strlen(json), client_encoding, true /* need_escapes */);
+ parse_result = pg_parse_json(lex, &nullSemAction);
+ if (JSON_SUCCESS == parse_result)
+ fprintf(stdout, _("VALID\n"));
+ else
+ {
+ const char *errstr = json_errdetail(parse_result, lex);
+ fprintf(stdout, _("%s\n"), errstr);
+ }
+}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index a43e31c60e..12204b2b5c 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -814,6 +814,30 @@ sub mkvcbuild
$proj->AddLibrary('ws2_32.lib');
}
+ # test programs in src/test/bin
+ $mf = Project::read_file('src/test/bin/Makefile');
+ $mf =~ s{\\\r?\n}{}g;
+ $mf =~ m{PROGRAMS\s*=\s*(.*)$}m
+ || die 'Could not match in src/test/bin/Makefile' . "\n";
+ foreach my $prg (split /\s+/, $1)
+ {
+ my $proj = $solution->AddProject($prg, 'exe', 'test/bin');
+ $mf =~ m{$prg\s*:\s*(.*)$}m
+ || die 'Could not find test define for $prg' . "\n";
+ my @files = split /\s+/, $1;
+ foreach my $f (@files)
+ {
+ $f =~ s/\.o$/\.c/;
+ if ($f =~ /\.c$/)
+ {
+ $proj->AddFile('src/test/bin/' . $f);
+ }
+ }
+ $proj->AddIncludeDir('src/interfaces/libpq');
+ $proj->AddReference($libpq, $libpgfeutils, $libpgcommon, $libpgport);
+ $proj->AddDirResourceFile('src/test/bin');
+ }
+
# Regression DLL and EXE
my $regress = $solution->AddProject('regress', 'dll', 'misc');
$regress->AddFile('src/test/regress/regress.c');
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index 672bb2d650..c7b25d4bd8 100755
--- a/src/tools/msvc/clean.bat
+++ b/src/tools/msvc/clean.bat
@@ -27,6 +27,7 @@ if exist src\pl\plperl\win32ver.rc del /q src\pl\plperl\win32ver.rc
if exist src\pl\plpgsql\src\win32ver.rc del /q src\pl\plpgsql\src\win32ver.rc
if exist src\pl\plpython\win32ver.rc del /q src\pl\plpython\win32ver.rc
if exist src\pl\tcl\win32ver.rc del /q src\pl\tcl\win32ver.rc
+if exist src\test\bin\win32ver.rc del /q src\test\bin\win32ver.rc
if exist src\test\isolation\win32ver.rc del /q src\test\isolation\win32ver.rc
if exist src\test\regress\win32ver.rc del /q src\test\regress\win32ver.rc
if exist src\timezone\win32ver.rc del /q src\timezone\win32ver.rc