Files
plane-agentd/tests/test_skips.py
T
jj.wang 72681db46b Heartbeat: record why each Todo item was not dispatched
Each tick lists skipped items with terminal and reason (concurrency n/m with
the holding runs, serialize group holder, busy_process not started by agentd,
relay down, no route for assignee, start failed) in heartbeat.json "skipped".
A reason is logged (agentd.log / cron.log) only when it is new for that item;
the last set is kept in the state file as "skips".
2026-10-21 13:21:16 +00:00

72 lines
2.8 KiB
Python

import json
import unittest
from tests.fakes import Harness
class FakeProbe:
def __init__(self, counts):
self.counts = counts
def process_count(self, name):
return self.counts.get(name, 0)
class SkipReasonTest(unittest.TestCase):
"""Why a Todo item was not dispatched: heartbeat "skipped", logged once per new reason."""
def setUp(self):
self.h = Harness()
self.p = self.h.plane
self.lines = []
self.h.d.log = lambda msg: self.lines.append(msg)
def tearDown(self):
self.h.close()
def skipped(self):
hb = json.loads((self.h.d.store.dir / "heartbeat.json").read_text())
return {s["item"]: (s["terminal"], s["reason"]) for s in hb["skipped"]}
def not_dispatched(self):
return [l for l in self.lines if "not dispatched" in l]
def test_reasons_in_heartbeat_and_logged_once(self):
self.p.add_issue(1) # starts on win10
self.p.add_issue(2) # win10 full
self.p.add_issue(3, assignee="kappiee") # no terminal for kappiee
self.p.add_issue(4, assignee="oregon", labels=["needs-game"]) # starts on oregon, holds the game group
self.p.add_issue(5, assignee="oregon", labels=["needs-game"]) # group held
self.h.tick()
self.assertEqual(self.skipped(), {
"GW-2": ("win10", "concurrency 1/1 (GW-1)"),
"GW-3": (None, "no route for assignee kappiee"),
"GW-5": ("oregon", "serialize_group game held by GW-4"),
})
self.assertEqual(len(self.not_dispatched()), 3)
self.h.tick() # same reasons: heartbeat still has them, the log does not repeat them
self.assertEqual(len(self.skipped()), 3)
self.assertEqual(len(self.not_dispatched()), 3)
def test_busy_process_and_relay_down(self):
self.h.cfg.terminals["win10"]["busy_processes"] = ["codex"]
probe = FakeProbe({"codex": 1})
self.h.d.transport_factory = lambda term: probe
self.p.add_issue(1)
self.h.tick()
self.assertEqual(self.skipped(), {"GW-1": ("win10", "busy_process codex (1 running, not started by agentd)")})
probe.counts = {}
self.h.tick() # leftover codex.exe gone: dispatched, nothing skipped
self.assertEqual(self.skipped(), {})
self.assertEqual(self.p.state_of("i1"), "In Progress")
self.p.add_issue(2, assignee="oregon")
self.h.cfg.terminals["oregon"]["busy_processes"] = ["claude"]
probe.counts = {"claude": None} # probe fails: relay down
probe.process_count = lambda name: None
self.h.tick()
self.assertEqual(self.skipped()["GW-2"], ("oregon", "relay down"))
if __name__ == "__main__":
unittest.main()