11"""End-to-end tests for LocalChannel using fake sockets."""
22
33import asyncio
4- from collections .abc import AsyncGenerator , Callable , Generator
5- from queue import Queue
6- from typing import Any
7- from unittest .mock import Mock , patch
4+ from collections .abc import AsyncGenerator
5+ from unittest .mock import patch
86
97import pytest
108
119from roborock .devices .local_channel import LocalChannel
1210from roborock .protocol import create_local_decoder , create_local_encoder
1311from roborock .roborock_message import RoborockMessage , RoborockMessageProtocol
14- from tests .conftest import RequestHandler
1512from tests .mock_data import LOCAL_KEY
1613
1714TEST_HOST = "192.168.1.100"
2118TEST_RANDOM = 13579
2219
2320
24- @pytest .fixture (name = "mock_create_local_connection" )
25- def create_local_connection_fixture (request_handler : RequestHandler ) -> Generator [None , None , None ]:
26- """Fixture that overrides the transport creation to wire it up to the mock socket."""
27-
28- async def create_connection (protocol_factory : Callable [[], asyncio .Protocol ], * args , ** kwargs ) -> tuple [Any , Any ]:
29- protocol = protocol_factory ()
30-
31- def handle_write (data : bytes ) -> None :
32- response = request_handler (data )
33- if response is not None :
34- # Call data_received directly to avoid loop scheduling issues in test
35- protocol .data_received (response )
36-
37- closed = asyncio .Event ()
38-
39- mock_transport = Mock ()
40- mock_transport .write = handle_write
41- mock_transport .close = closed .set
42- mock_transport .is_reading = lambda : not closed .is_set ()
43-
44- return (mock_transport , protocol )
45-
46- with patch ("roborock.devices.local_channel.asyncio.get_running_loop" ) as mock_loop :
47- mock_loop .return_value .create_connection .side_effect = create_connection
48- yield
49-
50-
5121@pytest .fixture (name = "local_channel" )
52- async def local_channel_fixture (mock_create_local_connection : None ) -> AsyncGenerator [LocalChannel , None ]:
22+ async def local_channel_fixture (mock_async_create_local_connection : None ) -> AsyncGenerator [LocalChannel , None ]:
5323 with patch (
5424 "roborock.devices.local_channel.get_next_int" , return_value = TEST_CONNECT_NONCE , device_uid = TEST_DEVICE_UID
5525 ):
@@ -80,19 +50,23 @@ def build_response(
8050
8151
8252async def test_connect (
83- local_channel : LocalChannel , response_queue : Queue [bytes ], received_requests : Queue [bytes ]
53+ local_channel : LocalChannel ,
54+ local_response_queue : asyncio .Queue [bytes ],
55+ local_received_requests : asyncio .Queue [bytes ],
8456) -> None :
8557 """Test connecting to the device."""
8658 # Queue HELLO response with payload to ensure it can be parsed
87- response_queue .put (build_response (RoborockMessageProtocol .HELLO_RESPONSE , 1 , payload = b"ok" , random = TEST_RANDOM ))
59+ local_response_queue .put_nowait (
60+ build_response (RoborockMessageProtocol .HELLO_RESPONSE , 1 , payload = b"ok" , random = TEST_RANDOM )
61+ )
8862
8963 await local_channel .connect ()
9064
9165 assert local_channel .is_connected
92- assert received_requests .qsize () == 1
66+ assert local_received_requests .qsize () == 1
9367
9468 # Verify HELLO request
95- request_bytes = received_requests .get ()
69+ request_bytes = await local_received_requests .get ()
9670 # Note: We cannot use create_local_decoder here because HELLO_REQUEST has payload=None
9771 # which causes MessageParser to fail parsing. For now we verify the raw bytes.
9872
@@ -104,17 +78,21 @@ async def test_connect(
10478
10579
10680async def test_send_command (
107- local_channel : LocalChannel , response_queue : Queue [bytes ], received_requests : Queue [bytes ]
81+ local_channel : LocalChannel ,
82+ local_response_queue : asyncio .Queue [bytes ],
83+ local_received_requests : asyncio .Queue [bytes ],
10884) -> None :
10985 """Test sending a command."""
11086 # Queue HELLO response
111- response_queue .put (build_response (RoborockMessageProtocol .HELLO_RESPONSE , 1 , payload = b"ok" , random = TEST_RANDOM ))
87+ local_response_queue .put_nowait (
88+ build_response (RoborockMessageProtocol .HELLO_RESPONSE , 1 , payload = b"ok" , random = TEST_RANDOM )
89+ )
11290
11391 await local_channel .connect ()
11492
11593 # Clear requests from handshake
116- while not received_requests .empty ():
117- received_requests .get ()
94+ while not local_received_requests .empty ():
95+ await local_received_requests .get ()
11896
11997 # Send command
12098 cmd_seq = 123
@@ -127,8 +105,8 @@ async def test_send_command(
127105 await local_channel .publish (msg )
128106
129107 # Verify request
130- assert received_requests . qsize () == 1
131- request_bytes = received_requests . get ()
108+ request_bytes = await local_received_requests . get ()
109+ assert local_received_requests . empty ()
132110
133111 # Decode request
134112 decoder = create_local_decoder (local_key = LOCAL_KEY , connect_nonce = TEST_CONNECT_NONCE , ack_nonce = TEST_ACK_NONCE )
0 commit comments