Files
rune/scripts/gen_connection_pool_truth.py
T

255 lines
10 KiB
Python

#!/usr/bin/env python3
"""gen_connection_pool_truth.py — freeze the connection_pool parity oracle
(dichotomy wave #2479 tranche).
Generator law: RUNE_CPOOL_CORE=python pinned (the Rust core must never see
the freeze), inputs deep-copied, every public kernel branch exercised
(new / reuse / stale-removal / capacity-eviction / commit / status /
close_all) against a REAL sqlite-backed pool in a temp dir. Output:
src/rust/connection_pool/frozen_cpool_truth.json — replayed VERBATIM by the
crate's cfg(test) battery.
"""
import copy
import json
import os
import sys
import tempfile
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
os.environ["RUNE_CPOOL_CORE"] = "python"
from rune import connection_pool as cp_mod # noqa: E402
from rune.connection_pool import ConnectionPool # noqa: E402
MAX = 2
cases: list = []
def pool_state(p: ConnectionPool) -> dict:
"""The kernel-shaped pool state, as the oracle holds it right now."""
st = p.get_status()
return {"max_connections": st["max_connections"],
"databases": copy.deepcopy(st["databases"])}
def record_begin_get(p: ConnectionPool, db_path: str, valid: bool) -> None:
"""Run one oracle get_connection op and freeze it: a cpool_begin_get
case (and, when the oracle created a connection, the matching
cpool_commit case)."""
before = pool_state(p)
pooled_before = dict(p.connections)
conn = p.get_connection(db_path)
after_full = pool_state(p)
reuse = db_path in pooled_before and conn is pooled_before[db_path]
if reuse:
after_begin = copy.deepcopy(before)
else:
after_begin = {"max_connections": after_full["max_connections"],
"databases": [d for d in after_full["databases"]
if d != db_path]}
evicted = (set(before["databases"]) - set(after_full["databases"])
- {db_path})
cases.append({
"fn": "cpool_begin_get",
"args": {"pool": copy.deepcopy(before), "db_path": db_path,
"valid": valid},
"expected": {"pool": after_begin, "reuse": reuse,
"evict": sorted(evicted)[0] if evicted else None},
})
if not reuse:
cases.append({
"fn": "cpool_commit",
"args": {"pool": copy.deepcopy(after_begin), "db_path": db_path},
"expected": {"pool": copy.deepcopy(after_full)},
})
def main() -> None:
with tempfile.TemporaryDirectory() as td:
p = ConnectionPool(max_connections=MAX)
cases.append({
"fn": "cpool_new",
"args": {"max_connections": MAX},
"expected": copy.deepcopy(pool_state(p)),
})
dbs = [os.path.join(td, f"{n}.db") for n in "ABCD"]
record_begin_get(p, dbs[0], True) # create A
record_begin_get(p, dbs[0], True) # reuse A
record_begin_get(p, dbs[1], True) # create B
record_begin_get(p, dbs[2], True) # create C — evicts A
# force B stale: close the underlying connection, then re-get
p.connections[dbs[1]].close()
record_begin_get(p, dbs[1], False) # stale B — no evict
record_begin_get(p, dbs[3], True) # create D — evicts C
before_status = pool_state(p)
cases.append({
"fn": "cpool_status",
"args": {"pool": copy.deepcopy(before_status)},
"expected": copy.deepcopy(p.get_status()),
})
before_close = pool_state(p)
p.close_all()
cases.append({
"fn": "cpool_close_all",
"args": {"pool": copy.deepcopy(before_close)},
"expected": copy.deepcopy(pool_state(p)),
})
record_begin_get(p, dbs[0], True) # fresh pool: create A
# ── orchestration residue: get_pool / _kernel_state /
# _get_connection_core (literal-100%) ─────────────────────
# A recording stand-in for the kernel protocol (new_pool /
# begin_get / commit / close_all / status), semantics identical
# to the facade's own python-path dict bookkeeping — the
# ORCHESTRATION under test is the oracle's _get_connection_core
# body itself; the state math is already parity-frozen above.
class RecordingCore:
def __init__(self, max_c):
self.max_c = max_c
self.calls = []
def new_pool(self, max_connections):
self.calls.append(f"new_pool:{max_connections}")
return {"max_connections": max_connections, "databases": []}
def begin_get(self, pool, db_path, valid):
dbs = pool["databases"]
if db_path in dbs:
if valid:
self.calls.append(f"begin_get:{os.path.basename(db_path)}:{valid}")
return {"pool": copy.deepcopy(pool), "reuse": True, "evict": None}
dbs = [d for d in dbs if d != db_path]
evict = None
if len(dbs) >= pool["max_connections"] and dbs:
evict = dbs.pop(0)
self.calls.append(f"begin_get:{os.path.basename(db_path)}:{valid}")
return {"pool": {"max_connections": pool["max_connections"],
"databases": dbs},
"reuse": False, "evict": evict}
def commit(self, pool, db_path):
self.calls.append(f"commit:{os.path.basename(db_path)}")
return {"max_connections": pool["max_connections"],
"databases": pool["databases"] + [db_path]}
def close_all(self, pool):
self.calls.append("close_all")
return {"max_connections": pool["max_connections"], "databases": []}
def status(self, pool):
self.calls.append("status")
return {"connections": len(pool["databases"]),
"max_connections": pool["max_connections"],
"databases": list(pool["databases"])}
# 1. _kernel_state lazy law (a fresh pool has NO kernel state; the
# first core op initializes it at the instance's max)
lazy_p = ConnectionPool(max_connections=2)
core = RecordingCore(2)
before = lazy_p._state
lazy_p._kernel_state(core)
cases.append({
"fn": "cpool_kernel_state_lazy",
"args": {},
"expected": {"before": before,
"after": lazy_p._state},
})
# 2. _get_connection_core orchestration over a real sqlite-backed
# pool: the full op ladder with the core-call trace + status
# snapshots frozen per op
orch_p = ConnectionPool(max_connections=2)
orch_core = RecordingCore(2)
orch_dbs = [os.path.join(td, f"{n}.db") for n in "abcd"]
orch = []
def orch_get(db_path):
handles_before = dict(orch_p.connections)
conn = orch_p._get_connection_core(orch_core, db_path)
reused = db_path in handles_before and conn is handles_before[db_path]
st = orch_core.status(orch_p._state)
st["databases"] = [d.replace(td, "TMPDIR") for d in st["databases"]]
orch.append({"db": os.path.basename(db_path),
"pooled": db_path in handles_before,
"reuse": reused,
"status": st})
return conn
orch_get(orch_dbs[0]) # create a
orch_get(orch_dbs[0]) # reuse a
orch_get(orch_dbs[1]) # create b
orch_get(orch_dbs[2]) # create c — evicts a
orch_p.connections[orch_dbs[1]].close() # force b stale
orch_get(orch_dbs[1]) # stale b — rejoin at END
orch_get(orch_dbs[3]) # create d — evicts c
cases.append({
"fn": "cpool_get_connection_core",
"args": {},
"expected": {"ops": orch, "core_calls": orch_core.calls},
})
# 3. the connect-failure branch: the exception propagates and the
# pool stays exactly as begin_get left it — NO commit
fail_p = ConnectionPool(max_connections=2)
fail_core = RecordingCore(2)
fail_p._get_connection_core(fail_core, orch_dbs[0])
real_sqlite = cp_mod.sqlite3
import types as _types
class _ConnectFail(Exception):
pass
cp_mod.sqlite3 = _types.SimpleNamespace(
connect=lambda *_a, **_k: (_ for _ in ()).throw(_ConnectFail("disk I/O error")),
Row=real_sqlite.Row)
try:
crashed = None
try:
fail_p._get_connection_core(fail_core, orch_dbs[1])
except Exception as e: # noqa: BLE001 — the crash class IS the truth
crashed = type(e).__name__
st = fail_core.status(fail_p._state)
st["databases"] = [d.replace(td, "TMPDIR") for d in st["databases"]]
cases.append({
"fn": "cpool_get_connection_core_connect_fail",
"args": {},
"expected": {"crash": crashed, "status": st,
"core_calls": fail_core.calls},
})
finally:
cp_mod.sqlite3 = real_sqlite
# 4. get_pool singleton law (fresh module state, one process)
import rune.connection_pool as cp_singleton
cp_singleton._pool = None
p1 = cp_singleton.get_pool()
p2 = cp_singleton.get_pool()
cases.append({
"fn": "cpool_get_pool_singleton",
"args": {},
"expected": {"same": p1 is p2, "max_connections": p1.max_connections},
})
doc = {
"module": "connection_pool",
"pin": "RUNE_CPOOL_CORE=python",
"frozen_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"cases": cases,
}
out = ROOT / "src" / "rust" / "connection_pool" / "frozen_cpool_truth.json"
out.write_text(json.dumps(doc, indent=1) + "\n")
print(f"frozen {len(cases)} cases -> {out}")
if __name__ == "__main__":
main()