import pytest from daynivo_kiosk import services from daynivo_kiosk.cdp import CDPError from daynivo_kiosk.config import save_config from daynivo_kiosk.healthcheck import CDP_FAILURES_BEFORE_RESTART, DISPLAY_RETRY_AFTER, HealthCheck class World: def __init__(self): self.units = {u: {"ActiveState": "active"} for u in (services.X_UNIT, services.BROWSER_UNIT, services.AGENT_UNIT, services.MANAGER_UNIT)} self.actions = [] self.now = 10_000.0 self.cdp_ok = True def unit_status(self, unit): return self.units[unit] def systemctl(self, *args): self.actions.append(args) def version(self): if not self.cdp_ok: raise CDPError("timeout") return {} @pytest.fixture def world(paths): w = World() hc = HealthCheck(paths, unit_status=w.unit_status, systemctl=w.systemctl, cdp=w, throttled=lambda: None, disk=lambda p: {"percent": 40}, now=lambda: w.now) return w, hc def test_all_healthy_no_actions(world): w, hc = world report = hc.run() assert report["actions"] == [] and w.actions == [] def test_failed_browser_waits_for_cooldown(world): w, hc = world w.units[services.BROWSER_UNIT] = {"ActiveState": "failed", "Result": "start-limit-hit"} hc.run() assert w.actions == [] w.now += DISPLAY_RETRY_AFTER hc.run() assert ("reset-failed", services.BROWSER_UNIT) in w.actions assert ("start", "--no-block", services.BROWSER_UNIT) in w.actions def test_failed_manager_restarts_immediately(world): w, hc = world w.units[services.MANAGER_UNIT] = {"ActiveState": "failed"} hc.run() assert ("start", "--no-block", services.MANAGER_UNIT) in w.actions def test_browser_restart_disabled_is_respected(world, paths): w, hc = world save_config(paths.config_file, {"browser_restart": False}) w.units[services.BROWSER_UNIT] = {"ActiveState": "inactive"} hc.run() assert w.actions == [] def test_unresponsive_devtools_restarts_browser(world): w, hc = world hc.run() # browser seen active w.now += 100 w.cdp_ok = False for _ in range(CDP_FAILURES_BEFORE_RESTART - 1): hc.run() assert w.actions == [] hc.run() assert ("restart", "--no-block", services.BROWSER_UNIT) in w.actions def test_maintenance_mode_blocks_actions(world, paths): w, hc = world (paths.health_run_dir / "maintenance").touch() w.units[services.AGENT_UNIT] = {"ActiveState": "inactive"} report = hc.run() assert report["maintenance"] is True and w.actions == []