@@ -622,6 +622,42 @@ def task(): |
|
|
622 |
622 |
self.assertFalse(t._must_cancel) # White-box test. |
623 |
623 |
self.assertFalse(t.cancel()) |
624 |
624 |
|
|
625 |
+def test_cancel_awaited_task(self): |
|
626 |
+# This tests for a relatively rare condition when |
|
627 |
+# a task cancellation is requested for a task which is not |
|
628 |
+# currently blocked, such as a task cancelling itself. |
|
629 |
+# In this situation we must ensure that whatever next future |
|
630 |
+# or task the cancelled task blocks on is cancelled correctly |
|
631 |
+# as well. See also bpo-34872. |
|
632 |
+loop = asyncio.new_event_loop() |
|
633 |
+self.addCleanup(lambda: loop.close()) |
|
634 |
+ |
|
635 |
+task = nested_task = None |
|
636 |
+fut = self.new_future(loop) |
|
637 |
+ |
|
638 |
+async def nested(): |
|
639 |
+await fut |
|
640 |
+ |
|
641 |
+async def coro(): |
|
642 |
+nonlocal nested_task |
|
643 |
+# Create a sub-task and wait for it to run. |
|
644 |
+nested_task = self.new_task(loop, nested()) |
|
645 |
+await asyncio.sleep(0) |
|
646 |
+ |
|
647 |
+# Request the current task to be cancelled. |
|
648 |
+task.cancel() |
|
649 |
+# Block on the nested task, which should be immediately |
|
650 |
+# cancelled. |
|
651 |
+await nested_task |
|
652 |
+ |
|
653 |
+task = self.new_task(loop, coro()) |
|
654 |
+with self.assertRaises(asyncio.CancelledError): |
|
655 |
+loop.run_until_complete(task) |
|
656 |
+ |
|
657 |
+self.assertTrue(task.cancelled()) |
|
658 |
+self.assertTrue(nested_task.cancelled()) |
|
659 |
+self.assertTrue(fut.cancelled()) |
|
660 |
+ |
625 |
661 |
def test_stop_while_run_in_complete(self): |
626 |
662 |
|
627 |
663 |
def gen(): |