reset
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
import base64
|
||||
|
||||
import pytest
|
||||
|
||||
from server.main import manager
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_screenshot() -> str:
|
||||
"""Return a reproducible base64 string representing a dummy screenshot."""
|
||||
return base64.b64encode(b"clickthrough-dummy").decode()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def default_grid_request(fake_screenshot):
|
||||
return {
|
||||
"width": 640,
|
||||
"height": 480,
|
||||
"screenshot_base64": fake_screenshot,
|
||||
"rows": 3,
|
||||
"columns": 3,
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_manager_state():
|
||||
manager._grids.clear()
|
||||
yield
|
||||
manager._grids.clear()
|
||||
@@ -1,79 +0,0 @@
|
||||
from typing import Any, Dict
|
||||
|
||||
from skill.agent_runner import ClickthroughAgentRunner
|
||||
from skill.clickthrough_skill import ActionPlan, ClickthroughSkill
|
||||
|
||||
|
||||
class DummySkill(ClickthroughSkill):
|
||||
def __init__(self):
|
||||
self.last_plan: ActionPlan | None = None
|
||||
|
||||
def describe_grid(
|
||||
self,
|
||||
screenshot_base64: str,
|
||||
width: int,
|
||||
height: int,
|
||||
rows: int = 4,
|
||||
columns: int = 4,
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"grid_id": "dummy-grid",
|
||||
"cells": [
|
||||
{"cell_id": "dummy-grid-1", "label": "button", "bounds": [0, 0, 100, 100]},
|
||||
{"cell_id": "dummy-grid-2", "label": "target", "bounds": [100, 0, 200, 100]},
|
||||
],
|
||||
}
|
||||
|
||||
def plan_with_planner(
|
||||
self,
|
||||
grid_id: str,
|
||||
preferred_label: str | None = None,
|
||||
action: str = "click",
|
||||
text: str | None = None,
|
||||
comment: str | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
cells = ["dummy-grid-1", "dummy-grid-2"]
|
||||
if preferred_label == "target":
|
||||
target = "dummy-grid-2"
|
||||
else:
|
||||
target = cells[len(cells) // 2]
|
||||
plan = {
|
||||
"grid_id": grid_id,
|
||||
"target_cell": target,
|
||||
"action": action,
|
||||
"text": text,
|
||||
"comment": comment,
|
||||
}
|
||||
return {
|
||||
"plan": plan,
|
||||
"result": {"success": True, "detail": "preview"},
|
||||
"descriptor": {"grid_id": grid_id},
|
||||
}
|
||||
|
||||
def plan_action(self, plan: ActionPlan) -> Dict[str, Any]:
|
||||
self.last_plan = plan
|
||||
return {"success": True, "target_cell": plan.target_cell}
|
||||
|
||||
def grid_summary(self, grid_id: str) -> Dict[str, Any]:
|
||||
return {"grid_id": grid_id, "summary": "ok"}
|
||||
|
||||
def grid_history(self, grid_id: str) -> Dict[str, Any]:
|
||||
return {"grid_id": grid_id, "history": []}
|
||||
|
||||
|
||||
def test_agent_runner_prefers_label():
|
||||
runner = ClickthroughAgentRunner(DummySkill())
|
||||
result = runner.run_once(
|
||||
screenshot_base64="AA==",
|
||||
width=120,
|
||||
height=80,
|
||||
preferred_label="target",
|
||||
)
|
||||
assert result.action["target_cell"] == "dummy-grid-2"
|
||||
assert result.summary["summary"] == "ok"
|
||||
|
||||
|
||||
def test_agent_runner_defaults_to_center():
|
||||
runner = ClickthroughAgentRunner(DummySkill())
|
||||
result = runner.run_once(screenshot_base64="AA==", width=120, height=80)
|
||||
assert result.action["target_cell"] == "dummy-grid-2"
|
||||
@@ -1,32 +0,0 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from server.main import app, manager
|
||||
|
||||
test_client = TestClient(app)
|
||||
|
||||
|
||||
def test_plan_endpoint(default_grid_request):
|
||||
init_response = test_client.post("/grid/init", json=default_grid_request)
|
||||
grid_id = init_response.json()["grid_id"]
|
||||
|
||||
plan_response = test_client.post(
|
||||
f"/grid/{grid_id}/plan",
|
||||
json={"preferred_label": None, "action": "click", "text": "hello"},
|
||||
)
|
||||
assert plan_response.status_code == 200
|
||||
payload = plan_response.json()
|
||||
assert payload["plan"]["grid_id"] == grid_id
|
||||
assert payload["result"]["success"]
|
||||
|
||||
|
||||
def test_refresh_endpoint(default_grid_request):
|
||||
init_response = test_client.post("/grid/init", json=default_grid_request)
|
||||
grid_id = init_response.json()["grid_id"]
|
||||
|
||||
refresh_response = test_client.post(
|
||||
f"/grid/{grid_id}/refresh", json={"screenshot_base64": "AAA", "memo": "updated"}
|
||||
)
|
||||
assert refresh_response.status_code == 200
|
||||
grid = manager.get_grid(grid_id)
|
||||
assert grid.screenshot == "AAA"
|
||||
assert grid.memo == "updated"
|
||||
@@ -1,51 +0,0 @@
|
||||
from server.config import ServerSettings
|
||||
from server.grid import GridManager
|
||||
from server.models import ActionPayload, ActionType, GridInitRequest
|
||||
|
||||
|
||||
def test_grid_creation_respects_dimensions(default_grid_request):
|
||||
settings = ServerSettings(grid_rows=2, grid_cols=2)
|
||||
manager = GridManager(settings)
|
||||
request = GridInitRequest(**default_grid_request)
|
||||
grid = manager.create_grid(request)
|
||||
|
||||
descriptor = grid.describe()
|
||||
assert descriptor.grid_id
|
||||
assert descriptor.rows == 3
|
||||
assert descriptor.columns == 3
|
||||
assert len(descriptor.cells) == 9
|
||||
assert descriptor.metadata.get("width") == 640
|
||||
assert descriptor.metadata.get("height") == 480
|
||||
|
||||
|
||||
def test_grid_action_records_history(default_grid_request):
|
||||
manager = GridManager(ServerSettings())
|
||||
request = GridInitRequest(**default_grid_request)
|
||||
grid = manager.create_grid(request)
|
||||
descriptor = grid.describe()
|
||||
target_cell = descriptor.cells[0].cell_id
|
||||
|
||||
payload = ActionPayload(
|
||||
grid_id=descriptor.grid_id,
|
||||
action=ActionType.CLICK,
|
||||
target_cell=target_cell,
|
||||
comment="click test",
|
||||
)
|
||||
result = grid.apply_action(payload)
|
||||
|
||||
assert result.success
|
||||
assert result.coordinates is not None
|
||||
assert grid.action_history[-1]["coordinates"] == result.coordinates
|
||||
|
||||
|
||||
def test_manager_get_grid_missing(default_grid_request):
|
||||
manager = GridManager(ServerSettings())
|
||||
request = GridInitRequest(**default_grid_request)
|
||||
_ = manager.create_grid(request)
|
||||
|
||||
try:
|
||||
manager.get_grid("does-not-exist")
|
||||
found = True
|
||||
except KeyError:
|
||||
found = False
|
||||
assert not found
|
||||
@@ -1,32 +0,0 @@
|
||||
from server.config import ServerSettings
|
||||
from server.grid import GridManager
|
||||
from server.planner import GridPlanner
|
||||
from server.models import ActionType, GridInitRequest
|
||||
|
||||
|
||||
def test_planner_preferred_label(default_grid_request):
|
||||
settings = ServerSettings()
|
||||
manager = GridManager(settings)
|
||||
request = GridInitRequest(**default_grid_request)
|
||||
grid = manager.create_grid(request)
|
||||
descriptor = grid.describe()
|
||||
descriptor.cells[0].label = "target"
|
||||
|
||||
planner = GridPlanner()
|
||||
payload = planner.build_payload(descriptor, preferred_label="target", action=ActionType.CLICK)
|
||||
|
||||
assert payload.target_cell == descriptor.cells[0].cell_id
|
||||
|
||||
|
||||
def test_planner_falls_back_to_center(default_grid_request):
|
||||
settings = ServerSettings()
|
||||
manager = GridManager(settings)
|
||||
request = GridInitRequest(**default_grid_request)
|
||||
grid = manager.create_grid(request)
|
||||
descriptor = grid.describe()
|
||||
|
||||
planner = GridPlanner()
|
||||
payload = planner.build_payload(descriptor, action=ActionType.CLICK)
|
||||
|
||||
assert payload.target_cell is not None
|
||||
assert payload.grid_id == descriptor.grid_id
|
||||
@@ -1,41 +0,0 @@
|
||||
import asyncio
|
||||
|
||||
from server.streamer import ScreenshotStreamer
|
||||
|
||||
|
||||
class DummyWebSocket:
|
||||
def __init__(self):
|
||||
self.sent = []
|
||||
self.accepted = False
|
||||
|
||||
async def accept(self) -> None:
|
||||
self.accepted = True
|
||||
|
||||
async def send_json(self, payload):
|
||||
self.sent.append(payload)
|
||||
|
||||
|
||||
def test_streamer_broadcasts_to_grid():
|
||||
streamer = ScreenshotStreamer()
|
||||
socket = DummyWebSocket()
|
||||
|
||||
async def scenario():
|
||||
key = await streamer.connect(socket, "grid-123")
|
||||
await streamer.broadcast("grid-123", {"frame": 1})
|
||||
streamer.disconnect(socket, key)
|
||||
|
||||
asyncio.run(scenario())
|
||||
assert socket.sent == [{"frame": 1}]
|
||||
|
||||
|
||||
def test_streamer_wildcard_listener_receives_updates():
|
||||
streamer = ScreenshotStreamer()
|
||||
socket = DummyWebSocket()
|
||||
|
||||
async def scenario():
|
||||
key = await streamer.connect(socket, None)
|
||||
await streamer.broadcast("grid-456", {"frame": 2})
|
||||
streamer.disconnect(socket, key)
|
||||
|
||||
asyncio.run(scenario())
|
||||
assert socket.sent == [{"frame": 2}]
|
||||
@@ -1,12 +0,0 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from server.main import app
|
||||
|
||||
|
||||
test_client = TestClient(app)
|
||||
|
||||
|
||||
def test_ui_root_serves_index():
|
||||
response = test_client.get("/ui/")
|
||||
assert response.status_code == 200
|
||||
assert "Clickthrough Control" in response.text
|
||||
Reference in New Issue
Block a user