Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,9 @@ jobs:
# when registered through AWS pg_tle's database-backed catalog instead of
# a filesystem .control file - relevant for pg_tle-based deployment
# targets (e.g. AWS RDS). Orthogonal to the fresh/update/upgrade axis
# above: this job only covers a fresh install via pg_tle, not update/
# upgrade through it (a further step, tracked separately).
# above: this job covers both a fresh install AND the 0.9.6 -> current
# update path via pg_tle (not a binary pg_upgrade through it - that's a
# further step, tracked separately).
pg-tle-test:
needs: [changes]
if: needs.changes.outputs.docs_only != 'true'
Expand Down Expand Up @@ -462,6 +463,33 @@ jobs:
fi
- name: Verify no stray extension control files after the fresh-install smoke test
run: bin/assert_fs_clean verify ${{ matrix.pg }} /tmp/control_baseline.txt pg_tle.control
- name: Update 0.9.6 -> current and run the suite, purely via pg_tle (existing mode)
# A SECOND, separate scratch database (created after the template1
# registration above, so it inherits both registrations, same
# reasoning as count_nulls_smoke above) - proves the extension-UPDATE
# path, not just a fresh install, also never touches the filesystem
# when deployed via pg_tle. update-scenario creates the database,
# CREATE EXTENSIONs at 0.9.6, plants + proves the dependency guard,
# ALTER EXTENSION UPDATEs to current, then runs the full pgTAP suite
# against that real updated database in existing mode - no changes
# needed to that flow itself, it's already pg_tle-transparent once
# the target database descends from the pg_tle-registered template1.
#
# TEST_EXISTING_DEPLOY=pgtle is the one piece of new plumbing this
# needed in bin/test_existing: without it, run_suite's normal
# `make test`/`make verify-results` would silently `make install`
# count_nulls onto the filesystem (pgxntool's `test` target
# unconditionally depends on `install`), defeating the entire point
# of this job. In pgtle mode it instead calls `make testdeps` +
# `make installcheck` directly (neither depends on `install`) and
# runs pgxntool/verify-results-pgtap.sh's pass/fail check directly -
# see bin/test_existing's TEST_EXISTING_DEPLOY comment for the full
# reasoning.
run: |
test ! -e /usr/share/postgresql/${{ matrix.pg }}/extension/count_nulls.control
TEST_EXISTING_DEPLOY=pgtle bin/test_existing update-scenario count_nulls_pgtle_update "" 0.9.6
- name: Verify no stray extension control files after the update-path test
run: bin/assert_fs_clean verify ${{ matrix.pg }} /tmp/control_baseline.txt pg_tle.control

