Skip to content

Actually run test/extension_upgrade.sh (#396) - #400

Open
ChronicallyJD wants to merge 3 commits into
commandprompt:mainfrom
ChronicallyJD:fix/396-run-extension-upgrade
Open

Actually run test/extension_upgrade.sh (#396)#400
ChronicallyJD wants to merge 3 commits into
commandprompt:mainfrom
ChronicallyJD:fix/396-run-extension-upgrade

Conversation

@ChronicallyJD

Copy link
Copy Markdown
Collaborator

Closes #396.

You were right, and the way you framed it is the part that stung: the suite had
pg_upgrade's exemption without pg_upgrade's invocation. That is the same shape as
the bug the suite exists to catch, one level up. It reported nothing and nothing ran it.

What changed

It runs. Invoked from run_all_versions.sh under PGC_RUN_UPGRADE=1, the same switch
and the same terms as pg_upgrade.sh. One major is enough, so it runs once against the
first config rather than per pair. Asking for the gate and getting nothing is a failure
rather than a quiet pass, matching the pair check above it.

It works without .git. The second argument now takes either a git ref or a path to
an already-checked-out old source tree. A tree that is not a git checkout says so, and
says what to pass instead, rather than failing on a missing tag as it did when you
reviewed #389.

docs/testing.md gains a section for it, beside the cross-major one, since it is a
different upgrade with a different failure.

Proof

Inspection is not proof for this one, given that the whole complaint is that nothing ran
it. All three entry points, on PG18:

=== A. ref form (needs .git + tags)
  old source: ref v1.0-alpha
  == extension_upgrade: PASS

=== B. directory form (no .git, as the container loop has it)
  /tmp/oldsrc has .git? no
  old source: directory /tmp/oldsrc
  == extension_upgrade: PASS

=== C. non-git tree with the ref form
  FAIL  /tmp/nogit is not a git checkout, so the ref form cannot work here.
        The container loop copies the tree without .git. Pass a directory:
        test/extension_upgrade.sh <pg_config> /path/to/old/source

And through the runner, which is the actual claim:

PGC_RUN_UPGRADE=1 test/run_all_versions.sh <pg18a> <pg19a>

  PASS  pg_upgrade PG18 -> PG19 (copy)
  PASS  pg_upgrade PG18 -> PG19 (link)
  PASS  extension_upgrade PG18
...
ALL VERSIONS PASSED

It appears in the live output and in the matrix summary, next to the gate it was modelled
on.

One thing I did not do

I did not put it in CI. PGC_RUN_UPGRADE is opt-in because of cost, and this suite builds
the extension twice, so adding it to the per-PR gate is a decision about CI minutes rather
than about coverage. Say the word if you would rather it ran nightly, which seems like the
natural home given nightly.yml already exists.

The suite landed in commandprompt#389 with pg_upgrade's exemption from the registration
check and without pg_upgrade's invocation, so nothing ran it. Not the matrix,
not CI, not the Makefile. It ran only when a human typed its name.

That is the gap commandprompt#257 existed to close, and it is worse here than there. The
break this suite catches is invisible to a build and to every suite that
creates the extension from scratch, so a guard nobody runs leaves exactly the
failure it was written for undetected.

It is invoked now from run_all_versions.sh under PGC_RUN_UPGRADE=1, the same
switch and the same terms as pg_upgrade. One major is enough, so it runs once
against the first config rather than per pair. Asking for the gate and getting
nothing is a failure rather than a quiet pass, matching the pair check above it.

Second problem from the same report: it could not run in the documented
container loop at all, because that loop copies the tree without .git and the
ref form needs tags. The second argument now takes either a git ref or a path
to an already-checked-out old source tree. A tree that is not a git checkout
now says so, and says what to pass instead, rather than failing on a missing
tag.

docs/testing.md gains a section for it, since the cross-major upgrade had one
and this is a different upgrade with a different failure.

@jdatcmd jdatcmd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran it in the container, which is the environment #396 was about. The suite is fixed; the runner is not.

Half of this works and is verified. The other half does not reach the place the issue
named.

What works

Form B, the directory form, passes in the container with no .git anywhere --
the case I could not run when reviewing #389:

$ ls -d /root/pgc400/.git      -> absent      (tree under test)
$ ls -d /root/oldsrc400/.git   -> absent      (v1.0-alpha source)

== extension_upgrade: PG18, old /root/oldsrc400
  old source: directory /root/oldsrc400
  old install: 1000 rows, extversion 1.0-dev
  ok    ALTER EXTENSION UPDATE -> 1.0-alpha
  PASS  existing rows still readable: 1000
  PASS  insert into an existing table: 1001
  PASS  new columnar table creatable: 3
  PASS  access method still bound: pgcolumnar
  PASS  maintenance function callable
  PASS  every C function's link name is namespaced
== extension_upgrade: PASS

The error text for the ref form on a non-git tree is genuinely helpful: it names the
container loop and prints the exact command to use instead.

What does not

Through the runner, in the container, the gate FAILS. Full run,
PGC_RUN_UPGRADE=1 test/run_all_versions.sh /usr/local/pgsql/bin/pg_config:

  FAIL  extension_upgrade PG18
      == extension_upgrade: PG18, old v1.0-alpha
              test/extension_upgrade.sh <pg_config> /path/to/old/source

===================== MATRIX SUMMARY ============================
  PASS   PG18  harness_selftest=PASS docs_style=PASS ... (all 112 suites)
  FAIL   extension_upgrade PG18

Every one of the 112 suites passed. The only real red is the new gate. (FAIL upgrade (no runnable pair) in that summary is mine -- I passed a single config and the
cross-major gate needs two. Correct behaviour.)

The cause is line 545:

if bash "$SRCDIR/test/extension_upgrade.sh" "$_ex" >"$_exlog" 2>&1; then

No second argument, so the runner always takes the ref form, and $SRCDIR in
the documented dev loop has no .git. I checked for a way to supply the directory and
there is none: no PGC_* variable reaches that call. So the directory form you added
is unreachable from the gate, and the gate is unusable in the container -- which is
exactly the environment #396 called out.

Why this is worth another round rather than a note

It creates a new source of false red in the documented loop, and this project's own
runner argues against precisely that:

a gate that goes red for reasons unrelated to the change teaches its readers to
discount red, which is worse than not running it

A developer following docs/testing.md who opts into PGC_RUN_UPGRADE=1 gets a
failure that is not a product defect. That is the same lesson as #396 wearing different
clothes: the first time the guard did not run, this time it runs and lies.

Smallest fix I can see

Either of these, and the second is cheap:

  1. An env var the runner passes through -- PGC_UPGRADE_OLD_SRC=/path appended as
    the second argument when set. Two lines, and it makes the directory form reachable.
  2. SKIP rather than FAIL when $SRCDIR is not a git checkout, with the reason
    printed. There is precedent in this file: PGC_SKIP_TIMING prints SKIP and
    returns 0 rather than failing.

I would do both: (1) so it can run in the container, (2) so it does not lie when it
cannot.

Everything else about the PR is right, including running it once against the first
config rather than per pair, and treating "asked for the gate, got nothing" as a
failure. Re-run my container check after the change and I will merge.

Joshua (D) Drake and others added 2 commits August 4, 2026 16:58
…an lie

jdatcmd ran the previous commit in the container, which is the environment
commandprompt#396 was about, and the gate went red there. The directory form was reachable
by a person and not by the runner: line 545 passed no second argument, so the
runner always took the ref form, and the documented container loop has no .git.

So it created a new source of false red in the loop the docs tell people to
use. This runner's own comment argues against exactly that, saying a gate that
goes red for reasons unrelated to the change teaches its readers to discount
red. That is commandprompt#396 wearing different clothes. The first time the guard did not
run. This time it ran and lied.

Two changes, both suggested in the review.

PGC_UPGRADE_OLD_SRC names a directory holding the old source, and the runner
appends it when set. That makes the directory form reachable from the gate.

Absent any named old source, a tree with no .git now reports SKIP and exits 2
rather than failing. The runner reports SKIP and records SKIP in the summary,
following PGC_SKIP_TIMING above it.

Skip and fail are different answers and the difference is who asked for what.
A caller who names an old source that cannot be honoured gets a failure. A
caller who names nothing, in a tree that cannot supply one, gets a skip. The
skip is loud, prints its reason, and is never reported as a pass, because a
gate reporting green having run nothing is the defect this suite was written
for.
Verifying the exit codes turned up a misleading message. A PGC_UPGRADE_OLD_SRC
that names a path which does not exist fell through to the ref branch, so the
user got an error about git checkouts and refs in answer to a question about a
directory. The exit code was right and the message pointed at the wrong thing.

A value containing a slash is now treated as a path, and a missing one says
that, rather than being reinterpreted as a ref.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nothing runs test/extension_upgrade.sh: it has pg_upgrade's exemption without pg_upgrade's invocation

2 participants