Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#11694 asyncioreactor state leak #11695

Merged
merged 6 commits into from Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 35 additions & 2 deletions src/twisted/internet/test/reactormixins.py
Expand Up @@ -18,7 +18,7 @@
import os
import signal
import time
from typing import Dict, Optional, Sequence, Type, Union
from typing import TYPE_CHECKING, Dict, Optional, Sequence, Type, Union

from zope.interface import Interface

Expand All @@ -30,6 +30,11 @@
from twisted.trial.unittest import SkipTest, SynchronousTestCase
from twisted.trial.util import DEFAULT_TIMEOUT_DURATION, acquireAttribute

if TYPE_CHECKING:
# Only bring in this name to support the type annotation below. We don't
# really want to import a reactor module this early at runtime.
from twisted.internet import asyncioreactor

# Access private APIs.
try:
from twisted.internet import process as _process
Expand Down Expand Up @@ -153,7 +158,7 @@ class ReactorBuilder:
]
)

_reactors.append("twisted.internet.asyncioreactor.AsyncioSelectorReactor")
_reactors.append("twisted.internet.test.reactormixins.AsyncioSelectorReactor")

if platform.isMacOSX():
_reactors.append("twisted.internet.cfreactor.CFReactor")
Expand Down Expand Up @@ -366,3 +371,31 @@ class testcase(cls, SynchronousTestCase): # type: ignore[valid-type,misc]
testcase.__qualname__ = ".".join(cls.__qualname__.split()[0:-1] + [name])
classes[testcase.__name__] = testcase
return classes


def asyncioSelectorReactor(self: object) -> "asyncioreactor.AsyncioSelectorReactor":
"""
Make a new asyncio reactor associated with a new event loop.

The test suite prefers this constructor because having a new event loop
for each reactor provides better test isolation. The real constructor
prefers to re-use (or create) a global loop because of how this interacts
with other asyncio-based libraries and applications (though maybe it
shouldn't).

@param self: The L{ReactorBuilder} subclass this is being called on. We
don't use this parameter but we get called with it anyway.
"""
from asyncio import new_event_loop, set_event_loop

from twisted.internet import asyncioreactor

loop = new_event_loop()
set_event_loop(loop)

return asyncioreactor.AsyncioSelectorReactor(loop)


# Give it an alias that makes the names of the generated test classes fit the
# pattern.
AsyncioSelectorReactor = asyncioSelectorReactor
16 changes: 2 additions & 14 deletions src/twisted/internet/test/test_threads.py
Expand Up @@ -172,20 +172,8 @@ def test_cleanUpThreadPoolEvenBeforeReactorIsRun(self):
reactor = self.buildReactor()
threadPoolRef = ref(reactor.getThreadPool())
reactor.fireSystemEvent("shutdown")

if reactor.__class__.__name__ == "AsyncioSelectorReactor":
self.assertIsNone(reactor.threadpool)
# ReactorBase.__init__ sets self.crash as a 'shutdown'
# event, which in turn calls stop on the underlying
# asyncio event loop, which in turn sets a _stopping
# attribute on it that's only unset after an iteration of
# the loop. Subsequent tests can only reuse the asyncio
# loop if it's allowed to run and unset that _stopping
# attribute.
self.runReactor(reactor)
else:
gc.collect()
self.assertIsNone(threadPoolRef())
gc.collect()
self.assertIsNone(threadPoolRef())

def test_isInIOThread(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion src/twisted/internet/test/test_time.py
Expand Up @@ -43,7 +43,7 @@ def eventSource(reactor, event):

else:
raise SkipTest(
"Do not know how to synthesize non-time event to " "stop the test"
"Do not know how to synthesize non-time event to stop the test"
)

# Pick a pretty big delay.
Expand Down
Empty file.