From d62a875a4af13ecce481936dd2c275424ea72e2e Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Mon, 12 Oct 2026 18:28:04 -0500 Subject: [PATCH 1/5] Fail `make test` on pgTap failures and plan problems in actual output `make test` failed only on `regression.diffs`, so a `not ok` line blessed into an expected file passed, as did a test that died before printing its plan, and `test/install` output was never checked at all. Add `test/bin/check-tap-output.sh`, which fails a file with TAP output on a `not ok` without `# TODO`, pgTap's "Looks like you planned" line, a missing or duplicate `1..N` plan line, or a test count that differs from the plan. Files without TAP output pass untouched. - The `test` recipe runs it over `$(TESTOUT)/results/*.out` and the `test/install` actual output, then still prints `regression.diffs`; either failing fails the run. New `PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT` (default `yes`) disables it. It lives in the recipe, not `TEST_DEPS`, so `make PGXNTOOL_ENABLE_VERIFY_RESULTS=no results` still blesses. - `verify-results-pgtap.sh` uses the same script for its TAP phase, so `make results` gains the plan checks and the `test/install` scan. - The `test/install` actual output is `$(TESTOUT)/install/.out`; the base.mk comment now says so. Part of #106. Related changes in pgxntool-test: - Unit tests for `check-tap-output.sh` and the new `verify-results-pgtap.sh` behavior - `make test` wiring tests, plus an end-to-end blessed `not ok` failure Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 4 +-- HISTORY.asc | 22 ++++++++++++ README.asc | 14 +++++--- README.html | 28 ++++++++++----- base.mk | 63 ++++++++++++++++++++++++++++----- test/bin/check-tap-output.sh | 68 ++++++++++++++++++++++++++++++++++++ verify-results-pgtap.sh | 35 ++++++------------- 7 files changed, 187 insertions(+), 47 deletions(-) create mode 100755 test/bin/check-tap-output.sh diff --git a/CLAUDE.md b/CLAUDE.md index cca492c..696ef46 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -179,7 +179,7 @@ make pgxntool-sync # Update to latest pgxntool via git subtree pull - Correct test dependency installation (`testdeps`, and `test-build` when enabled); `testdeps`' default `pgtap` prerequisite auto-installs pgtap via `pgxn install`, a no-op when `PGXNTOOL_ENABLE_PGXN_INSTALL=no` - Extension is filesystem-installed before tests run (`install`), unless `PGXNTOOL_ENABLE_FS_INSTALL=no` - Test comparison via `installcheck`, with diffs shown on failure -- Safeguard checks that fail the run: the stale-expected-file check (orphaned or non-`.out` files in `test/expected/`, run after `pg_regress`), and, when `test/install` is in use, the check that every `test/install/*.sql` file sets `ON_ERROR_STOP` +- Safeguard checks that fail the run: the pgTap output check (a `not ok` without `# TODO`, a missing or duplicate `1..N` plan, or a plan/test count mismatch in `test/results/*.out` or the `test/install` actual output -- even when the output matches its expected file; `PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT=no` disables it), the stale-expected-file check (orphaned or non-`.out` files in `test/expected/`, run after `pg_regress`), and, when `test/install` is in use, the check that every `test/install/*.sql` file sets `ON_ERROR_STOP` Note: `make test` intentionally does *not* depend on `clean` — depending on `clean` caused problems with incremental/watch-based builds (see `base.mk`). If your tests need a clean build to pass, that's a sign of a missing dependency elsewhere, not something to fix by adding `clean` back. @@ -207,7 +207,7 @@ When tests fail, examine the diff output carefully. The actual test output in `t **Exceptions to the above** -- `test-build` and `test/install` (both optional, see `README.asc`) don't follow the `test/results` vs `test/expected` model: - **test-build** runs first, in its own separate `pg_regress` pass over `test/build/*.sql`, and gates the main suite: if it fails, `test/install`/`test/sql` never run at all. It does compare actual vs expected normally (`test/build/results/` vs `test/build/expected/`) -- use `make results-build` to refresh its expected output, not `make results`. -- **test/install** does NOT get a real diff at all: its actual output is written to the exact same file as its expected output, so a content difference can never fail the build, no matter what changed. The only thing that still fails the build is a hard SQL error, and only if the file has `ON_ERROR_STOP` set (directly, or via `\i test/pgxntool/psql.sql`) -- pgxntool checks for this by default, passing any file that includes `psql.sql` or has its own `\set`/`\unset ON_ERROR_STOP`, whatever the value. If a `test/install/*.sql` file is misbehaving, don't go looking for a diff; check whether it errored, and don't assume a stale-looking `.out` for it means anything. +- **test/install** does NOT get a real diff at all: its actual output is written to the exact same file as its expected output, so a content difference can never fail the build, no matter what changed. Apart from pgTap failures (caught by the pgTap output check above), the only thing that still fails the build is a hard SQL error, and only if the file has `ON_ERROR_STOP` set (directly, or via `\i test/pgxntool/psql.sql`) -- pgxntool checks for this by default, passing any file that includes `psql.sql` or has its own `\set`/`\unset ON_ERROR_STOP`, whatever the value. If a `test/install/*.sql` file is misbehaving, don't go looking for a diff; check whether it errored, and don't assume a stale-looking `.out` for it means anything. ## Key Implementation Details diff --git a/HISTORY.asc b/HISTORY.asc index 3d588c0..1e0b13c 100644 --- a/HISTORY.asc +++ b/HISTORY.asc @@ -1,3 +1,25 @@ +STABLE +------ +== Breaking changes + +=== `make test` now fails on pgTap failures in actual output +`make test` used to fail only on `regression.diffs`, so a `not ok` line +blessed into an expected file passed. It now also scans +`test/results/*.out` and the `test/install` actual output, failing on a +`not ok` without `# TODO`, a missing or duplicate `1..N` plan line, or a +plan that doesn't match the number of tests run (a test that died partway +through). Files with no TAP output are not checked. `make results` (via +`verify-results` in its default `pgtap` mode) gains the same plan checks +and the `test/install` scan. See `PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT` to +disable the `make test` side. Part of #106. + +== New features + +=== Add `PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT` +Set to `no` to stop `make test` from checking pgTap output (see above). +`make results` still runs the check in `pgtap` mode; use +`PGXNTOOL_ENABLE_VERIFY_RESULTS=no` to bypass it there. + 2.4.0 ----- == Breaking changes diff --git a/README.asc b/README.asc index 92f132d..910003f 100644 --- a/README.asc +++ b/README.asc @@ -52,7 +52,9 @@ Warns if two `$(DOCS)` entries would install to the same filename, which would o === test Runs your extension's test suite: filesystem-installs the extension (unless `PGXNTOOL_ENABLE_FS_INSTALL=no`) and runs it through PGXS's `installcheck`, first pulling in anything you've hooked into <<_testdeps>> and, if enabled, sanity-checking your test SQL via <<_test_build>>. -`make test` also fails on two safeguard checks: +`make test` also fails on these safeguard checks: + +- The pgTap output check, run after `pg_regress` finishes: fails if `test/results/*.out` or the <<_testinstall,test/install>> actual output has a `not ok` line without `# TODO`, a missing or duplicate `1..N` plan line, or a different number of tests than planned -- even when the output matches its expected file, so a blessed failure still fails. Files with no TAP output are not checked. See <<_pgxntool_enable_check_tap_output>>. - The stale-expected-file check, run after `pg_regress` finishes: fails if `test/expected/` (or `test/build/expected/`) has a `.out` file with no matching `.sql`, or a file that isn't `.out`. See <<_pgxntool_enable_check_stale_expected>>. - When <<_testinstall,test/install>> is in use, the `ON_ERROR_STOP` check: fails if any `test/install/*.sql` file neither includes `test/pgxntool/psql.sql` nor sets `ON_ERROR_STOP` itself. See <<_pgxntool_enable_test_install_error_stop_check>>. @@ -68,7 +70,7 @@ Whether `test-build` runs is controlled by the `PGXNTOOL_ENABLE_TEST_BUILD` vari NOTE: `test` intentionally does *not* depend on `clean` — that caused problems with incremental/watch-based builds. If your tests need a clean build to pass, that's a sign of a missing dependency elsewhere rather than something to fix by adding `clean` back. -NOTE: `test` exits non-zero (after printing `regression.diffs`) if any test fails, so CI and other automation can rely on its exit code. +NOTE: `test` exits non-zero (after printing any pgTap problems and `regression.diffs`) if any test fails, so CI and other automation can rely on its exit code. NOTE: While you can still run `make installcheck` or any other valid PGXS make target directly, it's recommended to use `make test` when using pgxntool. The `test` target ensures proper test isolation and correct dependency installation. @@ -206,7 +208,7 @@ Without `test/install`, each test file typically needs to run `CREATE EXTENSION` **Key detail:** Install files and regular tests run in a single `pg_regress` invocation. This means the database is NOT dropped between install and test phases — state created by install files persists into the main test suite. -WARNING: **`+test/install/*.out+` is never actually compared against anything.** Unlike every other test type pgxntool supports, the `test/install` directory's actual output is written to the exact same file as its expected output, so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. The *only* thing that still fails the build is a hard SQL error, and only if the file sets `ON_ERROR_STOP` (directly, or via `\i test/pgxntool/psql.sql`) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (`_check-test-install-error-stop`, see `PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK` to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in `test/sql` instead (or use pgTap assertions from within the install file itself). +WARNING: **`+test/install/*.out+` is never actually compared against anything.** Unlike every other test type pgxntool supports, the `test/install` directory's actual output is written to the exact same file as its expected output, so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. Apart from pgTap failures (below), the *only* thing that still fails the build is a hard SQL error, and only if the file sets `ON_ERROR_STOP` (directly, or via `\i test/pgxntool/psql.sql`) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (`_check-test-install-error-stop`, see `PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK` to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in `test/sql` instead, or use pgTap assertions from within the install file itself: its actual output goes through the same pgTap output check as `test/sql` (see <<_pgxntool_enable_check_tap_output>>), so a `not ok` or plan problem there does fail `make test`. ==== Update & Upgrade (U&U) Testing @@ -274,7 +276,7 @@ Never run `make results` without first verifying the test changes are correct. T ==== verify-results safeguard By default, `make results` will refuse to run if your tests are failing, so you can't accidentally promote incorrect output into the new expected results. Which failures it looks for is controlled by `PGXNTOOL_VERIFY_RESULTS_MODE`, which must be one of these two values (case-insensitive; anything else is a hard `make` error): -`pgtap` (the default):: Scans `test/results/*.out` for pgTAP `not ok` lines (ignoring `# TODO` items) and plan-count mismatches, then also checks `test/regression.diffs` for any output mismatch pgTAP itself wouldn't catch. A test that has no expected output file yet is the one exception: it always shows up in `regression.diffs` (pgxntool creates an empty expected file for it, because `pg_regress` aborts on a missing one), so `make results` is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. +`pgtap` (the default):: Scans `test/results/*.out` and the <<_testinstall,test/install>> actual output for pgTAP `not ok` lines (ignoring `# TODO` items), missing or duplicate plan lines, and plan-count mismatches (the same check `make test` runs; it applies here regardless of `PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT`), then also checks `test/regression.diffs` for any output mismatch pgTAP itself wouldn't catch. A test that has no expected output file yet is the one exception: it always shows up in `regression.diffs` (pgxntool creates an empty expected file for it, because `pg_regress` aborts on a missing one), so `make results` is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. `diffs`:: Only checks whether `test/regression.diffs` exists, so it can't create a new test's first expected output; use `pgtap` mode, or `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` for that one run. If tests are failing, `make results` prints an explanation of what failed and exits without touching `test/expected/`; fix the failures, then re-run `make results`. @@ -826,6 +828,10 @@ Default: `yes`. Enables or disables the `_check-stale-expected` safeguard, which This is also the supported pattern for disabling one specific optional pgxntool feature: a documented `PGXNTOOL_ENABLE_*` variable, gating both the target's registration into `TEST_DEPS`/etc. and (where applicable) the target's own definition. Cleanly replacing or overriding an arbitrary pgxntool-generated recipe with your own entirely is a separate, larger, and not-yet-decided design question -- see https://github.com/Postgres-Extensions/pgxntool/issues/30[issue #30] (two proposed approaches) -- and is *not* what this mechanism solves. +=== PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT * + +Default: `yes`. Enables or disables the pgTap output check that `make test` runs after `pg_regress`: it fails on a `not ok` line without `# TODO`, a missing or duplicate `1..N` plan line, or a plan/test count mismatch in `test/results/*.out` or the <<_testinstall,test/install>> actual output. Files with no TAP output are not checked. This governs only `make test`; the <<_verify_results_safeguard,verify-results safeguard>>'s `pgtap` mode always runs the same check before `make results` (use `PGXNTOOL_ENABLE_VERIFY_RESULTS=no` to bypass it there). + === PGXNTOOL_CHECK_EXPECTED_FILE_TYPES * Default: `yes`. Sub-check of `_check-stale-expected`, independent of `PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED`: fails (with a distinct error message and exit code from the orphaned-`.out` check) if `test/expected/` (or `test/build/expected/`) contains any file that isn't `*.out`. Set to `no` to disable just this sub-check while leaving the orphaned-`.out` check active. diff --git a/README.html b/README.html index 10a92d7..8cea436 100644 --- a/README.html +++ b/README.html @@ -518,8 +518,9 @@

