1
1
import asyncio
2
- from unittest .mock import patch
2
+ from unittest .mock import AsyncMock , patch
3
3
4
4
import pytest
5
5
@@ -118,48 +118,6 @@ async def test_probe_multiple(device, make_znp_server):
118
118
assert not any ([t ._is_connected for t in znp_server ._transports ])
119
119
120
120
121
- @pytest .mark .parametrize ("device" , FORMED_DEVICES )
122
- async def test_reconnect (device , make_application ):
123
- app , znp_server = make_application (
124
- server_cls = device ,
125
- client_config = {
126
- # Make auto-reconnection happen really fast
127
- conf .CONF_ZNP_CONFIG : {
128
- conf .CONF_AUTO_RECONNECT_RETRY_DELAY : 0.01 ,
129
- conf .CONF_SREQ_TIMEOUT : 0.1 ,
130
- }
131
- },
132
- shorten_delays = False ,
133
- )
134
-
135
- # Start up the server
136
- await app .startup (auto_form = False )
137
- assert app ._znp is not None
138
-
139
- # Don't reply to anything for a bit
140
- with patch .object (znp_server , "frame_received" , lambda _ : None ):
141
- # Now that we're connected, have the server close the connection
142
- znp_server ._uart ._transport .close ()
143
-
144
- # ZNP should be closed
145
- assert app ._znp is None
146
-
147
- # Wait for more than the SREQ_TIMEOUT to pass, we should still fail to reconnect
148
- await asyncio .sleep (0.3 )
149
-
150
- assert not app ._reconnect_task .done ()
151
- assert app ._znp is None
152
-
153
- # Our reconnect task should complete a moment after we send the ping reply
154
- while app ._znp is None :
155
- await asyncio .sleep (0.1 )
156
-
157
- assert app ._znp is not None
158
- assert app ._znp ._uart is not None
159
-
160
- await app .shutdown ()
161
-
162
-
163
121
@pytest .mark .parametrize ("device" , FORMED_DEVICES )
164
122
async def test_shutdown_from_app (device , mocker , make_application ):
165
123
app , znp_server = make_application (server_cls = device )
@@ -185,7 +143,6 @@ async def test_clean_shutdown(make_application):
185
143
await app .shutdown ()
186
144
187
145
assert app ._znp is None
188
- assert app ._reconnect_task .cancelled ()
189
146
190
147
191
148
async def test_multiple_shutdown (make_application ):
@@ -197,100 +154,6 @@ async def test_multiple_shutdown(make_application):
197
154
await app .shutdown ()
198
155
199
156
200
- @pytest .mark .parametrize ("device" , FORMED_DEVICES )
201
- async def test_reconnect_lockup (device , make_application , mocker ):
202
- mocker .patch ("zigpy_znp.zigbee.application.WATCHDOG_PERIOD" , 0.1 )
203
-
204
- app , znp_server = make_application (
205
- server_cls = device ,
206
- client_config = {
207
- # Make auto-reconnection happen really fast
208
- conf .CONF_ZNP_CONFIG : {
209
- conf .CONF_AUTO_RECONNECT_RETRY_DELAY : 0.01 ,
210
- conf .CONF_SREQ_TIMEOUT : 0.1 ,
211
- }
212
- },
213
- )
214
-
215
- # Start up the server
216
- await app .startup (auto_form = False )
217
-
218
- # Stop responding
219
- with patch .object (znp_server , "frame_received" , lambda _ : None ):
220
- assert app ._znp is not None
221
- assert app ._reconnect_task .done ()
222
-
223
- # Wait for more than the SREQ_TIMEOUT to pass, the watchdog will notice
224
- await asyncio .sleep (0.3 )
225
-
226
- # We will treat this as a disconnect
227
- assert app ._znp is None
228
- assert app ._watchdog_task .done ()
229
- assert not app ._reconnect_task .done ()
230
-
231
- # Our reconnect task should complete after that
232
- while app ._znp is None :
233
- await asyncio .sleep (0.1 )
234
-
235
- assert app ._znp is not None
236
- assert app ._znp ._uart is not None
237
-
238
- await app .shutdown ()
239
-
240
-
241
- @pytest .mark .parametrize ("device" , [FormedLaunchpadCC26X2R1 ])
242
- async def test_reconnect_lockup_pyserial (device , make_application , mocker ):
243
- mocker .patch ("zigpy_znp.zigbee.application.WATCHDOG_PERIOD" , 0.1 )
244
-
245
- app , znp_server = make_application (
246
- server_cls = device ,
247
- client_config = {
248
- conf .CONF_ZNP_CONFIG : {
249
- conf .CONF_AUTO_RECONNECT_RETRY_DELAY : 0.01 ,
250
- conf .CONF_SREQ_TIMEOUT : 0.1 ,
251
- }
252
- },
253
- )
254
-
255
- # Start up the server
256
- await app .startup (auto_form = False )
257
-
258
- # On Linux, a connection error during read with queued writes will cause PySerial to
259
- # swallow the exception. This makes it appear like we intentionally closed the
260
- # connection.
261
-
262
- # We are connected
263
- assert app ._znp is not None
264
-
265
- did_start_network = asyncio .get_running_loop ().create_future ()
266
-
267
- async def patched_start_network (old_start_network = app .start_network , ** kwargs ):
268
- try :
269
- return await old_start_network (** kwargs )
270
- finally :
271
- did_start_network .set_result (True )
272
-
273
- with patch .object (app , "start_network" , patched_start_network ):
274
- # "Drop" the connection like PySerial
275
- app ._znp ._uart .connection_lost (exc = None )
276
-
277
- # Wait until we are reconnecting
278
- await did_start_network
279
-
280
- # "Drop" the connection like PySerial again, but during connect
281
- app ._znp ._uart .connection_lost (exc = None )
282
-
283
- # We should reconnect soon
284
- mocker .spy (app , "_watchdog_loop" )
285
-
286
- while app ._watchdog_loop .call_count == 0 :
287
- await asyncio .sleep (0.1 )
288
-
289
- assert app ._znp and app ._znp ._uart
290
-
291
- await app .shutdown ()
292
-
293
-
294
157
@pytest .mark .parametrize ("device" , [FormedLaunchpadCC26X2R1 ])
295
158
async def test_disconnect (device , make_application ):
296
159
app , znp_server = make_application (
@@ -335,3 +198,18 @@ async def test_disconnect_failure(device, make_application):
335
198
await app .disconnect ()
336
199
337
200
assert app ._znp is None
201
+
202
+
203
+ @pytest .mark .parametrize ("device" , [FormedLaunchpadCC26X2R1 ])
204
+ async def test_watchdog (device , make_application ):
205
+ app , znp_server = make_application (server_cls = device )
206
+ await app .startup (auto_form = False )
207
+
208
+ app ._watchdog_feed = AsyncMock (wraps = app ._watchdog_feed )
209
+
210
+ with patch ("zigpy.application.ControllerApplication._watchdog_period" , new = 0.1 ):
211
+ await asyncio .sleep (0.6 )
212
+
213
+ assert len (app ._watchdog_feed .mock_calls ) >= 5
214
+
215
+ await app .shutdown ()
0 commit comments