Skip to content

Commit bc4f278

Browse files
Clean up client connection (#93)
Co-authored-by: Martin Hjelmare <[email protected]>
1 parent b196e17 commit bc4f278

File tree

5 files changed

+108
-197
lines changed

5 files changed

+108
-197
lines changed

pylintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ disable=
2323
too-few-public-methods,
2424
too-many-public-methods,
2525
too-many-instance-attributes,
26+
too-many-branches,
2627
no-self-use
2728

2829
[REPORTS]

test/conftest.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from aiohttp import ClientSession, ClientWebSocketResponse
99
from aiohttp.http_websocket import WSMessage, WSMsgType
1010

11-
from zwave_js_server.client import STATE_CONNECTED, Client
11+
from zwave_js_server.client import Client
1212
from zwave_js_server.const import MIN_SERVER_VERSION
1313
from zwave_js_server.model.controller import Controller
1414
from zwave_js_server.model.driver import Driver
@@ -48,35 +48,35 @@ def client_session_fixture(ws_client):
4848

4949

5050
@pytest.fixture(name="ws_client")
51-
async def ws_client_fixture(loop, version_data, ws_message):
51+
async def ws_client_fixture(loop, version_data, ws_message, result):
5252
"""Mock a websocket client.
5353
5454
This fixture only allows a single message to be received.
5555
"""
5656
ws_client = AsyncMock(spec_set=ClientWebSocketResponse, closed=False)
57-
ws_client.receive_json.return_value = version_data
58-
receive_event = asyncio.Event()
57+
ws_client.receive_json.side_effect = (version_data, result)
5958

6059
async def receive():
6160
"""Return a websocket message."""
6261
await asyncio.sleep(0)
63-
await receive_event.wait()
62+
ws_client.closed = True
6463
return ws_message
6564

6665
ws_client.receive.side_effect = receive
6766

68-
async def close_client(*args):
67+
async def close_client(msg):
6968
"""Close the client."""
69+
if msg["command"] == "start_listening":
70+
return
71+
7072
await asyncio.sleep(0)
7173
ws_client.closed = True
72-
receive_event.set()
7374

7475
ws_client.send_json.side_effect = close_client
7576

7677
async def reset_close():
7778
"""Reset the websocket client close method."""
78-
ws_client.closed = False
79-
receive_event.clear()
79+
ws_client.closed = True
8080

8181
ws_client.close.side_effect = reset_close
8282

@@ -155,8 +155,7 @@ async def client_fixture(loop, client_session, ws_client, uuid4):
155155
when creating the client.
156156
"""
157157
client = Client("ws://test.org", client_session)
158-
client.state = STATE_CONNECTED
159-
client.client = ws_client
158+
client._client = ws_client
160159
return client
161160

162161

test/test_client.py

Lines changed: 11 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from zwave_js_server.client import Client
1111
from zwave_js_server.exceptions import (
1212
CannotConnect,
13-
ConnectionClosed,
1413
ConnectionFailed,
1514
FailedCommand,
1615
InvalidMessage,
@@ -55,7 +54,11 @@ async def test_invalid_server_version(client_session, url, version_data, caplog)
5554

5655
assert not client.connected
5756

57+
58+
async def test_newer_server_version(client_session, url, version_data, caplog):
59+
"""Test client connect with invalid server version."""
5860
version_data["serverVersion"] = "99999.0.0"
61+
client = Client(url, client_session)
5962

6063
await client.connect()
6164

@@ -73,33 +76,7 @@ async def test_send_json_when_disconnected(client_session, url):
7376
await client._send_json_message({"test": None})
7477

7578

76-
async def test_connect_with_existing_driver(
77-
client_session, url, ws_client, driver_ready, await_other
78-
):
79-
"""Test connecting again with an existing driver raises."""
80-
client = Client(url, client_session)
81-
assert not client.connected
82-
assert not client.driver
83-
84-
await client.connect()
85-
86-
assert client.connected
87-
88-
await client.listen(driver_ready)
89-
await await_other(asyncio.current_task())
90-
91-
assert client.driver
92-
93-
ws_client.receive.reset_mock()
94-
ws_client.closed = False
95-
96-
with pytest.raises(InvalidState):
97-
await client.connect()
98-
99-
ws_client.receive.assert_not_awaited()
100-
101-
102-
async def test_listen(client_session, url, driver_ready, await_other):
79+
async def test_listen(client_session, url, driver_ready):
10380
"""Test client listen."""
10481
client = Client(url, client_session)
10582

@@ -109,13 +86,11 @@ async def test_listen(client_session, url, driver_ready, await_other):
10986

11087
assert client.connected
11188

112-
await client.listen(driver_ready)
113-
await await_other(asyncio.current_task())
114-
89+
asyncio.create_task(client.listen(driver_ready))
90+
await driver_ready.wait()
11591
assert client.driver
11692

11793
await client.disconnect()
118-
11994
assert not client.connected
12095

12196

@@ -132,7 +107,8 @@ async def test_listen_client_error(
132107
ws_client.closed = False
133108

134109
# This should break out of the listen loop before any message is received.
135-
await client.listen(driver_ready)
110+
with pytest.raises(asyncio.CancelledError):
111+
await client.listen(driver_ready)
136112

137113
assert not ws_message.json.called
138114

@@ -142,7 +118,6 @@ async def test_listen_client_error(
142118
[
143119
(WSMsgType.ERROR, ConnectionFailed),
144120
(WSMsgType.BINARY, InvalidMessage),
145-
(WSMsgType.CLOSE, ConnectionClosed),
146121
],
147122
)
148123
async def test_listen_error_message_types(
@@ -168,12 +143,10 @@ async def test_listen_disconnect_message_types(
168143
async with Client(url, client_session) as client:
169144
assert client.connected
170145
ws_message.type = message_type
171-
# ws_client.closed = False
172146

173147
# This should break out of the listen loop before handling the received message.
174148
# Otherwise there will be an error.
175149
await client.listen(driver_ready)
176-
await await_other(asyncio.current_task())
177150

178151
# Assert that we received a message.
179152
ws_client.receive.assert_awaited()
@@ -194,9 +167,7 @@ async def test_listen_invalid_message_data(
194167
await client.listen(driver_ready)
195168

196169

197-
async def test_listen_not_success(
198-
client_session, url, result, driver_ready, await_other
199-
):
170+
async def test_listen_not_success(client_session, url, result, driver_ready):
200171
"""Test receive result message with success False on listen."""
201172
result["success"] = False
202173
result["errorCode"] = "error_code"
@@ -205,38 +176,8 @@ async def test_listen_not_success(
205176

206177
with pytest.raises(FailedCommand):
207178
await client.listen(driver_ready)
208-
await await_other(asyncio.current_task())
209-
210-
assert client.connected
211-
212179

213-
async def test_listen_invalid_state(
214-
client_session, url, result, driver_ready, await_other
215-
):
216-
"""Test missing driver state on listen."""
217-
result["type"] = "event"
218-
result["event"] = {
219-
"source": "node",
220-
"event": "value updated",
221-
"nodeId": 52,
222-
"args": {
223-
"commandClassName": "Basic",
224-
"commandClass": 32,
225-
"endpoint": 0,
226-
"property": "currentValue",
227-
"newValue": 255,
228-
"prevValue": 255,
229-
"propertyName": "currentValue",
230-
},
231-
}
232-
client = Client(url, client_session)
233-
await client.connect()
234-
235-
with pytest.raises(InvalidState):
236-
await client.listen(driver_ready)
237-
await await_other(asyncio.current_task())
238-
239-
assert client.connected
180+
assert not client.connected
240181

241182

242183
async def test_listen_without_connect(client_session, url, driver_ready):
@@ -256,11 +197,7 @@ async def test_listen_event(
256197
await client.connect()
257198

258199
assert client.connected
259-
await client.listen(driver_ready)
260-
await await_other(asyncio.current_task())
261-
assert client.driver
262200

263-
result.clear()
264201
result["type"] = "event"
265202
result["event"] = {
266203
"source": "node",
@@ -277,18 +214,7 @@ async def test_listen_event(
277214
},
278215
}
279216

280-
ws_client.receive.reset_mock()
281-
ws_client.closed = False
282-
283-
async def receive():
284-
"""Return a websocket message."""
285-
ws_client.closed = True
286-
return ws_message
287-
288-
ws_client.receive.side_effect = receive
289-
290217
await client.listen(driver_ready)
291-
292218
ws_client.receive.assert_awaited()
293219

294220

0 commit comments

Comments
 (0)