PGXNtool

  • 8.14. PGXNTOOL_ENABLE_PGXN_INSTALL *
  • 8.15. PGXNTOOL_ENABLE_VERIFY_RESULTS *
  • 8.16. PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED *
  • -
  • 8.17. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *
  • -
  • 8.18. PGXNTOOL_NO_PGXS_INCLUDE
  • +
  • 8.17. PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *
  • +
  • 8.18. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *
  • +
  • 8.19. PGXNTOOL_NO_PGXS_INCLUDE
  • 9. General PostgreSQL Notes
  • @@ -633,11 +634,14 @@

    Runs your extension’s test suite: filesystem-installs the extension (unless PGXNTOOL_ENABLE_FS_INSTALL=no) and runs it through PGXS’s installcheck, first pulling in anything you’ve hooked into testdeps and, if enabled, sanity-checking your test SQL via test-build.

    -

    make test also fails on two safeguard checks:

    +

    make test also fails on these safeguard checks:

    • +

      The pgTap output check, run after pg_regress finishes: fails if test/results/*.out or the test/install actual output has a not ok line without # TODO, a missing or duplicate 1..N plan line, or a different number of tests than planned — even when the output matches its expected file, so a blessed failure still fails. Files with no TAP output are not checked. See PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *.

      +
    • +
    • The stale-expected-file check, run after pg_regress finishes: fails if test/expected/ (or test/build/expected/) has a .out file with no matching .sql, or a file that isn’t .out. See PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED *.

    • @@ -683,7 +687,7 @@

      Note

    -test exits non-zero (after printing regression.diffs) if any test fails, so CI and other automation can rely on its exit code. +test exits non-zero (after printing any pgTap problems and regression.diffs) if any test fails, so CI and other automation can rely on its exit code. @@ -926,7 +930,7 @@

    Warning -test/install/*.out is never actually compared against anything. Unlike every other test type pgxntool supports, the test/install directory’s actual output is written to the exact same file as its expected output, so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. The only thing that still fails the build is a hard SQL error, and only if the file sets ON_ERROR_STOP (directly, or via \i test/pgxntool/psql.sql) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (_check-test-install-error-stop, see PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in test/sql instead (or use pgTap assertions from within the install file itself). +test/install/*.out is never actually compared against anything. Unlike every other test type pgxntool supports, the test/install directory’s actual output is written to the exact same file as its expected output, so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. Apart from pgTap failures (below), the only thing that still fails the build is a hard SQL error, and only if the file sets ON_ERROR_STOP (directly, or via \i test/pgxntool/psql.sql) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (_check-test-install-error-stop, see PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in test/sql instead, or use pgTap assertions from within the install file itself: its actual output goes through the same pgTap output check as test/sql (see PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *), so a not ok or plan problem there does fail make test. @@ -1088,7 +1092,7 @@

    pgtap (the default)
    -

    Scans test/results/*.out for pgTAP not ok lines (ignoring # TODO items) and plan-count mismatches, then also checks test/regression.diffs for any output mismatch pgTAP itself wouldn’t catch. A test that has no expected output file yet is the one exception: it always shows up in regression.diffs (pgxntool creates an empty expected file for it, because pg_regress aborts on a missing one), so make results is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    +

    Scans test/results/*.out and the test/install actual output for pgTAP not ok lines (ignoring # TODO items), missing or duplicate plan lines, and plan-count mismatches (the same check make test runs; it applies here regardless of PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT), then also checks test/regression.diffs for any output mismatch pgTAP itself wouldn’t catch. A test that has no expected output file yet is the one exception: it always shows up in regression.diffs (pgxntool creates an empty expected file for it, because pg_regress aborts on a missing one), so make results is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    diffs
    @@ -2179,13 +2183,19 @@

    -

    8.17. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *

    +

    8.17. PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *

    +
    +

    Default: yes. Enables or disables the pgTap output check that make test runs after pg_regress: it fails on a not ok line without # TODO, a missing or duplicate 1..N plan line, or a plan/test count mismatch in test/results/*.out or the test/install actual output. Files with no TAP output are not checked. This governs only make test; the verify-results safeguard's pgtap mode always runs the same check before make results (use PGXNTOOL_ENABLE_VERIFY_RESULTS=no to bypass it there).

    +
    + +
    +

    8.18. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *

    Default: yes. Sub-check of _check-stale-expected, independent of PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED: fails (with a distinct error message and exit code from the orphaned-.out check) if test/expected/ (or test/build/expected/) contains any file that isn’t *.out. Set to no to disable just this sub-check while leaving the orphaned-.out check active.

    -

    8.18. PGXNTOOL_NO_PGXS_INCLUDE

    +

    8.19. PGXNTOOL_NO_PGXS_INCLUDE

    Default: unset (PGXS is included normally). Skips including PGXS ($(PGXS)) entirely. This is only for advanced scenarios where you need to manage the PGXS include yourself; most projects should never set this.

    @@ -2217,7 +2227,7 @@
    -test/install/*.out is never actually compared against anything. Unlike every other test type pgxntool supports, the test/install directory’s actual output is written to the exact same file as its expected output, so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. Apart from pgTap failures (below), the only thing that still fails the build is a hard SQL error, and only if the file sets ON_ERROR_STOP (directly, or via \i test/pgxntool/psql.sql) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (_check-test-install-error-stop, see PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in test/sql instead, or use pgTap assertions from within the install file itself: its actual output goes through the same pgTap output check as test/sql (see PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *), so a not ok or plan problem there does fail make test. +test/install/*.out is never actually compared against anything. Unlike every other test type pgxntool supports, the test/install directory’s actual output is written to the exact same file as its expected output (in $(TESTDIR)/install/, even when TESTOUT is set; see TESTOUT), so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. Apart from pgTap failures (below), the only thing that still fails the build is a hard SQL error, and only if the file sets ON_ERROR_STOP (directly, or via \i test/pgxntool/psql.sql) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (_check-test-install-error-stop, see PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in test/sql instead, or use pgTap assertions from within the install file itself: its actual output goes through the same pgTap output check as test/sql (see PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *), so a not ok or plan problem there does fail make test. @@ -2116,7 +2116,7 @@

    8.8. TESTOUT

    -

    Default: $(TESTDIR). Directory pg_regress writes actual test output to — $(TESTOUT)/results/, $(TESTOUT)/regression.diffs, etc. — via --outputdir in REGRESS_OPTS. Kept separate from TESTDIR so generated output can be pointed somewhere other than the directory holding your checked-in sql/expected files, if you want that separation.

    +

    Default: $(TESTDIR). Directory pg_regress writes actual test output to — $(TESTOUT)/results/, $(TESTOUT)/regression.diffs, etc. — via --outputdir in REGRESS_OPTS. Kept separate from TESTDIR so generated output can be pointed somewhere other than the directory holding your checked-in sql/expected files, if you want that separation. The one exception is test/install output, which always lands in $(TESTDIR)/install/ (gitignored): when TESTOUT differs from TESTDIR, make test creates $(TESTOUT)/install as a symlink to it, and fails rather than replace anything else already at that path.

    @@ -2227,7 +2227,7 @@

    +
    pgtap-only
    +
    +

    Like pgtap, except that a test whose output is TAP is judged only by its pgTAP output and by having no SQL error line; its regression.diffs entry is ignored. This mode governs make test too; see pgtap-only.

    +
    diffs

    Only checks whether test/regression.diffs exists, so it can’t create a new test’s first expected output; use pgtap mode, or PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    @@ -1112,7 +1119,7 @@

    # In your Makefile
    -PGXNTOOL_VERIFY_RESULTS_MODE = diffs  # or pgtap (the default)
    +PGXNTOOL_VERIFY_RESULTS_MODE = diffs # or pgtap-only, or pgtap (the default)
    @@ -2122,7 +2129,7 @@

    8.9. PGXNTOOL_VERIFY_RESULTS_MODE

    -

    Default: pgtap. Controls how the verify-results safeguard decides whether tests are failing. Must be pgtap or diffs (case-insensitive) when given explicitly; any other value, including an empty one, is a hard make error.

    +

    Default: pgtap. Controls how the verify-results safeguard decides whether tests are failing. Must be pgtap, pgtap-only or diffs (case-insensitive) when given explicitly; any other value, including an empty one, is a hard make error.

    8.9.1. pgtap

    @@ -2131,7 +2138,19 @@

    -

    8.9.2. diffs

    +

    8.9.2. pgtap-only

    +
    +

    For pgTap suites whose output can’t byte-match a committed expected file, such as assertion descriptions that embed a per-run role name. A test whose result file is TAP output (it has a top-level ok N, not ok N or 1..N line) passes on two things: the pgTap output check, and no SQL error line (ERROR: as psql prints it). Its regression.diffs entry is ignored. This applies to make test as well as make results; make test prints one NOTE line naming the TAP tests whose differences it ignored.

    +
    +
    +

    A test without TAP output is still judged by its diff: any difference fails make test, and make results applies the pgtap rules above. test/install output gets the pgTap output check only.

    +
    +
    +

    Requires PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT=yes; setting it to no in this mode is a hard make error, since TAP tests would then pass on nothing.

    +
    +
    +
    +

    8.9.3. diffs

    Checks only for regression.diffs, matching classic pg_regress behavior. Use this mode when your tests use plain SQL expected-output comparison only.

    @@ -2185,7 +2204,7 @@

    8.17. PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *

    -

    Default: yes. Enables or disables the pgTap output check that make test runs after pg_regress: it fails on a not ok line without # TODO, a missing or duplicate 1..N plan line, or a plan/test count mismatch in test/results/*.out or the test/install actual output. Files with no TAP output are not checked. This governs only make test; the verify-results safeguard's pgtap mode always runs the same check before make results (use PGXNTOOL_ENABLE_VERIFY_RESULTS=no to bypass it there).

    +

    Default: yes. Enables or disables the pgTap output check that make test runs after pg_regress: it fails on a not ok line without # TODO, a missing or duplicate 1..N plan line, or a plan/test count mismatch in test/results/*.out or the test/install actual output. Files with no TAP output are not checked. This governs only make test; the verify-results safeguard's pgtap and pgtap-only modes always run the same check before make results (use PGXNTOOL_ENABLE_VERIFY_RESULTS=no to bypass it there).

    @@ -2227,7 +2246,7 @@

    • -

      The pgTap output check, run after pg_regress finishes: fails if test/results/*.out or the test/install actual output has a not ok line without # TODO, a missing or duplicate 1..N plan line, or a different number of tests than planned — even when the output matches its expected file, so a blessed failure still fails. Files with no TAP output are not checked. See PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *.

      +

      The pgTap output check, run after pg_regress finishes: fails if test/results/*.out or the test/install actual output has a not ok line without # TODO, a missing or duplicate 1..N plan line, or a different number of tests than planned — even when the output matches its expected file, so a blessed failure still fails. Files with no TAP output are not checked. Runs unless PGXNTOOL_VERIFY_RESULTS_MODE is diffs.

    • regression.diffs: any difference from expected output fails, except, under PGXNTOOL_VERIFY_RESULTS_MODE=pgtap-only, in a test whose output is TAP. Such a test fails instead on a SQL error line, and make test prints a NOTE naming the TAP tests whose differences it ignored.

      @@ -933,7 +932,7 @@

      Warning

    -test/install/*.out is never actually compared against anything. Unlike every other test type pgxntool supports, the test/install directory’s actual output is written to the exact same file as its expected output (in $(TESTDIR)/install/, even when TESTOUT is set; see TESTOUT), so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. Apart from pgTap failures (below), the only thing that still fails the build is a hard SQL error, and only if the file sets ON_ERROR_STOP (directly, or via \i test/pgxntool/psql.sql) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (_check-test-install-error-stop, see PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in test/sql instead, or use pgTap assertions from within the install file itself: its actual output goes through the same pgTap output check as test/sql (see PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *), so a not ok or plan problem there does fail make test. +test/install/*.out is never actually compared against anything. Unlike every other test type pgxntool supports, the test/install directory’s actual output is written to the exact same file as its expected output (in $(TESTDIR)/install/, even when TESTOUT is set; see TESTOUT), so there is no diff — a wrong or changed result will never fail the build, no matter how much it changes. Apart from pgTap failures (below), the only thing that still fails the build is a hard SQL error, and only if the file sets ON_ERROR_STOP (directly, or via \i test/pgxntool/psql.sql) — without it, psql prints the error, keeps going, and the file "passes" regardless. pgxntool enforces this by default (_check-test-install-error-stop, see PGXNTOOL_ENABLE_TEST_INSTALL_ERROR_STOP_CHECK to disable), but that only guarantees errors are caught — it does not give you real output validation. If you need actual output comparison, put that logic in test/sql instead, or use pgTap assertions from within the install file itself: its actual output goes through the same pgTap output check as test/sql (see PGXNTOOL_VERIFY_RESULTS_MODE), so a not ok or plan problem there does fail make test. @@ -1095,7 +1094,7 @@

    pgtap (the default)
    -

    Scans test/results/*.out and the test/install actual output for pgTAP not ok lines (ignoring # TODO items), missing or duplicate plan lines, and plan-count mismatches (the same check make test runs; it applies here regardless of PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT), then also checks test/regression.diffs for any output mismatch pgTAP itself wouldn’t catch. A test that has no expected output file yet is the one exception: it always shows up in regression.diffs (pgxntool creates an empty expected file for it, because pg_regress aborts on a missing one), so make results is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    +

    Scans test/results/*.out and the test/install actual output for pgTAP not ok lines (ignoring # TODO items), missing or duplicate plan lines, and plan-count mismatches (the same check make test runs in this mode), then also checks test/regression.diffs for any output mismatch pgTAP itself wouldn’t catch. A test that has no expected output file yet is the one exception: it always shows up in regression.diffs (pgxntool creates an empty expected file for it, because pg_regress aborts on a missing one), so make results is allowed to create its first expected output — provided its own pgTAP output is clean and free of SQL errors. If a new test legitimately needs output containing a SQL error blessed, use PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    pgtap-only
    @@ -1103,7 +1102,7 @@

    diffs
    -

    Only checks whether test/regression.diffs exists, so it can’t create a new test’s first expected output; use pgtap mode, or PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    +

    Only checks whether test/regression.diffs exists, and make test skips the pgTap output check. It can’t create a new test’s first expected output; use pgtap mode, or PGXNTOOL_ENABLE_VERIFY_RESULTS=no for that one run.

    @@ -2129,7 +2128,7 @@

    8.9. PGXNTOOL_VERIFY_RESULTS_MODE

    -

    Default: pgtap. Controls how the verify-results safeguard decides whether tests are failing. Must be pgtap, pgtap-only or diffs (case-insensitive) when given explicitly; any other value, including an empty one, is a hard make error.

    +

    Default: pgtap. Controls how the verify-results safeguard decides whether tests are failing, and whether make test runs the pgTap output check (it does in pgtap and pgtap-only modes, and skips it in diffs mode). Must be pgtap, pgtap-only or diffs (case-insensitive) when given explicitly; any other value, including an empty one, is a hard make error.

    -
    -

    Requires PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT=yes; setting it to no in this mode is a hard make error, since TAP tests would then pass on nothing.

    -

    8.9.3. diffs

    -

    Checks only for regression.diffs, matching classic pg_regress behavior. Use this mode when your tests use plain SQL expected-output comparison only.

    +

    Checks only for regression.diffs, matching classic pg_regress behavior; make test skips the pgTap output check. Use this mode when your tests use plain SQL expected-output comparison only.

    @@ -2202,19 +2198,13 @@

    -

    8.17. PGXNTOOL_ENABLE_CHECK_TAP_OUTPUT *

    -
    -

    Default: yes. Enables or disables the pgTap output check that make test runs after pg_regress: it fails on a not ok line without # TODO, a missing or duplicate 1..N plan line, or a plan/test count mismatch in test/results/*.out or the test/install actual output. Files with no TAP output are not checked. This governs only make test; the verify-results safeguard's pgtap and pgtap-only modes always run the same check before make results (use PGXNTOOL_ENABLE_VERIFY_RESULTS=no to bypass it there).

    -
    - -
    -

    8.18. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *

    +

    8.17. PGXNTOOL_CHECK_EXPECTED_FILE_TYPES *

    Default: yes. Sub-check of _check-stale-expected, independent of PGXNTOOL_ENABLE_CHECK_STALE_EXPECTED: fails (with a distinct error message and exit code from the orphaned-.out check) if test/expected/ (or test/build/expected/) contains any file that isn’t *.out. Set to no to disable just this sub-check while leaving the orphaned-.out check active.

    -

    8.19. PGXNTOOL_NO_PGXS_INCLUDE

    +

    8.18. PGXNTOOL_NO_PGXS_INCLUDE

    Default: unset (PGXS is included normally). Skips including PGXS ($(PGXS)) entirely. This is only for advanced scenarios where you need to manage the PGXS include yourself; most projects should never set this.

    @@ -2246,7 +2236,7 @@