|
5 | 5 | import types |
6 | 6 | import unittest |
7 | 7 | import weakref |
| 8 | +from test import support |
8 | 9 | from test.script_helper import assert_python_ok |
| 10 | +from unittest import mock |
9 | 11 |
|
10 | 12 | import asyncio |
11 | 13 | from asyncio import tasks |
12 | 14 | from asyncio import test_utils |
13 | 15 |
|
14 | 16 |
|
| 17 | +PY34 = (sys.version_info >= (3, 4)) |
15 | 18 | PY35 = (sys.version_info >= (3, 5)) |
16 | 19 |
|
17 | 20 |
|
@@ -1501,9 +1504,45 @@ def call(arg): |
1501 | 1504 | def test_corowrapper_weakref(self): |
1502 | 1505 | wd = weakref.WeakValueDictionary() |
1503 | 1506 | def foo(): yield from [] |
1504 | | - cw = asyncio.tasks.CoroWrapper(foo(), foo) |
1505 | | - wd['cw'] = cw # Would fail without __weakref__ slot. |
1506 | | - cw.gen = None # Suppress warning from __del__. |
| 1507 | + |
| 1508 | + @unittest.skipUnless(PY34, |
| 1509 | + 'need python 3.4 or later') |
| 1510 | + def test_log_destroyed_pending_task(self): |
| 1511 | + @asyncio.coroutine |
| 1512 | + def kill_me(loop): |
| 1513 | + future = asyncio.Future(loop=loop) |
| 1514 | + yield from future |
| 1515 | + # at this point, the only reference to kill_me() task is |
| 1516 | + # the Task._wakeup() method in future._callbacks |
| 1517 | + raise Exception("code never reached") |
| 1518 | + |
| 1519 | + mock_handler = mock.Mock() |
| 1520 | + self.loop.set_exception_handler(mock_handler) |
| 1521 | + |
| 1522 | + # schedule the task |
| 1523 | + coro = kill_me(self.loop) |
| 1524 | + task = asyncio.async(coro, loop=self.loop) |
| 1525 | + self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), {task}) |
| 1526 | + |
| 1527 | + # execute the task so it waits for future |
| 1528 | + self.loop._run_once() |
| 1529 | + self.assertEqual(len(self.loop._ready), 0) |
| 1530 | + |
| 1531 | + # remove the future used in kill_me(), and references to the task |
| 1532 | + del coro.gi_frame.f_locals['future'] |
| 1533 | + coro = None |
| 1534 | + task = None |
| 1535 | + |
| 1536 | + # no more reference to kill_me() task: the task is destroyed by the GC |
| 1537 | + support.gc_collect() |
| 1538 | + |
| 1539 | + self.assertEqual(asyncio.Task.all_tasks(loop=self.loop), set()) |
| 1540 | + |
| 1541 | + mock_handler.assert_called_with(self.loop, { |
| 1542 | + 'message': 'Task was destroyed but it is pending!', |
| 1543 | + 'task': mock.ANY, |
| 1544 | + }) |
| 1545 | + mock_handler.reset_mock() |
1507 | 1546 |
|
1508 | 1547 |
|
1509 | 1548 | class GatherTestsBase: |
|
0 commit comments