"""Tests for _shared.heartbeat — Task A1.""" import json import sys from pathlib import Path import pytest # Make `_shared` importable (same pattern as test_reliable_queue.py) sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent)) from _shared.heartbeat import WorkerStats, build_payload, render_state def test_build_payload_has_contract_fields(): s = WorkerStats(); s.jobs_done = 3; s.last_job_at = "2026-06-29T00:00:00Z" payload = json.loads(build_payload("image-render", "render", "idle", s)) assert payload["name"] == "image-render" assert payload["kind"] == "render" assert payload["state"] == "idle" assert payload["jobs_done"] == 3 assert payload["last_job_at"] == "2026-06-29T00:00:00Z" assert payload["ts"].endswith("Z") def test_build_payload_merges_extra(): payload = json.loads(build_payload("task-watcher", "watcher", "free", WorkerStats(), extra={"mode": "free"})) assert payload["mode"] == "free" class _FakeRedis: def __init__(self, paused): self._paused = paused async def get(self, key): return b"1" if self._paused else None @pytest.mark.asyncio async def test_render_state_paused_overrides_busy(): s = WorkerStats(); s.busy = True assert await render_state(_FakeRedis(paused=True), s) == "paused" @pytest.mark.asyncio async def test_render_state_busy_then_idle(): s = WorkerStats(); s.busy = True assert await render_state(_FakeRedis(paused=False), s) == "busy" s.busy = False assert await render_state(_FakeRedis(paused=False), s) == "idle"