Skip to content
Draft
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
59 changes: 59 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
# Run test/install/load.sql (extension install) COMMITTED, once, before the
# main pgTAP suite, via pgxntool's test/install feature. Set explicitly
# (rather than left to auto-detect) so an accidentally emptied test/install/
# is a hard build error instead of silently falling back to "disabled".
# Must be set before `include pgxntool/base.mk` below -- base.mk reads it
# while parsing.
PGXNTOOL_ENABLE_TEST_INSTALL = yes

# TEST_LOAD_SOURCE selects how test/install/load.sql installs extension_drop:
# - fresh (default): CREATE EXTENSION extension_drop (current version).
# - update: CREATE EXTENSION at TEST_UPDATE_FROM, then ALTER EXTENSION
# UPDATE -- to TEST_UPDATE_TO if set, otherwise to the current version.
# Running the SAME suite/expected output against the result asserts
# update behaves identically to a fresh install. NOTE: extension_drop has
# never had a real second released version (PGXN's only listing is
# 0.1.x from 2017, predating the current SQL entirely -- see HISTORY.asc
# and RELEASE.md), so TEST_UPDATE_FROM has no safe default; this mode is
# wired up and structurally ready, but there is nothing real to update
# FROM yet, and so no CI leg exercises it in this repo today.
# - existing: the extension is ALREADY installed (a real pg_upgrade, or an
# ALTER EXTENSION UPDATE done outside the suite). load.sql does not
# touch it; it only asserts presence + current version. Pair with
# CONTRIB_TESTDB=<db> and EXTRA_REGRESS_OPTS=--use-existing to point
# pg_regress at that database instead of a throwaway one.
#
# Propagated to load.sql as a GUC: pg_regress doesn't forward make variables,
# but the psql processes it spawns inherit the environment, so PGOPTIONS
# reaches load.sql. Exported UNCONDITIONALLY so load.sql can read it without
# missing_ok and fail loudly if it didn't propagate, rather than silently
# defaulting to the wrong mode. The mode is also validated here at
# make-parse-time, so a typo like `TEST_LOAD_SOURCE=fresh ` or
# `TEST_LOAD_SOURCE=typo` fails immediately instead of quietly running the
# default.
TEST_LOAD_SOURCE ?= fresh
ifeq ($(filter $(TEST_LOAD_SOURCE),fresh update existing),)
$(error TEST_LOAD_SOURCE must be 'fresh', 'update' or 'existing', got '$(TEST_LOAD_SOURCE)')
endif

# update-mode version range (load.sql only reads these in update mode).
# Empty TEST_UPDATE_TO means "update to the current default_version". There
# is no safe default for TEST_UPDATE_FROM (see above) -- require it
# explicitly rather than pointing it at a version that doesn't exist.
TEST_UPDATE_FROM ?=
TEST_UPDATE_TO ?=
ifeq ($(TEST_LOAD_SOURCE),update)
ifeq ($(strip $(TEST_UPDATE_FROM)),)
$(error TEST_UPDATE_FROM must be set when TEST_LOAD_SOURCE=update -- extension_drop has no prior released version yet to default it to)
endif
endif

export PGOPTIONS := $(PGOPTIONS) -c extension_drop.test_load_mode=$(TEST_LOAD_SOURCE) -c extension_drop.test_update_from=$(TEST_UPDATE_FROM) -c extension_drop.test_update_to=$(TEST_UPDATE_TO)

# 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.
.PHONY: test-update
test-update:
$(MAKE) test TEST_LOAD_SOURCE=update

include pgxntool/base.mk

testdeps: test_extension
Expand Down
32 changes: 8 additions & 24 deletions test/deps.sql
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
-- IF NOT EXISTS will emit NOTICEs, which is annoying
SET client_min_messages = WARNING;

-- Add any test dependency statements here
-- Note: pgTap is loaded by setup.sql

