3
3
import asyncio
4
4
import functools
5
5
import time
6
- from unittest .mock import MagicMock , Mock , patch
6
+ from unittest .mock import MagicMock , patch
7
7
8
8
import pytest
9
9
10
10
from zha import async_ as zha_async
11
11
from zha .application .gateway import Gateway
12
12
from zha .async_ import AsyncUtilMixin , ZHAJob , ZHAJobType , create_eager_task
13
- from zha .decorators import callback
14
-
15
-
16
- async def test_zhajob_forbid_coroutine () -> None :
17
- """Test zhajob forbids coroutines."""
18
-
19
- async def bla ():
20
- pass
21
-
22
- coro = bla ()
23
-
24
- with pytest .raises (ValueError ):
25
- _ = ZHAJob (coro ).job_type
26
-
27
- # To avoid warning about unawaited coro
28
- await coro
29
13
30
14
31
15
@pytest .mark .parametrize ("eager_start" , [True , False ])
32
16
async def test_cancellable_zhajob (zha_gateway : Gateway , eager_start : bool ) -> None :
33
17
"""Simulate a shutdown, ensure cancellable jobs are cancelled."""
34
18
job = MagicMock ()
35
19
36
- @callback
37
20
def run_job (job : ZHAJob ) -> None :
38
21
"""Call the action."""
39
22
zha_gateway .async_run_zha_job (job , eager_start = eager_start )
40
23
41
24
timer1 = zha_gateway .loop .call_later (
42
- 60 , run_job , ZHAJob (callback ( job ) , cancel_on_shutdown = True )
25
+ 60 , run_job , ZHAJob (job , cancel_on_shutdown = True )
43
26
)
44
- timer2 = zha_gateway .loop .call_later (60 , run_job , ZHAJob (callback ( job ) ))
27
+ timer2 = zha_gateway .loop .call_later (60 , run_job , ZHAJob (job ))
45
28
46
29
await zha_gateway .shutdown ()
47
30
@@ -57,7 +40,7 @@ async def test_async_add_zha_job_schedule_callback() -> None:
57
40
zha_gateway = MagicMock (loop = MagicMock (wraps = asyncio .get_running_loop ()))
58
41
job = MagicMock ()
59
42
60
- AsyncUtilMixin .async_add_zha_job (zha_gateway , ZHAJob (callback ( job ) ))
43
+ AsyncUtilMixin .async_add_zha_job (zha_gateway , ZHAJob (job ))
61
44
assert len (zha_gateway .loop .call_soon .mock_calls ) == 1
62
45
assert len (zha_gateway .loop .create_task .mock_calls ) == 0
63
46
assert len (zha_gateway .add_job .mock_calls ) == 0
@@ -71,9 +54,7 @@ async def test_async_add_zha_job_eager_start_coro_suspends(
71
54
async def job_that_suspends ():
72
55
await asyncio .sleep (0 )
73
56
74
- task = zha_gateway .async_add_zha_job (
75
- ZHAJob (callback (job_that_suspends )), eager_start = True
76
- )
57
+ task = zha_gateway .async_add_zha_job (ZHAJob (job_that_suspends ), eager_start = True )
77
58
assert not task .done ()
78
59
assert task in zha_gateway ._tracked_completable_tasks
79
60
await task
@@ -88,7 +69,7 @@ async def test_async_run_zha_job_eager_start_coro_suspends(
88
69
async def job_that_suspends ():
89
70
await asyncio .sleep (0 )
90
71
91
- task = zha_gateway .async_run_zha_job (ZHAJob (callback ( job_that_suspends ) ))
72
+ task = zha_gateway .async_run_zha_job (ZHAJob (job_that_suspends ))
92
73
assert not task .done ()
93
74
assert task in zha_gateway ._tracked_completable_tasks
94
75
await task
@@ -101,9 +82,7 @@ async def test_async_add_zha_job_background(zha_gateway: Gateway) -> None:
101
82
async def job_that_suspends ():
102
83
await asyncio .sleep (0 )
103
84
104
- task = zha_gateway .async_add_zha_job (
105
- ZHAJob (callback (job_that_suspends )), background = True
106
- )
85
+ task = zha_gateway .async_add_zha_job (ZHAJob (job_that_suspends ), background = True )
107
86
assert not task .done ()
108
87
assert task in zha_gateway ._background_tasks
109
88
await task
@@ -116,9 +95,7 @@ async def test_async_run_zha_job_background(zha_gateway: Gateway) -> None:
116
95
async def job_that_suspends ():
117
96
await asyncio .sleep (0 )
118
97
119
- task = zha_gateway .async_run_zha_job (
120
- ZHAJob (callback (job_that_suspends )), background = True
121
- )
98
+ task = zha_gateway .async_run_zha_job (ZHAJob (job_that_suspends ), background = True )
122
99
assert not task .done ()
123
100
assert task in zha_gateway ._background_tasks
124
101
await task
@@ -131,9 +108,7 @@ async def test_async_add_zha_job_eager_background(zha_gateway: Gateway) -> None:
131
108
async def job_that_suspends ():
132
109
await asyncio .sleep (0 )
133
110
134
- task = zha_gateway .async_add_zha_job (
135
- ZHAJob (callback (job_that_suspends )), background = True
136
- )
111
+ task = zha_gateway .async_add_zha_job (ZHAJob (job_that_suspends ), background = True )
137
112
assert not task .done ()
138
113
assert task in zha_gateway ._background_tasks
139
114
await task
@@ -146,43 +121,28 @@ async def test_async_run_zha_job_eager_background(zha_gateway: Gateway) -> None:
146
121
async def job_that_suspends ():
147
122
await asyncio .sleep (0 )
148
123
149
- task = zha_gateway .async_run_zha_job (
150
- ZHAJob (callback (job_that_suspends )), background = True
151
- )
124
+ task = zha_gateway .async_run_zha_job (ZHAJob (job_that_suspends ), background = True )
152
125
assert not task .done ()
153
126
assert task in zha_gateway ._background_tasks
154
127
await task
155
128
assert task not in zha_gateway ._background_tasks
156
129
157
130
158
- async def test_async_run_zha_job_background_synchronous (
131
+ @pytest .mark .parametrize ("background" , [True , False ])
132
+ async def test_async_run_zha_job_background_no_suspend (
159
133
zha_gateway : Gateway ,
134
+ background : bool ,
160
135
) -> None :
161
136
"""Test scheduling a coro as an eager background task with async_run_zha_job."""
162
137
163
138
async def job_that_does_not_suspends ():
164
139
pass
165
140
166
141
task = zha_gateway .async_run_zha_job (
167
- ZHAJob (callback (job_that_does_not_suspends )),
168
- background = True ,
169
- )
170
- assert task .done ()
171
- assert task not in zha_gateway ._background_tasks
172
- assert task not in zha_gateway ._tracked_completable_tasks
173
- await task
174
-
175
-
176
- async def test_async_run_zha_job_synchronous (zha_gateway : Gateway ) -> None :
177
- """Test scheduling a coro as an eager task with async_run_zha_job."""
178
-
179
- async def job_that_does_not_suspends ():
180
- pass
181
-
182
- task = zha_gateway .async_run_zha_job (
183
- ZHAJob (callback (job_that_does_not_suspends )),
184
- background = False ,
142
+ ZHAJob (job_that_does_not_suspends ),
143
+ background = background ,
185
144
)
145
+ assert task is not None
186
146
assert task .done ()
187
147
assert task not in zha_gateway ._background_tasks
188
148
assert task not in zha_gateway ._tracked_completable_tasks
@@ -219,7 +179,7 @@ async def test_async_add_zha_job_schedule_partial_callback() -> None:
219
179
"""Test that we schedule partial coros and add jobs to the job pool."""
220
180
zha_gateway = MagicMock (loop = MagicMock (wraps = asyncio .get_running_loop ()))
221
181
job = MagicMock ()
222
- partial = functools .partial (callback ( job ) )
182
+ partial = functools .partial (job )
223
183
224
184
AsyncUtilMixin .async_add_zha_job (zha_gateway , ZHAJob (partial ))
225
185
assert len (zha_gateway .loop .call_soon .mock_calls ) == 1
@@ -252,6 +212,7 @@ async def job():
252
212
) as mock_create_eager_task :
253
213
zha_job = ZHAJob (job )
254
214
task = AsyncUtilMixin .async_add_zha_job (zha_gateway , zha_job , eager_start = True )
215
+ assert task is not None
255
216
assert len (zha_gateway .loop .call_soon .mock_calls ) == 0
256
217
assert len (zha_gateway .add_job .mock_calls ) == 0
257
218
assert mock_create_eager_task .mock_calls
@@ -283,9 +244,9 @@ def job():
283
244
pass
284
245
285
246
AsyncUtilMixin .async_add_zha_job (zha_gateway , ZHAJob (job ))
286
- assert len (zha_gateway .loop .call_soon .mock_calls ) == 0
247
+ assert len (zha_gateway .loop .call_soon .mock_calls ) == 1
287
248
assert len (zha_gateway .loop .create_task .mock_calls ) == 0
288
- assert len (zha_gateway .loop .run_in_executor .mock_calls ) == 2
249
+ assert len (zha_gateway .loop .run_in_executor .mock_calls ) == 0
289
250
290
251
291
252
async def test_async_create_task_schedule_coroutine () -> None :
@@ -337,7 +298,7 @@ def job():
337
298
asyncio .get_running_loop () # ensure we are in the event loop
338
299
calls .append (1 )
339
300
340
- AsyncUtilMixin .async_run_zha_job (zha_gateway , ZHAJob (callback ( job ) ))
301
+ AsyncUtilMixin .async_run_zha_job (zha_gateway , ZHAJob (job ))
341
302
assert len (calls ) == 1
342
303
343
304
@@ -360,24 +321,11 @@ async def test_async_run_zha_job_calls_callback() -> None:
360
321
def job ():
361
322
calls .append (1 )
362
323
363
- AsyncUtilMixin .async_run_zha_job (zha_gateway , ZHAJob (callback ( job ) ))
324
+ AsyncUtilMixin .async_run_zha_job (zha_gateway , ZHAJob (job ))
364
325
assert len (calls ) == 1
365
326
assert len (zha_gateway .async_add_job .mock_calls ) == 0
366
327
367
328
368
- async def test_async_run_zha_job_delegates_non_async () -> None :
369
- """Test that the callback annotation is respected."""
370
- zha_gateway = MagicMock ()
371
- calls = []
372
-
373
- def job ():
374
- calls .append (1 )
375
-
376
- AsyncUtilMixin .async_run_zha_job (zha_gateway , ZHAJob (job ))
377
- assert len (calls ) == 0
378
- assert len (zha_gateway .async_add_zha_job .mock_calls ) == 1
379
-
380
-
381
329
async def test_async_create_task_pending_tasks_coro (zha_gateway : Gateway ) -> None :
382
330
"""Add a coro to pending tasks."""
383
331
call_count = []
@@ -395,34 +343,6 @@ async def test_coro():
395
343
assert len (zha_gateway ._tracked_completable_tasks ) == 0
396
344
397
345
398
- async def test_async_run_job_starts_tasks_eagerly (zha_gateway : Gateway ) -> None :
399
- """Test async_run_job starts tasks eagerly."""
400
- runs = []
401
-
402
- async def _test ():
403
- runs .append (True )
404
-
405
- task = zha_gateway .async_run_job (_test )
406
- # No call to zha_gateway.async_block_till_done to ensure the task is run eagerly
407
- assert len (runs ) == 1
408
- assert task .done ()
409
- await task
410
-
411
-
412
- async def test_async_run_job_starts_coro_eagerly (zha_gateway : Gateway ) -> None :
413
- """Test async_run_job starts coros eagerly."""
414
- runs = []
415
-
416
- async def _test ():
417
- runs .append (True )
418
-
419
- task = zha_gateway .async_run_job (_test ())
420
- # No call to zha_gateway.async_block_till_done to ensure the task is run eagerly
421
- assert len (runs ) == 1
422
- assert task .done ()
423
- await task
424
-
425
-
426
346
@pytest .mark .parametrize ("eager_start" , [True , False ])
427
347
async def test_background_task (zha_gateway : Gateway , eager_start : bool ) -> None :
428
348
"""Test background tasks being quit."""
@@ -447,7 +367,6 @@ async def test_task():
447
367
def test_ZHAJob_passing_job_type ():
448
368
"""Test passing the job type to ZHAJob when we already know it."""
449
369
450
- @callback
451
370
def callback_func ():
452
371
pass
453
372
@@ -506,31 +425,6 @@ async def _async_add_executor_job():
506
425
await task
507
426
508
427
509
- @patch ("concurrent.futures.Future" )
510
- @patch ("threading.get_ident" )
511
- def test_run_callback_threadsafe_from_inside_event_loop (mock_ident , _ ) -> None :
512
- """Testing calling run_callback_threadsafe from inside an event loop."""
513
- callback_fn = MagicMock ()
514
-
515
- loop = Mock (spec = ["call_soon_threadsafe" ])
516
-
517
- loop ._thread_ident = None
518
- mock_ident .return_value = 5
519
- zha_async .run_callback_threadsafe (loop , callback_fn )
520
- assert len (loop .call_soon_threadsafe .mock_calls ) == 1
521
-
522
- loop ._thread_ident = 5
523
- mock_ident .return_value = 5
524
- with pytest .raises (RuntimeError ):
525
- zha_async .run_callback_threadsafe (loop , callback_fn )
526
- assert len (loop .call_soon_threadsafe .mock_calls ) == 1
527
-
528
- loop ._thread_ident = 1
529
- mock_ident .return_value = 5
530
- zha_async .run_callback_threadsafe (loop , callback_fn )
531
- assert len (loop .call_soon_threadsafe .mock_calls ) == 2
532
-
533
-
534
428
async def test_gather_with_limited_concurrency () -> None :
535
429
"""Test gather_with_limited_concurrency limits the number of running tasks."""
536
430
@@ -553,74 +447,6 @@ async def _increment_runs_if_in_time():
553
447
assert results == [2 , 2 , - 1 , - 1 ]
554
448
555
449
556
- async def test_shutdown_run_callback_threadsafe (zha_gateway : Gateway ) -> None :
557
- """Test we can shutdown run_callback_threadsafe."""
558
- zha_async .shutdown_run_callback_threadsafe (zha_gateway .loop )
559
- callback_fn = MagicMock ()
560
-
561
- with pytest .raises (RuntimeError ):
562
- zha_async .run_callback_threadsafe (zha_gateway .loop , callback_fn )
563
-
564
-
565
- async def test_run_callback_threadsafe (zha_gateway : Gateway ) -> None :
566
- """Test run_callback_threadsafe runs code in the event loop."""
567
- it_ran = False
568
-
569
- def callback_fn ():
570
- nonlocal it_ran
571
- it_ran = True
572
-
573
- assert zha_async .run_callback_threadsafe (zha_gateway .loop , callback_fn )
574
- assert it_ran is False
575
-
576
- # Verify that async_block_till_done will flush
577
- # out the callback
578
- await zha_gateway .async_block_till_done ()
579
- assert it_ran is True
580
-
581
-
582
- async def test_run_callback_threadsafe_exception (zha_gateway : Gateway ) -> None :
583
- """Test run_callback_threadsafe runs code in the event loop."""
584
- it_ran = False
585
-
586
- def callback_fn ():
587
- nonlocal it_ran
588
- it_ran = True
589
- raise ValueError ("Test" )
590
-
591
- future = zha_async .run_callback_threadsafe (zha_gateway .loop , callback_fn )
592
- assert future
593
- assert it_ran is False
594
-
595
- # Verify that async_block_till_done will flush
596
- # out the callback
597
- await zha_gateway .async_block_till_done ()
598
- assert it_ran is True
599
-
600
- with pytest .raises (ValueError ):
601
- future .result ()
602
-
603
-
604
- async def test_callback_is_always_scheduled (zha_gateway : Gateway ) -> None :
605
- """Test run_callback_threadsafe always calls call_soon_threadsafe before checking for shutdown."""
606
- # We have to check the shutdown state AFTER the callback is scheduled otherwise
607
- # the function could continue on and the caller call `future.result()` after
608
- # the point in the main thread where callbacks are no longer run.
609
-
610
- callback_fn = MagicMock ()
611
- zha_async .shutdown_run_callback_threadsafe (zha_gateway .loop )
612
-
613
- with (
614
- patch .object (
615
- zha_gateway .loop , "call_soon_threadsafe"
616
- ) as mock_call_soon_threadsafe ,
617
- pytest .raises (RuntimeError ),
618
- ):
619
- zha_async .run_callback_threadsafe (zha_gateway .loop , callback_fn )
620
-
621
- mock_call_soon_threadsafe .assert_called_once ()
622
-
623
-
624
450
async def test_create_eager_task_312 (zha_gateway : Gateway ) -> None : # pylint: disable=unused-argument
625
451
"""Test create_eager_task schedules a task eagerly in the event loop.
626
452
0 commit comments