From d8bacc71491265184bbb37ae304cd0492ae90faa Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 6 Oct 2026 18:45:57 -0400 Subject: [PATCH] test(docker): #5152's tests read rows with SQL and the clock they render against - The status test imported the plugin's models after the app had mapped them ("already defined"); it reads docker_host_status with SQL. - The swarm-expiry count awaited inside a generator expression. - The page test's since came from the module's NOW, so |ago said "5m 4s"; it is built at test time and the assertion checks the minutes. Co-Authored-By: Claude Opus 5.5 --- tests/integration/test_docker.py | 22 +++++++++++++++------- tests/plugins/docker/test_docker_page.py | 7 ++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tests/integration/test_docker.py b/tests/integration/test_docker.py index ffabf3e..b8c407b 100644 --- a/tests/integration/test_docker.py +++ b/tests/integration/test_docker.py @@ -422,6 +422,7 @@ def test_an_empty_snapshot_from_a_docker_that_answered_clears_the_host(app): @_NEEDS_DB def test_docker_status_is_recorded_once_a_host_has_had_docker(app): + from sqlalchemy import text from steward.models.hosts import Host persist = _persist_fn(app) @@ -430,7 +431,6 @@ def test_docker_status_is_recorded_once_a_host_has_had_docker(app): t3 = t1 + timedelta(seconds=60) async def _go(): - from plugins.docker.models import DockerHostStatus seen = [] async with app.db_sessionmaker() as s: async with s.begin(): @@ -440,14 +440,20 @@ def test_docker_status_is_recorded_once_a_host_has_had_docker(app): await s.flush() gone = {"status": "unavailable", "detail": "no Docker socket at /var/run/docker.sock"} await persist(s, never, [], status=dict(gone, at=t1)) - seen.append(await s.get(DockerHostStatus, never.id)) + await s.flush() + + async def row(host): + return (await s.execute(text( + "SELECT status, detail, since, reported_at FROM docker_host_status " + "WHERE host_id = :h"), {"h": host.id})).first() + + seen.append(await row(never)) for status, at in (({"status": "ok", "detail": None}, t1), (gone, t2), (gone, t3), ({"status": "error", "detail": "permission denied on /var/run/docker.sock"}, t3)): await persist(s, had, [], status=dict(status, at=at)) await s.flush() - row = await s.get(DockerHostStatus, had.id) - seen.append((row.status, row.detail, row.since, row.reported_at)) + seen.append(tuple(await row(had))) return seen never, ok, gone1, gone2, err = asyncio.run(_go()) @@ -476,9 +482,11 @@ def test_a_node_that_is_no_longer_a_manager_loses_its_swarm_rows(app): await s.flush() async def counts(): - return tuple((await s.execute(text( - f"SELECT count(*) FROM {t} WHERE host_id = :h"), {"h": h.id})).scalar() - for t in ("docker_swarm_services", "docker_swarm_nodes")) + out = [] + for t in ("docker_swarm_services", "docker_swarm_nodes"): + out.append((await s.execute(text( + f"SELECT count(*) FROM {t} WHERE host_id = :h"), {"h": h.id})).scalar()) + return tuple(out) await persist(s, h, [], swarm, status={"status": "ok", "detail": None, "at": t1}) manager = await counts() diff --git a/tests/plugins/docker/test_docker_page.py b/tests/plugins/docker/test_docker_page.py index a93696b..343af45 100644 --- a/tests/plugins/docker/test_docker_page.py +++ b/tests/plugins/docker/test_docker_page.py @@ -80,10 +80,11 @@ async def test_a_healthy_board_has_no_attention_card(app): async def test_a_host_whose_docker_stopped_answering_says_so(app): + now = datetime.now(timezone.utc) # not the module's NOW: |ago reads the clock down = [{"host_id": "h1", "host_name": "nas", "status": "unavailable", - "detail": "no Docker socket at /var/run/docker.sock", "since": NOW - timedelta(minutes=5)}, + "detail": "no Docker socket at /var/run/docker.sock", "since": now - timedelta(minutes=5)}, {"host_id": "h2", "host_name": "web-1", "status": "error", - "detail": "permission denied on /var/run/docker.sock", "since": NOW - timedelta(minutes=1)}] + "detail": "permission denied on /var/run/docker.sock", "since": now - timedelta(minutes=1)}] async with app.test_request_context("/plugins/docker/rows"): page = await render_plugin_template( app, "docker", "docker/rows.html", docker_down=down, attention=[], says=svc.PROBLEM_SAYS, @@ -92,7 +93,7 @@ async def test_a_host_whose_docker_stopped_answering_says_so(app): page = re.sub(r">\s+<", "><", " ".join(page.split())) card = page[page.index("Docker not answering"):page.index("")] assert 'No Dockernas' in card - assert "no Docker socket at /var/run/docker.sock · since 5m ago" in card + assert "no Docker socket at /var/run/docker.sock · since 5m " in card assert 'Errorweb-1' in card