Skip to content
165 changes: 150 additions & 15 deletions test/standard/make-test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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"
}
Expand Down Expand Up @@ -315,21 +450,21 @@ 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
# of what the real script would have decided for the same directory.
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
}

Expand Down