"""Gemeinsames Ziel-Modell (Phase 2, 24.09.2026) und die KI-Box als erster Adapter.""" import pytest from kern.ziele import BausteinStand, ZielStand from services import box_updates, maintenance, system, update_verlauf def test_als_dict_ordnet_nach_dringlichkeit_und_zaehlt(): ziel = ZielStand(id="ct-104", name="Gitea", art="container", instanz="homelab", bausteine=[ BausteinStand(id="os", name="Betriebssystem", zustand="aktuell"), BausteinStand(id="app", name="Gitea", zustand="neu", kurz="1.27.2 → 1.27.3"), BausteinStand(id="docker", name="Docker", zustand="unbekannt", grund="nicht erreichbar"), ]) daten = ziel.als_dict() assert [b["id"] for b in daten["bausteine"]] == ["docker", "app", "os"] assert daten["zaehlung"] == {"aktuell": 1, "neu": 1, "unbekannt": 1} and daten["offen"] == 1 @pytest.fixture def box(monkeypatch): monkeypatch.setattr(maintenance, "_installed_engine_build", lambda: 11160) monkeypatch.setattr(maintenance, "_installed_swap_version", lambda: 257) monkeypatch.setattr(maintenance, "_latest_engine_asset_release", lambda: {"tag_name": "b11172"}) monkeypatch.setattr(maintenance, "_github_json", lambda pfad, timeout=8: {"tag_name": "v258"}) monkeypatch.setattr(maintenance, "_hermes_version", lambda pfad: "0.21.4") monkeypatch.setattr(system, "find_hermes_agent_git", lambda: {"path": "/x", "hash": "abc1234"}) monkeypatch.setattr(update_verlauf, "festgehalten", list) monkeypatch.setattr(box_updates, "gelesen", lambda: True) def setzen(daten: dict) -> None: monkeypatch.setattr(box_updates, "gecacht", lambda: daten) return setzen def _nach_id(ziel: ZielStand) -> dict[str, BausteinStand]: return {b.id: b for b in ziel.bausteine} def test_ki_box_neu_aktuell_und_knoepfe(box): box({"os": 10, "engine": 1, "swap": 0, "pruef_fehler": {}, "components": [{"key": "hermes_agent", "update": True, "behind": 743, "current": "abc1234"}]}) b = _nach_id(box_updates.ki_box_ziel()) assert (b["os"].zustand, b["os"].kurz) == ("neu", "10 Pakete") assert (b["engine"].installiert, b["engine"].verfuegbar) == ("b11160", "b11172") assert (b["swap"].zustand, b["swap"].installiert, b["swap"].verfuegbar) == ("aktuell", "v257", None) assert (b["hermes"].installiert, b["hermes"].verfuegbar) == ("0.21.4", "+743 Änderungen") assert b["engine"].aktion.pfad == "/api/maintenance/engine-update" assert b["swap"].aktion is None def test_ki_box_unbekannt_und_festgehalten_ohne_knopf(box, monkeypatch): monkeypatch.setattr(update_verlauf, "festgehalten", lambda: [ {"baustein": "engine", "name": "Motor", "version": "10819", "seit": "13.09.", "grund": "Check rot"}]) box({"os": 0, "engine": 1, "swap": 0, "pruef_fehler": {"swap": "GitHub nicht erreichbar"}, "components": []}) b = _nach_id(box_updates.ki_box_ziel()) assert b["engine"].zustand == "festgehalten" and b["engine"].aktion is None assert b["engine"].grund == "Seit 13.09. auf 10819: Check rot" assert (b["swap"].zustand, b["swap"].grund) == ("unbekannt", "GitHub nicht erreichbar") assert b["os"].zustand == "aktuell" def test_ki_box_vor_der_ersten_pruefung(box, monkeypatch): monkeypatch.setattr(box_updates, "gelesen", lambda: False) box({}) ziel = box_updates.ki_box_ziel() assert {b.zustand for b in ziel.bausteine} == {"wird-geprueft"} and len(ziel.bausteine) == 4