mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-30 01:41:43 +00:00
refactor(restructure): rewrite all imports for hermes_agent package
Rewrite all import statements, patch() targets, sys.modules keys, importlib.import_module() strings, and subprocess -m references to use hermes_agent.* paths. Strip sys.path.insert hacks from production code (rely on editable install). Update COMPONENT_PREFIXES for logger filtering. Fix 3 hardcoded getLogger() calls to use __name__. Update transport and tool registry discovery paths. Update plugin module path strings. Add legacy process-name patterns for gateway PID detection. Add main() to skills_sync for console_script entry point. Fix _get_bundled_dir() path traversal after move. Part of #14182, #14183
This commit is contained in:
parent
65ca3ba93b
commit
4b16341975
898 changed files with 12494 additions and 12019 deletions
|
|
@ -45,35 +45,35 @@ class TestUploadPasteRs:
|
|||
"""Test paste.rs upload path."""
|
||||
|
||||
def test_upload_paste_rs_success(self):
|
||||
from hermes_cli.debug import _upload_paste_rs
|
||||
from hermes_agent.cli.debug import _upload_paste_rs
|
||||
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.read.return_value = b"https://paste.rs/abc123\n"
|
||||
mock_resp.__enter__ = lambda s: s
|
||||
mock_resp.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
with patch("hermes_cli.debug.urllib.request.urlopen", return_value=mock_resp):
|
||||
with patch("hermes_agent.cli.debug.urllib.request.urlopen", return_value=mock_resp):
|
||||
url = _upload_paste_rs("hello world")
|
||||
|
||||
assert url == "https://paste.rs/abc123"
|
||||
|
||||
def test_upload_paste_rs_bad_response(self):
|
||||
from hermes_cli.debug import _upload_paste_rs
|
||||
from hermes_agent.cli.debug import _upload_paste_rs
|
||||
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.read.return_value = b"<html>error</html>"
|
||||
mock_resp.__enter__ = lambda s: s
|
||||
mock_resp.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
with patch("hermes_cli.debug.urllib.request.urlopen", return_value=mock_resp):
|
||||
with patch("hermes_agent.cli.debug.urllib.request.urlopen", return_value=mock_resp):
|
||||
with pytest.raises(ValueError, match="Unexpected response"):
|
||||
_upload_paste_rs("test")
|
||||
|
||||
def test_upload_paste_rs_network_error(self):
|
||||
from hermes_cli.debug import _upload_paste_rs
|
||||
from hermes_agent.cli.debug import _upload_paste_rs
|
||||
|
||||
with patch(
|
||||
"hermes_cli.debug.urllib.request.urlopen",
|
||||
"hermes_agent.cli.debug.urllib.request.urlopen",
|
||||
side_effect=urllib.error.URLError("connection refused"),
|
||||
):
|
||||
with pytest.raises(urllib.error.URLError):
|
||||
|
|
@ -84,14 +84,14 @@ class TestUploadDpasteCom:
|
|||
"""Test dpaste.com fallback upload path."""
|
||||
|
||||
def test_upload_dpaste_com_success(self):
|
||||
from hermes_cli.debug import _upload_dpaste_com
|
||||
from hermes_agent.cli.debug import _upload_dpaste_com
|
||||
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.read.return_value = b"https://dpaste.com/ABCDEFG\n"
|
||||
mock_resp.__enter__ = lambda s: s
|
||||
mock_resp.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
with patch("hermes_cli.debug.urllib.request.urlopen", return_value=mock_resp):
|
||||
with patch("hermes_agent.cli.debug.urllib.request.urlopen", return_value=mock_resp):
|
||||
url = _upload_dpaste_com("hello world", expiry_days=7)
|
||||
|
||||
assert url == "https://dpaste.com/ABCDEFG"
|
||||
|
|
@ -101,9 +101,9 @@ class TestUploadToPastebin:
|
|||
"""Test the combined upload with fallback."""
|
||||
|
||||
def test_tries_paste_rs_first(self):
|
||||
from hermes_cli.debug import upload_to_pastebin
|
||||
from hermes_agent.cli.debug import upload_to_pastebin
|
||||
|
||||
with patch("hermes_cli.debug._upload_paste_rs",
|
||||
with patch("hermes_agent.cli.debug._upload_paste_rs",
|
||||
return_value="https://paste.rs/test") as prs:
|
||||
url = upload_to_pastebin("content")
|
||||
|
||||
|
|
@ -111,11 +111,11 @@ class TestUploadToPastebin:
|
|||
prs.assert_called_once()
|
||||
|
||||
def test_falls_back_to_dpaste_com(self):
|
||||
from hermes_cli.debug import upload_to_pastebin
|
||||
from hermes_agent.cli.debug import upload_to_pastebin
|
||||
|
||||
with patch("hermes_cli.debug._upload_paste_rs",
|
||||
with patch("hermes_agent.cli.debug._upload_paste_rs",
|
||||
side_effect=Exception("down")), \
|
||||
patch("hermes_cli.debug._upload_dpaste_com",
|
||||
patch("hermes_agent.cli.debug._upload_dpaste_com",
|
||||
return_value="https://dpaste.com/TEST") as dp:
|
||||
url = upload_to_pastebin("content")
|
||||
|
||||
|
|
@ -123,11 +123,11 @@ class TestUploadToPastebin:
|
|||
dp.assert_called_once()
|
||||
|
||||
def test_raises_when_both_fail(self):
|
||||
from hermes_cli.debug import upload_to_pastebin
|
||||
from hermes_agent.cli.debug import upload_to_pastebin
|
||||
|
||||
with patch("hermes_cli.debug._upload_paste_rs",
|
||||
with patch("hermes_agent.cli.debug._upload_paste_rs",
|
||||
side_effect=Exception("err1")), \
|
||||
patch("hermes_cli.debug._upload_dpaste_com",
|
||||
patch("hermes_agent.cli.debug._upload_dpaste_com",
|
||||
side_effect=Exception("err2")):
|
||||
with pytest.raises(RuntimeError, match="Failed to upload"):
|
||||
upload_to_pastebin("content")
|
||||
|
|
@ -141,7 +141,7 @@ class TestReadFullLog:
|
|||
"""Test _read_full_log for standalone log uploads."""
|
||||
|
||||
def test_reads_small_file(self, hermes_home):
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
|
||||
content = _read_full_log("agent")
|
||||
assert content is not None
|
||||
|
|
@ -152,19 +152,19 @@ class TestReadFullLog:
|
|||
home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
assert _read_full_log("agent") is None
|
||||
|
||||
def test_returns_none_for_empty(self, hermes_home):
|
||||
# Truncate agent.log to empty
|
||||
(hermes_home / "logs" / "agent.log").write_text("")
|
||||
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
assert _read_full_log("agent") is None
|
||||
|
||||
def test_truncates_large_file(self, hermes_home):
|
||||
"""Files larger than max_bytes get tail-truncated."""
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
|
||||
# Write a file larger than 1KB
|
||||
big_content = "x" * 100 + "\n"
|
||||
|
|
@ -175,12 +175,12 @@ class TestReadFullLog:
|
|||
assert "truncated" in content
|
||||
|
||||
def test_unknown_log_returns_none(self, hermes_home):
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
assert _read_full_log("nonexistent") is None
|
||||
|
||||
def test_falls_back_to_rotated_file(self, hermes_home):
|
||||
"""When gateway.log doesn't exist, falls back to gateway.log.1."""
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
|
||||
logs_dir = hermes_home / "logs"
|
||||
# Remove the primary (if any) and create a .1 rotation
|
||||
|
|
@ -195,7 +195,7 @@ class TestReadFullLog:
|
|||
|
||||
def test_prefers_primary_over_rotated(self, hermes_home):
|
||||
"""Primary log is used when it exists, even if .1 also exists."""
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
|
||||
logs_dir = hermes_home / "logs"
|
||||
(logs_dir / "gateway.log").write_text("primary content\n")
|
||||
|
|
@ -207,7 +207,7 @@ class TestReadFullLog:
|
|||
|
||||
def test_falls_back_when_primary_empty(self, hermes_home):
|
||||
"""Empty primary log falls back to .1 rotation."""
|
||||
from hermes_cli.debug import _read_full_log
|
||||
from hermes_agent.cli.debug import _read_full_log
|
||||
|
||||
logs_dir = hermes_home / "logs"
|
||||
(logs_dir / "agent.log").write_text("")
|
||||
|
|
@ -226,9 +226,9 @@ class TestCollectDebugReport:
|
|||
"""Test the debug report builder."""
|
||||
|
||||
def test_report_includes_dump_output(self, hermes_home):
|
||||
from hermes_cli.debug import collect_debug_report
|
||||
from hermes_agent.cli.debug import collect_debug_report
|
||||
|
||||
with patch("hermes_cli.dump.run_dump") as mock_dump:
|
||||
with patch("hermes_agent.cli.dump.run_dump") as mock_dump:
|
||||
mock_dump.side_effect = lambda args: print(
|
||||
"--- hermes dump ---\nversion: 0.8.0\n--- end dump ---"
|
||||
)
|
||||
|
|
@ -238,27 +238,27 @@ class TestCollectDebugReport:
|
|||
assert "version: 0.8.0" in report
|
||||
|
||||
def test_report_includes_agent_log(self, hermes_home):
|
||||
from hermes_cli.debug import collect_debug_report
|
||||
from hermes_agent.cli.debug import collect_debug_report
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
report = collect_debug_report(log_lines=50)
|
||||
|
||||
assert "--- agent.log" in report
|
||||
assert "session started" in report
|
||||
|
||||
def test_report_includes_errors_log(self, hermes_home):
|
||||
from hermes_cli.debug import collect_debug_report
|
||||
from hermes_agent.cli.debug import collect_debug_report
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
report = collect_debug_report(log_lines=50)
|
||||
|
||||
assert "--- errors.log" in report
|
||||
assert "connection lost" in report
|
||||
|
||||
def test_report_includes_gateway_log(self, hermes_home):
|
||||
from hermes_cli.debug import collect_debug_report
|
||||
from hermes_agent.cli.debug import collect_debug_report
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
report = collect_debug_report(log_lines=50)
|
||||
|
||||
assert "--- gateway.log" in report
|
||||
|
|
@ -268,9 +268,9 @@ class TestCollectDebugReport:
|
|||
home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
|
||||
from hermes_cli.debug import collect_debug_report
|
||||
from hermes_agent.cli.debug import collect_debug_report
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
report = collect_debug_report(log_lines=50)
|
||||
|
||||
assert "(file not found)" in report
|
||||
|
|
@ -285,14 +285,14 @@ class TestRunDebugShare:
|
|||
|
||||
def test_local_flag_prints_full_logs(self, hermes_home, capsys):
|
||||
"""--local prints the report plus full log contents."""
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
args.expire = 7
|
||||
args.local = True
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
run_debug_share(args)
|
||||
|
||||
out = capsys.readouterr().out
|
||||
|
|
@ -302,7 +302,7 @@ class TestRunDebugShare:
|
|||
|
||||
def test_share_uploads_three_pastes(self, hermes_home, capsys):
|
||||
"""Successful share uploads report + agent.log + gateway.log."""
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
|
|
@ -316,8 +316,8 @@ class TestRunDebugShare:
|
|||
uploaded_content.append(content)
|
||||
return f"https://paste.rs/paste{call_count[0]}"
|
||||
|
||||
with patch("hermes_cli.dump.run_dump") as mock_dump, \
|
||||
patch("hermes_cli.debug.upload_to_pastebin",
|
||||
with patch("hermes_agent.cli.dump.run_dump") as mock_dump, \
|
||||
patch("hermes_agent.cli.debug.upload_to_pastebin",
|
||||
side_effect=_mock_upload):
|
||||
mock_dump.side_effect = lambda a: print("--- hermes dump ---\nversion: test\n--- end dump ---")
|
||||
run_debug_share(args)
|
||||
|
|
@ -346,7 +346,7 @@ class TestRunDebugShare:
|
|||
home.mkdir()
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
|
|
@ -358,8 +358,8 @@ class TestRunDebugShare:
|
|||
call_count[0] += 1
|
||||
return f"https://paste.rs/paste{call_count[0]}"
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"), \
|
||||
patch("hermes_cli.debug.upload_to_pastebin",
|
||||
with patch("hermes_agent.cli.dump.run_dump"), \
|
||||
patch("hermes_agent.cli.debug.upload_to_pastebin",
|
||||
side_effect=_mock_upload):
|
||||
run_debug_share(args)
|
||||
|
||||
|
|
@ -370,7 +370,7 @@ class TestRunDebugShare:
|
|||
|
||||
def test_share_continues_on_log_upload_failure(self, hermes_home, capsys):
|
||||
"""Log upload failure doesn't stop the report from being shared."""
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
|
|
@ -384,8 +384,8 @@ class TestRunDebugShare:
|
|||
raise RuntimeError("upload failed")
|
||||
return "https://paste.rs/report"
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"), \
|
||||
patch("hermes_cli.debug.upload_to_pastebin",
|
||||
with patch("hermes_agent.cli.dump.run_dump"), \
|
||||
patch("hermes_agent.cli.debug.upload_to_pastebin",
|
||||
side_effect=_mock_upload):
|
||||
run_debug_share(args)
|
||||
|
||||
|
|
@ -396,15 +396,15 @@ class TestRunDebugShare:
|
|||
|
||||
def test_share_exits_on_report_upload_failure(self, hermes_home, capsys):
|
||||
"""If the main report fails to upload, exit with code 1."""
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
args.expire = 7
|
||||
args.local = False
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"), \
|
||||
patch("hermes_cli.debug.upload_to_pastebin",
|
||||
with patch("hermes_agent.cli.dump.run_dump"), \
|
||||
patch("hermes_agent.cli.debug.upload_to_pastebin",
|
||||
side_effect=RuntimeError("all failed")):
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
run_debug_share(args)
|
||||
|
|
@ -420,7 +420,7 @@ class TestRunDebugShare:
|
|||
|
||||
class TestRunDebug:
|
||||
def test_no_subcommand_shows_usage(self, capsys):
|
||||
from hermes_cli.debug import run_debug
|
||||
from hermes_agent.cli.debug import run_debug
|
||||
|
||||
args = MagicMock()
|
||||
args.debug_command = None
|
||||
|
|
@ -433,7 +433,7 @@ class TestRunDebug:
|
|||
assert "delete" in out
|
||||
|
||||
def test_share_subcommand_routes(self, hermes_home):
|
||||
from hermes_cli.debug import run_debug
|
||||
from hermes_agent.cli.debug import run_debug
|
||||
|
||||
args = MagicMock()
|
||||
args.debug_command = "share"
|
||||
|
|
@ -441,7 +441,7 @@ class TestRunDebug:
|
|||
args.expire = 7
|
||||
args.local = True
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
run_debug(args)
|
||||
|
||||
|
||||
|
|
@ -455,36 +455,36 @@ class TestRunDebug:
|
|||
|
||||
class TestExtractPasteId:
|
||||
def test_paste_rs_url(self):
|
||||
from hermes_cli.debug import _extract_paste_id
|
||||
from hermes_agent.cli.debug import _extract_paste_id
|
||||
assert _extract_paste_id("https://paste.rs/abc123") == "abc123"
|
||||
|
||||
def test_paste_rs_trailing_slash(self):
|
||||
from hermes_cli.debug import _extract_paste_id
|
||||
from hermes_agent.cli.debug import _extract_paste_id
|
||||
assert _extract_paste_id("https://paste.rs/abc123/") == "abc123"
|
||||
|
||||
def test_http_variant(self):
|
||||
from hermes_cli.debug import _extract_paste_id
|
||||
from hermes_agent.cli.debug import _extract_paste_id
|
||||
assert _extract_paste_id("http://paste.rs/xyz") == "xyz"
|
||||
|
||||
def test_non_paste_rs_returns_none(self):
|
||||
from hermes_cli.debug import _extract_paste_id
|
||||
from hermes_agent.cli.debug import _extract_paste_id
|
||||
assert _extract_paste_id("https://dpaste.com/ABCDEF") is None
|
||||
|
||||
def test_empty_returns_none(self):
|
||||
from hermes_cli.debug import _extract_paste_id
|
||||
from hermes_agent.cli.debug import _extract_paste_id
|
||||
assert _extract_paste_id("") is None
|
||||
|
||||
|
||||
class TestDeletePaste:
|
||||
def test_delete_sends_delete_request(self):
|
||||
from hermes_cli.debug import delete_paste
|
||||
from hermes_agent.cli.debug import delete_paste
|
||||
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.status = 200
|
||||
mock_resp.__enter__ = lambda s: s
|
||||
mock_resp.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
with patch("hermes_cli.debug.urllib.request.urlopen",
|
||||
with patch("hermes_agent.cli.debug.urllib.request.urlopen",
|
||||
return_value=mock_resp) as mock_open:
|
||||
result = delete_paste("https://paste.rs/abc123")
|
||||
|
||||
|
|
@ -494,7 +494,7 @@ class TestDeletePaste:
|
|||
assert "paste.rs/abc123" in req.full_url
|
||||
|
||||
def test_delete_rejects_non_paste_rs(self):
|
||||
from hermes_cli.debug import delete_paste
|
||||
from hermes_agent.cli.debug import delete_paste
|
||||
|
||||
with pytest.raises(ValueError, match="only paste.rs"):
|
||||
delete_paste("https://dpaste.com/something")
|
||||
|
|
@ -521,7 +521,7 @@ class TestScheduleAutoDelete:
|
|||
"""
|
||||
import ast
|
||||
import inspect
|
||||
from hermes_cli.debug import _schedule_auto_delete
|
||||
from hermes_agent.cli.debug import _schedule_auto_delete
|
||||
|
||||
# Strip the docstring before scanning so the regression-rationale
|
||||
# prose inside it doesn't trigger our banned-word checks.
|
||||
|
|
@ -576,7 +576,7 @@ class TestScheduleAutoDelete:
|
|||
|
||||
def test_records_pending_to_json(self, hermes_home):
|
||||
"""Scheduled URLs are persisted to pending.json with expiration."""
|
||||
from hermes_cli.debug import _schedule_auto_delete, _pending_file
|
||||
from hermes_agent.cli.debug import _schedule_auto_delete, _pending_file
|
||||
import json
|
||||
|
||||
_schedule_auto_delete(
|
||||
|
|
@ -600,7 +600,7 @@ class TestScheduleAutoDelete:
|
|||
|
||||
def test_skips_non_paste_rs_urls(self, hermes_home):
|
||||
"""dpaste.com URLs auto-expire — don't track them."""
|
||||
from hermes_cli.debug import _schedule_auto_delete, _pending_file
|
||||
from hermes_agent.cli.debug import _schedule_auto_delete, _pending_file
|
||||
|
||||
_schedule_auto_delete(["https://dpaste.com/something"])
|
||||
|
||||
|
|
@ -609,7 +609,7 @@ class TestScheduleAutoDelete:
|
|||
|
||||
def test_merges_with_existing_pending(self, hermes_home):
|
||||
"""Subsequent calls merge into existing pending.json."""
|
||||
from hermes_cli.debug import _schedule_auto_delete, _load_pending
|
||||
from hermes_agent.cli.debug import _schedule_auto_delete, _load_pending
|
||||
|
||||
_schedule_auto_delete(["https://paste.rs/first"], delay_seconds=10)
|
||||
_schedule_auto_delete(["https://paste.rs/second"], delay_seconds=10)
|
||||
|
|
@ -620,7 +620,7 @@ class TestScheduleAutoDelete:
|
|||
|
||||
def test_dedupes_same_url(self, hermes_home):
|
||||
"""Same URL recorded twice → one entry with the later expire_at."""
|
||||
from hermes_cli.debug import _schedule_auto_delete, _load_pending
|
||||
from hermes_agent.cli.debug import _schedule_auto_delete, _load_pending
|
||||
|
||||
_schedule_auto_delete(["https://paste.rs/dup"], delay_seconds=10)
|
||||
_schedule_auto_delete(["https://paste.rs/dup"], delay_seconds=100)
|
||||
|
|
@ -634,14 +634,14 @@ class TestSweepExpiredPastes:
|
|||
"""Test the opportunistic sweep that replaces the sleeping subprocess."""
|
||||
|
||||
def test_sweep_empty_is_noop(self, hermes_home):
|
||||
from hermes_cli.debug import _sweep_expired_pastes
|
||||
from hermes_agent.cli.debug import _sweep_expired_pastes
|
||||
|
||||
deleted, remaining = _sweep_expired_pastes()
|
||||
assert deleted == 0
|
||||
assert remaining == 0
|
||||
|
||||
def test_sweep_deletes_expired_entries(self, hermes_home):
|
||||
from hermes_cli.debug import (
|
||||
from hermes_agent.cli.debug import (
|
||||
_sweep_expired_pastes,
|
||||
_save_pending,
|
||||
_load_pending,
|
||||
|
|
@ -660,7 +660,7 @@ class TestSweepExpiredPastes:
|
|||
delete_calls.append(url)
|
||||
return True
|
||||
|
||||
with patch("hermes_cli.debug.delete_paste", side_effect=fake_delete):
|
||||
with patch("hermes_agent.cli.debug.delete_paste", side_effect=fake_delete):
|
||||
deleted, remaining = _sweep_expired_pastes()
|
||||
|
||||
assert delete_calls == ["https://paste.rs/expired"]
|
||||
|
|
@ -672,7 +672,7 @@ class TestSweepExpiredPastes:
|
|||
assert urls == {"https://paste.rs/future"}
|
||||
|
||||
def test_sweep_leaves_future_entries_alone(self, hermes_home):
|
||||
from hermes_cli.debug import _sweep_expired_pastes, _save_pending
|
||||
from hermes_agent.cli.debug import _sweep_expired_pastes, _save_pending
|
||||
import time
|
||||
|
||||
_save_pending([
|
||||
|
|
@ -680,7 +680,7 @@ class TestSweepExpiredPastes:
|
|||
{"url": "https://paste.rs/future2", "expire_at": time.time() + 7200},
|
||||
])
|
||||
|
||||
with patch("hermes_cli.debug.delete_paste") as mock_delete:
|
||||
with patch("hermes_agent.cli.debug.delete_paste") as mock_delete:
|
||||
deleted, remaining = _sweep_expired_pastes()
|
||||
|
||||
mock_delete.assert_not_called()
|
||||
|
|
@ -689,7 +689,7 @@ class TestSweepExpiredPastes:
|
|||
|
||||
def test_sweep_survives_network_failure(self, hermes_home):
|
||||
"""Failed DELETEs stay in pending.json until the 24h grace window."""
|
||||
from hermes_cli.debug import (
|
||||
from hermes_agent.cli.debug import (
|
||||
_sweep_expired_pastes,
|
||||
_save_pending,
|
||||
_load_pending,
|
||||
|
|
@ -701,7 +701,7 @@ class TestSweepExpiredPastes:
|
|||
])
|
||||
|
||||
with patch(
|
||||
"hermes_cli.debug.delete_paste",
|
||||
"hermes_agent.cli.debug.delete_paste",
|
||||
side_effect=Exception("network down"),
|
||||
):
|
||||
deleted, remaining = _sweep_expired_pastes()
|
||||
|
|
@ -713,7 +713,7 @@ class TestSweepExpiredPastes:
|
|||
|
||||
def test_sweep_drops_entries_past_grace_window(self, hermes_home):
|
||||
"""After 24h past expiration, give up even on network failures."""
|
||||
from hermes_cli.debug import (
|
||||
from hermes_agent.cli.debug import (
|
||||
_sweep_expired_pastes,
|
||||
_save_pending,
|
||||
_load_pending,
|
||||
|
|
@ -727,7 +727,7 @@ class TestSweepExpiredPastes:
|
|||
])
|
||||
|
||||
with patch(
|
||||
"hermes_cli.debug.delete_paste",
|
||||
"hermes_agent.cli.debug.delete_paste",
|
||||
side_effect=Exception("network down"),
|
||||
):
|
||||
deleted, remaining = _sweep_expired_pastes()
|
||||
|
|
@ -741,25 +741,25 @@ class TestRunDebugSweepsOnInvocation:
|
|||
"""``run_debug`` must sweep expired pastes on every invocation."""
|
||||
|
||||
def test_run_debug_calls_sweep(self, hermes_home):
|
||||
from hermes_cli.debug import run_debug
|
||||
from hermes_agent.cli.debug import run_debug
|
||||
|
||||
args = MagicMock()
|
||||
args.debug_command = None # default → prints help
|
||||
|
||||
with patch("hermes_cli.debug._sweep_expired_pastes") as mock_sweep:
|
||||
with patch("hermes_agent.cli.debug._sweep_expired_pastes") as mock_sweep:
|
||||
run_debug(args)
|
||||
|
||||
mock_sweep.assert_called_once()
|
||||
|
||||
def test_run_debug_survives_sweep_failure(self, hermes_home, capsys):
|
||||
"""If the sweep throws, the subcommand still runs."""
|
||||
from hermes_cli.debug import run_debug
|
||||
from hermes_agent.cli.debug import run_debug
|
||||
|
||||
args = MagicMock()
|
||||
args.debug_command = None
|
||||
|
||||
with patch(
|
||||
"hermes_cli.debug._sweep_expired_pastes",
|
||||
"hermes_agent.cli.debug._sweep_expired_pastes",
|
||||
side_effect=RuntimeError("boom"),
|
||||
):
|
||||
run_debug(args) # must not raise
|
||||
|
|
@ -771,12 +771,12 @@ class TestRunDebugSweepsOnInvocation:
|
|||
|
||||
class TestRunDebugDelete:
|
||||
def test_deletes_valid_url(self, capsys):
|
||||
from hermes_cli.debug import run_debug_delete
|
||||
from hermes_agent.cli.debug import run_debug_delete
|
||||
|
||||
args = MagicMock()
|
||||
args.urls = ["https://paste.rs/abc"]
|
||||
|
||||
with patch("hermes_cli.debug.delete_paste", return_value=True):
|
||||
with patch("hermes_agent.cli.debug.delete_paste", return_value=True):
|
||||
run_debug_delete(args)
|
||||
|
||||
out = capsys.readouterr().out
|
||||
|
|
@ -784,12 +784,12 @@ class TestRunDebugDelete:
|
|||
assert "paste.rs/abc" in out
|
||||
|
||||
def test_handles_delete_failure(self, capsys):
|
||||
from hermes_cli.debug import run_debug_delete
|
||||
from hermes_agent.cli.debug import run_debug_delete
|
||||
|
||||
args = MagicMock()
|
||||
args.urls = ["https://paste.rs/abc"]
|
||||
|
||||
with patch("hermes_cli.debug.delete_paste",
|
||||
with patch("hermes_agent.cli.debug.delete_paste",
|
||||
side_effect=Exception("network error")):
|
||||
run_debug_delete(args)
|
||||
|
||||
|
|
@ -797,7 +797,7 @@ class TestRunDebugDelete:
|
|||
assert "Could not delete" in out
|
||||
|
||||
def test_no_urls_shows_usage(self, capsys):
|
||||
from hermes_cli.debug import run_debug_delete
|
||||
from hermes_agent.cli.debug import run_debug_delete
|
||||
|
||||
args = MagicMock()
|
||||
args.urls = []
|
||||
|
|
@ -812,17 +812,17 @@ class TestShareIncludesAutoDelete:
|
|||
"""Verify that run_debug_share schedules auto-deletion and prints TTL."""
|
||||
|
||||
def test_share_schedules_auto_delete(self, hermes_home, capsys):
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
args.expire = 7
|
||||
args.local = False
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"), \
|
||||
patch("hermes_cli.debug.upload_to_pastebin",
|
||||
with patch("hermes_agent.cli.dump.run_dump"), \
|
||||
patch("hermes_agent.cli.debug.upload_to_pastebin",
|
||||
return_value="https://paste.rs/test1"), \
|
||||
patch("hermes_cli.debug._schedule_auto_delete") as mock_sched:
|
||||
patch("hermes_agent.cli.debug._schedule_auto_delete") as mock_sched:
|
||||
run_debug_share(args)
|
||||
|
||||
# auto-delete was scheduled with the uploaded URLs
|
||||
|
|
@ -834,31 +834,31 @@ class TestShareIncludesAutoDelete:
|
|||
assert "auto-delete" in out
|
||||
|
||||
def test_share_shows_privacy_notice(self, hermes_home, capsys):
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
args.expire = 7
|
||||
args.local = False
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"), \
|
||||
patch("hermes_cli.debug.upload_to_pastebin",
|
||||
with patch("hermes_agent.cli.dump.run_dump"), \
|
||||
patch("hermes_agent.cli.debug.upload_to_pastebin",
|
||||
return_value="https://paste.rs/test"), \
|
||||
patch("hermes_cli.debug._schedule_auto_delete"):
|
||||
patch("hermes_agent.cli.debug._schedule_auto_delete"):
|
||||
run_debug_share(args)
|
||||
|
||||
out = capsys.readouterr().out
|
||||
assert "public paste service" in out
|
||||
|
||||
def test_local_no_privacy_notice(self, hermes_home, capsys):
|
||||
from hermes_cli.debug import run_debug_share
|
||||
from hermes_agent.cli.debug import run_debug_share
|
||||
|
||||
args = MagicMock()
|
||||
args.lines = 50
|
||||
args.expire = 7
|
||||
args.local = True
|
||||
|
||||
with patch("hermes_cli.dump.run_dump"):
|
||||
with patch("hermes_agent.cli.dump.run_dump"):
|
||||
run_debug_share(args)
|
||||
|
||||
out = capsys.readouterr().out
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue