main
py 80 lines 2.23 KB
Raw
1 import asyncio
2 import sys
3 import threading
4 import time
5 from pathlib import Path
6
7 import pytest
8
9 PROJECT_ROOT = Path(__file__).resolve().parents[1]
10 if str(PROJECT_ROOT) not in sys.path:
11 sys.path.insert(0, str(PROJECT_ROOT))
12
13 from helpers.ws_manager import WsManager
14
15 NAMESPACE = "/ws"
16
17
18 class FakeSocketIOServer:
19 def __init__(self) -> None:
20 from unittest.mock import AsyncMock
21
22 self.emit = AsyncMock()
23 self.disconnect = AsyncMock()
24
25
26 @pytest.mark.asyncio
27 async def test_state_sync_handshake_and_initial_snapshot_work_with_no_selected_context() -> None:
28 """
29 Regression for Welcome screen: the UI has no selected context, so `state_request.context`
30 is null. We must still handshake and receive an initial `state_push` quickly (no hang).
31 """
32
33 from helpers.state_snapshot import validate_snapshot_schema_v1
34 from helpers.state_monitor import _reset_state_monitor_for_testing
35 from api.ws_webui import WsWebui
36
37 socketio = FakeSocketIOServer()
38 manager = WsManager(socketio, threading.RLock())
39
40 _reset_state_monitor_for_testing()
41
42 lock = threading.RLock()
43 handler = WsWebui(socketio, lock, manager=manager, namespace=NAMESPACE)
44
45 await manager.handle_connect(NAMESPACE, "sid-1")
46 await handler.on_connect("sid-1")
47
48 push_ready = asyncio.Event()
49 captured: dict[str, object] = {}
50
51 async def _emit(event_type, envelope, **_kwargs):
52 if event_type == "state_push":
53 captured["envelope"] = envelope
54 push_ready.set()
55
56 socketio.emit.side_effect = _emit
57
58 start = time.monotonic()
59 result = await handler.process(
60 "state_request",
61 {
62 "correlationId": "client-welcome",
63 "context": None,
64 "log_from": 0,
65 "notifications_from": 0,
66 "timezone": "UTC",
67 },
68 "sid-1",
69 )
70
71 await asyncio.wait_for(push_ready.wait(), timeout=1.0)
72 assert (time.monotonic() - start) <= 1.0
73
74 envelope = captured.get("envelope")
75 assert isinstance(envelope, dict)
76 data = envelope.get("data")
77 assert isinstance(data, dict)
78 assert set(data.keys()) >= {"runtime_epoch", "seq", "snapshot"}
79 assert isinstance(data["snapshot"], dict)
80 validate_snapshot_schema_v1(data["snapshot"])