Das Hermes-Update vom 25.09. scheiterte halb: neuer Code geholt, dann baute python-olm (Matrix-Extra) nicht – CMake 4 und kein clang auf der Box. MC2 startete das Gateway ohne daemon-reload neu, es lief weiter aus dem alten venv (neuer Code, alte Pakete), und die Übersicht zeigte „v0.0.0 · Aktuell“. - Update über Hermes' eigenen Starter (.hermes/bin/hermes), gebaut mit CC=gcc CXX=g++ CMAKE_POLICY_VERSION_MINIMUM=3.5, doctor-Hinweise nicht fatal, daemon-reload vor dem Neustart. - deploy/hermes-plugin-deps.sh legt trafilatura (mc2-web-lesen) in Hermes' aktive Umgebung. - Version: bei „0.0.0“ in der pyproject das Commit-Datum im Stil der neuen Tags. - Ehrliche Meldung „UNVOLLSTÄNDIG“, wenn der Code schon neu ist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
122 lines
6.0 KiB
Python
122 lines
6.0 KiB
Python
"""Kleinigkeiten der Update-Seite (24.09.2026): Größe je Quantisierung, GitHub-Zwischenspeicher,
|
|
Hermes-Version auch dann, wenn der Abruf scheitert."""
|
|
|
|
import subprocess
|
|
|
|
import httpx
|
|
import pytest
|
|
from services import hf, maintenance
|
|
|
|
|
|
def test_quants_mit_groesse(monkeypatch):
|
|
baum = [
|
|
{"path": "Q8_0/M-Q8_0-00001-of-00002.gguf", "size": 50},
|
|
{"path": "Q8_0/M-Q8_0-00002-of-00002.gguf", "size": 50},
|
|
{"path": "M-Q4_K_M.gguf", "lfs": {"size": 30}},
|
|
{"path": "mmproj-F16.gguf", "size": 5},
|
|
{"path": "README.md", "size": 1},
|
|
]
|
|
aufrufe = []
|
|
monkeypatch.setattr(hf, "_tree", lambda repo: aufrufe.append(repo) or baum)
|
|
assert hf.list_quants("x/y") == [{"quant": "Q4_K_M", "total_bytes": 35}, {"quant": "Q8_0", "total_bytes": 105}]
|
|
assert aufrufe == ["x/y"] # ein Abruf für alle Stufen
|
|
|
|
|
|
class _Antwort:
|
|
def __init__(self, status: int, daten: object):
|
|
self.status_code = status
|
|
self._daten = daten
|
|
|
|
def raise_for_status(self):
|
|
if self.status_code >= 400:
|
|
raise httpx.HTTPStatusError("fehler", request=httpx.Request("GET", "https://x"),
|
|
response=httpx.Response(self.status_code))
|
|
|
|
def json(self):
|
|
return self._daten
|
|
|
|
|
|
def test_github_antworten_werden_gemerkt_fehler_nicht(monkeypatch):
|
|
from kern import github
|
|
|
|
monkeypatch.setattr(github, "_cache", {})
|
|
antworten = [_Antwort(403, {"message": "API rate limit exceeded"}),
|
|
_Antwort(200, {"tag_name": "v258", "published_at": "2026-09-20T10:00:00Z"})]
|
|
aufrufe = []
|
|
monkeypatch.setattr(github.httpx, "get", lambda url, **kw: aufrufe.append(url) or antworten.pop(0))
|
|
with pytest.raises(httpx.HTTPStatusError):
|
|
github.github_json("repos/a/b/releases/latest")
|
|
assert github.neueste_version("a/b") == {"tag": "v258", "tag_roh": "v258", "version": "258",
|
|
"datum": "2026-09-20"}
|
|
assert github.github_json("repos/a/b/releases/latest")["tag_name"] == "v258"
|
|
assert len(aufrufe) == 2
|
|
assert maintenance._github_json is github.github_json
|
|
|
|
|
|
def test_hermes_version_auch_wenn_der_abruf_haengt(monkeypatch, tmp_path):
|
|
(tmp_path / "pyproject.toml").write_text('[project]\nversion = "0.21.4"\n', encoding="utf-8")
|
|
monkeypatch.setattr(maintenance.system, "find_hermes_agent_git", lambda: {"path": str(tmp_path)})
|
|
|
|
def run(befehl, **kw):
|
|
if "fetch" in befehl:
|
|
raise subprocess.TimeoutExpired(befehl, 25)
|
|
return subprocess.CompletedProcess(befehl, 0, stdout="main\n", stderr="")
|
|
|
|
monkeypatch.setattr(maintenance.subprocess, "run", run)
|
|
info = maintenance.hermes_update_details()
|
|
assert info["installed_version"] == "0.21.4"
|
|
assert "error" in info
|
|
|
|
|
|
def test_hermes_version_nach_dem_neuen_paketmanager(monkeypatch, tmp_path):
|
|
"""25.09.2026: In der pyproject.toml steht „0.0.0“, die Tags heißen nach dem Datum — gezeigt wird das Datum des
|
|
ausgecheckten Commits (die Übersicht zeigte „v0.0.0“)."""
|
|
(tmp_path / "pyproject.toml").write_text('[project]\nversion = "0.0.0"\n', encoding="utf-8")
|
|
monkeypatch.setattr(maintenance.subprocess, "run", lambda befehl, **kw: subprocess.CompletedProcess(
|
|
befehl, 0, stdout="2026-09-25\n" if "log" in befehl else "", stderr=""))
|
|
assert maintenance._hermes_version(str(tmp_path)) == "2026.9.25"
|
|
monkeypatch.setattr(maintenance.subprocess, "run", lambda befehl, **kw: subprocess.CompletedProcess(
|
|
befehl, 128, stdout="", stderr="kein git"))
|
|
assert maintenance._hermes_version(str(tmp_path)) == "0.0.0"
|
|
|
|
|
|
def test_hermes_update_mit_neuem_starter(monkeypatch, tmp_path):
|
|
"""Nach dem Update vom 25.09.2026: eigener Starter, Build-Umgebung für python-olm, daemon-reload vor dem
|
|
Neustart, doctor-Hinweise nicht fatal, Plugin-Pakete nachlegen, ehrliche Meldung bei halbem Stand."""
|
|
monkeypatch.setattr(maintenance.system, "find_hermes_agent_git", lambda: {"path": str(tmp_path)})
|
|
alt = maintenance._hermes_update_cmd()
|
|
assert f"{tmp_path.as_posix()}/venv/bin/python -m hermes_cli.main update" in alt.replace("\\", "/")
|
|
(tmp_path / ".hermes" / "bin").mkdir(parents=True)
|
|
(tmp_path / ".hermes" / "bin" / "hermes").write_text("#!/bin/sh\n", encoding="utf-8")
|
|
cmd = maintenance._hermes_update_cmd().replace("\\", "/")
|
|
assert f"CC=gcc CXX=g++ CMAKE_POLICY_VERSION_MINIMUM=3.5 {tmp_path.as_posix()}/.hermes/bin/hermes update --yes" in cmd
|
|
assert "doctor || echo" in cmd and "hermes-plugin-deps.sh || true" in cmd
|
|
assert cmd.index("daemon-reload") < cmd.index("systemctl --user restart hermes-gateway")
|
|
assert "HERMES-UPDATE UNVOLLSTÄNDIG" in cmd and "aber alter Stand" in cmd
|
|
|
|
|
|
def test_update_per_knopf_landet_im_verlauf(monkeypatch):
|
|
"""Einzel-Updates und „Alle aktualisieren“ schreiben ins strukturierte Verlauf-Format; bei einer
|
|
gescheiterten Kette zeigt die letzte Teil-Marke, welcher Teil scheiterte."""
|
|
from services import jobengine, update_verlauf
|
|
|
|
zeilen: list[tuple] = []
|
|
monkeypatch.setattr(update_verlauf, "eintragen", lambda *a: zeilen.append(a))
|
|
job = {"id": "x", "state": "done", "returncode": 0, "started_at": 1790000000.0,
|
|
"abschluss_daten": {"bausteine": ["engine"]}}
|
|
maintenance._update_im_verlauf(job)
|
|
assert zeilen[-1][1:] == ("Update von Hand", "engine", "eingespielt", "Per Knopf eingespielt, Prüfung grün.")
|
|
|
|
zeilen.clear()
|
|
monkeypatch.setattr(jobengine, "protokoll", lambda job_id: [
|
|
"$ bash -c …", "════════ [1/3] Engine (llama.cpp) ════════", "ok",
|
|
"════════ [2/3] Router (llama-swap) ════════", "Stack-Check rot"])
|
|
maintenance._update_im_verlauf({**job, "state": "failed", "returncode": 1,
|
|
"abschluss_daten": {"bausteine": ["engine", "swap", "hermes"]}})
|
|
assert [(z[2], z[3]) for z in zeilen] == [
|
|
("engine", "eingespielt"), ("swap", "zurueckgerollt"), ("hermes", "offen")]
|
|
|
|
zeilen.clear()
|
|
maintenance._update_im_verlauf({**job, "abschluss_daten": {}})
|
|
assert zeilen == []
|