test: the request commit check sees Core DML and row locks

A db.execute(update/delete) fires no flush and stages nothing, so a handler whose
only write was Core DML could forget its commit and stay green. The check now
asks Postgres whether the request opened a writing transaction. It found one
real case: a repeated issue send returned with the session row still locked.
This commit is contained in:
2026-10-20 00:45:20 +02:00
parent d73cdcee97
commit e27656ee7e
3 changed files with 44 additions and 1 deletions
+12 -1
View File
@@ -105,6 +105,11 @@ def pytest_configure(config):
)
def _write_xact(db) -> str | None:
"""The id of the open transaction if it has written anything, else None (a read never takes one)."""
return db.scalar(text("SELECT pg_current_xact_id_if_assigned()::text"))
def _request_dep(db, unfinished: list[str]):
"""`get_db` for a test request: the test's own session, plus the check a shared session hides.
@@ -124,6 +129,7 @@ def _request_dep(db, unfinished: list[str]):
def dep(conn: HTTPConnection):
db.flush()
state = {"dirty": False}
before = _write_xact(db)
def flushed(session, ctx):
state["dirty"] = True
@@ -138,7 +144,12 @@ def _request_dep(db, unfinished: list[str]):
try:
yield db
staged = db.new or db.deleted or any(db.is_modified(o) for o in db.dirty)
if state["dirty"] or staged:
# Core DML (`db.execute(update(...))`) fires no flush and stages nothing; the database
# itself says whether a write is open — a transaction that wrote and was not committed
# holds an id it did not hold when the request began (see `release_read_connection`). A
# row lock (`FOR UPDATE`) takes one too: the handler ends what it locked.
core_dml = (after := _write_xact(db)) is not None and after != before
if state["dirty"] or staged or core_dml:
unfinished.append(f"{conn.scope.get('method', 'WS')} {conn.url.path}")
except Exception:
db.rollback()