# A single stable check name for use as a required status check in branch
# protection rules. Matrix jobs produce check names like
Expand Down
35 changes: 35 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,41 @@ export PGOPTIONS := $(PGOPTIONS) -c count_nulls.test_load_mode=$(TEST_LOAD_SOURC
TEST_SCHEMA ?=
export PGOPTIONS := $(PGOPTIONS) -c count_nulls.test_schema=$(TEST_SCHEMA)

# TEST_EXISTING_DEPLOY: in 'existing' mode (TEST_LOAD_SOURCE=existing), how
# was the extension actually deployed onto the cluster before this run
# started? Unlike TEST_LOAD_SOURCE/TEST_SCHEMA above, this does not select or
# change any install behavior - it only tells test/deps.sql's existing-mode
# assertion where to cross-check "what does the cluster consider count_nulls's
# current version" against the actually-installed extversion:
# - filesystem (default): a real .control file is on disk (a real `make
# install`, or a pg_upgrade'd cluster carrying one over) - cross-check
# against pg_available_extensions.default_version, which reads .control
# files directly off disk.
# - pgtle: count_nulls was registered purely through pg_tle's
# database-backed catalog (see the pg-tle-test CI job), never touching
# the filesystem. pg_available_extensions does NOT see pg_tle
# registrations at all - it only ever reads .control files off disk - so
# its default_version comes back NULL for a pg_tle-only extension even
# though a version-less CREATE EXTENSION resolves correctly through
# pg_tle. pg_tle ships its own separate, non-integrated analog instead:
# pgtle.available_extensions(), a C function whose own doc comment in
# pg_tle's tleextension.c says "The system view pg_available_extensions
# provides a user interface to this SRF" - i.e. pg_tle's SRF is modeled
# on pg_available_extensions, but pg_tle never hooks or populates the
# real view itself. In this mode, cross-check against pg_tle's SRF
# instead.
#
# Deliberately the SAME env var name bin/test_existing already reads (to
# decide between `make test`/`verify-results` and `make testdeps`/
# `installcheck`), not a second variable: it's already exported to any `make`
# invocation bin/test_existing spawns as a child process, so no extra
# plumbing is needed to get it here.
TEST_EXISTING_DEPLOY ?= filesystem
ifeq ($(filter $(TEST_EXISTING_DEPLOY),filesystem pgtle),)
$(error TEST_EXISTING_DEPLOY must be 'filesystem' or 'pgtle', got '$(TEST_EXISTING_DEPLOY)')
endif
export PGOPTIONS := $(PGOPTIONS) -c count_nulls.test_existing_deploy=$(TEST_EXISTING_DEPLOY)

# Convenience wrapper: `make test-update` == `make test TEST_LOAD_SOURCE=update`.
# Must recurse (a fresh $(MAKE)) rather than depend on `test`, so the
# parse-time TEST_LOAD_SOURCE conditional above re-evaluates with update set.
Expand Down
39 changes: 37 additions & 2 deletions bin/test_existing
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,28 @@
# non-CASCADE DROP EXTENSION fails, and actively PROVE that (see
# bin/test_existing.sql/assert_guard.sql): if the drop unexpectedly succeeds,
# this script fails CI rather than silently passing.
#
# TEST_EXISTING_DEPLOY (optional environment variable, read by run_suite):
# unset/filesystem (default): count_nulls was deployed the normal way (a
# real `make install`). run_suite uses `make test` / `make verify-results`
# as it always has.
# pgtle: count_nulls was deployed purely through pg_tle's database-backed
# catalog (see the pg-tle-test CI job), never `make install`ed onto the
# filesystem. pgxntool's `test` target unconditionally depends on
# `install` (TEST_DEPS += install installcheck in base.mk), so naively
# calling `make test` here would silently `make install` count_nulls onto
# disk, creating a filesystem count_nulls.control that would shadow the
# pg_tle registration on any FUTURE version-less CREATE EXTENSION in the
# same cluster - defeating the entire point of a pg_tle-only proof, and
# doing so without ever raising an error. In this mode run_suite instead
# calls `make testdeps` + `make installcheck` directly (neither depends on
# `install` - see base.mk's `testdeps: pgtap` and
# `installcheck: $(TEST_RESULT_FILES) ...`), then runs
# pgxntool/verify-results-pgtap.sh directly against the results - the same
# check `make verify-results` runs, but the script itself takes only
# TESTOUT as an argument and has no dependency on the `test` target, so
# calling it directly gets the same pass/fail logic without the
# `install` side effect.
set -euo pipefail

# Run from the repository root (where `make` works and test paths resolve),
Expand Down Expand Up @@ -213,8 +235,21 @@ run_suite() {
# would re-run FRESH (against a new throwaway DB) instead of
# verifying THIS existing database.
local existing_args="TEST_LOAD_SOURCE=existing TEST_SCHEMA=$schema CONTRIB_TESTDB=$db EXTRA_REGRESS_OPTS=--use-existing PGXNTOOL_ENABLE_TEST_BUILD=no"
make test $existing_args
make verify-results $existing_args
if [ "${TEST_EXISTING_DEPLOY:-}" = pgtle ]; then
# pg_tle mode: see the TEST_EXISTING_DEPLOY comment in the file header.
# `make test`/`make verify-results` are NOT used here because `test`
# unconditionally depends on `install` (a real filesystem install) - the
# whole point of this mode is proving count_nulls is never touched on
# disk. `testdeps` and `installcheck` carry no such dependency.
make testdeps $existing_args
make installcheck $existing_args
local testout
testout=$(make -s print-TESTOUT $existing_args 2>/dev/null | sed -n 's/.*set to "\(.*\)"$/\1/p')
pgxntool/verify-results-pgtap.sh "$testout"
else
make test $existing_args
make verify-results $existing_args
fi
}

usage() {
Expand Down
35 changes: 33 additions & 2 deletions test/deps.sql
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,48 @@ SET client_min_messages = NOTICE;
* real extension matching this run's TEST_SCHEMA (or the default location,
* if empty) before getting here, so the rest of the suite sees the same
* schema regardless of mode.
*
* The "current version" half of that assertion (v_default below) has two
* sources depending on count_nulls.test_existing_deploy (see the
* TEST_EXISTING_DEPLOY comment in the Makefile):
* - filesystem (default): pg_available_extensions.default_version, read
* straight from a real .control file on disk.
* - pgtle: count_nulls was registered purely through pg_tle's
* database-backed catalog, never touching the filesystem.
* pg_available_extensions does NOT see pg_tle registrations at all - it
* only ever reads .control files off disk - so it comes back NULL here
* even though CREATE EXTENSION correctly resolves the default version
* through pg_tle. pg_tle ships its own separate, non-integrated analog
* for this: pgtle.available_extensions() (see pg_tle's tleextension.c,
* which documents pg_available_extensions as merely modeled on this SRF,
* not backed by it). Use that instead when running under pg_tle, rather
* than weakening the check for the filesystem case.
*/
DO $$
DECLARE
v_installed text := (SELECT extversion FROM pg_extension WHERE extname = 'count_nulls');
v_default text := (SELECT default_version FROM pg_available_extensions WHERE name = 'count_nulls');
v_deploy text := current_setting('count_nulls.test_existing_deploy');
v_default text;
BEGIN
IF v_installed IS NULL THEN
RAISE EXCEPTION 'count_nulls.test_load_mode=existing but count_nulls is not installed';
END IF;

IF v_deploy = 'pgtle' THEN
SELECT default_version INTO v_default
FROM pgtle.available_extensions() WHERE name = 'count_nulls';
ELSIF v_deploy = 'filesystem' THEN
SELECT default_version INTO v_default
FROM pg_available_extensions WHERE name = 'count_nulls';
ELSE
RAISE EXCEPTION
'count_nulls.test_existing_deploy must be ''filesystem'' or ''pgtle'', got ''%'''
, v_deploy
;
END IF;

IF v_installed IS DISTINCT FROM v_default THEN
RAISE EXCEPTION 'count_nulls installed at % but default_version is %', v_installed, v_default;
RAISE EXCEPTION 'count_nulls installed at % but default_version (deploy=%) is %', v_installed, v_deploy, v_default;
END IF;
END
$$;
Expand Down
Loading