-- Re-enable notices
SET client_min_messages = NOTICE;
/*
* extension_drop itself used to be (re)installed here, per test file. It's
* now installed ONCE, COMMITTED, by test/install/load.sql (pgxntool's
* test/install feature) before this suite runs at all -- this file no
* longer touches it. test/sql/schema.sql is the one test that actually
* drops/recreates the extension itself (that's what it's testing); every
* other test file just uses the extension load.sql already installed.
*/

\set TT extension_drop_test_table
CREATE TEMP TABLE :TT (i int);

CREATE SCHEMA :TEST_SCHEMA;
SET search_path = :TEST_SCHEMA, tap, "$user";

/*
* Now load our extension. We don't use IF NOT EXISTs here because we want an
* error if the extension is already loaded (because we want to ensure we're
* getting the very latest version).
*/
SET client_min_messages = WARNING; -- Squelch notice from CASCADE
DO $$ BEGIN
IF current_setting('server_version_num')::int < 100000 THEN
CREATE EXTENSION IF NOT EXISTS cat_tools;
CREATE EXTENSION extension_drop ;
ELSE
EXECUTE $exec$CREATE EXTENSION extension_drop CASCADE$exec$;
END IF;
END$$;
SET client_min_messages = NOTICE;

-- vi: expandtab ts=2 sw=2
6 changes: 6 additions & 0 deletions test/expected/dependency_guard.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
\set ECHO none
1..3
ok 1 - Non-CASCADE DROP EXTENSION extension_drop is blocked by the dependency guard
ok 2 - extension_drop is still installed after the blocked drop attempt
ok 3 - Dependency guard view is still present after the blocked drop attempt
# TRANSACTION INTENTIONALLY LEFT OPEN!
10 changes: 5 additions & 5 deletions test/expected/schema.out
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ ok 1 - Create test extension
ok 2 - Test extension exists
ok 3 - Drop test extension
ok 4 - Test extension does not exist
ok 5 - Table _test_ed.extension_drop__commands should exist
ok 5 - Table "_Test_Ed".extension_drop__commands should exist
ok 6 - Drop extension
ok 7 - Create extension in schema _test_ed_2
ok 8 - Table _test_ed_2.extension_drop__commands should exist
ok 9 - Create test extension in _test_ed_2
ok 7 - Create extension in schema _Test_Ed_2
ok 8 - Table "_Test_Ed_2".extension_drop__commands should exist
ok 9 - Create test extension in _Test_Ed_2
ok 10 - extension_drop__update()
ok 11 - Verify extension_drop__get()
ok 12 - Drop schema _test_ed without cascade succeeds
ok 12 - Drop schema _Test_Ed without cascade succeeds
# TRANSACTION INTENTIONALLY LEFT OPEN!
28 changes: 26 additions & 2 deletions test/expected/zzz_build.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
\set ECHO none
NOTICE: 42710: extension "cat_tools" already exists, skipping
LOCATION: CreateExtension, extension.c:2011

INSTALL

Expand All @@ -9,14 +11,36 @@ INSTALL



psql:sql/extension_drop.sql:198: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:198: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156


psql:sql/extension_drop.sql:218: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:218: NOTICE: 00000: type reference extension_drop__commands.sql%TYPE converted to text
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:218: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:218: NOTICE: 00000: type reference extension_drop__commands.sql%TYPE converted to text
LOCATION: LookupTypeNameExtended, parse_type.c:156


psql:sql/extension_drop.sql:236: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:236: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156




psql:sql/extension_drop.sql:256: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:256: NOTICE: 00000: type reference extension_drop__commands.sql%TYPE converted to text
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:256: NOTICE: 00000: type reference extension_drop__commands.extension_name%TYPE converted to name
LOCATION: LookupTypeNameExtended, parse_type.c:156
psql:sql/extension_drop.sql:256: NOTICE: 00000: type reference extension_drop__commands.sql%TYPE converted to text
LOCATION: LookupTypeNameExtended, parse_type.c:156



