diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index fffdbaf..35537a3 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -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 diff --git a/backend/tests/flow/test_supervision.py b/backend/tests/flow/test_supervision.py index 63be469..a5a6746 100644 --- a/backend/tests/flow/test_supervision.py +++ b/backend/tests/flow/test_supervision.py @@ -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() diff --git a/backend/tests/sdk/test_imports.py b/backend/tests/sdk/test_imports.py index a21e282..3b171cf 100644 --- a/backend/tests/sdk/test_imports.py +++ b/backend/tests/sdk/test_imports.py @@ -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())