Skip to content

Add TEST_SCHEMA test-harness switch - #54

Open
jnasbyupgrade wants to merge 5 commits into
Postgres-Extensions:masterfrom
jnasbyupgrade:feature/test-schema
Open

Add TEST_SCHEMA test-harness switch#54
jnasbyupgrade wants to merge 5 commits into
Postgres-Extensions:masterfrom
jnasbyupgrade:feature/test-schema

Conversation

@jnasbyupgrade

@jnasbyupgrade jnasbyupgrade commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Add TEST_SCHEMA, a second independent test-harness switch that targets a schema before installing cat_tools, following the exact same make-var -> PGOPTIONS -> GUC -> psql propagation pattern already established by TEST_LOAD_SOURCE.

Empty (the default) leaves search_path untouched, so CREATE EXTENSION cat_tools runs exactly as a brand-new user would type it. A non-empty value creates that schema (quoting it, so mixed-case names work) and SETs search_path to it first. cat_tools' control file pins schema = 'cat_tools' with relocatable = false, so this does not relocate the extension itself -- what it proves is that the propagation pipeline handles a quoting-requiring schema name correctly end to end, and that installing while some other, possibly hostile, schema is ambient doesn't break anything. The guard in test/install/load.sql checks the RESOLVED search_path (current_schemas(false), not pg_namespace -- checking pg_namespace only proves CREATE SCHEMA worked, not that SET search_path actually resolved to it) so a quoting bug in either statement is actually caught. \set ON_ERROR_STOP on is set near the top of load.sql so that check (and every other RAISE EXCEPTION in the file) can actually fail the pg_regress run instead of psql printing an error and continuing past it.

A new TEST_LONG_SCENARIOS make variable drives test-long, which loops verify-results once per explicit TEST_LOAD_SOURCE:TEST_SCHEMA scenario -- deliberately an explicit list, not a full cross product: fresh:<empty>, fresh:CatToolsSchema, and update:CatToolsSchema are kept, but update:<empty> is dropped because it's exactly what CI's extension-update-test job already proves, more thoroughly (it also plants and proves the dependency guard), on the same PostgreSQL majors -- repeating just the suite-pass subset of that here would add CI wall-clock with no added confidence. test-all runs test (a quick smoke build; gates via test's own regression.diffs check as of pgxntool 2.3.0+, but not as strict as verify-results's pgtap-aware check) followed by test-long. CI's test job runs make test-long on every supported PostgreSQL major, so all three scenarios are covered everywhere, with no separate matrix leg needed for any of them.

