133 lines
5.0 KiB
Python
133 lines
5.0 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
from hockey_data.agent_bridge import VmixAgentHub
|
|
from hockey_data.auth_bridge import HockeyUser
|
|
from hockey_data.models import OperatorSession
|
|
from tests.support import LocalTestDatabase
|
|
|
|
|
|
class FakeWebSocket:
|
|
def __init__(self) -> None:
|
|
self.client = SimpleNamespace(host="127.0.0.1")
|
|
self.sent: list[dict] = []
|
|
self.closed = False
|
|
|
|
async def send_json(self, payload: dict) -> None:
|
|
self.sent.append(payload)
|
|
|
|
async def close(self, **_kwargs) -> None:
|
|
self.closed = True
|
|
|
|
|
|
async def _ack_latest(hub: VmixAgentHub, device_id: str, ws: FakeWebSocket) -> dict:
|
|
command = None
|
|
for _ in range(100):
|
|
await asyncio.sleep(0)
|
|
commands = [item for item in ws.sent if item.get("type") == "vmix.command"]
|
|
if commands:
|
|
command = commands[-1]
|
|
break
|
|
assert command is not None
|
|
await hub.receive_command_ack(
|
|
device_id,
|
|
{"type": "command.ack", "request_id": command["request_id"], "ok": True},
|
|
)
|
|
return command
|
|
|
|
|
|
def test_multiple_agents_stay_enabled_and_runtime_routes_to_explicit_browser_agent(tmp_path: Path) -> None:
|
|
database = LocalTestDatabase(tmp_path / "multi-agent.sqlite3")
|
|
database.create_all()
|
|
hub = VmixAgentHub(database) # type: ignore[arg-type]
|
|
user = HockeyUser(id="multi-1", login="multi", display_name="Multi")
|
|
ws_test = FakeWebSocket()
|
|
ws_live = FakeWebSocket()
|
|
|
|
async def scenario() -> None:
|
|
for device_id, secret, ws in (
|
|
("GFX-MULTI-TEST", "t" * 40, ws_test),
|
|
("GFX-MULTI-LIVE", "l" * 40, ws_live),
|
|
):
|
|
await hub.register(
|
|
ws, # type: ignore[arg-type]
|
|
{
|
|
"device_id": device_id,
|
|
"device_secret": secret,
|
|
"device_name": device_id,
|
|
"hostname": device_id,
|
|
"agent_version": "1.4.0",
|
|
"vmix": {"connected": True, "url": "http://127.0.0.1:8088/api/"},
|
|
},
|
|
)
|
|
await hub.pair_device(device_id, user)
|
|
|
|
devices = await hub.list_for_user(user)
|
|
assert set(devices["active_device_ids"]) == {"GFX-MULTI-TEST", "GFX-MULTI-LIVE"}
|
|
|
|
with database.session() as session:
|
|
session.add(
|
|
OperatorSession(
|
|
session_token="multi-session",
|
|
wfl_user_id=user.id,
|
|
login_snapshot=user.login,
|
|
tournament_external_id="1437",
|
|
game_external_id="902918",
|
|
status="active",
|
|
)
|
|
)
|
|
|
|
assert await hub.assign_match(
|
|
wfl_user_id=user.id,
|
|
tournament_external_id="1437",
|
|
game_external_id="902918",
|
|
device_id="GFX-MULTI-TEST",
|
|
operator_session_token="multi-session",
|
|
)
|
|
assert await hub.assign_match(
|
|
wfl_user_id=user.id,
|
|
tournament_external_id="1437",
|
|
game_external_id="902918",
|
|
device_id="GFX-MULTI-LIVE",
|
|
operator_session_token="multi-session",
|
|
)
|
|
|
|
# Ignore pairing / assignment traffic and count only runtime vmix.command messages.
|
|
before_test = len([item for item in ws_test.sent if item.get("type") == "vmix.command"])
|
|
before_live = len([item for item in ws_live.sent if item.get("type") == "vmix.command"])
|
|
|
|
task_test = asyncio.create_task(
|
|
hub.run_vmix_sequence_for_user(
|
|
user,
|
|
[{"Function": "OverlayInput1In", "Input": "score-key"}],
|
|
device_id="GFX-MULTI-TEST",
|
|
session_token="multi-session",
|
|
)
|
|
)
|
|
command_test = await _ack_latest(hub, "GFX-MULTI-TEST", ws_test)
|
|
result_test = await task_test
|
|
assert result_test["device_id"] == "GFX-MULTI-TEST"
|
|
assert command_test["command"]["Function"] == "OverlayInput1In"
|
|
assert len([item for item in ws_test.sent if item.get("type") == "vmix.command"]) == before_test + 1
|
|
assert len([item for item in ws_live.sent if item.get("type") == "vmix.command"]) == before_live
|
|
|
|
task_live = asyncio.create_task(
|
|
hub.run_vmix_sequence_for_user(
|
|
user,
|
|
[{"Function": "OverlayInput1Out", "Input": "score-key"}],
|
|
device_id="GFX-MULTI-LIVE",
|
|
session_token="multi-session",
|
|
)
|
|
)
|
|
command_live = await _ack_latest(hub, "GFX-MULTI-LIVE", ws_live)
|
|
result_live = await task_live
|
|
assert result_live["device_id"] == "GFX-MULTI-LIVE"
|
|
assert command_live["command"]["Function"] == "OverlayInput1Out"
|
|
assert len([item for item in ws_live.sent if item.get("type") == "vmix.command"]) == before_live + 1
|
|
assert len([item for item in ws_test.sent if item.get("type") == "vmix.command"]) == before_test + 1
|
|
|
|
asyncio.run(scenario())
|