Expand Down
14 changes: 14 additions & 0 deletions test/install/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# pg_regress writes the install step's result here, because the install
# schedule references tests as ../install/<name> -- one directory up from
# both test/expected/ and test/results/, which cancels back out to this same
# directory for both. So load.out is simultaneously "expected" and "actual":
# confirmed by hand (deliberately breaking load.sql's existing-mode assertion
# and seeing pg_regress still report the step "ok" while the real error text
# showed up in this file) that pg_regress can never see a diff for it here,
# regardless of what load.sql actually does. Never track it -- it would just
# be reformatted/overwritten noise on every run, not a real expectation.
load.out
# Precautionary: haven't observed pg_regress emit a *.diff for this
# self-comparing path locally, but if it ever does, it'd be equally
# meaningless to track for the same reason as load.out above.
install.out.diff
162 changes: 162 additions & 0 deletions test/install/load.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
\set ECHO none
/*
* Committed-once installer for the test suite's one real dependency: the
* extension_drop extension itself. (No test roles exist for this extension
* -- see test/deps.sql -- so unlike cat_tools' equivalent load.sql, there is
* nothing role-related to install here.)
*
* pgxntool's test/install feature runs this file COMMITTED, in its own
* pg_regress session, BEFORE the main pgTAP suite, so the extension persists
* into every (rolled-back) test/sql/ file instead of each one re-installing
* it from scratch. test/deps.sql (run per test) no longer creates the
* extension; it only sets the psql variables the suite references.
* test/sql/schema.sql is the one exception: proving the schema-targeting
* pipeline works is its actual job, so it explicitly drops this committed
* install and recreates its own copies in schemas it chooses -- safely,
* since that all happens inside its own rolled-back transaction and never
* escapes that one file.
*
* Three modes, selected by the extension_drop.test_load_mode placeholder
* GUC, which the Makefile's TEST_LOAD_SOURCE block sets via PGOPTIONS
* (fresh is the default):
* - fresh (default): plain CREATE EXTENSION extension_drop (current
* version).
* - update: CREATE EXTENSION at an older version
* (extension_drop.test_update_from) then ALTER EXTENSION UPDATE -- to
* extension_drop.test_update_to when that GUC is non-empty, otherwise to
* the current default_version. NOTE: extension_drop has never had a
* real second released version -- PGXN's only listing (0.1.x, 2017)
* predates the current SQL entirely (see HISTORY.asc/RELEASE.md), so
* there is no version that could legitimately fill
* extension_drop.test_update_from today. This branch is wired up and
* structurally correct (the Makefile refuses to select this mode
* without TEST_UPDATE_FROM set explicitly), but has nothing real to
* update FROM yet, so it exists ready for the day a second version
* ships rather than because it's exercised in CI now.
* - existing: the extension is ALREADY installed (by a real binary
* pg_upgrade, or an ALTER EXTENSION UPDATE performed outside the
* suite). This branch must NOT drop/create/update it -- that would
* destroy exactly what "existing" mode exists to test. It only asserts
* presence + current version.
*
* Unlike cat_tools (whose control file pins schema = 'cat_tools' --
* CREATE EXTENSION always lands in the same place, no choice), extension_drop's
* control file has no schema= line, so CREATE EXTENSION here lands wherever
* the ambient search_path resolves when this file runs -- a fresh psql
* session's default "$user", public, i.e. public in practice. That's a
* deliberate, useful default: it proves nothing in extension_drop's install
* script is hardcoded to a specific schema, the same property
* test/sql/schema.sql proves again explicitly for non-default schemas.
*/
SET client_min_messages = WARNING;

/*
* The Makefile always exports extension_drop.test_load_mode via PGOPTIONS.
* Read it WITHOUT missing_ok: if the GUC did not propagate (a break
* anywhere in make -> PGOPTIONS -> env -> psql), current_setting errors here
* and the whole install step fails loudly, instead of silently defaulting
* and running the wrong suite.
*/
SELECT current_setting('extension_drop.test_load_mode') AS extension_drop_test_load_mode
\gset

