Skip to content

Fix upgrade test#2403

Open
jrgemignani wants to merge 1 commit intoapache:masterfrom
jrgemignani:fix_upgrade_template_regression_test
Open

Fix upgrade test#2403
jrgemignani wants to merge 1 commit intoapache:masterfrom
jrgemignani:fix_upgrade_template_regression_test

Conversation

@jrgemignani
Copy link
Copy Markdown
Contributor

Fix upgrade test: replace data-integrity checks with catalog comparison

The age_upgrade regression test (added in #2364, improved in #2377, #2397) was designed to validate the upgrade template (age----y.y.y.sql) by creating graph data before the upgrade and verifying it survived afterward. This approach had two fundamental problems:

  1. It did not detect incomplete upgrade templates. The test verified that graph data (vertices, edges, checksums, GIN indexes) survived ALTER EXTENSION UPDATE, but never checked whether new SQL objects (functions, views, relations) were actually created by the template. A developer could add a new function to sql/ and sql_files, forget to add it to the upgrade template, and all tests would pass — the function existed via the fresh CREATE EXTENSION install that ran before the upgrade test, but would be missing for users who upgraded via ALTER EXTENSION UPDATE.

  2. The data-integrity checks relied on cypher queries (MATCH/RETURN) within the same backend session after DROP EXTENSION + CREATE EXTENSION. This caused intermittent failures on some PostgreSQL versions where AGE's internal type cache (agtype OID) was not properly refreshed after the extension was dropped and recreated, resulting in 'type with OID 0 does not exist' errors. The data-integrity aspect was also redundant — ALTER EXTENSION UPDATE runs DDL statements and does not touch heap data, so data survival is guaranteed by PostgreSQL and not a meaningful test.

The fix replaces the entire test with a catalog comparison approach:

  1. Snapshot ag_catalog's functions (pg_proc) and relations (pg_class) from the fresh install (the --load-extension=age default version).
  2. DROP EXTENSION, CREATE EXTENSION at the synthetic initial version, then ALTER EXTENSION UPDATE to the current version via the stamped upgrade template.
  3. Snapshot the catalog again after upgrade.
  4. Compare: any function or relation present in the fresh snapshot but missing after upgrade means the template is incomplete. Any object present after upgrade but not in the fresh snapshot means the template creates something unexpected.

This approach:

  • Catches the actual failure mode: incomplete upgrade templates.
  • Uses only plain SQL catalog queries — no cypher, no .so cache issues.
  • Works reliably across all PostgreSQL versions.
  • Reports the exact missing/extra object name in the diff output.
  • Is simpler: 130 lines of SQL vs 306, no graph data setup needed.

Makefile: updated step 5 comment to reflect catalog comparison approach.

All 33 regression tests pass.

modified: Makefile
modified: regress/expected/age_upgrade.out
modified: regress/sql/age_upgrade.sql

Fix upgrade test: replace data-integrity checks with catalog comparison

The age_upgrade regression test (added in apache#2364, improved in apache#2377, apache#2397)
was designed to validate the upgrade template (age--<VER>--y.y.y.sql) by
creating graph data before the upgrade and verifying it survived afterward.
This approach had two fundamental problems:

1. It did not detect incomplete upgrade templates. The test verified that
   graph data (vertices, edges, checksums, GIN indexes) survived ALTER
   EXTENSION UPDATE, but never checked whether new SQL objects (functions,
   views, relations) were actually created by the template. A developer
   could add a new function to sql/ and sql_files, forget to add it to
   the upgrade template, and all tests would pass — the function existed
   via the fresh CREATE EXTENSION install that ran before the upgrade test,
   but would be missing for users who upgraded via ALTER EXTENSION UPDATE.

2. The data-integrity checks relied on cypher queries (MATCH/RETURN) within
   the same backend session after DROP EXTENSION + CREATE EXTENSION. This
   caused intermittent failures on some PostgreSQL versions where AGE's
   internal type cache (agtype OID) was not properly refreshed after the
   extension was dropped and recreated, resulting in 'type with OID 0
   does not exist' errors. The data-integrity aspect was also redundant —
   ALTER EXTENSION UPDATE runs DDL statements and does not touch heap data,
   so data survival is guaranteed by PostgreSQL and not a meaningful test.

The fix replaces the entire test with a catalog comparison approach:

  1. Snapshot ag_catalog's functions (pg_proc) and relations (pg_class)
     from the fresh install (the --load-extension=age default version).
  2. DROP EXTENSION, CREATE EXTENSION at the synthetic initial version,
     then ALTER EXTENSION UPDATE to the current version via the stamped
     upgrade template.
  3. Snapshot the catalog again after upgrade.
  4. Compare: any function or relation present in the fresh snapshot but
     missing after upgrade means the template is incomplete. Any object
     present after upgrade but not in the fresh snapshot means the template
     creates something unexpected.

This approach:
  - Catches the actual failure mode: incomplete upgrade templates.
  - Uses only plain SQL catalog queries — no cypher, no .so cache issues.
  - Works reliably across all PostgreSQL versions.
  - Reports the exact missing/extra object name in the diff output.
  - Is simpler: 130 lines of SQL vs 306, no graph data setup needed.

Makefile: updated step 5 comment to reflect catalog comparison approach.

All 33 regression tests pass.

modified:   Makefile
modified:   regress/expected/age_upgrade.out
modified:   regress/sql/age_upgrade.sql
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the age_upgrade regression test to validate upgrade templates by comparing the installed catalog objects from a fresh install vs. an upgrade-from-initial install, avoiding cypher-based integrity checks and related type-cache flakiness.

Changes:

  • Replace graph/data creation + cypher-based data integrity assertions with catalog snapshots and diffs for ag_catalog.
  • Update expected regression output to reflect the new catalog-comparison workflow.
  • Adjust Makefile commentary to describe the new test approach.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
regress/sql/age_upgrade.sql Reworks the upgrade regression test to snapshot and compare pg_proc / pg_class entries for ag_catalog before vs. after upgrade.
regress/expected/age_upgrade.out Updates expected output to match the new SQL and result sets (0-row diffs + summary counts).
Makefile Updates documentation comment for the upgrade test to reflect catalog comparison behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 38 to +39
SELECT drop_graph(name, true) FROM ag_graph ORDER BY name;

Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The cleanup query will produce different, non-deterministic regression output if any graphs exist (it returns 1 row per graph and may emit NOTICEs). Since the expected output assumes 0 rows, this can fail the test for reasons unrelated to upgrade validation. Consider performing the drops in a DO block with PERFORM (and optionally suppressing NOTICEs) so the output is stable regardless of prior graph state.

Suggested change
SELECT drop_graph(name, true) FROM ag_graph ORDER BY name;
DO $$
DECLARE
graph_name ag_graph.name%TYPE;
BEGIN
PERFORM set_config('client_min_messages', 'warning', true);
FOR graph_name IN
SELECT name
FROM ag_graph
ORDER BY name
LOOP
PERFORM drop_graph(graph_name, true);
END LOOP;
END
$$;

Copilot uses AI. Check for mistakes.
SELECT relname::text, relkind::text
FROM pg_class
WHERE relnamespace = 'ag_catalog'::regnamespace
AND relkind IN ('r', 'v', 'S')
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The pg_class snapshot is labeled as capturing “relations”, but the relkind filter excludes indexes (relkind='i') and other relation kinds. ag_catalog defines several indexes (e.g., in sql/age_main.sql), so an upgrade template could miss creating an index/constraint and this test would still pass. Either broaden the relkind filter to include the relation kinds you intend to validate (at least indexes), or update the comments/docs to clearly state you’re only comparing tables/views/sequences.

Suggested change
AND relkind IN ('r', 'v', 'S')
AND relkind IN ('r', 'v', 'S', 'i')

Copilot uses AI. Check for mistakes.
Comment on lines +130 to +137
SELECT f.relname AS missing_relation
FROM _fresh_rels f
LEFT JOIN _upgraded_rels u USING (relname, relkind)
WHERE u.relname IS NULL
ORDER BY 1;

-- Step 14: Relations in upgraded but NOT in fresh install.
SELECT u.relname AS extra_relation
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The missing/extra relation diagnostics only print relname, but the comparison key includes relkind. If a relation’s kind changes (e.g., table ↔ view), the output will show the same name in both lists without indicating why. Consider including relkind in the SELECT output (or selecting both columns) to make failures actionable.

Suggested change
SELECT f.relname AS missing_relation
FROM _fresh_rels f
LEFT JOIN _upgraded_rels u USING (relname, relkind)
WHERE u.relname IS NULL
ORDER BY 1;
-- Step 14: Relations in upgraded but NOT in fresh install.
SELECT u.relname AS extra_relation
SELECT f.relname || ' (' || f.relkind || ')' AS missing_relation
FROM _fresh_rels f
LEFT JOIN _upgraded_rels u USING (relname, relkind)
WHERE u.relname IS NULL
ORDER BY 1;
-- Step 14: Relations in upgraded but NOT in fresh install.
SELECT u.relname || ' (' || u.relkind || ')' AS extra_relation

Copilot uses AI. Check for mistakes.
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.

2 participants