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
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ jobs:
steps:
- uses: actions/checkout@v4

# THE RELEASE TAGS, for native_upgrade_converge's fixture checks (#1341). Each
# fixture in test/fixtures must be byte-identical to what its tag shipped, and
# the pytest twin compares it with `git rev-parse v<version>:<file>`.
# actions/checkout fetches no tags, and with none the twin declares those
# checks unrunnable, which leaves this job incomplete. Depth 1 is enough: only
# the file at each tag is read.
- name: fetch the release tags, for the fixture checks
run: git fetch --depth=1 origin '+refs/tags/v*:refs/tags/v*'

- name: Add the PGDG repository and install PostgreSQL ${{ matrix.pg }} with its headers
run: |
set -euo pipefail
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,15 @@ jobs:
steps:
- uses: actions/checkout@v4

# THE RELEASE TAGS, for native_upgrade_converge's fixture checks (#1341). Each
# fixture in test/fixtures must be byte-identical to what its tag shipped, and
# the pytest twin compares it with `git rev-parse v<version>:<file>`.
# actions/checkout fetches no tags, and with none the twin declares those
# checks unrunnable, which leaves this job incomplete. Depth 1 is enough: only
# the file at each tag is read.
- name: fetch the release tags, for the fixture checks
run: git fetch --depth=1 origin '+refs/tags/v*:refs/tags/v*'

