test_futures.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. from panda3d import core
  2. import pytest
  3. import threading
  4. import time
  5. import sys
  6. if sys.version_info >= (3,):
  7. from concurrent.futures._base import TimeoutError, CancelledError
  8. else:
  9. TimeoutError = Exception
  10. CancelledError = Exception
  11. def test_future_cancelled():
  12. fut = core.AsyncFuture()
  13. assert not fut.done()
  14. assert not fut.cancelled()
  15. fut.cancel()
  16. assert fut.done()
  17. assert fut.cancelled()
  18. with pytest.raises(CancelledError):
  19. fut.result()
  20. # Works more than once
  21. with pytest.raises(CancelledError):
  22. fut.result()
  23. def test_future_timeout():
  24. fut = core.AsyncFuture()
  25. with pytest.raises(TimeoutError):
  26. fut.result(0.001)
  27. # Works more than once
  28. with pytest.raises(TimeoutError):
  29. fut.result(0.001)
  30. def test_future_wait():
  31. fut = core.AsyncFuture()
  32. # Launch a thread to set the result value.
  33. def thread_main():
  34. time.sleep(0.001)
  35. fut.set_result(None)
  36. thread = threading.Thread(target=thread_main)
  37. thread.start()
  38. # Make sure it didn't sneakily already run the thread
  39. assert not fut.done()
  40. assert fut.result() is None
  41. assert fut.done()
  42. assert not fut.cancelled()
  43. assert fut.result() is None
  44. def test_future_wait_cancel():
  45. fut = core.AsyncFuture()
  46. # Launch a thread to cancel the future.
  47. def thread_main():
  48. time.sleep(0.001)
  49. fut.cancel()
  50. thread = threading.Thread(target=thread_main)
  51. thread.start()
  52. # Make sure it didn't sneakily already run the thread
  53. assert not fut.done()
  54. with pytest.raises(CancelledError):
  55. fut.result()
  56. assert fut.done()
  57. assert fut.cancelled()
  58. with pytest.raises(CancelledError):
  59. fut.result()
  60. def test_task_cancel():
  61. task_mgr = core.AsyncTaskManager.get_global_ptr()
  62. task = core.PythonTask(lambda task: task.done)
  63. task_mgr.add(task)
  64. assert not task.done()
  65. task_mgr.remove(task)
  66. assert task.done()
  67. assert task.cancelled()
  68. with pytest.raises(CancelledError):
  69. task.result()
  70. def test_task_cancel_during_run():
  71. task_mgr = core.AsyncTaskManager.get_global_ptr()
  72. task_chain = task_mgr.make_task_chain("test_task_cancel_during_run")
  73. def task_main(task):
  74. task.remove()
  75. # It won't yet be marked done until after it returns.
  76. assert not task.done()
  77. return task.done
  78. task = core.PythonTask(task_main)
  79. task.set_task_chain(task_chain.name)
  80. task_mgr.add(task)
  81. task_chain.wait_for_tasks()
  82. assert task.done()
  83. assert task.cancelled()
  84. with pytest.raises(CancelledError):
  85. task.result()
  86. def test_task_result():
  87. task_mgr = core.AsyncTaskManager.get_global_ptr()
  88. task_chain = task_mgr.make_task_chain("test_task_result")
  89. def task_main(task):
  90. task.set_result(42)
  91. # It won't yet be marked done until after it returns.
  92. assert not task.done()
  93. return core.PythonTask.done
  94. task = core.PythonTask(task_main)
  95. task.set_task_chain(task_chain.name)
  96. task_mgr.add(task)
  97. task_chain.wait_for_tasks()
  98. assert task.done()
  99. assert not task.cancelled()
  100. assert task.result() == 42
  101. def test_coro_exception():
  102. task_mgr = core.AsyncTaskManager.get_global_ptr()
  103. task_chain = task_mgr.make_task_chain("test_coro_exception")
  104. def coro_main():
  105. raise RuntimeError
  106. yield None
  107. task = core.PythonTask(coro_main())
  108. task.set_task_chain(task_chain.name)
  109. task_mgr.add(task)
  110. task_chain.wait_for_tasks()
  111. assert task.done()
  112. assert not task.cancelled()
  113. with pytest.raises(RuntimeError):
  114. task.result()
  115. def test_future_gather():
  116. fut1 = core.AsyncFuture()
  117. fut2 = core.AsyncFuture()
  118. # 0 and 1 arguments are special
  119. assert core.AsyncFuture.gather().done()
  120. assert core.AsyncFuture.gather(fut1) == fut1
  121. # Gathering not-done futures
  122. gather = core.AsyncFuture.gather(fut1, fut2)
  123. assert not gather.done()
  124. # One future done
  125. fut1.set_result(1)
  126. assert not gather.done()
  127. # Two futures done
  128. fut2.set_result(2)
  129. assert gather.done()
  130. assert not gather.cancelled()
  131. assert tuple(gather.result()) == (1, 2)
  132. def test_future_gather_cancel_inner():
  133. fut1 = core.AsyncFuture()
  134. fut2 = core.AsyncFuture()
  135. # Gathering not-done futures
  136. gather = core.AsyncFuture.gather(fut1, fut2)
  137. assert not gather.done()
  138. # One future cancelled
  139. fut1.cancel()
  140. assert not gather.done()
  141. # Two futures cancelled
  142. fut2.set_result(2)
  143. assert gather.done()
  144. assert not gather.cancelled()
  145. with pytest.raises(CancelledError):
  146. assert gather.result()
  147. def test_future_gather_cancel_outer():
  148. fut1 = core.AsyncFuture()
  149. fut2 = core.AsyncFuture()
  150. # Gathering not-done futures
  151. gather = core.AsyncFuture.gather(fut1, fut2)
  152. assert not gather.done()
  153. assert gather.cancel()
  154. assert gather.done()
  155. assert gather.cancelled()
  156. with pytest.raises(CancelledError):
  157. assert gather.result()
  158. def test_future_done_callback():
  159. fut = core.AsyncFuture()
  160. # Use the list hack since Python 2 doesn't have the "nonlocal" keyword.
  161. called = [False]
  162. def on_done(arg):
  163. assert arg == fut
  164. called[0] = True
  165. fut.add_done_callback(on_done)
  166. fut.cancel()
  167. assert fut.done()
  168. task_mgr = core.AsyncTaskManager.get_global_ptr()
  169. task_mgr.poll()
  170. assert called[0]
  171. def test_future_done_callback_already_done():
  172. # Same as above, but with the future already done when add_done_callback
  173. # is called.
  174. fut = core.AsyncFuture()
  175. fut.cancel()
  176. assert fut.done()
  177. # Use the list hack since Python 2 doesn't have the "nonlocal" keyword.
  178. called = [False]
  179. def on_done(arg):
  180. assert arg == fut
  181. called[0] = True
  182. fut.add_done_callback(on_done)
  183. task_mgr = core.AsyncTaskManager.get_global_ptr()
  184. task_mgr.poll()
  185. assert called[0]
  186. def test_event_future():
  187. queue = core.EventQueue()
  188. handler = core.EventHandler(queue)
  189. fut = handler.get_future("test")
  190. # If we ask again, we should get the same one.
  191. assert handler.get_future("test") == fut
  192. event = core.Event("test")
  193. handler.dispatch_event(event)
  194. assert fut.done()
  195. assert not fut.cancelled()
  196. assert fut.result() == event
  197. def test_event_future_cancel():
  198. # This is a very strange thing to do, but it's possible, so let's make
  199. # sure it gives defined behavior.
  200. queue = core.EventQueue()
  201. handler = core.EventHandler(queue)
  202. fut = handler.get_future("test")
  203. fut.cancel()
  204. assert fut.done()
  205. assert fut.cancelled()
  206. event = core.Event("test")
  207. handler.dispatch_event(event)
  208. assert fut.done()
  209. assert fut.cancelled()
  210. def test_event_future_cancel2():
  211. queue = core.EventQueue()
  212. handler = core.EventHandler(queue)
  213. # Make sure we get a new future if we cancelled the first one.
  214. fut = handler.get_future("test")
  215. fut.cancel()
  216. fut2 = handler.get_future("test")
  217. assert fut != fut2
  218. assert fut.done()
  219. assert fut.cancelled()
  220. assert not fut2.done()
  221. assert not fut2.cancelled()