Skip to content

Commit 783eacc

Browse files
committed
Add unit tests for asyncSlot error and asyncClose
1 parent 7ddee57 commit 783eacc

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

tests/test_qeventloop.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import threading
1515
import time
1616
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
17+
from unittest import mock
1718

1819
import pytest
1920

@@ -801,6 +802,8 @@ def test_async_slot(loop):
801802
no_args_called = asyncio.Event()
802803
with_args_called = asyncio.Event()
803804
trailing_args_called = asyncio.Event()
805+
error_called = asyncio.Event()
806+
cancel_called = asyncio.Event()
804807

805808
async def slot_no_args():
806809
no_args_called.set()
@@ -815,6 +818,14 @@ async def slot_trailing_args(flag: bool):
815818

816819
async def slot_signature_mismatch(_: bool): ...
817820

821+
async def slot_with_error():
822+
error_called.set()
823+
raise ValueError("Test")
824+
825+
async def slot_with_cancel():
826+
cancel_called.set()
827+
raise asyncio.CancelledError()
828+
818829
async def main():
819830
# passing kwargs to the underlying Slot such as name, arguments, return
820831
sig = qasync._make_signaller(qasync.QtCore)
@@ -839,6 +850,73 @@ async def main():
839850
)
840851
await asyncio.wait_for(all_done, timeout=1.0)
841852

853+
with mock.patch.object(sys, "excepthook") as excepthook:
854+
sig3 = qasync._make_signaller(qasync.QtCore)
855+
sig3.signal.connect(qasync.asyncSlot()(slot_with_error))
856+
sig3.signal.emit()
857+
await asyncio.wait_for(error_called.wait(), timeout=1.0)
858+
excepthook.assert_called_once()
859+
assert isinstance(excepthook.call_args[0][1], ValueError)
860+
861+
with mock.patch.object(sys, "excepthook") as excepthook:
862+
sig4 = qasync._make_signaller(qasync.QtCore)
863+
sig4.signal.connect(qasync.asyncSlot()(slot_with_cancel))
864+
sig4.signal.emit()
865+
await asyncio.wait_for(cancel_called.wait(), timeout=1.0)
866+
excepthook.assert_not_called()
867+
868+
loop.run_until_complete(main())
869+
870+
871+
def test_async_close(loop, application):
872+
close_called = asyncio.Event()
873+
close_err_called = asyncio.Event()
874+
close_hang_called = asyncio.Event()
875+
876+
@qasync.asyncClose
877+
async def close():
878+
close_called.set()
879+
return 33
880+
881+
@qasync.asyncClose
882+
async def close_err():
883+
close_err_called.set()
884+
raise ValueError("Test")
885+
886+
@qasync.asyncClose
887+
async def close_hang():
888+
# do an actual cancel instead of directly raising, for completeness.
889+
current = asyncio.current_task()
890+
assert current is not None
891+
892+
async def killer():
893+
await asyncio.sleep(0.001)
894+
current.cancel()
895+
896+
asyncio.create_task(killer())
897+
close_hang_called.set()
898+
await asyncio.Event().wait()
899+
assert False, "Should have been cancelled"
900+
901+
# need to run in async context to have a running event loop
902+
async def main():
903+
# close() is a synchronous top level call, need
904+
# to wrap it to be able to enter event loop
905+
906+
# test that a regular close works
907+
assert await qasync.asyncWrap(close) == 33
908+
assert close_called.is_set()
909+
910+
# test that an exception in the async close is propagated
911+
with pytest.raises(ValueError) as err:
912+
await qasync.asyncWrap(close_err)
913+
assert err.value.args[0] == "Test"
914+
assert close_err_called.is_set()
915+
916+
# test that a CancelledError is not propagated
917+
assert qasync.asyncWrap(close_hang) is None
918+
assert close_hang_called.is_set()
919+
842920
loop.run_until_complete(main())
843921

844922

0 commit comments

Comments
 (0)