"""Der Wächter gibt rote Hinweise an Lucy (seit 25.09.2026, Ausbauplan Welle 3): Die KI-Box antwortet mit der Antwortzeile für den Knopf des Hinweises und ob Lucy nachsieht; der Wächter hängt beides an seine Nachricht.""" import httpx from services import waechter class Antwort: status_code = 200 def __init__(self, daten): self._daten = daten def json(self): return self._daten def _vorbereiten(monkeypatch, tmp_path, post): monkeypatch.setattr(waechter, "LUCY_BEFUND", True) monkeypatch.setattr(waechter, "STORE_PATH", tmp_path / "waechter.json") monkeypatch.setattr(waechter, "ZUSTAND_PATH", tmp_path / "zustand.json") monkeypatch.setattr(waechter, "_stand", {"hinweise": {}, "kandidaten": {}, "verlauf": [], "auto": {}, "stand": 0.0}) monkeypatch.setattr(waechter, "_update_laeuft", lambda: False) monkeypatch.setattr(waechter, "FAIL_AFTER", 1) monkeypatch.setattr(waechter, "REMIND_S", 0) monkeypatch.setattr(waechter.httpx, "post", post) befund = waechter.Befund(id="dienst:lucy-stimme", stufe="rot", titel="Lucys Stimme ist gestoppt", text="Die Unit lucy-stimme läuft nicht.", quelle="lucy-stimme", aktionen=[{"id": "neustart", "label": "Starten", "dienst": "lucy-stimme"}]) monkeypatch.setattr(waechter, "PRUEFUNGEN", (lambda: [befund],)) meldungen: list[tuple[str, list[str] | None]] = [] monkeypatch.setattr(waechter, "_telegram", lambda betreff, text, knoepfe=None: meldungen.append((text, knoepfe))) return meldungen def test_roter_hinweis_mit_antwortzeile(monkeypatch, tmp_path): gesendet = [] def post(url, timeout=None, json=None): gesendet.append((url, json)) return Antwort({"zeilen": ["Antworte „ja 3“, dann starte ich lucy-stimme.", "Ich sehe nach und melde mich mit Ursache und Weg."], "knoepfe": ["ja 3", "nein 3"]}) meldungen = _vorbereiten(monkeypatch, tmp_path, post) waechter.takt() url, daten = gesendet[0] assert url == "http://127.0.0.1:9/api/lucy/befund" # conftest: MC2 zeigt in Tests ins Leere assert daten["bereich"] == "box" and daten["erinnerung"] is False and daten["aktionen"][0]["id"] == "neustart" assert meldungen == [(("Lucys Stimme ist gestoppt. Die Unit lucy-stimme läuft nicht.\n" "Antworte „ja 3“, dann starte ich lucy-stimme.\n" "Ich sehe nach und melde mich mit Ursache und Weg."), ["ja 3", "nein 3"])] # Die Erinnerung sagt es der Box (dort gibt es dann nur die Antwortzeile wieder, keine zweite Untersuchung). waechter.takt() assert gesendet[1][1]["erinnerung"] is True and meldungen[1][0].startswith("Immer noch: Lucys Stimme") def test_ohne_box_bleibt_die_meldung_wie_bisher(monkeypatch, tmp_path): def kaputt(*a, **k): raise httpx.ConnectError("weg") meldungen = _vorbereiten(monkeypatch, tmp_path, kaputt) waechter.takt() assert meldungen == [("Lucys Stimme ist gestoppt. Die Unit lucy-stimme läuft nicht.", None)]