- name: Add the PGDG repository and install PostgreSQL ${{ matrix.pg }} with its headers
run: |
set -euo pipefail
Expand Down
4 changes: 3 additions & 1 deletion test/pytest/TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7531,7 +7531,7 @@ Part of the pytest twin of `test/drop_cleanup.sh` (#1265, ported for #1341): its

## 143. test_native_upgrade_converge.py: every release upgrades to a fresh catalog, and the window before it

The pytest twin of `test/native_upgrade_converge.sh` (#1341), by the shell's names, except its release-tag checks, so the pair is declared INCOMPLETE. `ALTER EXTENSION pgcolumnar UPDATE` must bring a database on any released version to a catalog identical to a fresh install of the current `default_version`: every function's definition, ACL and comment, and every relation, column, type and foreign-data wrapper. The released starting points are the install scripts in `test/fixtures`. They are staged into the extension directory once for the module, under a lock that makes a second stager wait, and whatever was there is put back after. A backup already there means an earlier run died, so it holds the original and is kept.
The pytest twin of `test/native_upgrade_converge.sh` (#1341), every check by the shell's name. `ALTER EXTENSION pgcolumnar UPDATE` must bring a database on any released version to a catalog identical to a fresh install of the current `default_version`: every function's definition, ACL and comment, and every relation, column, type and foreign-data wrapper. The released starting points are the install scripts in `test/fixtures`. They are staged into the extension directory once for the module, under a lock that makes a second stager wait, and whatever was there is put back after. A backup already there means an earlier run died, so it holds the original and is kept.

Between installing a new library and running the update, a database runs the new library over its previous release's catalog (#1341 item 66). Reads and writes must work there. `DROP TABLE`, `TRUNCATE` and `pgcolumnar.vacuum()` need a catalog table the old one lacks, so they must be refused with 42P01, change nothing, and carry a hint naming the update. After the update all three succeed on the same rows.

Expand All @@ -7541,6 +7541,8 @@ Between installing a new library and running the update, a database runs the new
| --- | --- |
| `test_a_run_after_one_that_died_keeps_the_original` | with a died run's state in a temporary directory, staging and restoring leave the prefix's own file, not the fixture |
| `test_two_stagings_at_once_keep_the_original` | a second staging that starts inside the first, as another `pytest -n` worker's would, waits for it under the staging lock, and the prefix's own file survives both |
| `test_the_fixture_sweep_found_fixtures` | premise: the fixtures read from `test/fixtures`, less the synthetic `1.0-alpha`, are not empty |
| `test_each_tagged_fixture_is_what_its_tag_shipped` | parametrized by those fixtures: each one's blob id equals the file's at its release tag. With no git repository or no release tags, unrunnable (`UNMET_PRECONDITION`); the CI pytest jobs fetch the tags |
| `test_the_staged_fixtures_are_the_committed_ones` | the control's `default_version`; no backup was already staged; every fixture was staged, and each staged script is the committed fixture |
| `test_each_release_upgrades_to_a_fresh_catalog` | parametrized by the four fixtures: a fresh install of the target has more than 100 objects to compare, the upgrade applies, the extension is at the target, and its catalog equals the fresh install's |
| `test_the_upgrade_window` | at the previous catalog: rows written, deleted and read; the three operations refused with the hint and nothing changed; after the update the rows are intact and all three succeed |
Expand Down
4 changes: 3 additions & 1 deletion test/pytest/expected_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -858,4 +858,6 @@ guard_tests 442
# tests, one per check, by collection over the cluster files.
# cluster_tests 1018 -> 1025 for #1341, test_native_upgrade_converge.py ported by name except its
# release-tag arms (1 -> 8 tests), by collection over the cluster files.
cluster_tests 1025
# cluster_tests 1025 -> 1029 for #1341, test_native_upgrade_converge.py's release-tag arms: the sweep
# premise and one test per tagged fixture (8 -> 12 tests), by collection over the cluster files.
cluster_tests 1029
7 changes: 1 addition & 6 deletions test/pytest/test_compare_to_bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
# The shape is `SHELL_REFERENCES`' in `test_harness_deps.py`, asserted in both
# directions for the same reason: a one-way list rots into a permanent exemption.
COMPLETE = ["advisory_lock_class",
"native_upgrade_converge",
"range_pruning",
"native_format",
"iceberg_data_files",
Expand Down Expand Up @@ -226,12 +227,6 @@
# about the PORT rather than a licence: the standing arm does not grade it, so the
# reason is the only thing standing between a declared gap and a forgotten one.
INCOMPLETE = {
# #1341 ported every arm but the release-tag ones: each tagged fixture is
# byte-identical to what its tag shipped. CI checks out without tags, so the shell
# skips them there with check_skip, and this layer has no verdict for an arm that
# runs on one checkout and not another.
"native_upgrade_converge": "every arm is ported except the release-tag sweep and "
"the per-tag fixture-blob comparisons",
# #1341 item 29 ported the arms four fixes added with shell arms only. Each
# pair below holds that fix's arms and nothing else of its shell suite.
"inheritance": "the #1259 arms (a partitioned columnar parent is refused with "
Expand Down
34 changes: 34 additions & 0 deletions test/pytest/test_native_upgrade_converge.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@
# The released starting points, oldest first; the last is the previous release.
VERSIONS = ["1.0-alpha", "1.0-alpha2", "1.0-alpha3", "1.0-alpha4"]

# The fixtures a release tag shipped, read from disk so a fixture added at the next
# cycle-open is checked without anyone adding it here. 1.0-alpha is synthetic: v1.0-alpha
# shipped pgcolumnar--1.0-dev.sql, so no tag holds a pgcolumnar--1.0-alpha.sql.
TAGGED = sorted(p.name[len("pgcolumnar--"):-len(".sql")] for p in FIXTURES.glob("pgcolumnar--*.sql")
if p.name != "pgcolumnar--1.0-alpha.sql")

# One line per object in the pgcolumnar schema: every function's definition, ACL and
# comment; every relation's kind, ACL and comment; every column's type, NOT NULL and
# comment; every non-base type; every foreign-data wrapper's handler and validator. The
Expand Down Expand Up @@ -294,6 +300,34 @@ def reference(pgc_cluster):
_admin(pgc_cluster, "DROP DATABASE IF EXISTS pgc_conv_fresh WITH (FORCE)")


def _git(*args):
"""-> git's output in the tree under test, or None when it fails."""
r = subprocess.run(["git", "-C", str(REPO), *args], capture_output=True, text=True)
return r.stdout.strip() if r.returncode == 0 else None


def test_the_fixture_sweep_found_fixtures(expect):
expect.num(len(TAGGED) > 0 and 1 or 0, 1,
"premise: the fixture sweep found fixtures to compare against their tags")


@pytest.mark.parametrize("v", TAGGED)
def test_each_tagged_fixture_is_what_its_tag_shipped(v, expect):
"""Each fixture is the released starting point only if it is what its tag shipped
(#901): compared by blob id, which is a lookup and has no similarity heuristic. The
local tag is trusted; if this fails and the fixture looks right, check the tag with
`git ls-remote origin refs/tags/v<version>`."""
name = f"the {v} fixture is byte-identical to what v{v} shipped"
if _git("rev-parse", "--git-dir") is None:
expect.cannot_run("UNMET_PRECONDITION", "no git repository in the tree under test", name=name)
return
if not _git("tag", "-l", "v1.0-alpha*"):
expect.cannot_run("UNMET_PRECONDITION", "no release tags in this checkout", name=name)
return
expect.text(_git("hash-object", str(FIXTURES / f"pgcolumnar--{v}.sql")) or "fixture missing",
_git("rev-parse", f"v{v}:pgcolumnar--{v}.sql") or f"no such path at v{v}", name)


def test_the_staged_fixtures_are_the_committed_ones(staging, expect):
extdir, staged, died = staging
target, _ = _target_and_previous()
Expand Down
Loading