Skip to content

Read the arguments a wrapper gathers into a C array as one operand #463

Read the arguments a wrapper gathers into a C array as one operand

Read the arguments a wrapper gathers into a C array as one operand #463

Workflow file for this run

name: tests
# Dogfoods the reusable provision-meos composite action, the single step every
# binding uses to obtain the MEOS artifacts from one pinned MobilityDB commit.
# The action builds and installs all-families libmeos (incl. pgPointCloud via
# PGDG PG17) and derives output/meos-idl.json from the installed, self-contained
# headers, then the pytest suite (type recovery + struct layout + portable
# alias parity) runs against that catalog — the same catalog correctness signal
# master had before, now produced by the shared action and FFI-accurate.
on:
pull_request:
push:
branches: [master]
workflow_dispatch:
jobs:
tests:
name: Build libmeos + regenerate catalog + pytest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Build + install all-families libmeos and derive the catalog from the
# installed headers — the exact step a native/FFI binding runs.
- name: Provision the MEOS catalog and libmeos
id: provision
uses: ./.github/actions/provision-meos
with:
mobilitydb-ref: master
build-libmeos: "true"
- name: Assert libmeos.so is installed and print the family summary
run: |
test -f "${{ steps.provision.outputs.libmeos-prefix }}/lib/libmeos.so"
echo "libmeos installed at ${{ steps.provision.outputs.libmeos-prefix }}/lib/libmeos.so"
echo "----- cmake family summary -----"
grep -E 'Including|Excluding' "$RUNNER_TEMP/cmake-configure.log" || true
- name: Install pytest
run: pip install pytest
# PyMEOS is the object-model parity oracle. The audit reads its
# factory.py and degrades to `oracle-unavailable` without it, so the two
# parity gates assert nothing until it is on disk.
- name: Check out the PyMEOS oracle
uses: actions/checkout@v4
with:
repository: MobilityDB/PyMEOS
path: _pymeos
# The action wrote output/meos-idl.json at the repo root, exactly where
# the suite loads it from; assert the advertised path and run the tests.
#
# Every environment variable here is a precondition some test guards on,
# and a guard that fails makes the test SKIP: it asserts nothing and the
# job still reports success. This job already had the material for all of
# them and named none, so 11 of 268 tests never ran.
#
# MDB_SRC_ROOT the MobilityDB checkout the catalog came from; the
# drift gates read meos_catalog.c and meos_error.h.
# MEOS_LIBRARY_PATH the libmeos just built; the ctypes engine suite
# decodes, invokes and round-trips against it.
# MEOS_INCLUDE_DIR the installed headers; the vendored-provenance test
# splits them by owner.
# PYMEOS_FACTORY the parity oracle checked out above.
#
# Each is asserted before the run, so a moved path fails the job here
# rather than turning into a silent skip.
- name: Run the test suite
env:
MDB_SRC_ROOT: ${{ steps.provision.outputs.mobilitydb-src }}
MEOS_LIBRARY_PATH: ${{ steps.provision.outputs.libmeos-prefix }}/lib/libmeos.so
MEOS_INCLUDE_DIR: ${{ steps.provision.outputs.libmeos-prefix }}/include
PYMEOS_FACTORY: ${{ github.workspace }}/_pymeos/pymeos/factory.py
run: |
set -o pipefail
test -s "${{ steps.provision.outputs.catalog-path }}"
test -f "$MDB_SRC_ROOT/meos/src/temporal/meos_catalog.c"
test -f "$MEOS_LIBRARY_PATH"
test -f "$MEOS_INCLUDE_DIR/meos.h"
test -f "$PYMEOS_FACTORY"
python3 -m pytest tests/ -v -rs | tee "$RUNNER_TEMP/pytest.log"
# A skipped test is indistinguishable from a passing one in the job's
# conclusion, which is how the eleven went unnoticed. Every precondition
# is supplied and asserted above, so a skip now means a guard reads a
# condition this job no longer satisfies — a defect, not a circumstance.
#
# The floor is the second half, and it guards what the skip count cannot
# see: a test the run never collects is reported nowhere, so removing one
# leaves the skip count at zero while coverage leaves. Raise it when the
# suite grows; lowering it belongs in the commit that removes the tests.
# Run the script from this checkout rather than through the action, which
# would fetch master: a pull request must be checked by the rules it
# carries, or a change to them is not exercised until after it merges.
# Consumers use the action; this repository owns the rules.
- name: Refuse a skip, and a suite that shrank
run: tools/check-test-outcome.py "$RUNNER_TEMP/pytest.log" --min-tests 547
# The rules earn their place by refusing a log that carries what they
# name. Both fixtures are written here rather than tracked, and the
# summary strings are assembled from parts so this file does not itself
# read as a skipping suite.
- name: Prove the check can fail
run: |
set -e
SK="skip""ped"
printf '===== 257 passed, 11 %s in 13.58s =====\n' "$SK" > "$RUNNER_TEMP/fx-skip.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-skip.log" --min-tests 268; then
echo "::error::the check passed a log reporting skips and a shrunken suite"
exit 1
fi
printf '===== 267 passed in 13.58s =====\n' > "$RUNNER_TEMP/fx-shrank.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-shrank.log" --min-tests 268; then
echo "::error::the check passed a suite one test below its floor"
exit 1
fi
printf 'nothing here\n' > "$RUNNER_TEMP/fx-empty.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-empty.log" --min-tests 268; then
echo "::error::the check passed a log carrying no summary at all"
exit 1
fi
# The Go dialect, which MobilityAPI tees. It carries no counts of its
# own: the totals are the tally of the result lines `go test -v`
# writes, subtests included. The positive control comes first, so a
# regex that matched nothing would fail here rather than read as a
# clean log below.
{
printf -- '--- PASS: TestOne (0.01s)\n'
printf -- ' --- PASS: TestOne/case (0.00s)\n'
printf -- '--- PASS: TestTwo (0.00s)\n'
} > "$RUNNER_TEMP/fx-go-ok.log"
if ! tools/check-test-outcome.py "$RUNNER_TEMP/fx-go-ok.log" --min-tests 3; then
echo "::error::the check refused a Go log that satisfies both rules"
exit 1
fi
{
cat "$RUNNER_TEMP/fx-go-ok.log"
printf -- '--- SK''IP: TestThree (0.00s)\n'
} > "$RUNNER_TEMP/fx-go-skip.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-go-skip.log" --min-tests 3; then
echo "::error::the check passed a Go log reporting a skip"
exit 1
fi
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-go-ok.log" --min-tests 4; then
echo "::error::the check passed a Go suite below its floor"
exit 1
fi
printf 'ok \tgithub.com/x/y\t0.42s\n' > "$RUNNER_TEMP/fx-go-quiet.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-go-quiet.log" --min-tests 3; then
echo "::error::the check passed a Go log written without -v, which carries no counts"
exit 1
fi
# The VSTest dialect, which MEOS.NET tees. An assembly holding no
# test at all writes no summary and exits 0, so the log it leaves is
# the thing to refuse.
printf 'Passed! - Failed: 0, Passed: 38, Skip''ped: 0, Total: 38, Duration: 182 ms - A.dll (net8.0)\n' \
> "$RUNNER_TEMP/fx-vstest-ok.log"
if ! tools/check-test-outcome.py "$RUNNER_TEMP/fx-vstest-ok.log" --min-tests 38; then
echo "::error::the check refused a VSTest log that satisfies both rules"
exit 1
fi
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-vstest-ok.log" --min-tests 39; then
echo "::error::the check passed a VSTest suite below its floor"
exit 1
fi
printf 'Failed! - Failed: 0, Passed: 36, Skip''ped: 2, Total: 38, Duration: 190 ms - A.dll (net8.0)\n' \
> "$RUNNER_TEMP/fx-vstest-skip.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-vstest-skip.log" --min-tests 38; then
echo "::error::the check passed a VSTest log reporting skips"
exit 1
fi
printf 'No test is available in /src/A.dll. Make sure that test discoverer & executors are registered.\n' \
> "$RUNNER_TEMP/fx-vstest-empty.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-vstest-empty.log" --min-tests 1; then
echo "::error::the check passed a VSTest run over an assembly holding no test"
exit 1
fi
# The Catch2 dialect, which the DuckDB test runner writes and a
# MobilityDuck suite tees. The passing form's test-case count
# EXCLUDES the skipped cases, so the floor is read off the sum.
printf 'All tests passed (2695 assertions in 102 test cases)\n' \
> "$RUNNER_TEMP/fx-catch-ok.log"
if ! tools/check-test-outcome.py "$RUNNER_TEMP/fx-catch-ok.log" --min-tests 102; then
echo "::error::the check refused a Catch2 log that satisfies both rules"
exit 1
fi
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-catch-ok.log" --min-tests 103; then
echo "::error::the check passed a Catch2 suite below its floor"
exit 1
fi
printf 'All tests passed (3 skip''ped tests, 2695 assertions in 99 test cases)\n' \
> "$RUNNER_TEMP/fx-catch-skip.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-catch-skip.log" --min-tests 102; then
echo "::error::the check passed a Catch2 log reporting skipped tests"
exit 1
fi
# The failure table carries `101 passed`, which the pytest pattern
# matches too; reading it as pytest would report 101 as the total.
printf 'test cases: 102 | 101 passed | 1 failed\n' \
> "$RUNNER_TEMP/fx-catch-table.log"
if tools/check-test-outcome.py "$RUNNER_TEMP/fx-catch-table.log" --min-tests 102 \
| grep -q 'pytest'; then
echo "::error::the check read a Catch2 failure table as pytest"
exit 1
fi
echo "the check refuses a skip, a shrunken suite, and a log with no summary, in every dialect it reads"
- name: Upload meos-idl.json as artefact
if: always()
uses: actions/upload-artifact@v4
with:
name: meos-idl
path: output/meos-idl.json
if-no-files-found: error