Skip to content

Commit a7d8544

Browse files
authored
test: improve api and cloud_api test coverage (#281)
1 parent 0872691 commit a7d8544

File tree

1 file changed

+77
-3
lines changed

1 file changed

+77
-3
lines changed

tests/test_api.py

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import json
23
from collections.abc import AsyncGenerator
34
from queue import Queue
@@ -15,7 +16,7 @@
1516
UserData,
1617
)
1718
from roborock.containers import DeviceData, RoomMapping, S7MaxVStatus
18-
from roborock.exceptions import RoborockException
19+
from roborock.exceptions import RoborockException, RoborockTimeout
1920
from roborock.protocol import MessageParser
2021
from roborock.roborock_message import RoborockMessage, RoborockMessageProtocol
2122
from roborock.version_1_apis import RoborockMqttClientV1
@@ -154,8 +155,6 @@ async def connected_mqtt_client_fixture(
154155
response_queue.put(mqtt_packet.gen_suback(1, 0))
155156
await mqtt_client.async_connect()
156157
yield mqtt_client
157-
if mqtt_client.is_connected():
158-
await mqtt_client.async_disconnect()
159158

160159

161160
async def test_async_connect(received_requests: Queue, connected_mqtt_client: RoborockMqttClientV1) -> None:
@@ -187,6 +186,58 @@ async def test_connect_failure(
187186
assert received_requests.qsize() == 1 # Connect attempt
188187

189188

189+
async def test_disconnect_already_disconnected(connected_mqtt_client: RoborockMqttClientV1) -> None:
190+
"""Test the MQTT client error handling for a no-op disconnect."""
191+
192+
assert connected_mqtt_client.is_connected()
193+
194+
# Make the MQTT client simulate returning that it already thinks it is disconnected
195+
with patch("roborock.cloud_api.mqtt.Client.disconnect", return_value=mqtt.MQTT_ERR_NO_CONN):
196+
await connected_mqtt_client.async_disconnect()
197+
198+
199+
async def test_disconnect_failure(connected_mqtt_client: RoborockMqttClientV1) -> None:
200+
"""Test that the MQTT client ignores MQTT client error handling for a no-op disconnect."""
201+
202+
assert connected_mqtt_client.is_connected()
203+
204+
# Make the MQTT client returns with an error when disconnecting
205+
with patch("roborock.cloud_api.mqtt.Client.disconnect", return_value=mqtt.MQTT_ERR_PROTOCOL), pytest.raises(
206+
RoborockException, match="Failed to disconnect"
207+
):
208+
await connected_mqtt_client.async_disconnect()
209+
210+
211+
async def test_async_release(connected_mqtt_client: RoborockMqttClientV1) -> None:
212+
"""Test the async_release API will disconnect the client."""
213+
await connected_mqtt_client.async_release()
214+
assert not connected_mqtt_client.is_connected()
215+
216+
217+
async def test_subscribe_failure(
218+
received_requests: Queue, response_queue: Queue, mqtt_client: RoborockMqttClientV1
219+
) -> None:
220+
"""Test the broker responding with the wrong message type on subscribe."""
221+
222+
response_queue.put(mqtt_packet.gen_connack(rc=0, flags=2))
223+
224+
with patch("roborock.cloud_api.mqtt.Client.subscribe", return_value=(mqtt.MQTT_ERR_NO_CONN, None)), pytest.raises(
225+
RoborockException, match="Failed to subscribe"
226+
):
227+
await mqtt_client.async_connect()
228+
229+
assert received_requests.qsize() == 1 # Connect attempt
230+
231+
# NOTE: The client is "connected" but not "subscribed" and cannot recover
232+
# from this state without disconnecting first. This can likely be improved.
233+
assert mqtt_client.is_connected()
234+
235+
# Attempting to reconnect is a no-op since the client already thinks it is connected
236+
await mqtt_client.async_connect()
237+
assert mqtt_client.is_connected()
238+
assert received_requests.qsize() == 1
239+
240+
190241
def build_rpc_response(message: dict[str, Any]) -> bytes:
191242
"""Build an encoded RPC response message."""
192243
return MessageParser.build(
@@ -228,3 +279,26 @@ async def test_get_room_mapping(
228279
RoomMapping(segment_id=16, iot_id="2362048"),
229280
RoomMapping(segment_id=17, iot_id="2362044"),
230281
]
282+
283+
284+
async def test_publish_failure(
285+
connected_mqtt_client: RoborockMqttClientV1,
286+
) -> None:
287+
"""Test a failure return code when publishing a messaage."""
288+
289+
msg = mqtt.MQTTMessageInfo(0)
290+
msg.rc = mqtt.MQTT_ERR_PROTOCOL
291+
with patch("roborock.cloud_api.mqtt.Client.publish", return_value=msg), pytest.raises(
292+
RoborockException, match="Failed to publish"
293+
):
294+
await connected_mqtt_client.get_room_mapping()
295+
296+
297+
async def test_future_timeout(
298+
connected_mqtt_client: RoborockMqttClientV1,
299+
) -> None:
300+
"""Test a timeout raised while waiting for an RPC response."""
301+
with patch("roborock.roborock_future.async_timeout.timeout", side_effect=asyncio.TimeoutError), pytest.raises(
302+
RoborockTimeout, match="Timeout after"
303+
):
304+
await connected_mqtt_client.get_room_mapping()

0 commit comments

Comments
 (0)