Skip to content
This repository was archived by the owner on May 9, 2024. It is now read-only.

Commit 9fb4d2a

Browse files
committed
Fixed test issues.
1 parent b4dea29 commit 9fb4d2a

File tree

5 files changed

+75
-49
lines changed

5 files changed

+75
-49
lines changed

pysmartapp/dispatch.py

+21-10
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
import asyncio
44
from collections import defaultdict
5-
from typing import Any, Callable, Dict, List
5+
from typing import Any, Callable, Dict, List, Sequence
66

77
TargetType = Callable[..., Any]
88
DisconnectType = Callable[[], None]
99
ConnectType = Callable[[str, TargetType], DisconnectType]
10-
SendType = Callable[..., None]
10+
SendType = Callable[..., Sequence[asyncio.Future]]
1111

1212

1313
class Dispatcher:
@@ -21,15 +21,18 @@ def __init__(self, *, connect: ConnectType = None, send: SendType = None,
2121
self._loop = loop or asyncio.get_event_loop()
2222
self._connect = connect or self._default_connect
2323
self._send = send or self._default_send
24+
self._last_sent = []
2425

2526
def connect(self, signal: str, target: TargetType) \
2627
-> DisconnectType:
2728
"""Connect function to signal. Must be ran in the event loop."""
2829
return self._connect(self._signal_prefix + signal, target)
2930

30-
def send(self, signal: str, *args: Any) -> None:
31+
def send(self, signal: str, *args: Any) -> Sequence[asyncio.Future]:
3132
"""Fire a signal. Must be ran in the event loop."""
32-
self._send(self._signal_prefix + signal, *args)
33+
sent = self._last_sent = self._send(
34+
self._signal_prefix + signal, *args)
35+
return sent
3336

3437
def _default_connect(self, signal: str, target: TargetType) \
3538
-> DisconnectType:
@@ -45,19 +48,27 @@ def remove_dispatcher() -> None:
4548
pass
4649
return remove_dispatcher
4750

48-
def _default_send(self, signal: str, *args: Any) -> None:
51+
def _default_send(self, signal: str, *args: Any) -> \
52+
Sequence[asyncio.Future]:
4953
"""Fire a signal. Must be ran in the event loop."""
5054
targets = self._signals[signal]
55+
futures = []
5156
for target in targets:
52-
self._call_target(target, *args)
57+
task = self._call_target(target, *args)
58+
futures.append(task)
59+
return futures
5360

54-
def _call_target(self, target, *args):
61+
def _call_target(self, target, *args) -> asyncio.Future:
5562
if asyncio.iscoroutinefunction(target):
56-
self._loop.create_task(target(*args))
57-
else:
58-
self._loop.run_in_executor(None, target, *args)
63+
return self._loop.create_task(target(*args))
64+
return self._loop.run_in_executor(None, target, *args)
5965

6066
@property
6167
def signals(self) -> Dict[str, List[TargetType]]:
6268
"""Get the dictionary of registered signals and callbaks."""
6369
return self._signals
70+
71+
@property
72+
def last_sent(self) -> Sequence[asyncio.Future]:
73+
"""Get the last sent asyncio tasks."""
74+
return self._last_sent

tests/conftest.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
import pytest
44

5+
from pysmartapp.dispatch import Dispatcher
56
from pysmartapp.smartapp import SmartApp, SmartAppManager
67

78

89
@pytest.fixture
9-
def smartapp() -> SmartApp:
10+
def smartapp(event_loop) -> SmartApp:
1011
"""Fixture for testing against the SmartApp class."""
11-
app = SmartApp()
12+
app = SmartApp(dispatcher=Dispatcher(loop=event_loop))
1213
app.name = 'SmartApp'
1314
app.description = 'SmartApp Description'
1415
app.permissions.append('l:devices')
@@ -17,18 +18,19 @@ def smartapp() -> SmartApp:
1718

1819

1920
@pytest.fixture
20-
def manager() -> SmartAppManager:
21+
def manager(event_loop) -> SmartAppManager:
2122
"""Fixture for testing against the SmartAppManager class."""
22-
return SmartAppManager('/path/to/app')
23+
return SmartAppManager('/path/to/app',
24+
dispatcher=Dispatcher(loop=event_loop))
2325

2426

2527
@pytest.fixture
2628
def handler():
2729
"""Fixture handler to mock in the dispatcher."""
2830
def target(*args, **kwargs):
31+
target.fired = True
2932
target.args = args
3033
target.kwargs = kwargs
31-
target.fired = True
3234
target.fired = False
3335
return target
3436

@@ -37,8 +39,8 @@ def target(*args, **kwargs):
3739
def async_handler():
3840
"""Fixture async handler to mock in the dispatcher."""
3941
async def target(*args, **kwargs):
42+
target.fired = True
4043
target.args = args
4144
target.kwargs = kwargs
42-
target.fired = True
4345
target.fired = False
4446
return target

tests/test_dispatch.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ async def test_send_async_handler(async_handler):
5454
dispatcher = Dispatcher()
5555
dispatcher.connect('TEST', async_handler)
5656
# Act
57-
dispatcher.send('TEST')
58-
# required so the execution switches to the handler
59-
await asyncio.sleep(0)
57+
await asyncio.gather(*dispatcher.send('TEST'))
6058
# Assert
6159
assert async_handler.fired
6260

@@ -69,7 +67,7 @@ async def test_send(handler):
6967
dispatcher.connect('TEST', handler)
7068
args = object()
7169
# Act
72-
dispatcher.send('TEST', args)
70+
await asyncio.gather(*dispatcher.send('TEST', args))
7371
# Assert
7472
assert handler.fired
7573
assert handler.args[0] == args

tests/test_smartapp.py

+43-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for the SmartApp file."""
22

33
import asyncio
4+
45
import pytest
56

67
from pysmartapp.dispatch import Dispatcher
@@ -61,7 +62,8 @@ async def test_ping(smartapp):
6162
smartapp.connect_ping(handler)
6263
# Act
6364
response = await smartapp.handle_request(request)
64-
await asyncio.sleep(0)
65+
# ensure dispatched tasks complete
66+
await asyncio.gather(*smartapp.dispatcher.last_sent)
6567
# Assert
6668
assert handler.fired
6769
assert response == expected_response
@@ -77,7 +79,8 @@ async def test_config_init(smartapp):
7779
smartapp.connect_config(handler)
7880
# Act
7981
response = await smartapp.handle_request(request, None, False)
80-
await asyncio.sleep(0)
82+
# ensure dispatched tasks complete
83+
await asyncio.gather(*smartapp.dispatcher.last_sent)
8184
# Assert
8285
assert handler.fired
8386
assert response == expected_response
@@ -93,7 +96,8 @@ async def test_config_page(smartapp):
9396
smartapp.connect_config(handler)
9497
# Act
9598
response = await smartapp.handle_request(request, None, False)
96-
await asyncio.sleep(0)
99+
# ensure dispatched tasks complete
100+
await asyncio.gather(*smartapp.dispatcher.last_sent)
97101
# Assert
98102
assert handler.fired
99103
assert response == expected_response
@@ -109,7 +113,8 @@ async def test_install(smartapp):
109113
smartapp.connect_install(handler)
110114
# Act
111115
response = await smartapp.handle_request(request, None, False)
112-
await asyncio.sleep(0)
116+
# ensure dispatched tasks complete
117+
await asyncio.gather(*smartapp.dispatcher.last_sent)
113118
# Assert
114119
assert handler.fired
115120
assert response == expected_response
@@ -125,7 +130,8 @@ async def test_update(smartapp):
125130
smartapp.connect_update(handler)
126131
# Act
127132
response = await smartapp.handle_request(request, None, False)
128-
await asyncio.sleep(0)
133+
# ensure dispatched tasks complete
134+
await asyncio.gather(*smartapp.dispatcher.last_sent)
129135
# Assert
130136
assert handler.fired
131137
assert response == expected_response
@@ -141,7 +147,8 @@ async def test_event(smartapp):
141147
smartapp.connect_event(handler)
142148
# Act
143149
response = await smartapp.handle_request(request, None, False)
144-
await asyncio.sleep(0)
150+
# ensure dispatched tasks complete
151+
await asyncio.gather(*smartapp.dispatcher.last_sent)
145152
# Assert
146153
assert handler.fired
147154
assert response == expected_response
@@ -157,7 +164,8 @@ async def test_oauth_callback(smartapp):
157164
smartapp.connect_oauth_callback(handler)
158165
# Act
159166
response = await smartapp.handle_request(request, None, False)
160-
await asyncio.sleep(0)
167+
# ensure dispatched tasks complete
168+
await asyncio.gather(*smartapp.dispatcher.last_sent)
161169
# Assert
162170
assert handler.fired
163171
assert response == expected_response
@@ -173,7 +181,8 @@ async def test_uninstall(smartapp):
173181
smartapp.connect_uninstall(handler)
174182
# Act
175183
response = await smartapp.handle_request(request, None, False)
176-
await asyncio.sleep(0)
184+
# ensure dispatched tasks complete
185+
await asyncio.gather(*smartapp.dispatcher.last_sent)
177186
# Assert
178187
assert handler.fired
179188
assert response == expected_response
@@ -231,7 +240,8 @@ async def test_handle_request_ping_not_registered(manager):
231240
manager.connect_ping(handler)
232241
# Act
233242
response = await manager.handle_request(request)
234-
await asyncio.sleep(0)
243+
# ensure dispatched tasks complete
244+
await asyncio.gather(*manager.dispatcher.last_sent)
235245
# Assert
236246
assert handler.fired
237247
assert response == expected_response
@@ -327,12 +337,13 @@ async def test_on_config(manager: SmartAppManager):
327337
"""Tests the config event handler at the manager level."""
328338
# Arrange
329339
request = get_fixture("config_init_request")
330-
handler = get_dispatch_handler(manager)
340+
app = manager.register(APP_ID, 'none')
341+
handler = get_dispatch_handler(app)
331342
manager.connect_config(handler)
332-
manager.register(APP_ID, 'none')
333343
# Act
334344
await manager.handle_request(request, None, False)
335-
await asyncio.sleep(0)
345+
# ensure dispatched tasks complete
346+
await asyncio.gather(*manager.dispatcher.last_sent)
336347
# Assert
337348
assert handler.fired
338349

@@ -342,12 +353,13 @@ async def test_on_install(manager: SmartAppManager):
342353
"""Tests the config event handler at the manager level."""
343354
# Arrange
344355
request = get_fixture("install_request")
345-
handler = get_dispatch_handler(manager)
356+
app = manager.register(APP_ID, 'none')
357+
handler = get_dispatch_handler(app)
346358
manager.connect_install(handler)
347-
manager.register(APP_ID, 'none')
348359
# Act
349360
await manager.handle_request(request, None, False)
350-
await asyncio.sleep(0)
361+
# ensure dispatched tasks complete
362+
await asyncio.gather(*manager.dispatcher.last_sent)
351363
# Assert
352364
assert handler.fired
353365

@@ -357,12 +369,13 @@ async def test_on_update(manager: SmartAppManager):
357369
"""Tests the config event handler at the manager level."""
358370
# Arrange
359371
request = get_fixture("update_request")
360-
handler = get_dispatch_handler(manager)
372+
app = manager.register(APP_ID, 'none')
373+
handler = get_dispatch_handler(app)
361374
manager.connect_update(handler)
362-
manager.register(APP_ID, 'none')
363375
# Act
364376
await manager.handle_request(request, None, False)
365-
await asyncio.sleep(0)
377+
# ensure dispatched tasks complete
378+
await asyncio.gather(*manager.dispatcher.last_sent)
366379
# Assert
367380
assert handler.fired
368381

@@ -372,12 +385,13 @@ async def test_on_event(manager: SmartAppManager):
372385
"""Tests the config event handler at the manager level."""
373386
# Arrange
374387
request = get_fixture("event_request")
375-
handler = get_dispatch_handler(manager)
388+
app = manager.register(APP_ID, 'none')
389+
handler = get_dispatch_handler(app)
376390
manager.connect_event(handler)
377-
manager.register(APP_ID, 'none')
378391
# Act
379392
await manager.handle_request(request, None, False)
380-
await asyncio.sleep(0)
393+
# ensure dispatched tasks complete
394+
await asyncio.gather(*manager.dispatcher.last_sent)
381395
# Assert
382396
assert handler.fired
383397

@@ -387,12 +401,13 @@ async def test_on_oauth_callback(manager: SmartAppManager):
387401
"""Tests the config event handler at the manager level."""
388402
# Arrange
389403
request = get_fixture("oauth_callback_request")
390-
handler = get_dispatch_handler(manager)
404+
app = manager.register(APP_ID, 'none')
405+
handler = get_dispatch_handler(app)
391406
manager.connect_oauth_callback(handler)
392-
manager.register(APP_ID, 'none')
393407
# Act
394408
await manager.handle_request(request, None, False)
395-
await asyncio.sleep(0)
409+
# ensure dispatched tasks complete
410+
await asyncio.gather(*manager.dispatcher.last_sent)
396411
# Assert
397412
assert handler.fired
398413

@@ -402,11 +417,12 @@ async def test_on_uninstall(manager: SmartAppManager):
402417
"""Tests the config event handler at the manager level."""
403418
# Arrange
404419
request = get_fixture("uninstall_request")
405-
handler = get_dispatch_handler(manager)
420+
app = manager.register(APP_ID, 'none')
421+
handler = get_dispatch_handler(app)
406422
manager.connect_uninstall(handler)
407-
manager.register(APP_ID, 'none')
408423
# Act
409424
await manager.handle_request(request, None, False)
410-
await asyncio.sleep(0)
425+
# ensure dispatched tasks complete
426+
await asyncio.gather(*manager.dispatcher.last_sent)
411427
# Assert
412428
assert handler.fired

tests/utilities.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""Testing utilities."""
2-
32
import json
43

54

@@ -14,7 +13,7 @@ def get_fixture(file: str, ext: str = 'json'):
1413

1514
def get_dispatch_handler(smartapp):
1615
"""Get a handler to mock in the dispatcher."""
17-
def handler(req, resp, app):
16+
async def handler(req, resp, app):
1817
handler.fired = True
1918
assert app == smartapp
2019
handler.fired = False

0 commit comments

Comments
 (0)