ยปCore Development>Code coverage>Lib/test/test_asyncio/test_futures.py

Python code coverage for Lib/test/test_asyncio/test_futures.py

#countcontent
1n/a"""Tests for futures.py."""
2n/a
3n/aimport concurrent.futures
4n/aimport re
5n/aimport sys
6n/aimport threading
7n/aimport unittest
8n/afrom unittest import mock
9n/a
10n/aimport asyncio
11n/afrom asyncio import test_utils
12n/afrom asyncio import futures
13n/atry:
14n/a from test import support
15n/aexcept ImportError:
16n/a from asyncio import test_support as support
17n/a
18n/a
19n/adef _fakefunc(f):
20n/a return f
21n/a
22n/adef first_cb():
23n/a pass
24n/a
25n/adef last_cb():
26n/a pass
27n/a
28n/a
29n/aclass DuckFuture:
30n/a # Class that does not inherit from Future but aims to be duck-type
31n/a # compatible with it.
32n/a
33n/a _asyncio_future_blocking = False
34n/a __cancelled = False
35n/a __result = None
36n/a __exception = None
37n/a
38n/a def cancel(self):
39n/a if self.done():
40n/a return False
41n/a self.__cancelled = True
42n/a return True
43n/a
44n/a def cancelled(self):
45n/a return self.__cancelled
46n/a
47n/a def done(self):
48n/a return (self.__cancelled
49n/a or self.__result is not None
50n/a or self.__exception is not None)
51n/a
52n/a def result(self):
53n/a assert not self.cancelled()
54n/a if self.__exception is not None:
55n/a raise self.__exception
56n/a return self.__result
57n/a
58n/a def exception(self):
59n/a assert not self.cancelled()
60n/a return self.__exception
61n/a
62n/a def set_result(self, result):
63n/a assert not self.done()
64n/a assert result is not None
65n/a self.__result = result
66n/a
67n/a def set_exception(self, exception):
68n/a assert not self.done()
69n/a assert exception is not None
70n/a self.__exception = exception
71n/a
72n/a def __iter__(self):
73n/a if not self.done():
74n/a self._asyncio_future_blocking = True
75n/a yield self
76n/a assert self.done()
77n/a return self.result()
78n/a
79n/a
80n/aclass DuckTests(test_utils.TestCase):
81n/a
82n/a def setUp(self):
83n/a super().setUp()
84n/a self.loop = self.new_test_loop()
85n/a self.addCleanup(self.loop.close)
86n/a
87n/a def test_wrap_future(self):
88n/a f = DuckFuture()
89n/a g = asyncio.wrap_future(f)
90n/a assert g is f
91n/a
92n/a def test_ensure_future(self):
93n/a f = DuckFuture()
94n/a g = asyncio.ensure_future(f)
95n/a assert g is f
96n/a
97n/a
98n/aclass BaseFutureTests:
99n/a
100n/a def _new_future(self, loop=None):
101n/a raise NotImplementedError
102n/a
103n/a def setUp(self):
104n/a super().setUp()
105n/a self.loop = self.new_test_loop()
106n/a self.addCleanup(self.loop.close)
107n/a
108n/a def test_isfuture(self):
109n/a class MyFuture:
110n/a _asyncio_future_blocking = None
111n/a
112n/a def __init__(self):
113n/a self._asyncio_future_blocking = False
114n/a
115n/a self.assertFalse(asyncio.isfuture(MyFuture))
116n/a self.assertTrue(asyncio.isfuture(MyFuture()))
117n/a self.assertFalse(asyncio.isfuture(1))
118n/a
119n/a # As `isinstance(Mock(), Future)` returns `False`
120n/a self.assertFalse(asyncio.isfuture(mock.Mock()))
121n/a
122n/a f = self._new_future(loop=self.loop)
123n/a self.assertTrue(asyncio.isfuture(f))
124n/a self.assertFalse(asyncio.isfuture(type(f)))
125n/a
126n/a # As `isinstance(Mock(Future), Future)` returns `True`
127n/a self.assertTrue(asyncio.isfuture(mock.Mock(type(f))))
128n/a
129n/a f.cancel()
130n/a
131n/a def test_initial_state(self):
132n/a f = self._new_future(loop=self.loop)
133n/a self.assertFalse(f.cancelled())
134n/a self.assertFalse(f.done())
135n/a f.cancel()
136n/a self.assertTrue(f.cancelled())
137n/a
138n/a def test_init_constructor_default_loop(self):
139n/a asyncio.set_event_loop(self.loop)
140n/a f = self._new_future()
141n/a self.assertIs(f._loop, self.loop)
142n/a
143n/a def test_constructor_positional(self):
144n/a # Make sure Future doesn't accept a positional argument
145n/a self.assertRaises(TypeError, self._new_future, 42)
146n/a
147n/a def test_cancel(self):
148n/a f = self._new_future(loop=self.loop)
149n/a self.assertTrue(f.cancel())
150n/a self.assertTrue(f.cancelled())
151n/a self.assertTrue(f.done())
152n/a self.assertRaises(asyncio.CancelledError, f.result)
153n/a self.assertRaises(asyncio.CancelledError, f.exception)
154n/a self.assertRaises(asyncio.InvalidStateError, f.set_result, None)
155n/a self.assertRaises(asyncio.InvalidStateError, f.set_exception, None)
156n/a self.assertFalse(f.cancel())
157n/a
158n/a def test_result(self):
159n/a f = self._new_future(loop=self.loop)
160n/a self.assertRaises(asyncio.InvalidStateError, f.result)
161n/a
162n/a f.set_result(42)
163n/a self.assertFalse(f.cancelled())
164n/a self.assertTrue(f.done())
165n/a self.assertEqual(f.result(), 42)
166n/a self.assertEqual(f.exception(), None)
167n/a self.assertRaises(asyncio.InvalidStateError, f.set_result, None)
168n/a self.assertRaises(asyncio.InvalidStateError, f.set_exception, None)
169n/a self.assertFalse(f.cancel())
170n/a
171n/a def test_exception(self):
172n/a exc = RuntimeError()
173n/a f = self._new_future(loop=self.loop)
174n/a self.assertRaises(asyncio.InvalidStateError, f.exception)
175n/a
176n/a # StopIteration cannot be raised into a Future - CPython issue26221
177n/a self.assertRaisesRegex(TypeError, "StopIteration .* cannot be raised",
178n/a f.set_exception, StopIteration)
179n/a
180n/a f.set_exception(exc)
181n/a self.assertFalse(f.cancelled())
182n/a self.assertTrue(f.done())
183n/a self.assertRaises(RuntimeError, f.result)
184n/a self.assertEqual(f.exception(), exc)
185n/a self.assertRaises(asyncio.InvalidStateError, f.set_result, None)
186n/a self.assertRaises(asyncio.InvalidStateError, f.set_exception, None)
187n/a self.assertFalse(f.cancel())
188n/a
189n/a def test_exception_class(self):
190n/a f = self._new_future(loop=self.loop)
191n/a f.set_exception(RuntimeError)
192n/a self.assertIsInstance(f.exception(), RuntimeError)
193n/a
194n/a def test_yield_from_twice(self):
195n/a f = self._new_future(loop=self.loop)
196n/a
197n/a def fixture():
198n/a yield 'A'
199n/a x = yield from f
200n/a yield 'B', x
201n/a y = yield from f
202n/a yield 'C', y
203n/a
204n/a g = fixture()
205n/a self.assertEqual(next(g), 'A') # yield 'A'.
206n/a self.assertEqual(next(g), f) # First yield from f.
207n/a f.set_result(42)
208n/a self.assertEqual(next(g), ('B', 42)) # yield 'B', x.
209n/a # The second "yield from f" does not yield f.
210n/a self.assertEqual(next(g), ('C', 42)) # yield 'C', y.
211n/a
212n/a def test_future_repr(self):
213n/a self.loop.set_debug(True)
214n/a f_pending_debug = self._new_future(loop=self.loop)
215n/a frame = f_pending_debug._source_traceback[-1]
216n/a self.assertEqual(repr(f_pending_debug),
217n/a '<Future pending created at %s:%s>'
218n/a % (frame[0], frame[1]))
219n/a f_pending_debug.cancel()
220n/a
221n/a self.loop.set_debug(False)
222n/a f_pending = self._new_future(loop=self.loop)
223n/a self.assertEqual(repr(f_pending), '<Future pending>')
224n/a f_pending.cancel()
225n/a
226n/a f_cancelled = self._new_future(loop=self.loop)
227n/a f_cancelled.cancel()
228n/a self.assertEqual(repr(f_cancelled), '<Future cancelled>')
229n/a
230n/a f_result = self._new_future(loop=self.loop)
231n/a f_result.set_result(4)
232n/a self.assertEqual(repr(f_result), '<Future finished result=4>')
233n/a self.assertEqual(f_result.result(), 4)
234n/a
235n/a exc = RuntimeError()
236n/a f_exception = self._new_future(loop=self.loop)
237n/a f_exception.set_exception(exc)
238n/a self.assertEqual(repr(f_exception),
239n/a '<Future finished exception=RuntimeError()>')
240n/a self.assertIs(f_exception.exception(), exc)
241n/a
242n/a def func_repr(func):
243n/a filename, lineno = test_utils.get_function_source(func)
244n/a text = '%s() at %s:%s' % (func.__qualname__, filename, lineno)
245n/a return re.escape(text)
246n/a
247n/a f_one_callbacks = self._new_future(loop=self.loop)
248n/a f_one_callbacks.add_done_callback(_fakefunc)
249n/a fake_repr = func_repr(_fakefunc)
250n/a self.assertRegex(repr(f_one_callbacks),
251n/a r'<Future pending cb=\[%s\]>' % fake_repr)
252n/a f_one_callbacks.cancel()
253n/a self.assertEqual(repr(f_one_callbacks),
254n/a '<Future cancelled>')
255n/a
256n/a f_two_callbacks = self._new_future(loop=self.loop)
257n/a f_two_callbacks.add_done_callback(first_cb)
258n/a f_two_callbacks.add_done_callback(last_cb)
259n/a first_repr = func_repr(first_cb)
260n/a last_repr = func_repr(last_cb)
261n/a self.assertRegex(repr(f_two_callbacks),
262n/a r'<Future pending cb=\[%s, %s\]>'
263n/a % (first_repr, last_repr))
264n/a
265n/a f_many_callbacks = self._new_future(loop=self.loop)
266n/a f_many_callbacks.add_done_callback(first_cb)
267n/a for i in range(8):
268n/a f_many_callbacks.add_done_callback(_fakefunc)
269n/a f_many_callbacks.add_done_callback(last_cb)
270n/a cb_regex = r'%s, <8 more>, %s' % (first_repr, last_repr)
271n/a self.assertRegex(repr(f_many_callbacks),
272n/a r'<Future pending cb=\[%s\]>' % cb_regex)
273n/a f_many_callbacks.cancel()
274n/a self.assertEqual(repr(f_many_callbacks),
275n/a '<Future cancelled>')
276n/a
277n/a def test_copy_state(self):
278n/a from asyncio.futures import _copy_future_state
279n/a
280n/a f = self._new_future(loop=self.loop)
281n/a f.set_result(10)
282n/a
283n/a newf = self._new_future(loop=self.loop)
284n/a _copy_future_state(f, newf)
285n/a self.assertTrue(newf.done())
286n/a self.assertEqual(newf.result(), 10)
287n/a
288n/a f_exception = self._new_future(loop=self.loop)
289n/a f_exception.set_exception(RuntimeError())
290n/a
291n/a newf_exception = self._new_future(loop=self.loop)
292n/a _copy_future_state(f_exception, newf_exception)
293n/a self.assertTrue(newf_exception.done())
294n/a self.assertRaises(RuntimeError, newf_exception.result)
295n/a
296n/a f_cancelled = self._new_future(loop=self.loop)
297n/a f_cancelled.cancel()
298n/a
299n/a newf_cancelled = self._new_future(loop=self.loop)
300n/a _copy_future_state(f_cancelled, newf_cancelled)
301n/a self.assertTrue(newf_cancelled.cancelled())
302n/a
303n/a def test_iter(self):
304n/a fut = self._new_future(loop=self.loop)
305n/a
306n/a def coro():
307n/a yield from fut
308n/a
309n/a def test():
310n/a arg1, arg2 = coro()
311n/a
312n/a self.assertRaises(AssertionError, test)
313n/a fut.cancel()
314n/a
315n/a @mock.patch('asyncio.base_events.logger')
316n/a def test_tb_logger_abandoned(self, m_log):
317n/a fut = self._new_future(loop=self.loop)
318n/a del fut
319n/a self.assertFalse(m_log.error.called)
320n/a
321n/a @mock.patch('asyncio.base_events.logger')
322n/a def test_tb_logger_result_unretrieved(self, m_log):
323n/a fut = self._new_future(loop=self.loop)
324n/a fut.set_result(42)
325n/a del fut
326n/a self.assertFalse(m_log.error.called)
327n/a
328n/a @mock.patch('asyncio.base_events.logger')
329n/a def test_tb_logger_result_retrieved(self, m_log):
330n/a fut = self._new_future(loop=self.loop)
331n/a fut.set_result(42)
332n/a fut.result()
333n/a del fut
334n/a self.assertFalse(m_log.error.called)
335n/a
336n/a @mock.patch('asyncio.base_events.logger')
337n/a def test_tb_logger_exception_unretrieved(self, m_log):
338n/a fut = self._new_future(loop=self.loop)
339n/a fut.set_exception(RuntimeError('boom'))
340n/a del fut
341n/a test_utils.run_briefly(self.loop)
342n/a support.gc_collect()
343n/a self.assertTrue(m_log.error.called)
344n/a
345n/a @mock.patch('asyncio.base_events.logger')
346n/a def test_tb_logger_exception_retrieved(self, m_log):
347n/a fut = self._new_future(loop=self.loop)
348n/a fut.set_exception(RuntimeError('boom'))
349n/a fut.exception()
350n/a del fut
351n/a self.assertFalse(m_log.error.called)
352n/a
353n/a @mock.patch('asyncio.base_events.logger')
354n/a def test_tb_logger_exception_result_retrieved(self, m_log):
355n/a fut = self._new_future(loop=self.loop)
356n/a fut.set_exception(RuntimeError('boom'))
357n/a self.assertRaises(RuntimeError, fut.result)
358n/a del fut
359n/a self.assertFalse(m_log.error.called)
360n/a
361n/a def test_wrap_future(self):
362n/a
363n/a def run(arg):
364n/a return (arg, threading.get_ident())
365n/a ex = concurrent.futures.ThreadPoolExecutor(1)
366n/a f1 = ex.submit(run, 'oi')
367n/a f2 = asyncio.wrap_future(f1, loop=self.loop)
368n/a res, ident = self.loop.run_until_complete(f2)
369n/a self.assertTrue(asyncio.isfuture(f2))
370n/a self.assertEqual(res, 'oi')
371n/a self.assertNotEqual(ident, threading.get_ident())
372n/a
373n/a def test_wrap_future_future(self):
374n/a f1 = self._new_future(loop=self.loop)
375n/a f2 = asyncio.wrap_future(f1)
376n/a self.assertIs(f1, f2)
377n/a
378n/a def test_wrap_future_use_global_loop(self):
379n/a with mock.patch('asyncio.futures.events') as events:
380n/a events.get_event_loop = lambda: self.loop
381n/a def run(arg):
382n/a return (arg, threading.get_ident())
383n/a ex = concurrent.futures.ThreadPoolExecutor(1)
384n/a f1 = ex.submit(run, 'oi')
385n/a f2 = asyncio.wrap_future(f1)
386n/a self.assertIs(self.loop, f2._loop)
387n/a
388n/a def test_wrap_future_cancel(self):
389n/a f1 = concurrent.futures.Future()
390n/a f2 = asyncio.wrap_future(f1, loop=self.loop)
391n/a f2.cancel()
392n/a test_utils.run_briefly(self.loop)
393n/a self.assertTrue(f1.cancelled())
394n/a self.assertTrue(f2.cancelled())
395n/a
396n/a def test_wrap_future_cancel2(self):
397n/a f1 = concurrent.futures.Future()
398n/a f2 = asyncio.wrap_future(f1, loop=self.loop)
399n/a f1.set_result(42)
400n/a f2.cancel()
401n/a test_utils.run_briefly(self.loop)
402n/a self.assertFalse(f1.cancelled())
403n/a self.assertEqual(f1.result(), 42)
404n/a self.assertTrue(f2.cancelled())
405n/a
406n/a def test_future_source_traceback(self):
407n/a self.loop.set_debug(True)
408n/a
409n/a future = self._new_future(loop=self.loop)
410n/a lineno = sys._getframe().f_lineno - 1
411n/a self.assertIsInstance(future._source_traceback, list)
412n/a self.assertEqual(future._source_traceback[-2][:3],
413n/a (__file__,
414n/a lineno,
415n/a 'test_future_source_traceback'))
416n/a
417n/a @mock.patch('asyncio.base_events.logger')
418n/a def check_future_exception_never_retrieved(self, debug, m_log):
419n/a self.loop.set_debug(debug)
420n/a
421n/a def memory_error():
422n/a try:
423n/a raise MemoryError()
424n/a except BaseException as exc:
425n/a return exc
426n/a exc = memory_error()
427n/a
428n/a future = self._new_future(loop=self.loop)
429n/a future.set_exception(exc)
430n/a future = None
431n/a test_utils.run_briefly(self.loop)
432n/a support.gc_collect()
433n/a
434n/a if sys.version_info >= (3, 4):
435n/a regex = r'^Future exception was never retrieved\n'
436n/a exc_info = (type(exc), exc, exc.__traceback__)
437n/a m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info)
438n/a else:
439n/a regex = r'^Future/Task exception was never retrieved\n'
440n/a m_log.error.assert_called_once_with(mock.ANY, exc_info=False)
441n/a message = m_log.error.call_args[0][0]
442n/a self.assertRegex(message, re.compile(regex, re.DOTALL))
443n/a
444n/a def test_future_exception_never_retrieved(self):
445n/a self.check_future_exception_never_retrieved(False)
446n/a
447n/a def test_future_exception_never_retrieved_debug(self):
448n/a self.check_future_exception_never_retrieved(True)
449n/a
450n/a def test_set_result_unless_cancelled(self):
451n/a fut = self._new_future(loop=self.loop)
452n/a fut.cancel()
453n/a futures._set_result_unless_cancelled(fut, 2)
454n/a self.assertTrue(fut.cancelled())
455n/a
456n/a def test_future_stop_iteration_args(self):
457n/a fut = self._new_future(loop=self.loop)
458n/a fut.set_result((1, 2))
459n/a fi = fut.__iter__()
460n/a result = None
461n/a try:
462n/a fi.send(None)
463n/a except StopIteration as ex:
464n/a result = ex.args[0]
465n/a else:
466n/a self.fail('StopIteration was expected')
467n/a self.assertEqual(result, (1, 2))
468n/a
469n/a def test_future_iter_throw(self):
470n/a fut = self._new_future(loop=self.loop)
471n/a fi = iter(fut)
472n/a self.assertRaises(TypeError, fi.throw,
473n/a Exception, Exception("elephant"), 32)
474n/a self.assertRaises(TypeError, fi.throw,
475n/a Exception("elephant"), Exception("elephant"))
476n/a self.assertRaises(TypeError, fi.throw, list)
477n/a
478n/a
479n/a@unittest.skipUnless(hasattr(futures, '_CFuture'),
480n/a 'requires the C _asyncio module')
481n/aclass CFutureTests(BaseFutureTests, test_utils.TestCase):
482n/a
483n/a def _new_future(self, *args, **kwargs):
484n/a return futures._CFuture(*args, **kwargs)
485n/a
486n/a
487n/aclass PyFutureTests(BaseFutureTests, test_utils.TestCase):
488n/a
489n/a def _new_future(self, *args, **kwargs):
490n/a return futures._PyFuture(*args, **kwargs)
491n/a
492n/a
493n/aclass BaseFutureDoneCallbackTests():
494n/a
495n/a def setUp(self):
496n/a super().setUp()
497n/a self.loop = self.new_test_loop()
498n/a
499n/a def run_briefly(self):
500n/a test_utils.run_briefly(self.loop)
501n/a
502n/a def _make_callback(self, bag, thing):
503n/a # Create a callback function that appends thing to bag.
504n/a def bag_appender(future):
505n/a bag.append(thing)
506n/a return bag_appender
507n/a
508n/a def _new_future(self):
509n/a raise NotImplementedError
510n/a
511n/a def test_callbacks_invoked_on_set_result(self):
512n/a bag = []
513n/a f = self._new_future()
514n/a f.add_done_callback(self._make_callback(bag, 42))
515n/a f.add_done_callback(self._make_callback(bag, 17))
516n/a
517n/a self.assertEqual(bag, [])
518n/a f.set_result('foo')
519n/a
520n/a self.run_briefly()
521n/a
522n/a self.assertEqual(bag, [42, 17])
523n/a self.assertEqual(f.result(), 'foo')
524n/a
525n/a def test_callbacks_invoked_on_set_exception(self):
526n/a bag = []
527n/a f = self._new_future()
528n/a f.add_done_callback(self._make_callback(bag, 100))
529n/a
530n/a self.assertEqual(bag, [])
531n/a exc = RuntimeError()
532n/a f.set_exception(exc)
533n/a
534n/a self.run_briefly()
535n/a
536n/a self.assertEqual(bag, [100])
537n/a self.assertEqual(f.exception(), exc)
538n/a
539n/a def test_remove_done_callback(self):
540n/a bag = []
541n/a f = self._new_future()
542n/a cb1 = self._make_callback(bag, 1)
543n/a cb2 = self._make_callback(bag, 2)
544n/a cb3 = self._make_callback(bag, 3)
545n/a
546n/a # Add one cb1 and one cb2.
547n/a f.add_done_callback(cb1)
548n/a f.add_done_callback(cb2)
549n/a
550n/a # One instance of cb2 removed. Now there's only one cb1.
551n/a self.assertEqual(f.remove_done_callback(cb2), 1)
552n/a
553n/a # Never had any cb3 in there.
554n/a self.assertEqual(f.remove_done_callback(cb3), 0)
555n/a
556n/a # After this there will be 6 instances of cb1 and one of cb2.
557n/a f.add_done_callback(cb2)
558n/a for i in range(5):
559n/a f.add_done_callback(cb1)
560n/a
561n/a # Remove all instances of cb1. One cb2 remains.
562n/a self.assertEqual(f.remove_done_callback(cb1), 6)
563n/a
564n/a self.assertEqual(bag, [])
565n/a f.set_result('foo')
566n/a
567n/a self.run_briefly()
568n/a
569n/a self.assertEqual(bag, [2])
570n/a self.assertEqual(f.result(), 'foo')
571n/a
572n/a
573n/a@unittest.skipUnless(hasattr(futures, '_CFuture'),
574n/a 'requires the C _asyncio module')
575n/aclass CFutureDoneCallbackTests(BaseFutureDoneCallbackTests,
576n/a test_utils.TestCase):
577n/a
578n/a def _new_future(self):
579n/a return futures._CFuture(loop=self.loop)
580n/a
581n/a
582n/aclass PyFutureDoneCallbackTests(BaseFutureDoneCallbackTests,
583n/a test_utils.TestCase):
584n/a
585n/a def _new_future(self):
586n/a return futures._PyFuture(loop=self.loop)
587n/a
588n/a
589n/aif __name__ == '__main__':
590n/a unittest.main()