- Waechter (pruefe_kern): prueft jetzt gezielt das Modell mit der Rolle hermes und seinen
Zustand in llama-swap (/running, v257 listet auch ladende Modelle), statt das Hirn fuer
bereit zu halten, sobald irgendein Modell laeuft. Ein Ladevorgang ist kein Ausfall, aber
nur bis 10 Minuten (MC_WAECHTER_HIRN_LADEN_S), sonst bliebe ein immer neu startendes Hirn
unbemerkt. Sonst die ueblichen Takte (FAIL_AFTER); Knopf "Protokoll des Motors".
- llamaswap: modell_zustaende() und hirn_zustand(); lade_modell() meldet ok false mit
deutschem Grund und der Meldung der Engine, "laedt noch" nach der Wartezeit ist kein Fehler,
ein geladenes Modell ohne Chat (embed) zaehlt als geladen. POST /api/models/{id}/load
reicht das Ergebnis durch (Router duenn).
- Radar "Jetzt suchen": startet die Suche als Auftrag (Job-Engine, Gruppe radar, hoechstens
einer, radar_lauf.py --nur-suche) und antwortet sofort mit der Auftrags-ID. Die Ansicht
zeigt "Sucht ..." bis der Auftrag fertig ist, liest danach das Radar neu und nennt eine
gescheiterte Suche; die Auftragskarte zeigt den Stand.
- Tests: Hirn-Zustaende und Frist, Laden gegen eine llama-swap-Attrappe, Radar-Auftrag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
3.3 KiB
Python
78 lines
3.3 KiB
Python
"""„Jetzt suchen“ im Radar als Auftrag (24.09.2026): Die Route antwortet sofort mit einer Auftrags-ID, gesucht wird
|
|
in radar_lauf.py --nur-suche. Vorher lief die Suche synchron in der Anfrage und konnte Minuten dauern."""
|
|
|
|
import sys
|
|
|
|
import pytest
|
|
import radar_lauf
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
from routers import radar as radar_router
|
|
from services import radar
|
|
|
|
|
|
@pytest.fixture
|
|
def auftraege(monkeypatch):
|
|
"""Job-Engine-Attrappe: merkt sich den Start; läuft schon einer, kommt der zurück."""
|
|
stand: dict = {"gestartet": [], "laeuft": None}
|
|
|
|
def start_job_exklusiv(gruppe, args, label, **kw):
|
|
if stand["laeuft"]:
|
|
return None, stand["laeuft"]
|
|
stand["gestartet"].append({"gruppe": gruppe, "args": args, "label": label, **kw})
|
|
return "job123", None
|
|
|
|
monkeypatch.setattr(radar.jobengine, "start_job_exklusiv", start_job_exklusiv)
|
|
return stand
|
|
|
|
|
|
def test_suche_startet_einen_auftrag(auftraege):
|
|
ergebnis = radar.suche_starten()
|
|
assert ergebnis["ok"] is True and ergebnis["job_id"] == "job123" and "Aufträge" in ergebnis["text"]
|
|
(start,) = auftraege["gestartet"]
|
|
assert start["gruppe"] == "radar" and start["zeitlimit_s"] == radar.SUCHE_ZEITLIMIT_S
|
|
assert start["args"][0] == sys.executable
|
|
assert start["args"][1].endswith("radar_lauf.py") and start["args"][2:] == ["--nur-suche"]
|
|
|
|
|
|
def test_laufende_suche_wird_nicht_doppelt_gestartet(auftraege):
|
|
auftraege["laeuft"] = {"id": "job-alt", "state": "running"}
|
|
ergebnis = radar.suche_starten()
|
|
assert (ergebnis["job_id"], ergebnis["laeuft_schon"]) == ("job-alt", True)
|
|
assert auftraege["gestartet"] == []
|
|
|
|
|
|
def test_route_antwortet_sofort_ohne_selbst_zu_suchen(auftraege, monkeypatch):
|
|
def nicht_hier():
|
|
raise AssertionError("Die Route darf nicht selbst suchen.")
|
|
|
|
monkeypatch.setattr(radar, "suche", nicht_hier)
|
|
app = FastAPI()
|
|
app.include_router(radar_router.router)
|
|
antwort = TestClient(app).post("/api/radar/suche")
|
|
assert antwort.status_code == 200 and antwort.json()["job_id"] == "job123"
|
|
|
|
|
|
@pytest.mark.parametrize("ergebnis, code, zeile", [
|
|
({"neu": ["Ornith 1.5"], "wartend": 2, "quellen": {"watchlist": True, "discover": True}}, 0,
|
|
"Suche fertig: 1 neu (Ornith 1.5), 2 warten auf den Nachttest."),
|
|
({"neu": [], "wartend": 1, "quellen": {"watchlist": True, "discover": False}}, 0,
|
|
"Suche fertig: nichts Neues, 1 warten auf den Nachttest, Hugging Face war nicht erreichbar."),
|
|
({"neu": [], "wartend": 0, "quellen": {"watchlist": False, "discover": False}}, 1,
|
|
("Suche fertig: nichts Neues, 0 warten auf den Nachttest, Hugging Face war nicht erreichbar, "
|
|
"die Merkliste war nicht lesbar.")),
|
|
])
|
|
def test_nur_suche_sagt_das_ergebnis_in_der_letzten_zeile(monkeypatch, capsys, ergebnis, code, zeile):
|
|
monkeypatch.setattr(radar_lauf.radar, "suche", lambda: ergebnis)
|
|
assert radar_lauf.nur_suche() == code
|
|
assert capsys.readouterr().out.strip().splitlines()[-1] == zeile
|
|
|
|
|
|
def test_nur_suche_bei_absturz(monkeypatch, capsys):
|
|
def kaputt():
|
|
raise OSError("Platte voll")
|
|
|
|
monkeypatch.setattr(radar_lauf.radar, "suche", kaputt)
|
|
assert radar_lauf.nur_suche() == 1
|
|
assert capsys.readouterr().out.strip().endswith("Die Suche ist gescheitert: OSError: Platte voll")
|