Scope boundary, called out explicitly in the Makefile and the ci.yml "Test strategy" comment rather than left implicit: extension-update-test and pg-upgrade-test do not exercise TEST_SCHEMA at all yet. Wiring TEST_SCHEMA through the update and pg_upgrade paths is a deliberately deferred follow-up (#65), not an oversight -- though update:CatToolsSchema above is a partial answer to it on the plain extension-update path.

Verified locally on scratch PostgreSQL clusters (isolated from the container's shared clusters, since concurrent agents were also exercising cat_tools's shared roles/databases there), including a real pg_tle 1.5.2 build to reproduce and fix a pg_tle-specific regression the ON_ERROR_STOP change exposed (the existing-mode version assertion previously compared against pg_available_extensions.default_version, which is filesystem-based and returns NULL for a pg_tle-only registration; it now reads a cat_tools.pgxn_version GUC instead, mirroring bin/test_existing's own current_version() helper). make test-long and make test-all both run exactly the three scenarios above end to end, passing the full suite each time with no expected-output divergence.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7f2db047-4ec8-44ae-9e8c-8a7784ebe7e4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread Makefile
Comment thread test/install/load.sql
…s a schema before installing cat_tools, following the exact same make-var -> PGOPTIONS -> GUC -> psql propagation pattern already established by TEST_LOAD_SOURCE.

Empty (the default) leaves search_path untouched, so CREATE EXTENSION cat_tools runs exactly as a brand-new user would type it. A non-empty value creates that schema (quoting it, so mixed-case names work) and SETs search_path to it first. cat_tools' control file pins schema = 'cat_tools' with relocatable = false, so this does not relocate the extension itself -- what it proves is that the propagation pipeline handles a quoting-requiring schema name correctly end to end, and that installing while some other, possibly hostile, schema is ambient doesn't break anything. A DO block in test/install/load.sql checks the RESOLVED search_path (current_schemas(false), not pg_namespace -- checking pg_namespace only proves CREATE SCHEMA worked, not that SET search_path actually resolved to it) so a quoting bug in either statement is actually caught rather than passing silently. \set ON_ERROR_STOP on is set near the top of load.sql so that check (and every other RAISE EXCEPTION in the file) can actually fail the pg_regress run instead of psql printing an error and continuing past it.

A new TEST_SCHEMAS make variable (default: empty and one mixed-case quoting-requiring name, `CatToolsSchema`) and TEST_LOAD_SOURCES (fresh, update) drive a new `test-long` target that loops `verify-results` once per {TEST_LOAD_SOURCE, TEST_SCHEMA} combination -- the only target that can actually gate on a regression, since plain `test`/`test-update` terminate in pgxntool's .IGNORE'd installcheck. `test-all` sequences `test` and `test-long` for a full local pre-push check. CI's `test` job runs `make test-long` on every supported PostgreSQL major, so all four combinations are covered everywhere, with no separate matrix leg needed for any of them.

Scope boundary, called out explicitly in the Makefile and the ci.yml "Test strategy" comment rather than left implicit: `extension-update-test` and `pg-upgrade-test` do not exercise TEST_SCHEMA/TEST_SCHEMAS at all yet (they drive the extension through bin/test_existing's own createdb/CREATE EXTENSION/ALTER EXTENSION UPDATE flow, not this Makefile's TEST_LOAD_SOURCE path). Wiring TEST_SCHEMA through the update and pg_upgrade paths is a deliberately deferred follow-up (Postgres-Extensions#65), not an oversight.
…e existing-mode version assertion in test/install/load.sql compared the installed version against pg_available_extensions.default_version, which is FILESYSTEM-based and returns NULL for an extension registered purely via pg_tle (no control file ever touches disk in that deployment path). Before ON_ERROR_STOP, this always-broken-for-pg_tle comparison silently printed an error and continued; with ON_ERROR_STOP now enforcing that RAISE EXCEPTION actually aborts the script, every pg_tle CI job started failing (confirmed by reproducing the exact existing-mode check against a local pg_tle-only registration, where pg_available_extensions came back NULL).

Fixed by threading PGXNVERSION (the distribution version from META.json) into a new cat_tools.pgxn_version GUC and comparing against that instead -- mirroring bin/test_existing's own current_version() helper, which already avoids pg_available_extensions for the identical reason. The export has to live in a second PGOPTIONS append AFTER `include sql.mk`, since PGXNVERSION isn't defined until base.mk's meta.mk include runs.

Re-verified end to end: reproduced the pg_tle failure locally (built and registered pg_tle 1.5.2 against a scratch cluster, ran bin/test_existing's exact update-scenario flow with TEST_EXISTING_DEPLOY=pgtle), confirmed the fix resolves it, and reran the full make test-long / test-all matrix (both TEST_LOAD_SOURCE values x both TEST_SCHEMA values) to confirm nothing else regressed.
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

1 similar comment
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

The rationale for this was only in the file's header comment, several
paragraphs above -- easy to miss and remove without realizing every
RAISE EXCEPTION guard in this file (TEST_SCHEMA, test_load_mode, the
existing-mode version assertion) would silently become a no-op.
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

…explicit

The mechanism set up an ambient schema and put it on search_path, but never
did the thing its own comments claimed: CREATE EXTENSION ran with no WITH
SCHEMA clause (implicit placement only, via the non-relocatable control
file), and nothing ever asserted that 'cat_tools' itself stays out of the
resolved search_path. The actual point of TEST_SCHEMA is to prove cat_tools'
own internal SQL doesn't secretly depend on unqualified name resolution to
its own schema -- a real, legitimate deployment keeps a tooling extension's
schema off every role's default search_path, and a latent dependency on it
being searchable would keep working by accident in every other ordinary
test run and only break there.

- CREATE EXTENSION now explicitly adds WITH SCHEMA cat_tools when TEST_SCHEMA
  is set, instead of relying on implicit placement.
- A CREATE SCHEMA IF NOT EXISTS cat_tools precedes it: unlike a bare CREATE
  EXTENSION (which auto-creates the control-file-pinned schema if needed),
  WITH SCHEMA requires that schema to already exist, even when it's the same
  name -- confirmed by testing this against a scratch cluster, which is also
  how the missing CREATE SCHEMA surfaced in the first place.
- A new assertion after install fails loudly if 'cat_tools' ever appears in
  the resolved search_path, which is the property this whole mechanism exists
  to prove. Verified it actually fires by manually forcing the violation.
- Rewrote the TEST_SCHEMA comments in both load.sql and the Makefile around
  this actual goal; the previous framing (a quoting-pipeline check) doesn't
  hold up -- psql substitutes the same variable identically regardless of
  which statement it appears in, so CREATE SCHEMA and SET search_path can't
  diverge on quoting -- and is left as a much narrower fixture sanity check.

Tested against an isolated scratch cluster (fresh/update x empty/CatToolsSchema,
plus test-long's full matrix), since this repo's usual pgstart-managed
clusters were too polluted with unrelated leftover test databases from other
concurrent work to trust for this.
@jnasbyupgrade jnasbyupgrade added the claude-debug Skip claude-code-review's cost gate and dump the full raw transcript to the job log label Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude finished @jnasbyupgrade's task in 5m 53s —— View job


Claude finished reviewing PR #54

  • Gather context (diff, CLAUDE.md, changed files)
  • Understand the request (code review per /code-review)
  • Review .github/workflows/ci.yml changes
  • Review Makefile changes
  • Review test/install/load.sql changes
  • Check prior automated review comments for context
  • Post final review

Summary

Both issues raised by the earlier automated review on this PR have already been fixed by later commits in this branch:

  • test-all gatingtest-all no longer calls the non-gating test/test-update pair for its update-mode coverage. It now runs test (quick smoke build) followed by test-long, and test-long routes every {TEST_LOAD_SOURCE, TEST_SCHEMA} combination — including update — through verify-results, the documented gate. ✅ resolved.
  • Search-path guard — the guard now checks the resolved side of the pipeline (current_setting('cat_tools.test_schema') <> ALL (current_schemas(false)) in test/install/load.sql:137) instead of pg_namespace, and \set ON_ERROR_STOP on (test/install/load.sql:61) makes RAISE EXCEPTION actually abort the script. ✅ resolved.

I re-reviewed the diff (95fb973..HEAD) fresh against both files for anything new. One finding:

Makefile:131-132 — comment mislabels make test as "non-gating", contradicting this repo's own documented behavior

# Runs every test target that can actually gate on a regression: test (fresh,
# non-gating -- see verify-results above -- but still useful as a quick smoke
# build) plus test-long, ...

CLAUDE.md (this repo's own docs, already current before this PR) states plainly: "make test returns non-zero on test regressions (pgxntool 2.3.0+): ... test's own recipe now checks test/regression.diffs and exits non-zero if it's non-empty." pgxntool/base.mk's test: recipe confirms this (@if [ -r $(TESTOUT)/regression.diffs ]; then cat ...; exit 1; fi). This PR's own ci.yml comment (lines 329-331) gets this right ("test's own recipe now exits non-zero as soon as it sees a regression"). So the new Makefile comment directly contradicts both CLAUDE.md and the parallel comment added in ci.yml in the same PR.

It's a comment-only inaccuracy (doesn't change test-all's actual behavior — test-long's verify-results calls are still the real gate either way), but it will mislead a future reader into thinking a local make test failure isn't a real signal, exactly the misconception CLAUDE.md's Bug Fixes section asks us to avoid perpetuating. Suggest rewording along the lines of: "test (fresh; gates via test's own regression.diffs check, pgxntool 2.3.0+, but not as strict as verify-results's pgtap-aware check -- still useful as a quick smoke build)".

Worth confirming, not a defect

test's "Test on PostgreSQL" step now runs make test-long instead of a single make verify-results — that's a ~4x increase in full-suite runs per matrix leg (2 TEST_LOAD_SOURCE × 2 TEST_SCHEMA), across all 7 supported majors (PG12–18). The PR description acknowledges the trade-off (comprehensive coverage without a separate matrix leg), so this looks deliberate rather than an oversight — just flagging the wall-clock cost in case it wasn't fully weighed, per this repo's own .github/workflows/CLAUDE.md guidance on CI time.

Everything else checked out: TEST_SCHEMAS ?= "" CatToolsSchema expands correctly in the test-long shell loop (the embedded "" is a real empty-string shell word, not swallowed by Make), the CREATE SCHEMA IF NOT EXISTS cat_tools/WITH SCHEMA ordering correctly avoids the extension "owning" a schema it didn't create (so DROP EXTENSION CASCADE won't drop it), the fixture's SET search_path doesn't leak into the actual pgTAP suite (separate connections), and all \endif/\if blocks are labeled per CLAUDE.md's non-indentable-block convention.

No code changes made — this was a review-only request.

… flagged by review.

test-all's comment claimed `make test` is "non-gating", contradicting CLAUDE.md and pgxntool 2.3.0+: test's own recipe already exits non-zero on a regression.diffs entry, it's just not as strict as verify-results's pgtap-aware check. Reworded to say what's actually true.

Verified a second finding before touching anything: test-long's {TEST_LOAD_SOURCE=update, TEST_SCHEMA=<empty>} scenario duplicates CI's extension-update-test job -- both run the SAME 0.2.2-to-current update on the SAME PostgreSQL majors (12-18), and extension-update-test does strictly more (plants and proves the dependency guard) than a bare verify-results call ever would. Replaced test-long's TEST_SCHEMAS x TEST_LOAD_SOURCES cross product with an explicit TEST_LONG_SCENARIOS list of exactly the three scenarios that add value (fresh:<empty>, fresh:CatToolsSchema, update:CatToolsSchema), dropping only the redundant one. Updated the Makefile and ci.yml "Test strategy" comments to match the three-scenario design and explain why the fourth is deliberately absent.
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Claude finished @jnasbyupgrade's task in 2m 22s —— View job


Claude finished reviewing PR #54

  • Gather context (diff, CLAUDE.md, prior review comments)
  • Review .github/workflows/ci.yml changes
  • Review Makefile changes
  • Review test/install/load.sql changes
  • Check whether prior review feedback (automated + human) has been addressed
  • Post final review

Summary

Both substantive issues flagged by the earlier automated review (2026-08-01) are resolved by the latest commits:

  • test-all gating gap (Makefile:158 comment) — test-all no longer calls the non-gating test/test-update pair for update-mode coverage. It's now $(MAKE) test (quick smoke build) followed by $(MAKE) test-long (Makefile:154-157), and test-long routes every {TEST_LOAD_SOURCE, TEST_SCHEMA} combination — including update:CatToolsSchema — through verify-results, the documented gate. ✅ resolved.
  • Search-path guard checking the wrong side / not fatal (test/install/load.sql:147 comment) — the guard now checks the resolved search_path (current_setting('cat_tools.test_schema') <> ALL (current_schemas(false)), test/install/load.sql:137) instead of pg_namespace, and \set ON_ERROR_STOP on (test/install/load.sql:61) makes RAISE EXCEPTION actually abort the script instead of psql printing and continuing. ✅ resolved.

The most recent commit (4272a4e) also fixes the follow-up finding from the automated review's last pass: the Makefile:145-148 comment previously mislabeled make test as non-gating, contradicting this repo's own CLAUDE.md ("make test returns non-zero on test regressions, pgxntool 2.3.0+") and the parallel comment already in ci.yml. I independently confirmed the underlying claim against the vendored pgxntool/base.mk: test: $(TEST_DEPS) does exit 1 on a nonempty regression.diffs (line 376), and verify-results deliberately depends on $(TEST_DEPS) directly rather than on test (lines 404-409) precisely so test's own early exit doesn't abort the chain before verify-results gets to inspect and report the diff — exactly what the Makefile's updated comment (Makefile:145-148) and ci.yml's parallel comment (lines 337-341) both now say. The wording is accurate.

I re-read both files in full against the PR description's claims (propagation of TEST_SCHEMA through PGOPTIONS, the TEST_LONG_SCENARIOS shell-loop parsing, \if/\endif nesting, and the CI job comments in ci.yml's "Test strategy" block) and didn't find anything new to flag:

  • TEST_SCHEMAS/TEST_LONG_SCENARIOS parsing (Makefile:112,128-133) is correct: ${scenario%%:*} / ${scenario#*:} split on the first colon as documented, and the three kept scenarios (fresh:, fresh:CatToolsSchema, update:CatToolsSchema) match what's described.
  • CREATE SCHEMA IF NOT EXISTS/WITH SCHEMA ordering (test/install/load.sql:247-260) correctly avoids the extension auto-creating (and thus "owning," for DROP EXTENSION CASCADE purposes) a schema it shouldn't.
  • The \if :cat_tools_mode_existing / \if :cat_tools_has_schema nesting is consistent, and every non-indentable closer (\endif) has the required trailing label comment per CLAUDE.md's convention.
  • The pg_tle-regression fix (existing-mode version check now reads cat_tools.pgxn_version instead of pg_available_extensions.default_version, test/install/load.sql:184-212) mirrors bin/test_existing's own current_version() helper as claimed.
  • ci.yml's "Test strategy" comment block (lines 242-301) accurately reflects the test job's make test-long step and calls out the extension-update-test/pg-upgrade-test TEST_SCHEMA scope boundary with a real issue link (#65), consistent with CLAUDE.md's full-URL-for-open-TODOs rule.

No code changes made — this was a review-only request, and no new findings survived scrutiny.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-debug Skip claude-code-review's cost gate and dump the full raw transcript to the job log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant