@@ -32,26 +32,36 @@ def mqtt_server_fixture(mock_create_connection: None, mock_select: None) -> None
3232
3333@pytest .fixture (autouse = True )
3434def mock_client_fixture (event_loop : asyncio .AbstractEventLoop ) -> Generator [None , None , None ]:
35- """Fixture to patch the MQTT underlying sync client to regularly read from the mock socket."""
35+ """Fixture to patch the MQTT underlying sync client.
36+
37+ The tests use fake sockets, so this ensures that the async mqtt client does not
38+ attempt to listen on them directly. We instead just poll the socket for
39+ data ourselves.
40+ """
3641
3742 orig_class = mqtt .Client
3843
39- async def ready_loop (client : mqtt .Client ) -> None :
40- """Run the mqtt read loop."""
44+ async def poll_sockets (client : mqtt .Client ) -> None :
45+ """Poll the mqtt client sockets in a loop to pick up new data ."""
4146 while True :
42- client .loop_read ( )
43- # event_loop.call_soon_threadsafe(client.loop_read )
47+ event_loop . call_soon_threadsafe ( client .loop_read )
48+ event_loop .call_soon_threadsafe (client .loop_write )
4449 await asyncio .sleep (0.1 )
4550
4651 task : asyncio .Task [None ] | None = None
4752
4853 def new_client (* args : Any , ** kwargs : Any ) -> mqtt .Client :
54+ """Create a new mqtt client and start the socket polling task."""
4955 nonlocal task
5056 client = orig_class (* args , ** kwargs )
51- task = event_loop .create_task (ready_loop (client ))
57+ task = event_loop .create_task (poll_sockets (client ))
5258 return client
5359
54- with patch ("aiomqtt.client.mqtt.Client" , side_effect = new_client ):
60+ with patch ("aiomqtt.client.Client._on_socket_open" ), patch ("aiomqtt.client.Client._on_socket_close" ), patch (
61+ "aiomqtt.client.Client._on_socket_register_write"
62+ ), patch ("aiomqtt.client.Client._on_socket_unregister_write" ), patch (
63+ "aiomqtt.client.mqtt.Client" , side_effect = new_client
64+ ):
5565 yield
5666 if task :
5767 task .cancel ()
0 commit comments