mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-02 14:28:59 +02:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U6zrBsUCNzpMBnov3rTVYV
188 lines
8.7 KiB
Python
188 lines
8.7 KiB
Python
"""Putting the bundled runtime back, instead of asking the user to (ENG-422).
|
|
|
|
Every case here is the real failure simulated on disk: a quarantined binary is just a missing file,
|
|
and an installer package is just a zip, so the whole repair is exercisable on any platform even
|
|
though the class has only ever been seen on Windows."""
|
|
|
|
import os
|
|
import zipfile
|
|
|
|
import pytest
|
|
|
|
from backend.apps.agents.core import cli_self_heal as heal
|
|
|
|
MEMBER = "lib/net45/resources/python-env/Lib/site-packages/claude_agent_sdk/_bundled/claude.exe"
|
|
SUFFIX = "_bundled/claude.exe"
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def p_fast(monkeypatch):
|
|
"""The re-take check is a real sleep in production; tests must not pay for it."""
|
|
monkeypatch.setattr(heal, "RETAKEN_CHECK_SECONDS", 0.01)
|
|
|
|
|
|
def p_package(dirpath, body=b"PRISTINE-RUNTIME", name="openswarm-1.7.9-full.nupkg", member=MEMBER):
|
|
p = os.path.join(dirpath, name)
|
|
with zipfile.ZipFile(p, "w") as z:
|
|
z.writestr(member, body)
|
|
return p
|
|
|
|
|
|
def test_it_restores_the_binary_from_the_installer_package(tmp_path):
|
|
cache = tmp_path / "packages"; cache.mkdir()
|
|
p_package(str(cache))
|
|
dest = tmp_path / "site-packages" / "claude_agent_sdk" / "_bundled" / "claude.exe"
|
|
r = heal.repair_bundled_cli(str(dest), SUFFIX, [str(cache)])
|
|
assert r.repaired and not r.retaken
|
|
assert dest.read_bytes() == b"PRISTINE-RUNTIME"
|
|
assert "restored" in r.detail
|
|
|
|
|
|
def test_a_restore_that_is_undone_is_NOT_reported_as_a_fix(tmp_path, monkeypatch):
|
|
"""The half that matters. Antivirus re-takes the file seconds later; calling that a repair sends
|
|
the user back to a broken app believing it works."""
|
|
cache = tmp_path / "packages"; cache.mkdir()
|
|
p_package(str(cache))
|
|
dest = tmp_path / "_bundled" / "claude.exe"
|
|
|
|
p_real_sleep = heal.time.sleep
|
|
|
|
def p_quarantine(_):
|
|
p_real_sleep(0)
|
|
if os.path.isfile(dest):
|
|
os.remove(dest) # the scanner takes it back
|
|
monkeypatch.setattr(heal.time, "sleep", p_quarantine)
|
|
|
|
r = heal.repair_bundled_cli(str(dest), SUFFIX, [str(cache)])
|
|
assert r.repaired and r.retaken, "a re-taken file must say so"
|
|
assert "exclusion" in r.detail, "and must name what would actually make it stay"
|
|
|
|
|
|
def test_no_package_on_disk_says_reinstall_rather_than_failing_silently(tmp_path):
|
|
empty = tmp_path / "packages"; empty.mkdir()
|
|
dest = tmp_path / "_bundled" / "claude.exe"
|
|
r = heal.repair_bundled_cli(str(dest), SUFFIX, [str(empty)])
|
|
assert not r.repaired and "reinstall" in r.detail
|
|
assert not dest.exists()
|
|
|
|
|
|
def test_it_prefers_the_NEWEST_package(tmp_path):
|
|
"""An older package holds an older binary; restoring that silently turns one bug into a version
|
|
mismatch nobody would think to look for."""
|
|
cache = tmp_path / "packages"; cache.mkdir()
|
|
old = p_package(str(cache), b"OLD-RUNTIME", "openswarm-1.7.8-full.nupkg")
|
|
new = p_package(str(cache), b"NEW-RUNTIME", "openswarm-1.7.9-full.nupkg")
|
|
os.utime(old, (1, 1))
|
|
os.utime(new, (10_000_000, 10_000_000))
|
|
dest = tmp_path / "_bundled" / "claude.exe"
|
|
r = heal.repair_bundled_cli(str(dest), SUFFIX, [str(cache)])
|
|
assert dest.read_bytes() == b"NEW-RUNTIME", "restored the stale copy"
|
|
assert r.source == new
|
|
|
|
|
|
def test_a_package_without_the_binary_is_skipped_not_trusted(tmp_path):
|
|
cache = tmp_path / "packages"; cache.mkdir()
|
|
p_package(str(cache), b"irrelevant", "openswarm-1.7.9-full.nupkg", member="lib/net45/README.txt")
|
|
good = p_package(str(cache), b"PRISTINE-RUNTIME", "openswarm-1.7.9-delta.nupkg")
|
|
os.utime(good, (1, 1))
|
|
dest = tmp_path / "_bundled" / "claude.exe"
|
|
r = heal.repair_bundled_cli(str(dest), SUFFIX, [str(cache)])
|
|
assert r.repaired and r.source == good
|
|
|
|
|
|
def test_a_corrupt_package_does_not_take_the_repair_down_with_it(tmp_path):
|
|
cache = tmp_path / "packages"; cache.mkdir()
|
|
(cache / "openswarm-broken.nupkg").write_bytes(b"not a zip at all")
|
|
good = p_package(str(cache), b"PRISTINE-RUNTIME", "openswarm-ok.nupkg")
|
|
os.utime(good, (1, 1))
|
|
dest = tmp_path / "_bundled" / "claude.exe"
|
|
assert heal.repair_bundled_cli(str(dest), SUFFIX, [str(cache)]).repaired
|
|
assert dest.read_bytes() == b"PRISTINE-RUNTIME"
|
|
|
|
|
|
def test_a_present_binary_is_never_overwritten(tmp_path):
|
|
"""The innocent case: this runs on a healthy install too, and must not clobber a good file with
|
|
an older packaged one."""
|
|
cache = tmp_path / "packages"; cache.mkdir()
|
|
p_package(str(cache), b"PACKAGED")
|
|
dest = tmp_path / "_bundled" / "claude.exe"
|
|
dest.parent.mkdir(parents=True)
|
|
dest.write_bytes(b"LIVE-AND-FINE")
|
|
r = heal.repair_bundled_cli(str(dest), SUFFIX, [str(cache)])
|
|
assert not r.repaired and dest.read_bytes() == b"LIVE-AND-FINE"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_detection_actually_CALLS_the_repair(monkeypatch):
|
|
"""A repair nothing calls is this codebase's recurring defect: present, reachable, doing nothing.
|
|
Detection already existed and left 22 of 25 installs dead precisely because nothing acted on it.
|
|
|
|
Behavioural, not a grep: an earlier version of this test asserted the NAME appeared in the
|
|
source, and passed happily when the call was replaced with a raise."""
|
|
import backend.apps.agents.core.bundled_cli_missing as det
|
|
import backend.apps.agents.core.cli_self_heal as sh
|
|
from backend.apps.agents.agents import subscriptions_health
|
|
|
|
called = {}
|
|
monkeypatch.setattr(det, "bundled_cli_missing", lambda: "/gone/claude.exe")
|
|
def p_fake(dest, *a, **k):
|
|
called["dest"] = dest
|
|
return sh.RepairResult(repaired=True, detail="restored in the test")
|
|
monkeypatch.setattr(sh, "repair_bundled_cli", p_fake)
|
|
monkeypatch.setattr("backend.apps.nine_router.is_running", lambda: False)
|
|
|
|
out = await subscriptions_health()
|
|
assert called.get("dest") == "/gone/claude.exe", "the repair was never attempted"
|
|
assert out.get("cli_repair") == "restored in the test", "the endpoint hid what the repair did"
|
|
|
|
|
|
def test_the_repair_never_heals_in_silence():
|
|
"""Every return path of the health endpoint carries what the repair did. A fix the user is not
|
|
told about is indistinguishable from a flaky app that broke and un-broke itself."""
|
|
src = open("backend/apps/agents/agents.py", encoding="utf-8").read()
|
|
i = src.index("async def subscriptions_health")
|
|
body = src[i:src.index("@agents.router", i + 10)]
|
|
returns = [ln for ln in body.splitlines() if "return {" in ln and "cli_missing" in ln]
|
|
assert returns, "the health endpoint stopped reporting cli_missing"
|
|
for ln in returns:
|
|
assert "cli_repair" in ln, f"a return path hides the repair: {ln.strip()[:80]}"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_a_MIDSESSION_quarantine_repairs_instead_of_carding(monkeypatch, tmp_path):
|
|
"""Boot-time repair only covers a quarantine that happened while the app was closed. The one
|
|
that happens while someone is working still ended the turn with an antivirus card, which is the
|
|
exact moment Kittie was in."""
|
|
import backend.apps.agents.manager.run.handle_run_error as hre
|
|
import backend.apps.agents.core.bundled_cli_missing as det
|
|
import backend.apps.agents.core.cli_self_heal as sh
|
|
from backend.apps.agents.core.models import AgentSession
|
|
|
|
monkeypatch.setattr(det, "bundled_cli_missing", lambda: "/gone/claude.exe")
|
|
monkeypatch.setattr(sh, "repair_bundled_cli",
|
|
lambda dest, *a, **k: sh.RepairResult(repaired=True, detail="restored"))
|
|
sent = []
|
|
async def p_send(sid, ev, payload): sent.append(payload)
|
|
monkeypatch.setattr(hre.ws_manager, "send_to_session", p_send)
|
|
|
|
s = AgentSession(name="t", model="opus-5")
|
|
assert await hre.p_try_runtime_repair(s, "sess") is True
|
|
assert sent and "restored" in str(sent[-1]).lower()
|
|
assert "send that message again" in str(sent[-1]).lower(), "tell them what to do next"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_a_repair_that_does_not_stick_lets_the_card_stand(monkeypatch):
|
|
"""The ambiguous outcomes must NOT suppress the card: a half-repair that reads as success is
|
|
worse than the card, because the user retries into the same wall with no explanation."""
|
|
import backend.apps.agents.manager.run.handle_run_error as hre
|
|
import backend.apps.agents.core.bundled_cli_missing as det
|
|
import backend.apps.agents.core.cli_self_heal as sh
|
|
from backend.apps.agents.core.models import AgentSession
|
|
|
|
monkeypatch.setattr(det, "bundled_cli_missing", lambda: "/gone/claude.exe")
|
|
for result in (sh.RepairResult(repaired=True, retaken=True, detail="taken again"),
|
|
sh.RepairResult(repaired=False, detail="no package")):
|
|
monkeypatch.setattr(sh, "repair_bundled_cli", lambda dest, *a, r=result, **k: r)
|
|
assert await hre.p_try_runtime_repair(AgentSession(name="t", model="opus-5"), "sess") is False
|