|
3 | 3 | import functools
|
4 | 4 | import async_timeout
|
5 | 5 |
|
6 |
| -from unittest.mock import Mock |
| 6 | +from unittest.mock import Mock, call |
7 | 7 |
|
8 | 8 | try:
|
9 | 9 | from unittest.mock import AsyncMock # noqa: F401
|
|
15 | 15 |
|
16 | 16 | from zigpy_znp.types import nvids
|
17 | 17 |
|
18 |
| -from zigpy_znp.api import ZNP, _deduplicate_commands |
| 18 | +from zigpy_znp.api import ( |
| 19 | + ZNP, |
| 20 | + _deduplicate_commands, |
| 21 | + OneShotResponseListener, |
| 22 | + CallbackResponseListener, |
| 23 | +) |
19 | 24 | from zigpy_znp.frames import TransportFrame
|
20 | 25 |
|
21 | 26 |
|
@@ -510,3 +515,81 @@ async def test_znp_nvram_writes(znp, event_loop):
|
510 | 515 | # Writing too big of a value should fail
|
511 | 516 | with pytest.raises(ValueError):
|
512 | 517 | await znp.nvram_write(nvids.NwkNvIds.STARTUP_OPTION, t.uint16_t(0xAABB))
|
| 518 | + |
| 519 | + |
| 520 | +@pytest_mark_asyncio_timeout() |
| 521 | +async def test_listeners_resolve(event_loop): |
| 522 | + callback = Mock() |
| 523 | + callback_listener = CallbackResponseListener( |
| 524 | + [c.SysCommands.Ping.Rsp(partial=True)], callback |
| 525 | + ) |
| 526 | + |
| 527 | + future = event_loop.create_future() |
| 528 | + one_shot_listener = OneShotResponseListener( |
| 529 | + [c.SysCommands.Ping.Rsp(partial=True)], future |
| 530 | + ) |
| 531 | + |
| 532 | + match = c.SysCommands.Ping.Rsp(Capabilities=c.types.MTCapabilities.CAP_SYS) |
| 533 | + no_match = c.SysCommands.OSALNVWrite.Rsp(Status=t.Status.Success) |
| 534 | + |
| 535 | + assert callback_listener.resolve(match) |
| 536 | + assert not callback_listener.resolve(no_match) |
| 537 | + assert callback_listener.resolve(match) |
| 538 | + assert not callback_listener.resolve(no_match) |
| 539 | + |
| 540 | + assert one_shot_listener.resolve(match) |
| 541 | + assert not one_shot_listener.resolve(no_match) |
| 542 | + |
| 543 | + callback.assert_has_calls([call(match), call(match)]) |
| 544 | + assert callback.call_count == 2 |
| 545 | + |
| 546 | + assert (await future) == match |
| 547 | + |
| 548 | + # Cancelling a callback will have no effect |
| 549 | + assert not callback_listener.cancel() |
| 550 | + |
| 551 | + # Cancelling a one-shot listener does not throw any errors |
| 552 | + assert one_shot_listener.cancel() |
| 553 | + assert one_shot_listener.cancel() |
| 554 | + assert one_shot_listener.cancel() |
| 555 | + |
| 556 | + |
| 557 | +@pytest_mark_asyncio_timeout() |
| 558 | +async def test_listener_cancel(event_loop): |
| 559 | + # Cancelling a one-shot listener prevents it from being fired |
| 560 | + future = event_loop.create_future() |
| 561 | + one_shot_listener = OneShotResponseListener( |
| 562 | + [c.SysCommands.Ping.Rsp(partial=True)], future |
| 563 | + ) |
| 564 | + one_shot_listener.cancel() |
| 565 | + |
| 566 | + match = c.SysCommands.Ping.Rsp(Capabilities=c.types.MTCapabilities.CAP_SYS) |
| 567 | + assert not one_shot_listener.resolve(match) |
| 568 | + |
| 569 | + with pytest.raises(asyncio.CancelledError): |
| 570 | + await future |
| 571 | + |
| 572 | + |
| 573 | +@pytest_mark_asyncio_timeout() |
| 574 | +async def test_listeners_cancel(event_loop): |
| 575 | + callback = Mock() |
| 576 | + callback_listener = CallbackResponseListener( |
| 577 | + [c.SysCommands.Ping.Rsp(partial=True)], callback |
| 578 | + ) |
| 579 | + |
| 580 | + future = event_loop.create_future() |
| 581 | + one_shot_listener = OneShotResponseListener( |
| 582 | + [c.SysCommands.Ping.Rsp(partial=True)], future |
| 583 | + ) |
| 584 | + |
| 585 | + match = c.SysCommands.Ping.Rsp(Capabilities=c.types.MTCapabilities.CAP_SYS) |
| 586 | + no_match = c.SysCommands.OSALNVWrite.Rsp(Status=t.Status.Success) |
| 587 | + |
| 588 | + assert callback_listener.resolve(match) |
| 589 | + assert not callback_listener.resolve(no_match) |
| 590 | + |
| 591 | + assert one_shot_listener.resolve(match) |
| 592 | + assert not one_shot_listener.resolve(no_match) |
| 593 | + |
| 594 | + callback.assert_called_once_with(match) |
| 595 | + assert (await future) == match |
0 commit comments