Make narrowed backend test runs and the quarantine test order- and load-proof
The session db fixture now disposes the engine before deleting the file, since a module under a no-op db (tests/sdk, tests/flow) may have connected first; the sdk import tests forget the study packages they import; the supervision tests keep the real quarantine length so it cannot expire mid-assertion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
This commit is contained in:
@@ -50,6 +50,9 @@ def db() -> Generator[Session, None, None]:
|
||||
assert url.database and url.database.endswith("_test.db"), url.database
|
||||
|
||||
path = Path(url.database)
|
||||
# A module that ran before this fixture (one under a no-op `db`) may have
|
||||
# connected already; a pooled connection would keep the unlinked file.
|
||||
engine.dispose()
|
||||
path.unlink(missing_ok=True)
|
||||
# The real path, so the suite runs against a database built the way a
|
||||
# deployment's is — including the alembic stamp the app's own startup
|
||||
|
||||
@@ -6,16 +6,16 @@ import pytest
|
||||
|
||||
from fluksio.flow import supervision
|
||||
from fluksio.flow.events import EventBus
|
||||
from fluksio.flow.supervision import FAILURE_BUDGET, Supervisor
|
||||
from fluksio.flow.supervision import FAILURE_BUDGET, QUARANTINE_BACKOFF, Supervisor
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def no_backoff(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Real backoff would make these tests a minute long."""
|
||||
monkeypatch.setattr(supervision, "BACKOFF", (0.0,))
|
||||
# Long enough that a quarantine holds for the length of an assertion, short
|
||||
# enough that the test asking it to expire does not wait five minutes.
|
||||
monkeypatch.setattr(supervision, "QUARANTINE_BACKOFF", (0.05,))
|
||||
# The quarantine keeps its real length, so it holds until a test cancels it
|
||||
# however slow the run is; 50ms here ran out mid-assertion on a loaded run.
|
||||
# The one test that wants it to expire shortens it itself.
|
||||
|
||||
|
||||
async def _settle() -> None:
|
||||
@@ -85,7 +85,7 @@ def test_a_flow_that_keeps_crashing_is_stood_down():
|
||||
assert supervisor.quarantined == {"heating"}
|
||||
assert [e["type"] for e in events].count("task_crashed") == FAILURE_BUDGET
|
||||
quarantine = [e for e in events if e["type"] == "flow_quarantined"][-1]
|
||||
assert quarantine["retry_in_s"] == 0.05
|
||||
assert quarantine["retry_in_s"] == QUARANTINE_BACKOFF[0]
|
||||
await supervisor.cancel_all()
|
||||
|
||||
asyncio.run(scenario())
|
||||
@@ -142,8 +142,11 @@ def test_two_tasks_on_one_flow_do_not_spend_each_others_budget():
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_a_quarantine_expires_and_the_task_tries_again():
|
||||
def test_a_quarantine_expires_and_the_task_tries_again(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
"""The whole point: a broker that comes back is picked up without a human."""
|
||||
monkeypatch.setattr(supervision, "QUARANTINE_BACKOFF", (0.05,))
|
||||
attempts = 0
|
||||
|
||||
async def loop() -> None:
|
||||
@@ -161,7 +164,7 @@ def test_a_quarantine_expires_and_the_task_tries_again():
|
||||
assert attempts == FAILURE_BUDGET
|
||||
assert supervisor.quarantined == {"power"}
|
||||
|
||||
# Sit out the rest, which the fixture has shortened to 50ms.
|
||||
# Sit out the rest, shortened to 50ms above.
|
||||
await asyncio.sleep(0.1)
|
||||
await _settle()
|
||||
|
||||
|
||||
@@ -3,9 +3,19 @@
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
from fluksio.sdk.imports import digest_of, reached
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _forget_studies():
|
||||
"""The packages below are temporary files under names other tests use too."""
|
||||
yield
|
||||
for name in [n for n in sys.modules if n.split(".")[0] in ("study", "arm")]:
|
||||
del sys.modules[name]
|
||||
|
||||
|
||||
def _write(root, name, body):
|
||||
path = root / f"{name}.py"
|
||||
path.write_text(textwrap.dedent(body).lstrip())
|
||||
|
||||
Reference in New Issue
Block a user