Files
pad/scripts/ci-pg-trace_test.py
T
xarmian 65cbd98607 ci: the PG trace guard fails on drift both ways; main race failures are loud everywhere (TASK-4224 r1)
- ci-pg-trace.py --expect now fails when a listed package never connected,
  and when no connection was seen at all, not only on an unexpected package.
  An empty trace (a renamed helper, a lost env gate) used to pass vacuously.
  Red first: three table cases.
- ci-pg-packages.txt: the list was validated by the full traced run; its
  CANDIDATE label is replaced by what it is and what enforces it.
- ci.yml: the non-server race steps in Go and Go (PostgreSQL) get the same
  STOP THE LINE step race.yml has (::error:: plus a job summary), keyed on
  the race step's own outcome.
- race.yml: the stop-the-line step also fires on a cancelled run.

Claude-Session: https://claude.ai/code/session_01Pa22hLbfHJSsjBT1mPFoPF
2026-11-02 13:29:44 +00:00

89 lines
4.4 KiB
Python

"""CLI regression cases for the Postgres connection evidence extractor."""
import json
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
ROOT = Path(__file__).resolve().parent.parent
SCRIPT = ROOT / "scripts" / "ci-pg-trace.py"
MODULE = "github.com/PerpetualSoftware/pad"
def event(package, output="PAD_PG_CONNECTED helper=probe\n", action="output"):
return {"Action": action, "Package": package, "Test": "TestProbe", "Output": output}
class TraceTest(unittest.TestCase):
def test_cli(self):
cases = [
("empty", [], None, 0, [], []),
("sort and deduplicate", [event(MODULE + "/internal/store"),
event(MODULE + "/cmd/pad"),
event(MODULE + "/internal/store")],
None, 0, [MODULE + "/cmd/pad", MODULE + "/internal/store"], []),
("only output events with packages",
[event("ignored", action="pass"), event("ignored", "ordinary log\n"),
{"Action": "output", "Output": "PAD_PG_CONNECTED helper=probe"}],
None, 0, [], []),
("relative and import paths",
[event(MODULE + "/cmd/pad"), event(MODULE + "/internal/store")],
"# candidate\n\n./cmd/pad/\n" + MODULE + "/internal/store\n",
0, [MODULE + "/cmd/pad", MODULE + "/internal/store"], []),
("unexpected and missing",
[event(MODULE + "/internal/server"), event(MODULE + "/cmd/pad")],
"./internal/store\n",
1, [MODULE + "/cmd/pad", MODULE + "/internal/server"],
["unexpected: " + MODULE + "/cmd/pad",
"unexpected: " + MODULE + "/internal/server",
"expected package never connected: " + MODULE + "/internal/store"]),
# A listed package that stopped connecting means the list (or the
# trace marker) drifted: fatal, not a warning (TASK-4224 r1 H1).
("listed package missing while others connect",
[event(MODULE + "/cmd/pad")], "./cmd/pad\n./internal/store\n",
1, [MODULE + "/cmd/pad"],
["expected package never connected: " + MODULE + "/internal/store"]),
# No marker at all means the trace is broken (renamed helper, env
# gate lost): it must not pass vacuously.
("empty trace fails", [], "./internal/store\n", 1, [],
["expected package never connected: " + MODULE + "/internal/store",
"no PAD_PG_CONNECTED markers: the trace saw no connection at all"]),
("empty trace fails even against an empty list", [], "# only comments\n", 1, [],
["no PAD_PG_CONNECTED markers: the trace saw no connection at all"]),
("package output without a test",
[{"Action": "output", "Package": MODULE + "/internal/store",
"Output": "PAD_PG_CONNECTED helper=probe\n"}], "./internal/store\n",
0, [MODULE + "/internal/store"], []),
]
for name, events, expected, code, packages, diagnostics in cases:
with self.subTest(name=name), tempfile.TemporaryDirectory() as tmp:
args = [sys.executable, str(SCRIPT)]
if expected is not None:
expect = Path(tmp) / "expected.txt"
expect.write_text(expected)
args += ["--expect", str(expect)]
result = subprocess.run(
args, input="".join(json.dumps(row) + "\n" for row in events),
text=True, capture_output=True, cwd=tmp, check=False,
)
self.assertEqual(result.returncode, code, result.stderr)
self.assertEqual(result.stdout.splitlines(), packages)
self.assertEqual(result.stderr.splitlines(), diagnostics)
class HumanOutputTest(unittest.TestCase):
def test_output_can_be_mirrored_without_losing_trace(self):
row = event(MODULE + '/internal/store', 'ordinary test output\n')
result = subprocess.run([sys.executable, str(SCRIPT), '--show-output'],
input=json.dumps(row) + '\n', text=True,
capture_output=True, check=False)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stdout, 'ordinary test output\n')
if __name__ == "__main__":
unittest.main()