114 lines
4.1 KiB
Python
114 lines
4.1 KiB
Python
import json
|
|
from pathlib import Path
|
|
|
|
import httpx
|
|
from typer.testing import CliRunner
|
|
|
|
from reyna_cli.cli import app
|
|
from reyna_cli.config import Device, Registry, get_device, resolve_device_host
|
|
from reyna_cli.tactility import TactilityClient
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
def test_friendly_name_lookup_is_case_insensitive():
|
|
registry = Registry(devices=[Device(id="kidsos_5c5c", display_name="Grace's 2.8-inch Tactility Board")])
|
|
assert get_device("Grace", registry).id == "kidsos_5c5c"
|
|
assert get_device("grace", registry).id == "kidsos_5c5c"
|
|
|
|
|
|
def test_resolve_device_host_prefers_live_mdns(monkeypatch):
|
|
monkeypatch.setattr("reyna_cli.config.socket.gethostbyname", lambda host: "192.168.68.141")
|
|
device = Device(id="kidsos_1234", host="kidsos-1234.local", reserved_ip="192.168.68.99")
|
|
assert resolve_device_host(device) == "192.168.68.141"
|
|
|
|
|
|
def test_resolve_device_host_falls_back_when_mdns_is_offline(monkeypatch):
|
|
def fail(_host):
|
|
raise OSError("offline")
|
|
|
|
monkeypatch.setattr("reyna_cli.config.socket.gethostbyname", fail)
|
|
device = Device(id="kidsos_1234", host="kidsos-1234.local", reserved_ip="192.168.68.99")
|
|
assert resolve_device_host(device) == "192.168.68.99"
|
|
|
|
|
|
def test_tactility_client_uses_web_api(monkeypatch, tmp_path):
|
|
requests = []
|
|
|
|
def handler(request: httpx.Request):
|
|
requests.append(request)
|
|
if request.url.path == "/api/sysinfo":
|
|
return httpx.Response(200, json={"version": "0.8.0-dev"})
|
|
if request.url.path == "/api/apps":
|
|
return httpx.Response(200, json={"apps": [{"id": "one.tactility.demo"}]})
|
|
if request.url.path == "/fs/list":
|
|
return httpx.Response(200, json={"path": "/sdcard", "entries": []})
|
|
return httpx.Response(200, json={"ok": True})
|
|
|
|
client = TactilityClient("http://kidsos-1234.local", transport=httpx.MockTransport(handler))
|
|
assert client.sysinfo()["version"] == "0.8.0-dev"
|
|
assert client.apps()["apps"][0]["id"] == "one.tactility.demo"
|
|
assert client.fs_list("/sdcard")["path"] == "/sdcard"
|
|
assert requests[0].url.host == "kidsos-1234.local"
|
|
|
|
|
|
def test_tactility_install_and_run_requests(tmp_path):
|
|
requests = []
|
|
|
|
def handler(request: httpx.Request):
|
|
requests.append(request)
|
|
return httpx.Response(200, json={"ok": True})
|
|
|
|
app_file = tmp_path / "demo.app"
|
|
app_file.write_bytes(b"APP")
|
|
client = TactilityClient("http://192.168.68.99", transport=httpx.MockTransport(handler))
|
|
client.install_app(app_file)
|
|
client.run_app("one.tactility.demo")
|
|
|
|
assert requests[0].method == "PUT"
|
|
assert requests[0].url.path == "/api/apps/install"
|
|
assert requests[1].url.path == "/api/apps/run"
|
|
assert requests[1].url.params["id"] == "one.tactility.demo"
|
|
|
|
|
|
def test_tactility_screen_text_clears_before_write():
|
|
requests = []
|
|
|
|
def handler(request: httpx.Request):
|
|
requests.append(request)
|
|
return httpx.Response(200, json={"ok": True})
|
|
|
|
client = TactilityClient("http://192.168.68.99", transport=httpx.MockTransport(handler))
|
|
result = client.screen_text("Grace", 20, 10, clear_first=True)
|
|
|
|
assert result["clear_first"] is True
|
|
assert [request.url.path for request in requests] == ["/api/screen/raw", "/api/screen/raw"]
|
|
assert requests[0].content == bytes(20 * 10 * 2)
|
|
assert len(requests[1].content) == 20 * 10 * 2
|
|
|
|
|
|
def test_tactility_cli_has_commands(monkeypatch, tmp_path):
|
|
registry_path = tmp_path / "devices.yaml"
|
|
registry_path.write_text(
|
|
"""
|
|
devices:
|
|
kidsos_1234:
|
|
type: esp32-s3-tactility
|
|
host: kidsos-1234.local
|
|
reserved_ip: 192.168.68.99
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
monkeypatch.setenv("REYNA_DEVICES_REGISTRY", str(registry_path))
|
|
|
|
result = runner.invoke(app, ["tactility", "--help"])
|
|
assert result.exit_code == 0
|
|
for command in ("discover", "sysinfo", "apps", "install", "run", "report", "fs", "screen"):
|
|
assert command in result.stdout
|
|
|
|
|
|
def test_robot_arm_is_not_a_cli_surface():
|
|
result = runner.invoke(app, ["devices", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "arm" not in result.stdout.lower()
|