test: real conflict-refresh assertions; AST-exact probe guard

- task-instances matrix test asserts same row id + rewritten due_time
  + pre-refresh None (the vacuous refreshed_same_id walrus is gone)
- compensating guard parses the two sanctioned functions' ASTs: each
  must contain its raw INSERT (children NOT NULL, admin_users PK),
  lexically inside a pytest.raises block, and no other raw SQL may
  name these tables anywhere else in the matrix file
This commit is contained in:
Joshua King
2026-09-14 08:52:30 -04:00
parent c41e28cb29
commit 2265b5c3f1
2 changed files with 76 additions and 29 deletions
+68 -23
View File
@@ -575,12 +575,14 @@ def test_startup_db_test_file_uses_dao_elsewhere() -> None:
def test_dao_matrix_test_file_raw_probes_are_only_constraint_probes() -> None: def test_dao_matrix_test_file_raw_probes_are_only_constraint_probes() -> None:
"""Compensating self-scan for the matrix-file exemption: outside the """Compensating self-scan for the matrix-file exemption, structurally
two sanctioned constraint-violation probes, test_dao_matrix.py must exact: parse the two sanctioned functions' ASTs and require that
contain no other raw SQL naming children/admin_users — and the two (a) they contain NO other raw SQL naming children/admin_users, and
probes themselves must be raising-expected violation inserts, not (b) every raw table insert among them is an expression nested inside
successful writes. a ``pytest.raises`` context whose matcher mentions IntegrityError.
Any additional raw write elsewhere in the file fails this guard.
""" """
import ast
import re import re
from pathlib import Path from pathlib import Path
@@ -602,25 +604,68 @@ def test_dao_matrix_test_file_raw_probes_are_only_constraint_probes() -> None:
"test_dao_matrix.py raw children/admin_users SQL is limited to " "test_dao_matrix.py raw children/admin_users SQL is limited to "
"the two sanctioned constraint probes" "the two sanctioned constraint probes"
) )
# The probes must sit inside pytest.raises blocks: strip any probe
# insert NOT preceded by pytest.raises and fail. tree = ast.parse(text)
probe_section = text[ probe_tables = {
text.index("test_matrix_children_crud_and_constraints"): "test_matrix_children_crud_and_constraints": "children",
text.index("test_matrix_admin_users_crud_and_constraints") "test_matrix_admin_users_crud_and_constraints": "admin_users",
] + text[ }
text.index("test_matrix_admin_users_crud_and_constraints"): found_probes = 0
text.index("def test_matrix_schedule_rules_crud_and_constraints") for node in ast.walk(tree):
] if (
insert_positions = [ not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
match.start() or node.name not in probe_tables
for match in re.finditer(r"await w\.database\.execute", probe_section) ):
] continue
for position in insert_positions: table = probe_tables[node.name]
window = probe_section[max(0, position - 200):position] # Walk the function body; require each raw execute naming the
assert "pytest.raises" in window, ( # table to be lexically inside a pytest.raises with block, and
"raw children/admin_users inserts in the matrix suite must " # require at least one such probe per sanctioned function.
"be expected-to-fail constraint probes" raw_inserts: list[ast.Await] = []
raises_blocks: list[ast.With] = []
for sub in ast.walk(node):
if (
isinstance(sub, ast.Await)
and isinstance(sub.value, ast.Call)
and isinstance(sub.value.func, ast.Attribute)
and sub.value.func.attr == "execute"
):
sql_arg = sub.value.args[0] if sub.value.args else None
rendered = ast.unparse(sql_arg) if sql_arg else ""
if re.search(
r"INSERT\s+INTO\s+" + table, rendered, re.IGNORECASE
):
raw_inserts.append(sub)
assert raw_inserts, (
f"{node.name} must contain its sanctioned raw {table} probe"
) )
# Collect the AST spans of every `with pytest.raises(...)` block
# in the function; each probe must fall inside one.
for sub in ast.walk(node):
if (
isinstance(sub, ast.With)
and isinstance(sub.items[0].context_expr, ast.Call)
and isinstance(
sub.items[0].context_expr.func, ast.Attribute
)
and sub.items[0].context_expr.func.attr == "raises"
):
raises_blocks.append(sub)
for insert in raw_inserts:
inside = any(
raises_block.lineno <= insert.lineno
and insert.end_lineno <= raises_block.end_lineno
for raises_block in raises_blocks
)
assert inside, (
f"the raw {table} insert in {node.name} must be nested "
"in a pytest.raises block (expected-to-fail constraint "
"probe, not a successful write)"
)
found_probes += 1
assert found_probes == 2, (
"exactly two sanctioned raw constraint probes must exist"
)
def test_dao_test_file_uses_dao_not_raw_table_sql() -> None: def test_dao_test_file_uses_dao_not_raw_table_sql() -> None:
+8 -6
View File
@@ -276,20 +276,22 @@ def test_matrix_task_instances_crud_and_constraints(tmp_path) -> None:
# insert (seeded) + read # insert (seeded) + read
fetched = await w.instances.get(w.definition.id, D1) fetched = await w.instances.get(w.definition.id, D1)
assert fetched == w.instance assert fetched == w.instance
# update path: conflict refresh on the OPEN instance # update path: conflict refresh on the OPEN instance — same row
# id, snapshot columns (due_time) actually rewritten.
refreshed = await w.instances.upsert( refreshed = await w.instances.upsert(
w.definition.id, w.child.id, D1, _stamp(), due_time="17:00" w.definition.id, w.child.id, D1, _stamp(), due_time="17:00"
) )
assert refreshed_same_id(fetched, refreshed := refreshed_same_id) assert refreshed.id == fetched.id, (
"the conflict path must refresh the existing row in place"
)
assert refreshed.due_time == "17:00"
assert fetched.due_time is None
assert await w.instances.get_by_id(fetched.id) is not None
return True return True
assert _with_world(tmp_path / "m-instances.db")(_body) is True assert _with_world(tmp_path / "m-instances.db")(_body) is True
def refreshed_same_id(original, replacement):
return replacement
def test_matrix_task_instances_constraints(tmp_path) -> None: def test_matrix_task_instances_constraints(tmp_path) -> None:
async def _body(w: World): async def _body(w: World):
# D20 has no instance yet: a raw insert succeeds, then an # D20 has no instance yet: a raw insert succeeds, then an