Skip to content

Commit 833be42

Browse files
authored
Add appropriate guards to websocket actions (#292)
1 parent 2f92156 commit 833be42

3 files changed

Lines changed: 52 additions & 49 deletions

File tree

simplipy/websocket.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ def __init__(
116116

117117
def _on_expire(self) -> None:
118118
"""Log and act when the watchdog expires."""
119-
LOGGER.info("Websocket watchdog expired")
120-
schedule_callback(self._action)
119+
if self._timer_task and not self._timer_task.cancelled():
120+
LOGGER.info("Websocket watchdog expired")
121+
schedule_callback(self._action)
121122

122123
def cancel(self) -> None:
123124
"""Cancel the watchdog."""
@@ -314,6 +315,9 @@ def add_event_callback(self, callback: Callable[..., Any]) -> Callable[..., None
314315

315316
async def async_connect(self) -> None:
316317
"""Connect to the websocket server."""
318+
if self.connected:
319+
return
320+
317321
try:
318322
self._client = await self._api.session.ws_connect(
319323
WEBSOCKET_SERVER_URL, heartbeat=55
@@ -330,15 +334,15 @@ async def async_connect(self) -> None:
330334

331335
async def async_disconnect(self) -> None:
332336
"""Disconnect from the websocket server."""
337+
if not self.connected:
338+
return
339+
333340
assert self._client
334341

335342
await self._client.close()
336343

337344
LOGGER.info("Disconnected from websocket server")
338345

339-
for callback in self._disconnect_callbacks:
340-
schedule_callback(callback)
341-
342346
async def async_listen(self) -> None:
343347
"""Start listening to the websocket server."""
344348
assert self._client

tests/conftest.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,6 @@ async def receive():
226226

227227
ws_client.receive.side_effect = receive
228228

229-
ws_client.send_json.side_effect = Mock()
230-
231229
async def reset_close():
232230
"""Reset the websocket client close method."""
233231
ws_client.closed = True

tests/test_websocket.py

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,46 @@
3333
from .common import create_ws_message
3434

3535

36+
@pytest.mark.asyncio
37+
async def test_callbacks(caplog, mock_api, ws_message_event, ws_messages):
38+
"""Test that callbacks are executed correctly."""
39+
caplog.set_level(logging.INFO)
40+
41+
mock_connect_callback = Mock()
42+
mock_disconnect_callback = Mock()
43+
mock_event_callback = Mock()
44+
45+
async def async_mock_connect_callback():
46+
"""Define a mock async conenct callback."""
47+
LOGGER.info("We are connected!")
48+
49+
client = WebsocketClient(mock_api)
50+
client.add_connect_callback(mock_connect_callback)
51+
client.add_connect_callback(async_mock_connect_callback)
52+
client.add_disconnect_callback(mock_disconnect_callback)
53+
client.add_event_callback(mock_event_callback)
54+
55+
assert mock_connect_callback.call_count == 0
56+
assert mock_disconnect_callback.call_count == 0
57+
assert mock_event_callback.call_count == 0
58+
59+
await client.async_connect()
60+
assert client.connected
61+
await asyncio.sleep(1)
62+
assert mock_connect_callback.call_count == 1
63+
assert any("We are connected!" in e.message for e in caplog.records)
64+
65+
ws_messages.append(create_ws_message(ws_message_event))
66+
await client.async_listen()
67+
await asyncio.sleep(1)
68+
expected_event = websocket_event_from_payload(ws_message_event)
69+
mock_event_callback.assert_called_once_with(expected_event)
70+
71+
await client.async_disconnect()
72+
assert not client.connected
73+
assert mock_disconnect_callback.call_count == 1
74+
75+
3676
@pytest.mark.asyncio
3777
@pytest.mark.parametrize(
3878
"error",
@@ -61,6 +101,9 @@ async def test_connect_disconnect(mock_api):
61101
await client.async_connect()
62102
assert client.connected
63103

104+
# Attempt to connect again, which should just return:
105+
await client.async_connect()
106+
64107
await client.async_disconnect()
65108
assert not client.connected
66109

@@ -159,48 +202,6 @@ async def test_listen_error_message_types(
159202
await client.async_listen()
160203

161204

162-
@pytest.mark.asyncio
163-
async def test_callbacks(caplog, mock_api, ws_message_event, ws_messages):
164-
"""Test that callbacks are executed correctly."""
165-
caplog.set_level(logging.INFO)
166-
167-
mock_connect_callback = Mock()
168-
mock_disconnect_callback = Mock()
169-
mock_event_callback = Mock()
170-
171-
async def async_mock_connect_callback():
172-
"""Define a mock async conenct callback."""
173-
LOGGER.info("We are connected!")
174-
175-
client = WebsocketClient(mock_api)
176-
client.add_connect_callback(mock_connect_callback)
177-
client.add_connect_callback(async_mock_connect_callback)
178-
client.add_disconnect_callback(mock_disconnect_callback)
179-
client.add_event_callback(mock_event_callback)
180-
181-
assert mock_connect_callback.call_count == 0
182-
assert mock_disconnect_callback.call_count == 0
183-
assert mock_event_callback.call_count == 0
184-
185-
await client.async_connect()
186-
assert client.connected
187-
await asyncio.sleep(1)
188-
assert mock_connect_callback.call_count == 1
189-
assert any("We are connected!" in e.message for e in caplog.records)
190-
191-
ws_messages.append(create_ws_message(ws_message_event))
192-
await client.async_listen()
193-
await asyncio.sleep(1)
194-
expected_event = websocket_event_from_payload(ws_message_event)
195-
mock_event_callback.assert_called_once_with(expected_event)
196-
197-
# Add another message to the queue to keep the websocket open while we disconnect
198-
# from it:
199-
await client.async_disconnect()
200-
assert not client.connected
201-
assert mock_disconnect_callback.call_count == 1
202-
203-
204205
@pytest.mark.asyncio
205206
async def test_reconnect(mock_api):
206207
"""Test reconnecting to the websocket."""

0 commit comments

Comments
 (0)