From b18cded4c2056080088b172aee96bffba0a6d72f Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Tue, 17 Feb 2026 14:26:53 -0700 Subject: [PATCH] Add PG version test matrix (14-18) Shell script drives the Dockerfile builder stage across PG versions, capturing pass/fail + timing per version. Makefile targets: test-matrix, test-pg%, test-matrix-clean. Also runs standalone DE reader test in the builder stage to catch compiler-version regressions. Fix pork chop grid test: add ORDER BY to CROSS JOIN (optimizer chooses different join nesting across PG versions, reordering rows). --- .gitignore | 4 ++ CLAUDE.md | 15 +++++ Dockerfile | 3 + Makefile | 17 ++++++ test/expected/lambert_transfer.out | 7 ++- test/pg-version-matrix.sh | 92 ++++++++++++++++++++++++++++++ test/sql/lambert_transfer.sql | 3 +- 7 files changed, 137 insertions(+), 4 deletions(-) create mode 100755 test/pg-version-matrix.sh diff --git a/.gitignore b/.gitignore index 6171108..f474074 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,10 @@ log/ .vscode/ .idea/ +# Test artifacts +test/matrix-logs/ +test/test_de_reader + # Docs site docs/node_modules/ docs/dist/ diff --git a/CLAUDE.md b/CLAUDE.md index 640b1a2..a44548d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -257,6 +257,21 @@ All numerical logic is byte-identical to upstream. Verified against 518 Vallado | de_ephemeris | DE function fallback to VSOP87, cross-provider consistency, error handling | | vallado_518 | 518 Vallado test vectors (AIAA 2006-6753-Rev1), per-satellite breakdown | +### PG Version Matrix + +Test all 13 regression suites + DE reader unit test across PostgreSQL 14-18 using Docker: + +```bash +make test-matrix # Full matrix (PG 14-18) +make test-pg18 # Single version +PG_TEST_VERSIONS="16 17" make test-matrix # Subset +make test-matrix-clean # Remove logs + test images +``` + +Logs saved to `test/matrix-logs/pg${ver}.log`. The script reuses the Dockerfile `builder` stage as the test engine — no additional test infrastructure. + +**Adding a new PG version:** Update `PG_TEST_VERSIONS` default in `Makefile` and `PG_VERSIONS` default in `test/pg-version-matrix.sh`. + ## Error Handling Patterns - `_safe()` variants (`sgp4_propagate_safe`, `observe_safe`, `star_observe_safe`) return NULL on error instead of raising exceptions. Use these for batch queries over potentially invalid data. diff --git a/Dockerfile b/Dockerfile index 9dec5d6..c5128de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,9 @@ RUN su postgres -c "/usr/lib/postgresql/${PG_MAJOR}/bin/initdb -D /tmp/pgtest" & make PG_CONFIG=${PG_CONFIG} installcheck && \ su postgres -c "/usr/lib/postgresql/${PG_MAJOR}/bin/pg_ctl -D /tmp/pgtest stop" +# Standalone DE reader unit test (no PostgreSQL dependency) +RUN make test-de-reader + # Capture artifacts under /pg_orrery prefix for the next stage RUN make PG_CONFIG=${PG_CONFIG} DESTDIR=/pg_orrery install diff --git a/Makefile b/Makefile index 55900c5..ed0d108 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,23 @@ test-de-reader: test/test_de_reader.c src/de_reader.c src/de_reader.h .PHONY: test-de-reader +# ── PG version test matrix ───────────────────────────────── +PG_TEST_VERSIONS ?= 14 15 16 17 18 + +test-matrix: + PG_VERSIONS="$(PG_TEST_VERSIONS)" bash test/pg-version-matrix.sh + +test-pg%: + PG_VERSIONS="$*" bash test/pg-version-matrix.sh + +test-matrix-clean: + rm -rf test/matrix-logs + @for v in $(PG_TEST_VERSIONS); do \ + docker rmi "pg_orrery-test:pg$$v" 2>/dev/null || true; \ + done + +.PHONY: test-matrix test-matrix-clean + # ── Docker packaging ──────────────────────────────────────── REGISTRY ?= git.supported.systems/warehack.ing IMAGE ?= pg_orrery diff --git a/test/expected/lambert_transfer.out b/test/expected/lambert_transfer.out index a21d379..756b934 100644 --- a/test/expected/lambert_transfer.out +++ b/test/expected/lambert_transfer.out @@ -125,14 +125,15 @@ SELECT 'pork_chop_mini' AS test, arr_date::date AS arr, round(lambert_c3(3, 4, dep_date, arr_date)::numeric, 1) AS c3 FROM generate_series('2026-04-01'::timestamptz, '2026-06-01'::timestamptz, interval '30 days') dep_date -CROSS JOIN generate_series('2027-01-01'::timestamptz, '2027-03-01'::timestamptz, interval '30 days') arr_date; +CROSS JOIN generate_series('2027-01-01'::timestamptz, '2027-03-01'::timestamptz, interval '30 days') arr_date +ORDER BY dep_date, arr_date; test | dep | arr | c3 ----------------+------------+------------+------- pork_chop_mini | 04-01-2026 | 01-01-2027 | 287.5 - pork_chop_mini | 05-01-2026 | 01-01-2027 | 215.8 - pork_chop_mini | 05-31-2026 | 01-01-2027 | 203.2 pork_chop_mini | 04-01-2026 | 01-31-2027 | 353.9 + pork_chop_mini | 05-01-2026 | 01-01-2027 | 215.8 pork_chop_mini | 05-01-2026 | 01-31-2027 | 215.2 + pork_chop_mini | 05-31-2026 | 01-01-2027 | 203.2 pork_chop_mini | 05-31-2026 | 01-31-2027 | 172.0 (6 rows) diff --git a/test/pg-version-matrix.sh b/test/pg-version-matrix.sh new file mode 100755 index 0000000..d1bd735 --- /dev/null +++ b/test/pg-version-matrix.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# test/pg-version-matrix.sh — Test pg_orrery across PostgreSQL versions +# +# Uses the Dockerfile builder stage as the test engine: compile, install, +# initdb, installcheck, and standalone DE reader test for each PG version. +# +# Usage: +# ./test/pg-version-matrix.sh # Test PG 14-18 +# PG_VERSIONS="16 17" ./test/pg-version-matrix.sh # Subset +# ./test/pg-version-matrix.sh --no-cache # Force fresh builds + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +LOG_DIR="$SCRIPT_DIR/matrix-logs" + +PG_VERSIONS="${PG_VERSIONS:-14 15 16 17 18}" + +# Parse flags +DOCKER_EXTRA_ARGS=() +for arg in "$@"; do + case "$arg" in + --no-cache) DOCKER_EXTRA_ARGS+=(--no-cache) ;; + *) echo "Unknown flag: $arg" >&2; exit 1 ;; + esac +done + +mkdir -p "$LOG_DIR" + +# Track results: "version status seconds" +declare -a RESULTS=() +FAILURES=0 + +echo "pg_orrery version matrix" +echo "========================" +echo "Versions: $PG_VERSIONS" +echo "Logs: $LOG_DIR/" +echo "" + +for ver in $PG_VERSIONS; do + log="$LOG_DIR/pg${ver}.log" + printf "Testing PG %-4s... " "$ver" + + start=$(date +%s) + + if docker build \ + --build-arg PG_MAJOR="$ver" \ + --target builder \ + "${DOCKER_EXTRA_ARGS[@]}" \ + -t "pg_orrery-test:pg${ver}" \ + "$PROJECT_DIR" \ + > "$log" 2>&1; then + end=$(date +%s) + elapsed=$((end - start)) + printf "PASS (%ds)\n" "$elapsed" + RESULTS+=("$ver PASS $elapsed") + else + end=$(date +%s) + elapsed=$((end - start)) + printf "FAIL (%ds) -> %s\n" "$elapsed" "$log" + RESULTS+=("$ver FAIL $elapsed") + FAILURES=$((FAILURES + 1)) + fi +done + +# Summary table +echo "" +echo "Summary" +echo "-------" +printf "%-6s %-6s %s\n" "PG" "Result" "Time" +printf "%-6s %-6s %s\n" "---" "------" "----" +for entry in "${RESULTS[@]}"; do + read -r ver status secs <<< "$entry" + printf "%-6s %-6s %ds\n" "$ver" "$status" "$secs" +done + +# Cleanup test images +echo "" +echo "Cleaning test images..." +for ver in $PG_VERSIONS; do + docker rmi "pg_orrery-test:pg${ver}" >/dev/null 2>&1 || true +done + +if [ "$FAILURES" -gt 0 ]; then + echo "" + echo "$FAILURES version(s) failed. Check logs in $LOG_DIR/" + exit 1 +fi + +echo "" +echo "All versions passed." diff --git a/test/sql/lambert_transfer.sql b/test/sql/lambert_transfer.sql index 8684e59..9268c8a 100644 --- a/test/sql/lambert_transfer.sql +++ b/test/sql/lambert_transfer.sql @@ -98,4 +98,5 @@ SELECT 'pork_chop_mini' AS test, arr_date::date AS arr, round(lambert_c3(3, 4, dep_date, arr_date)::numeric, 1) AS c3 FROM generate_series('2026-04-01'::timestamptz, '2026-06-01'::timestamptz, interval '30 days') dep_date -CROSS JOIN generate_series('2027-01-01'::timestamptz, '2027-03-01'::timestamptz, interval '30 days') arr_date; +CROSS JOIN generate_series('2027-01-01'::timestamptz, '2027-03-01'::timestamptz, interval '30 days') arr_date +ORDER BY dep_date, arr_date;