DO $DO$
BEGIN
IF current_setting('extension_drop.test_load_mode') NOT IN ('fresh', 'update', 'existing') THEN
RAISE EXCEPTION
'extension_drop.test_load_mode must be ''fresh'', ''update'' or ''existing'', got ''%'''
, current_setting('extension_drop.test_load_mode')
;
END IF;
END
$DO$;

SELECT
:'extension_drop_test_load_mode' = 'update' AS extension_drop_mode_update
, :'extension_drop_test_load_mode' = 'existing' AS extension_drop_mode_existing
\gset

\if :extension_drop_mode_existing
/*
* existing mode: do NOT touch the extension. Assert it is installed and at
* the current default_version -- the pg_upgrade / external update the
* database just went through is exactly what the suite is validating, so
* dropping or reinstalling it would defeat the test. Fail loudly on absence
* or mismatch.
*/
DO $DO$
DECLARE
v_installed text := (SELECT extversion FROM pg_extension WHERE extname = 'extension_drop');
v_default text := (SELECT default_version FROM pg_available_extensions WHERE name = 'extension_drop');
BEGIN
IF v_installed IS NULL THEN
RAISE EXCEPTION 'test_load_mode=existing but the extension_drop extension is not installed';
END IF;
IF v_installed IS DISTINCT FROM v_default THEN
RAISE EXCEPTION
'extension_drop is installed at version % but the current default_version is %'
, v_installed, v_default
;
END IF;
END
$DO$;
\else
/*
* fresh / update: (re)install from scratch. Drop-first (CASCADE, matching
* cat_tools' own load.sql) so a re-run on a persistent cluster installs the
* newest build instead of reusing stale objects.
*
* extension_drop requires cat_tools. CASCADE auto-installs it on PG10+;
* event triggers exist from 9.3 but CREATE EXTENSION ... CASCADE was only
* added in PG10, so pre-PG10 needs cat_tools created explicitly first. This
* mirrors the check test/deps.sql used to do per-test before this file took
* over installing the extension. server_version_num is read once into a
* psql variable rather than a runtime DO block, so it can drive \if
* (client-side) branching around the VERSION-qualified CREATE EXTENSION
* calls below without needing psql variables interpolated inside a
* dollar-quoted DO body.
*/
DROP EXTENSION IF EXISTS extension_drop CASCADE;

SELECT current_setting('server_version_num')::int >= 100000 AS extension_drop_pg10_plus
\gset

\if :extension_drop_mode_update
SELECT current_setting('extension_drop.test_update_from') AS extension_drop_test_update_from \gset
SELECT current_setting('extension_drop.test_update_to') AS extension_drop_test_update_to \gset
/*
* Build the optional target clause once so a SINGLE ALTER EXTENSION covers
* both cases: an empty test_update_to yields '' (update to the current
* default_version -- the widest path); a non-empty value yields
* "TO '<v>'". format(%L) quotes the version literal safely.
*/
SELECT CASE WHEN :'extension_drop_test_update_to' = '' THEN ''
ELSE format('TO %L', :'extension_drop_test_update_to') END
AS extension_drop_update_to_clause \gset

\if :extension_drop_pg10_plus
CREATE EXTENSION extension_drop VERSION :'extension_drop_test_update_from' CASCADE;
\else
CREATE EXTENSION IF NOT EXISTS cat_tools;
CREATE EXTENSION extension_drop VERSION :'extension_drop_test_update_from';
\endif

/*
* Suppress the deprecation NOTICEs an update script might emit.
*/
SET client_min_messages = ERROR;
ALTER EXTENSION extension_drop UPDATE :extension_drop_update_to_clause;
SET client_min_messages = WARNING;
\else
\if :extension_drop_pg10_plus
CREATE EXTENSION extension_drop CASCADE;
\else
CREATE EXTENSION IF NOT EXISTS cat_tools;
CREATE EXTENSION extension_drop;
\endif
\endif
-- end \if :extension_drop_mode_update (fresh vs. update install branch)
\endif
-- end \if :extension_drop_mode_existing (existing mode skips the whole (re)install block)

-- vi: expandtab ts=2 sw=2
Loading