Install extension_drop into a fresh, randomly named schema on every test run - #36
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
bbdcdf4 to
082fd68
Compare
082fd68 to
c255286
Compare
|
Claude finished @jnasbyupgrade's task in 4m 4s —— View job Claude finished the review
SummaryThis implements the schema-independence testing scheme described in the repo's One real correctness/safety issue and a couple of minor observations below. Findings1. Unescaped FOR r IN SELECT nspname FROM pg_namespace WHERE nspname LIKE 'extension_drop test schema %' LOOP
EXECUTE format('DROP SCHEMA %I CASCADE', r.nspname);
END LOOP;In SQL Given this drives an unattended WHERE nspname LIKE 'extension\_drop test schema %' ESCAPE '\'
-- or
WHERE left(nspname, 28) = 'extension_drop test schema '2. (Minor)
3. (Observation, not a bug) The PR description states Nice touches worth calling out
|
|
Claude finished @jnasbyupgrade's task in 3m 3s —— View job Claude finished the re-review
SummaryThis is a re-review after two new commits ( Previously-flagged issue: fixed ✅Unescaped Remaining observations (unchanged from prior review, non-blocking)1.
2. The PR description says Nice touches
I wasn't able to actually execute |
e64bcd4 to
485aef2
Compare
Replaces the two-fixed-legs (empty/ambient-default vs. a hardcoded mixed-case name) TEST_SCHEMA GUC approach with an always-on scheme: test/install/load.sql now installs extension_drop into a freshly created schema with a constant, quote-forcing name prefix plus a random suffix on every fresh/update-mode run, instead of only when a special make target is remembered. This catches hardcoded-schema bugs in one run instead of two, automatically, every time. test/deps.sql rediscovers the random schema (a separate psql session per test file) via pg_namespace/pg_extension and adds it to search_path for the rest of the suite's convenience; test/sql/schema.sql remains the one file that proves the stricter "excluded from search_path" property. existing mode is untouched -- it creates nothing and asserts against whatever a real pg_upgrade already produced. Inspired by pg_count_nulls#55's create_test_schema.sql, adapted (not ported) for this repo's simpler pgTAP-per-file suite, its cat_tools dependency, and its separate fresh/update/existing TEST_LOAD_SOURCE modes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
'extension_drop test schema %' contains an unescaped underscore (between "extension" and "drop"), which LIKE treats as a single-character wildcard, not a literal -- so the pattern matched any schema name of that shape regardless of the character there, before running an unattended DROP SCHEMA ... CASCADE. Switch to a literal prefix comparison instead of LIKE.
…r cleanup match _ isn't a regex metacharacter, so a plain anchored ~ match on the literal prefix is simpler and clearer than escaping/working around LIKE's wildcard semantics for it.
… CREATE EXTENSION Adding the random schema to search_path (for the rest of the suite's convenience) defeated the whole point: an accidentally-unqualified self-reference inside extension_drop's own functions would resolve correctly too, masking exactly the class of bug this scheme exists to catch. test/sql/simple.sql and test/sql/dependency_guard.sql now qualify their calls into extension_drop's own functions explicitly via :'extension_drop_schema' instead of relying on search_path. Since this suite has no shared teardown-function library to hook a check into (plain pgTAP files, not runtests()), add test/finish.sql: every test file now calls it instead of test/pgxntool/finish.sql directly, and it asserts extension_drop's schema was never reachable via search_path before delegating to the real finish.sql. Also simplify test/install/load.sql: build the CASCADE-clause suffix once instead of duplicating the entire CREATE EXTENSION statement (schema + version + cascade) per fresh/update branch.
schema.sql's job -- proving extension_drop works when installed outside search_path, with an explicit second schema and qualified cross-schema calls -- is now redundant: every fresh/update run already installs into a random, never-on-search_path schema (load.sql), and every other test file already qualifies its calls into extension_drop's own functions (simple.sql, dependency_guard.sql). Tracing each of schema.sql's own assertions against the rest of the suite confirmed every one has a real equivalent elsewhere. test/finish.sql no longer needs to rediscover the schema fresh -- that was only necessary because schema.sql moved extension_drop mid-file; with it gone, no test file ever does, so finish.sql can just reuse test/deps.sql's :'extension_drop_schema' variable directly. test/install/load.sql: build ONE combined suffix (schema + version + cascade, chained CASE expressions in a single \gset) covering every fresh/update x pre/post-PG10 combination, so a single CREATE EXTENSION statement replaces what used to be duplicated per combination. Also updates CLAUDE.md to describe the actual implemented approach (always-random, not a configurable TEST_SCHEMA switch) and drops local-only file-path references per Postgres-Extensions/ai's now-published conventions.
… follow-through Completes the previous commit: consolidates load.sql's CREATE EXTENSION into one statement (combined schema+version+cascade suffix via chained CASE expressions), simplifies finish.sql to reuse test/deps.sql's :'extension_drop_schema' instead of rediscovering it (no test file moves extension_drop mid-run anymore now that schema.sql is gone), and updates CLAUDE.md to describe the actual always-random approach instead of the superseded TEST_SCHEMA-switch description.
In existing mode, extension_drop was installed by a real pg_upgrade
external to this suite (bin/test_existing's plain CREATE EXTENSION
... CASCADE, no schema targeting), landing wherever that process's
own ambient defaults put it -- typically public, which stays on
search_path by default. We have no control over that placement, so
asserting it's off search_path there was a guaranteed false failure,
caught by the pg-upgrade-test CI job's real binary pg_upgrade legs.
Skip the assertion in that one mode instead. Since existing mode now
produces different, but equally correct, output text ("# SKIP ...")
than fresh/update mode for the same test file, add the numbered
alternate expected files (_1.out) pg_regress needs to accept both --
same pattern Postgres-Extensions/pg_count_nulls uses for this exact
per-scenario-output situation.
Verified directly: installed extension_drop via bin/test_existing's
own prepare() command (plain CREATE EXTENSION ... CASCADE, landing in
public) and ran the suite in existing mode against it -- confirmed
the skip fires and the suite passes, matching the CI job's actual
scenario exactly rather than just the local fresh-mode default.
227566a to
9175bbf
Compare
|
Claude finished @jnasbyupgrade's task in 3m 31s —— View job Claude finished the re-review
SummaryFour new commits since the last review substantially reshape the PR to match its current description: Previously-flagged issues are both resolved:
One new issue found in this pass: Findings1. EXISTING_MODE_EXCLUDE="schema"
Functionally this is harmless today: Nice touches (new this pass)
I wasn't able to execute |
|
Claude finished @jnasbyupgrade's task in 2m 27s —— View job Claude finished the re-review
SummarySince the last review pass, two new commits landed ( The design is unchanged and still matches the CLAUDE.md guidance: fresh/update installs target a freshly created, randomly named, quoting-forcing schema via Both previously-flagged correctness issues (unescaped Outstanding from the last review (still unresolved)
This PR's diff doesn't touch Other observations (unchanged, non-blocking)
Nice touches
I wasn't able to execute |
….sql references test/sql/schema.sql was removed earlier in this branch, but this script still had EXISTING_MODE_EXCLUDE="schema" plus ~20 lines of comments explaining why it needed excluding, and a stale reference to "the schema.sql conflict above". Harmless (the exclude matched nothing since the file no longer exists), but stale rationale a future reader would trip over. existing_mode_regress() simplifies to listing every test/sql/*.sql basename unconditionally now that there's nothing left to exclude. Verified against the real flow: prepare + run-suite against a live database, matching what the pg-upgrade-test CI job actually calls -- correctly runs "dependency_guard simple" (no schema.sql, no exclude logic needed).
|
Claude finished @jnasbyupgrade's task in 1m 34s —— View job Claude finished the re-review
SummaryOnly one new commit since the last review pass: Previously-flagged issue: fixed ✅
No new issues found in this pass. With this fix, all issues raised across the review history of this PR are resolved:
The one remaining item is an observation, not a bug: I wasn't able to execute |

Summary
test/install/load.sqlinstallsextension_dropinto a freshly created schema with a constant, quote-forcing name prefix plus a random suffix, on every single fresh/update-mode test run.extension_drop's control file has noschema=line, so it's genuinely install-schema-flexible -- nothing in its own SQL may assume where it landed.test/install/load.sql(fresh/update modes only): cleans up any leftover schema from a crashed prior run, generates a new random name,CREATE SCHEMAs it, and targets a SINGLECREATE EXTENSION extension_drop:suffixstatement at it via a combined schema+version+cascade suffix built from chainedCASEexpressions -- never by mutatingsearch_pathfirst, which would mask exactly the qualification bug this exists to catch.existingmode is untouched.test/deps.sqlrediscovers that schema per test-file session (pg_namespacejoined topg_extension, notextnamespace::regnamespace, which would reinterpret its quoted display form's literal quote characters as part of the name) -- and deliberately does NOT add it tosearch_path.test/sql/simple.sqlandtest/sql/dependency_guard.sqlqualify their calls intoextension_drop's own functions explicitly via:'extension_drop_schema'instead.test/finish.sql: this suite has no shared teardown-function library to hook a check into (plain pgTAP files, notruntests()), so every test file calls this instead oftest/pgxntool/finish.sqldirectly -- it assertsextension_drop's schema was never reachable viasearch_path, then delegates to the realfinish.sql.test/sql/schema.sql(the original dedicated schema-targeting test) is removed: its job -- proving the extension works installed outsidesearch_path, with an explicit second schema and qualified cross-schema calls -- is now redundant. Every fresh/update run already installs into a random, never-on-search_path schema, and every remaining test file already qualifies its own calls. Traced each of its assertions against the rest of the suite individually before removing it; every one has a real equivalent elsewhere.Reference, not a port
Inspired by
https://github.com/Postgres-Extensions/pg_count_nulls/pull/55'stest/helpers/create_test_schema.sql, which implements the same idea for that (structurally simpler) extension. Deliberately NOT ported wholesale:bin/script that independently needs to rediscover the schema name outsideload.sql's own session -- onlytest/deps.sqldoes, so nofind_test_schema.sql-style helper file was added.lives_ok/bag_eq/plan()directly, not count_nulls' sharedruntests()/ncs()library architecture.extension_dropdepends oncat_tools(CASCADE-installed, with pre-PG10 special-casing); count_nulls has no extension dependencies. That logic inload.sqlis untouched -- schema-targeting was added on top of it.extension_drop_test(a helper extension this suite installs to exerciseextension_drop's commands) is NOT randomized here -- deliberately deferred, tracked ashttps://github.com/Postgres-Extensions/extension_tools/issues/37.TEST_LOAD_SOURCE's fresh/update/existing modes are untouched and unrelated to this change.Verification
make testruns (install-check + build groups both "All N tests passed") andmake lint(zero findings) -- not dry runs, and re-verified from a fresh fetch of the pushed branch.pg_extension/pg_namespacedirectly against the resulting test database across separate runs: confirmed a schema matching the constant prefix (neverpublic), and confirmed different random suffixes across runs (not computed once and cached).extension_drop's own functions are all created via a shared helper that attachesSET search_path FROM CURRENT, so internal cross-references are structurally protected by the schema captured at install time regardless of caller context -- this is what makes it safe fortest/deps.sqlto never add the schema tosearch_pathwhile still relying on it structurally.