fix(test): avoid autobegin-vs-begin collision in the log toggle/exclude test [M79 step 5]
test_persist_logs_respects_toggle_and_exclude read via s.execute(SELECT) between two `async with s.begin()` blocks; that SELECT autobegins a transaction, so the next begin() raised "A transaction is already begun". Move both reads after the final begin block (the toggle-off persist stores nothing, so end-state still reflects the exclude phase), and pass a SimpleNamespace stand-in host to sidestep ORM attribute-expiry across the commit boundaries. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAGR73DUowdVFVvYzLXC5C
This commit is contained in:
@@ -214,6 +214,7 @@ def test_persist_logs_stores_lines(app):
|
||||
def test_persist_logs_respects_toggle_and_exclude(app):
|
||||
"""Server-side controls (Settings): an excluded container's lines are dropped
|
||||
while others persist; the global toggle off stores nothing new."""
|
||||
from types import SimpleNamespace
|
||||
from sqlalchemy import text
|
||||
from steward.models.hosts import Host
|
||||
from steward.core.settings import set_setting
|
||||
@@ -225,33 +226,41 @@ def test_persist_logs_respects_toggle_and_exclude(app):
|
||||
{"container": "noisy", "stream": "stdout", "ts": None, "line": "drop-me"},
|
||||
])]
|
||||
|
||||
hid = str(uuid.uuid4())
|
||||
# Stand-in host: the logs-only persist path reads only host.id, so a plain
|
||||
# object sidesteps ORM attribute-expiry across the commit boundaries below.
|
||||
host = SimpleNamespace(id=hid, name="loghost3")
|
||||
|
||||
async def _go():
|
||||
async with app.db_sessionmaker() as s:
|
||||
# Back-to-back begin blocks with NO read in between — a SELECT between
|
||||
# them would autobegin a txn and make the next begin() collide.
|
||||
async with s.begin():
|
||||
await s.execute(text("DELETE FROM docker_logs"))
|
||||
await set_setting(s, "docker.logs.enabled", True)
|
||||
await set_setting(s, "docker.logs.exclude", ["noisy"])
|
||||
h = Host(id=str(uuid.uuid4()), name="loghost3", address="10.7.7.10")
|
||||
s.add(h)
|
||||
await s.flush()
|
||||
hid = h.id
|
||||
await persist(s, h, [], None, None, batch)
|
||||
kept = {r[0] for r in (await s.execute(text(
|
||||
"SELECT DISTINCT container_name FROM docker_logs WHERE host_id=:h"),
|
||||
{"h": hid})).all()}
|
||||
async with s.begin(): # flip the global kill-switch off
|
||||
s.add(Host(id=hid, name="loghost3", address="10.7.7.10"))
|
||||
await s.flush() # host row before its log rows (FK order)
|
||||
await persist(s, host, [], None, None, batch) # web kept, noisy excluded
|
||||
async with s.begin(): # global kill-switch off → nothing stored
|
||||
await set_setting(s, "docker.logs.enabled", False)
|
||||
await persist(s, h, [], None, None, batch)
|
||||
after_off = (await s.execute(text(
|
||||
"SELECT COUNT(*) FROM docker_logs WHERE host_id=:h"), {"h": hid})).scalar()
|
||||
await persist(s, host, [], None, None, batch)
|
||||
async with s.begin(): # restore defaults for other tests
|
||||
await set_setting(s, "docker.logs.enabled", True)
|
||||
await set_setting(s, "docker.logs.exclude", [])
|
||||
# Reads only after the last begin block (they autobegin, but nothing
|
||||
# opens a begin() after them). Toggle-off added nothing, so the state
|
||||
# here still reflects the exclude phase.
|
||||
kept = {r[0] for r in (await s.execute(text(
|
||||
"SELECT DISTINCT container_name FROM docker_logs WHERE host_id=:h"),
|
||||
{"h": hid})).all()}
|
||||
after_off = (await s.execute(text(
|
||||
"SELECT COUNT(*) FROM docker_logs WHERE host_id=:h"), {"h": hid})).scalar()
|
||||
return kept, after_off
|
||||
|
||||
kept, after_off = asyncio.run(_go())
|
||||
assert kept == {"web"} # excluded 'noisy' dropped on ingest
|
||||
assert after_off == 1 # toggle off → no new rows (still just the one 'web')
|
||||
assert after_off == 1 # toggle off added nothing → still just the one 'web' line
|
||||
|
||||
|
||||
@_NEEDS_DB
|
||||
|
||||
Reference in New Issue
Block a user