diff --git a/test/standard/make-test.bats b/test/standard/make-test.bats index 4b93eb5..83b6117 100755 --- a/test/standard/make-test.bats +++ b/test/standard/make-test.bats @@ -11,6 +11,10 @@ # - unique per-directory database naming (REGRESS_DBNAME) # - installcheck always runs after install, even when pulled in indirectly # (issue #79) +# - PGXNTOOL_ENABLE_FS_INSTALL can disable the install prerequisite entirely, +# for "existing mode"/pg_tle-style testing (issues #55, #90) +# - PGXNTOOL_ENABLE_PGXN_INSTALL can independently disable the pgtap +# dependency's own `pgxn install --sudo` auto-install # - check-stale-expected catches orphaned test/expected/*.out files (issue #14) # - `make test` exits non-zero on a real regression.diffs mismatch (issue #49) # - verify-results blocks `make results` when tests are failing, detects @@ -170,29 +174,160 @@ EOF prereq_line=$(echo "$output" | awk '/^installcheck:/{print; exit}') [ -n "$prereq_line" ] || error "installcheck rule not found in 'make -p' database dump" - echo "$prereq_line" | grep -qw install || \ + # Split on whitespace and match the exact "install" token -- grep -w alone + # would also match inside "test/install/schedule" (PGXNTOOL_ENABLE_TEST_INSTALL's + # generated schedule file path), which is word-bounded by slashes too. + echo "$prereq_line" | tr ' ' '\n' | grep -qx install || \ error "installcheck's parsed prerequisite list does not include 'install': $prereq_line" } -@test "make test succeeds from a genuinely uninstalled state (issue #79)" { +@test "make test fails with PGXNTOOL_ENABLE_FS_INSTALL=no, but succeeds by default, from a genuinely uninstalled tree (issues #55, #79)" { skip_if_no_postgres - # The `make -p` test above is the primary proof for this issue (the - # dependency edge genuinely exists in the parsed makefile). This test is a - # complementary real-world sanity check of the whole pipeline: on a - # genuinely uninstalled tree, does pg_regress actually find the extension - # already installed by the time it runs? `make uninstall` forces that - # precondition regardless of what any earlier test in this file already - # installed on the shared PostgreSQL instance -- the original bug was - # historically masked in exactly that way. + # Shares one `make uninstall` for issue #79's original regression check, + # issue #55's proof that install doesn't happen as a side effect (below), + # and the dry-run recipe check further below, instead of each uninstalling + # separately. run make uninstall assert_success + # `install` is declared .PHONY (via PGXS's Makefile.global, pulled in by + # pgxs.mk's include chain), so its recipe would show in a dry run whenever + # it remains a prerequisite regardless of what's on disk -- checking this + # against a genuinely uninstalled tree (the uninstall above) means the + # result can't be dismissed as coincidental with on-disk state either way. + run make -n test PGXNTOOL_ENABLE_FS_INSTALL=no + assert_success + assert_not_contains "$output" "install -c -m 644" + + # issue #55: with FS install disabled, nothing reinstalls the extension as + # a side effect, so pg_regress runs against a genuinely uninstalled tree + # and fails. The structural test further below already proves the + # `installcheck: install` edge is genuinely gone; this proves it matters. + run make test PGXNTOOL_ENABLE_FS_INSTALL=no + assert_failure + assert_contains "$output" "does not exist" + + # issue #79: by default, does pg_regress actually find the extension + # already installed by the time it runs? The `make -p` test above is the + # primary proof (the dependency edge genuinely exists in the parsed + # makefile); this is the complementary real-world sanity check of the + # whole pipeline. The original bug was historically masked because some + # earlier test had already installed the extension on the shared + # PostgreSQL instance -- the uninstall above forces the precondition + # regardless. run make test assert_success assert_not_contains "$output" "does not exist" } +# ============================================================================ +# install/installcheck can skip filesystem install (issues #55, #90) +# ============================================================================ +# +# `test`/`verify-results` always filesystem-installed the extension via +# PGXS's `install`, and `installcheck` always depended on `install` (the +# issue #79 fix, tested above) -- with no way to disable either. That defeats +# "existing mode" testing, where the extension under test was deployed some +# other way (e.g. a pg_tle registration, or a real pg_upgrade) and the whole +# point is to prove that other deployment path works -- filesystem-installing +# as a side effect defeats it. PGXNTOOL_ENABLE_FS_INSTALL=no removes both the +# TEST_DEPS `install` entry and the `installcheck: install` edge. + +@test "PGXNTOOL_ENABLE_FS_INSTALL=no removes install from installcheck's parsed prerequisite list" { + # Same structural technique as the issue #79 test above, inverted: prove + # the edge is genuinely gone, not just that a real run happened to succeed + # regardless of scheduling order. + run make -p -n installcheck PGXNTOOL_ENABLE_FS_INSTALL=no + assert_success + + local prereq_line + prereq_line=$(echo "$output" | awk '/^installcheck:/{print; exit}') + [ -n "$prereq_line" ] || error "installcheck rule not found in 'make -p' database dump" + + # Split on whitespace and match the exact "install" token -- grep -w would + # false-positive on the unrelated "test/install/schedule" path (PGXNTOOL_ENABLE_TEST_INSTALL's + # generated schedule file), which is also a word-bounded "install" once + # surrounded by slashes. + if echo "$prereq_line" | tr ' ' '\n' | grep -qx install; then + error "installcheck's parsed prerequisite list still includes 'install' with PGXNTOOL_ENABLE_FS_INSTALL=no: $prereq_line" + fi +} + +@test "PGXNTOOL_ENABLE_FS_INSTALL rejects invalid values" { + run make print-PGXNTOOL_ENABLE_FS_INSTALL PGXNTOOL_ENABLE_FS_INSTALL=bogus + assert_failure + assert_contains "$output" "PGXNTOOL_ENABLE_FS_INSTALL must be" +} + +@test "make test succeeds with PGXNTOOL_ENABLE_FS_INSTALL=no when the extension is already installed" { + skip_if_no_postgres + + # Stands in for "existing mode": the extension is already deployed (here, + # via a normal install) before test/installcheck ever runs, so disabling + # the FS install prerequisite shouldn't stop the suite from passing. + # State is already installed at this point, but the explicit install below + # documents the precondition this test actually relies on. + run make install + assert_success + + run make test PGXNTOOL_ENABLE_FS_INSTALL=no + assert_success +} + +# ---------------------------------------------------------------------------- +# pgtap auto-install can be disabled independently (PGXNTOOL_ENABLE_PGXN_INSTALL) +# ---------------------------------------------------------------------------- +# +# `installcheck` also auto-installs the pgtap dependency via `pgxn install +# pgtap --sudo` when it isn't already filesystem-installed -- itself a +# filesystem-install side effect, and the same problem +# PGXNTOOL_ENABLE_FS_INSTALL solves for the extension under test. +# PGXNTOOL_ENABLE_PGXN_INSTALL defaults to following PGXNTOOL_ENABLE_FS_INSTALL, +# but can be set independently. + +@test "PGXNTOOL_ENABLE_PGXN_INSTALL defaults to following PGXNTOOL_ENABLE_FS_INSTALL" { + run make print-PGXNTOOL_ENABLE_PGXN_INSTALL + assert_success + assert_contains "$output" 'set to "yes"' + + run make print-PGXNTOOL_ENABLE_PGXN_INSTALL PGXNTOOL_ENABLE_FS_INSTALL=no + assert_success + assert_contains "$output" 'set to "no"' +} + +@test "PGXNTOOL_ENABLE_PGXN_INSTALL can be set independently of PGXNTOOL_ENABLE_FS_INSTALL" { + run make print-PGXNTOOL_ENABLE_PGXN_INSTALL PGXNTOOL_ENABLE_FS_INSTALL=no PGXNTOOL_ENABLE_PGXN_INSTALL=yes + assert_success + assert_contains "$output" 'set to "yes"' +} + +@test "PGXNTOOL_ENABLE_PGXN_INSTALL=no removes pgtap's recipe from a dry-run installcheck" { + # pgtap's file-check target ($(DESTDIR)$(datadir)/extension/pgtap.control) + # is already satisfied on this machine (pgtap is genuinely installed), so + # a plain dry-run never shows the "pgxn install" recipe regardless of this + # variable -- it wouldn't prove anything either way. Pointing DESTDIR at a + # nonexistent path makes that file-check target genuinely unsatisfied, + # forcing the recipe to appear in a *dry* run (nothing is actually + # installed there -- -n never executes it) -- that's what actually proves + # PGXNTOOL_ENABLE_PGXN_INSTALL gates it. + local fake_destdir="$BATS_TEST_TMPDIR/fake-destdir" + + run make -n installcheck "DESTDIR=$fake_destdir" + assert_success + assert_contains "$output" "pgxn install pgtap --sudo" + + run make -n installcheck "DESTDIR=$fake_destdir" PGXNTOOL_ENABLE_PGXN_INSTALL=no + assert_success + assert_not_contains "$output" "pgxn install pgtap --sudo" +} + +@test "PGXNTOOL_ENABLE_PGXN_INSTALL rejects invalid values" { + run make print-PGXNTOOL_ENABLE_PGXN_INSTALL PGXNTOOL_ENABLE_PGXN_INSTALL=bogus + assert_failure + assert_contains "$output" "PGXNTOOL_ENABLE_PGXN_INSTALL must be" +} + # Test: check-stale-expected (issue #14) # # `make test` never caught a stale test/expected/*.out left behind after a @@ -269,7 +404,7 @@ EOF # script must never even be invoked, not merely have a failure from it # ignored. That's a materially stronger claim than "make test succeeds # despite a stale file", so prove it directly: point - # _CHECK_STALE_EXPECTED_SCRIPT -- the one variable the + # _PGXNTOOL_CHECK_STALE_EXPECTED_SCRIPT -- the one variable the # check-stale-expected recipe actually invokes (see base.mk) -- at a stub # that only touches a marker file and fails. No need to fake out # PGXNTOOL_DIR itself, since this variable is the sole thing standing @@ -281,7 +416,7 @@ EOF local stub_script stub_script=$(make_stub_script check-stale-expected-stub 1 "" "$marker") - run make test PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED=no _CHECK_STALE_EXPECTED_SCRIPT="$stub_script" + run make test PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED=no _PGXNTOOL_CHECK_STALE_EXPECTED_SCRIPT="$stub_script" assert_success assert_file_not_exists "$marker" } @@ -315,7 +450,7 @@ EOF # base.mk's responsibility, not the script's decision logic (the real # script's distinct exit codes and messages are already covered directly # in check-stale-expected-script.bats): does `make check-stale-expected` - # correctly surface whatever _CHECK_STALE_EXPECTED_SCRIPT does? A + # correctly surface whatever _PGXNTOOL_CHECK_STALE_EXPECTED_SCRIPT does? A # stub that deterministically prints a message and exits nonzero must # make the target (and `make`'s own recipe-failure handling) fail and # show that message; a stub that exits 0 must let it pass -- regardless @@ -323,13 +458,13 @@ EOF local stub_script stub_script=$(make_stub_script fail-stub 5 "STUB SENTINEL MESSAGE") - run make check-stale-expected _CHECK_STALE_EXPECTED_SCRIPT="$stub_script" + run make check-stale-expected _PGXNTOOL_CHECK_STALE_EXPECTED_SCRIPT="$stub_script" assert_failure assert_contains "$output" "STUB SENTINEL MESSAGE" stub_script=$(make_stub_script pass-stub 0) - run make check-stale-expected _CHECK_STALE_EXPECTED_SCRIPT="$stub_script" + run make check-stale-expected _PGXNTOOL_CHECK_STALE_EXPECTED_SCRIPT="$stub_script" assert_success }