%PDF- %PDF-
Direktori : /lib/python3/dist-packages/twisted/internet/test/ |
Current File : //lib/python3/dist-packages/twisted/internet/test/test_asyncioreactor.py |
# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Tests for L{twisted.internet.asyncioreactor}. """ import gc import sys from asyncio import ( AbstractEventLoop, AbstractEventLoopPolicy, DefaultEventLoopPolicy, Future, SelectorEventLoop, get_event_loop, get_event_loop_policy, set_event_loop, set_event_loop_policy, ) from unittest import skipIf from twisted.internet.asyncioreactor import AsyncioSelectorReactor from twisted.python.runtime import platform from twisted.trial.unittest import SynchronousTestCase from .reactormixins import ReactorBuilder hasWindowsProactorEventLoopPolicy = False hasWindowsSelectorEventLoopPolicy = False try: if sys.platform.startswith("win32"): from asyncio import ( WindowsProactorEventLoopPolicy, WindowsSelectorEventLoopPolicy, ) hasWindowsProactorEventLoopPolicy = True hasWindowsSelectorEventLoopPolicy = True except ImportError: pass _defaultEventLoop = DefaultEventLoopPolicy().new_event_loop() _defaultEventLoopIsSelector = isinstance(_defaultEventLoop, SelectorEventLoop) _defaultEventLoop.close() class AsyncioSelectorReactorTests(ReactorBuilder, SynchronousTestCase): """ L{AsyncioSelectorReactor} tests. """ def assertReactorWorksWithAsyncioFuture(self, reactor): """ Ensure that C{reactor} has an event loop that works properly with L{asyncio.Future}. """ future = Future() result = [] def completed(future): result.append(future.result()) reactor.stop() future.add_done_callback(completed) future.set_result(True) self.assertEqual(result, []) self.runReactor(reactor, timeout=1) self.assertEqual(result, [True]) def newLoop(self, policy: AbstractEventLoopPolicy) -> AbstractEventLoop: """ Make a new asyncio loop from a policy for use with a reactor, and add appropriate cleanup to restore any global state. """ existingLoop = get_event_loop() existingPolicy = get_event_loop_policy() result = policy.new_event_loop() @self.addCleanup def cleanUp(): result.close() set_event_loop(existingLoop) set_event_loop_policy(existingPolicy) return result @skipIf( not _defaultEventLoopIsSelector, "default event loop: {}\nis not of type SelectorEventLoop " "on Python {}.{} ({})".format( type(_defaultEventLoop), sys.version_info.major, sys.version_info.minor, platform.getType(), ), ) def test_defaultSelectorEventLoopFromGlobalPolicy(self): """ L{AsyncioSelectorReactor} wraps the global policy's event loop by default. This ensures that L{asyncio.Future}s and coroutines created by library code that uses L{asyncio.get_event_loop} are bound to the same loop. """ reactor = AsyncioSelectorReactor() self.assertReactorWorksWithAsyncioFuture(reactor) @skipIf( not _defaultEventLoopIsSelector, "default event loop: {}\nis not of type SelectorEventLoop " "on Python {}.{} ({})".format( type(_defaultEventLoop), sys.version_info.major, sys.version_info.minor, platform.getType(), ), ) def test_newSelectorEventLoopFromDefaultEventLoopPolicy(self): """ If we use the L{asyncio.DefaultLoopPolicy} to create a new event loop, and then pass that event loop to a new L{AsyncioSelectorReactor}, this reactor should work properly with L{asyncio.Future}. """ event_loop = self.newLoop(DefaultEventLoopPolicy()) reactor = AsyncioSelectorReactor(event_loop) set_event_loop(event_loop) self.assertReactorWorksWithAsyncioFuture(reactor) @skipIf( _defaultEventLoopIsSelector, "default event loop: {}\nis of type SelectorEventLoop " "on Python {}.{} ({})".format( type(_defaultEventLoop), sys.version_info.major, sys.version_info.minor, platform.getType(), ), ) def test_defaultNotASelectorEventLoopFromGlobalPolicy(self): """ On Windows Python 3.5 to 3.7, L{get_event_loop()} returns a L{WindowsSelectorEventLoop} by default. On Windows Python 3.8+, L{get_event_loop()} returns a L{WindowsProactorEventLoop} by default. L{AsyncioSelectorReactor} should raise a L{TypeError} if the default event loop is not a L{WindowsSelectorEventLoop}. """ self.assertRaises(TypeError, AsyncioSelectorReactor) @skipIf( not hasWindowsProactorEventLoopPolicy, "WindowsProactorEventLoop not available" ) def test_WindowsProactorEventLoop(self): """ L{AsyncioSelectorReactor} will raise a L{TypeError} if instantiated with a L{asyncio.WindowsProactorEventLoop} """ event_loop = self.newLoop(WindowsProactorEventLoopPolicy()) self.assertRaises(TypeError, AsyncioSelectorReactor, event_loop) @skipIf( not hasWindowsSelectorEventLoopPolicy, "WindowsSelectorEventLoop only on Windows", ) def test_WindowsSelectorEventLoop(self): """ L{WindowsSelectorEventLoop} works with L{AsyncioSelectorReactor} """ event_loop = self.newLoop(WindowsSelectorEventLoopPolicy()) reactor = AsyncioSelectorReactor(event_loop) set_event_loop(event_loop) self.assertReactorWorksWithAsyncioFuture(reactor) @skipIf( not hasWindowsProactorEventLoopPolicy, "WindowsProactorEventLoopPolicy only on Windows", ) def test_WindowsProactorEventLoopPolicy(self): """ L{AsyncioSelectorReactor} will raise a L{TypeError} if L{asyncio.WindowsProactorEventLoopPolicy} is default. """ set_event_loop_policy(WindowsProactorEventLoopPolicy()) self.addCleanup(lambda: set_event_loop_policy(None)) with self.assertRaises(TypeError): AsyncioSelectorReactor() @skipIf( not hasWindowsSelectorEventLoopPolicy, "WindowsSelectorEventLoopPolicy only on Windows", ) def test_WindowsSelectorEventLoopPolicy(self): """ L{AsyncioSelectorReactor} will work if if L{asyncio.WindowsSelectorEventLoopPolicy} is default. """ set_event_loop_policy(WindowsSelectorEventLoopPolicy()) self.addCleanup(lambda: set_event_loop_policy(None)) reactor = AsyncioSelectorReactor() self.assertReactorWorksWithAsyncioFuture(reactor) def test_seconds(self): """L{seconds} should return a plausible epoch time.""" if hasWindowsSelectorEventLoopPolicy: set_event_loop_policy(WindowsSelectorEventLoopPolicy()) self.addCleanup(lambda: set_event_loop_policy(None)) reactor = AsyncioSelectorReactor() result = reactor.seconds() # greater than 2020-01-01 self.assertGreater(result, 1577836800) # less than 2120-01-01 self.assertLess(result, 4733510400) def test_delayedCallResetToLater(self): """ L{DelayedCall.reset()} properly reschedules timer to later time """ if hasWindowsSelectorEventLoopPolicy: set_event_loop_policy(WindowsSelectorEventLoopPolicy()) self.addCleanup(lambda: set_event_loop_policy(None)) reactor = AsyncioSelectorReactor() timer_called_at = [None] def on_timer(): timer_called_at[0] = reactor.seconds() start_time = reactor.seconds() dc = reactor.callLater(0, on_timer) dc.reset(0.5) reactor.callLater(1, reactor.stop) reactor.run() self.assertIsNotNone(timer_called_at[0]) self.assertGreater(timer_called_at[0] - start_time, 0.4) def test_delayedCallResetToEarlier(self): """ L{DelayedCall.reset()} properly reschedules timer to earlier time """ if hasWindowsSelectorEventLoopPolicy: set_event_loop_policy(WindowsSelectorEventLoopPolicy()) reactor = AsyncioSelectorReactor() timer_called_at = [None] def on_timer(): timer_called_at[0] = reactor.seconds() start_time = reactor.seconds() dc = reactor.callLater(0.5, on_timer) dc.reset(0) reactor.callLater(1, reactor.stop) import io from contextlib import redirect_stderr stderr = io.StringIO() with redirect_stderr(stderr): reactor.run() self.assertEqual(stderr.getvalue(), "") self.assertIsNotNone(timer_called_at[0]) self.assertLess(timer_called_at[0] - start_time, 0.4) if hasWindowsSelectorEventLoopPolicy: set_event_loop_policy(None) def test_noCycleReferencesInCallLater(self): """ L{AsyncioSelectorReactor.callLater()} doesn't leave cyclic references """ if hasWindowsSelectorEventLoopPolicy: set_event_loop_policy(WindowsSelectorEventLoopPolicy()) gc_was_enabled = gc.isenabled() gc.disable() try: objects_before = len(gc.get_objects()) timer_count = 1000 reactor = AsyncioSelectorReactor() for _ in range(timer_count): reactor.callLater(0, lambda: None) reactor.runUntilCurrent() objects_after = len(gc.get_objects()) self.assertLess((objects_after - objects_before) / timer_count, 1) finally: if gc_was_enabled: gc.enable() if hasWindowsSelectorEventLoopPolicy: set_event_loop_policy(None)