This commit is contained in:
2026-07-26 18:49:51 -06:00
parent e9d92b0ba2
commit c16fada8d8
12 changed files with 1007 additions and 17 deletions
+135
View File
@@ -5,6 +5,7 @@ the live wake threshold.
Needs a QApplication (signals), so run with QT_QPA_PLATFORM=offscreen.
"""
import json
import sys
from pathlib import Path
@@ -79,6 +80,62 @@ def test_petctl_nap_also_flips_the_controller_state(ctrl):
assert ctrl._napping is True
# ── filectl routing ──────────────────────────────────────────────────────────
# filectl's wire format is a single-line JSON envelope (see file_ops.py's
# module docstring for why) — build commands with json.dumps so the tests
# don't hardcode escaping by hand.
def _filectl(payload: dict) -> str:
return "filectl " + json.dumps(payload)
def test_filectl_commands_never_reach_the_shell(monkeypatch, ctrl, tmp_path):
ran = []
monkeypatch.setattr(controller_mod.server_client, "run_local_command", lambda cmd: ran.append(cmd))
target = tmp_path / "a.txt"
output = ctrl._handle_command(_filectl({"op": "write", "path": str(target), "content": "hello"}))
assert ran == []
assert target.read_text() == "hello"
assert str(target) in output
def test_filectl_edit_round_trips_through_the_relay(monkeypatch, ctrl, tmp_path):
monkeypatch.setattr(controller_mod.server_client, "run_local_command",
lambda cmd: (_ for _ in ()).throw(AssertionError("should not shell out")))
target = tmp_path / "a.py"
target.write_text("x = 1\n")
output = ctrl._handle_command(
_filectl({"op": "edit", "path": str(target), "old": "x = 1", "new": "x = 2"})
)
assert target.read_text() == "x = 2\n"
assert str(target) in output
def test_bad_filectl_syntax_is_reported_back_not_executed(monkeypatch, ctrl):
ran = []
monkeypatch.setattr(controller_mod.server_client, "run_local_command", lambda cmd: ran.append(cmd))
output = ctrl._handle_command("filectl {not valid json")
assert ran == []
assert "[filectl]" in output
def test_filectl_execution_failure_is_reported_back_not_raised(monkeypatch, ctrl):
output = ctrl._handle_command(_filectl({"op": "read", "path": "/no/such/file.txt"}))
assert "[filectl]" in output
def test_ordinary_commands_still_run_locally_alongside_filectl(monkeypatch, ctrl):
ran = []
monkeypatch.setattr(controller_mod.server_client, "run_local_command",
lambda cmd: ran.append(cmd) or "[exit 0]\n")
ctrl._handle_command("df -h /")
assert ran == ["df -h /"]
# ── barge-in ────────────────────────────────────────────────────────────────
def test_the_interrupt_log_reports_what_fired_not_the_reset_counters(monkeypatch, ctrl):
@@ -383,3 +440,81 @@ def test_near_misses_are_recorded_for_the_tuner(ctrl):
ctrl.reset_wake_stats()
assert ctrl.wake_stats()["near_misses"] == []
# ── file delivery ────────────────────────────────────────────────────────────
def test_check_deliveries_downloads_and_saves_queued_files(monkeypatch, ctrl, tmp_path):
monkeypatch.setattr(controller_mod.config, "DELIVERED_FILES_DIR", tmp_path)
monkeypatch.setattr(controller_mod.server_client, "list_outbox_files",
lambda: [{"id": "abc", "name": "report.pdf", "size": 5}])
monkeypatch.setattr(controller_mod.server_client, "download_outbox_file",
lambda file_id: b"hello" if file_id == "abc" else b"")
ctrl._check_deliveries()
assert (tmp_path / "report.pdf").read_bytes() == b"hello"
def test_check_deliveries_is_a_noop_when_nothing_queued(monkeypatch, ctrl, tmp_path):
monkeypatch.setattr(controller_mod.config, "DELIVERED_FILES_DIR", tmp_path)
monkeypatch.setattr(controller_mod.server_client, "list_outbox_files", lambda: [])
downloaded = []
monkeypatch.setattr(controller_mod.server_client, "download_outbox_file",
lambda file_id: downloaded.append(file_id))
ctrl._check_deliveries()
assert downloaded == []
def test_check_deliveries_can_be_disabled(monkeypatch, ctrl):
monkeypatch.setattr(controller_mod.config, "RECEIVE_FILES", False)
called = {"n": 0}
monkeypatch.setattr(controller_mod.server_client, "list_outbox_files",
lambda: called.__setitem__("n", called["n"] + 1))
ctrl._check_deliveries()
assert called["n"] == 0
def test_check_deliveries_logs_and_continues_on_download_failure(monkeypatch, ctrl, tmp_path):
monkeypatch.setattr(controller_mod.config, "DELIVERED_FILES_DIR", tmp_path)
monkeypatch.setattr(controller_mod.server_client, "list_outbox_files", lambda: [
{"id": "bad", "name": "a.txt", "size": 1},
{"id": "good", "name": "b.txt", "size": 1},
])
def fake_download(file_id):
if file_id == "bad":
raise controller_mod.server_client.ServerError("gone")
return b"ok"
monkeypatch.setattr(controller_mod.server_client, "download_outbox_file", fake_download)
logs = _capture(ctrl.log)
ctrl._check_deliveries()
assert (tmp_path / "b.txt").read_bytes() == b"ok"
assert not (tmp_path / "a.txt").exists()
assert any("bad" in msg or "a.txt" in msg for msg in logs)
def test_check_deliveries_runs_after_a_conversation_turn(monkeypatch, ctrl, tmp_path):
monkeypatch.setattr(controller_mod.mic, "record_utterance",
lambda *a, **k: np.zeros(10, dtype=np.int16))
monkeypatch.setattr(controller_mod.stt, "transcribe", lambda pcm: "send me that file")
monkeypatch.setattr(controller_mod.server_client, "converse",
lambda text, on_command=None: "it's on the way")
monkeypatch.setattr(controller_mod.tts, "speak",
lambda text, on_error=None, should_stop=None: True)
monkeypatch.setattr(controller_mod.config, "DELIVERED_FILES_DIR", tmp_path)
monkeypatch.setattr(controller_mod.server_client, "list_outbox_files",
lambda: [{"id": "abc", "name": "notes.txt", "size": 2}])
monkeypatch.setattr(controller_mod.server_client, "download_outbox_file",
lambda file_id: b"hi")
ctrl._handle_conversation_turn()
assert (tmp_path / "notes.txt").read_bytes() == b"hi"