summaryrefslogtreecommitdiffstats
path: root/contrib/python/Twisted/py3/twisted/internet/testing.py
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-06-22 18:50:56 +0300
committerrobot-piglet <[email protected]>2025-06-22 19:04:42 +0300
commitc7cbc6d480c5488ff6e921c709680fd2c1340a10 (patch)
tree10843f44b67c0fb5717ad555556064095f701d8c /contrib/python/Twisted/py3/twisted/internet/testing.py
parent26d391cdb94d2ce5efc8d0cc5cea7607dc363c0b (diff)
Intermediate changes
commit_hash:28750b74281710ec1ab5bdc2403c8ab24bdd164b
Diffstat (limited to 'contrib/python/Twisted/py3/twisted/internet/testing.py')
-rw-r--r--contrib/python/Twisted/py3/twisted/internet/testing.py125
1 files changed, 109 insertions, 16 deletions
diff --git a/contrib/python/Twisted/py3/twisted/internet/testing.py b/contrib/python/Twisted/py3/twisted/internet/testing.py
index 6563184edf9..a7e1de67286 100644
--- a/contrib/python/Twisted/py3/twisted/internet/testing.py
+++ b/contrib/python/Twisted/py3/twisted/internet/testing.py
@@ -7,6 +7,8 @@ Assorted functionality which is commonly useful when writing unit tests.
"""
from __future__ import annotations
+import typing
+from dataclasses import dataclass
from io import BytesIO
from socket import AF_INET, AF_INET6
from time import time
@@ -33,17 +35,22 @@ from twisted.internet.address import IPv4Address, IPv6Address, UNIXAddress
from twisted.internet.defer import Deferred, ensureDeferred, succeed
from twisted.internet.error import UnsupportedAddressFamily
from twisted.internet.interfaces import (
+ IAddress,
IConnector,
IConsumer,
+ IHostnameResolver,
+ IHostResolution,
IListeningPort,
IProtocol,
IPushProducer,
IReactorCore,
IReactorFDSet,
+ IReactorPluggableNameResolver,
IReactorSocket,
IReactorSSL,
IReactorTCP,
IReactorUNIX,
+ IResolutionReceiver,
ITransport,
)
from twisted.internet.task import Clock
@@ -72,6 +79,14 @@ __all__ = [
_P = ParamSpec("_P")
+class _ProtocolConnectionMadeHaver(typing.Protocol):
+ """
+ Explicit stipulation of the implicit requirement of L{AccumulatingProtocol}'s factory.
+ """
+
+ protocolConnectionMade: Deferred[AccumulatingProtocol] | None
+
+
class AccumulatingProtocol(protocol.Protocol):
"""
L{AccumulatingProtocol} is an L{IProtocol} implementation which collects
@@ -87,26 +102,29 @@ class AccumulatingProtocol(protocol.Protocol):
C{connectionLost} is called.
"""
+ made: int
+ closed: int
made = closed = 0
- closedReason = None
-
- closedDeferred = None
+ closedReason: failure.Failure | None = None
+ closedDeferred: Deferred[None] | None = None
+ data: bytes = b""
- data = b""
+ factory: protocol.Factory | None = None
- factory = None
-
- def connectionMade(self):
+ def connectionMade(self) -> None:
self.made = 1
- if self.factory is not None and self.factory.protocolConnectionMade is not None:
- d = self.factory.protocolConnectionMade
- self.factory.protocolConnectionMade = None
+ factory: _ProtocolConnectionMadeHaver | None = (
+ self.factory # type:ignore[assignment]
+ )
+ if factory is not None and factory.protocolConnectionMade is not None:
+ d = factory.protocolConnectionMade
+ factory.protocolConnectionMade = None
d.callback(self)
- def dataReceived(self, data):
+ def dataReceived(self, data: bytes) -> None:
self.data += data
- def connectionLost(self, reason):
+ def connectionLost(self, reason: failure.Failure | None = None) -> None:
self.closed = 1
self.closedReason = reason
if self.closedDeferred is not None:
@@ -414,8 +432,54 @@ class _FakeConnector:
return self._address
+@implementer(IHostResolution)
+@dataclass
+class _SynchronousResolution:
+ name: str
+
+ def cancel(self) -> None:
+ """
+ Provided just for interface compliance; it should be impossible to
+ reach here, since it's resolved synchronously.
+ """
+ raise Exception("already resolved") # pragma: no cover
+
+
+@implementer(IHostnameResolver)
+class SynchronousResolver:
+ """
+ A very simple L{IHostnameResolver} that immediately, synchronously resolves
+ all host names to a single static address (TCPv4, 127.0.0.1) while
+ preserving any requested port number.
+ """
+
+ def resolveHostName(
+ self,
+ resolutionReceiver: IResolutionReceiver,
+ hostName: str,
+ portNumber: int = 0,
+ addressTypes: Sequence[type[IAddress]] | None = None,
+ transportSemantics: str = "TCP",
+ ) -> IHostResolution:
+ """
+ Implement L{IHostnameResolver.resolveHostName} to synchronously resolve
+ the name and complete resolution before returning.
+ """
+ resolution = _SynchronousResolution(hostName)
+ resolutionReceiver.resolutionBegan(resolution)
+ resolutionReceiver.addressResolved(IPv4Address("TCP", "127.0.0.1", portNumber))
+ resolutionReceiver.resolutionComplete()
+ return resolution
+
+
@implementer(
- IReactorCore, IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket, IReactorFDSet
+ IReactorCore,
+ IReactorTCP,
+ IReactorSSL,
+ IReactorUNIX,
+ IReactorSocket,
+ IReactorFDSet,
+ IReactorPluggableNameResolver,
)
class MemoryReactor:
"""
@@ -474,6 +538,8 @@ class MemoryReactor:
connections added using C{adoptStreamConnection}.
"""
+ nameResolver: IHostnameResolver
+
def __init__(self):
"""
Initialize the tracking lists.
@@ -500,6 +566,15 @@ class MemoryReactor:
self.readers = set()
self.writers = set()
+ self.nameResolver = SynchronousResolver()
+
+ def installNameResolver(self, resolver: IHostnameResolver) -> IHostnameResolver:
+ """
+ Implement L{IReactorPluggableNameResolver}.
+ """
+ oldResolver = self.nameResolver
+ self.nameResolver = resolver
+ return oldResolver
def install(self):
"""
@@ -761,7 +836,13 @@ class MemoryReactorClock(MemoryReactor, Clock):
Clock.__init__(self)
-@implementer(IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket)
+@implementer(
+ IReactorTCP,
+ IReactorSSL,
+ IReactorUNIX,
+ IReactorSocket,
+ IReactorPluggableNameResolver,
+)
class RaisingMemoryReactor:
"""
A fake reactor to be used in tests. It accepts TCP connection setup
@@ -771,7 +852,11 @@ class RaisingMemoryReactor:
@ivar _connectException: An instance of an L{Exception}
"""
- def __init__(self, listenException=None, connectException=None):
+ def __init__(
+ self,
+ listenException: Exception | None = None,
+ connectException: Exception | None = None,
+ ) -> None:
"""
@param listenException: An instance of an L{Exception} to raise
when any C{listen} method is called.
@@ -781,6 +866,14 @@ class RaisingMemoryReactor:
"""
self._listenException = listenException
self._connectException = connectException
+ self.nameResolver: IHostnameResolver = SynchronousResolver()
+
+ def installNameResolver(self, nameResolver: IHostnameResolver) -> IHostnameResolver:
+ """
+ Implement L{IReactorPluggableNameResolver}.
+ """
+ previous, self.nameResolver = self.nameResolver, nameResolver
+ return previous
def adoptStreamPort(self, fileno, addressFamily, factory):
"""
@@ -991,7 +1084,7 @@ def _benchmarkWithReactor(
Generator[Deferred[Any], Any, _T],
Deferred[_T],
],
- ]
+ ],
) -> Callable[[Any], None]: # pragma: no cover
"""
Decorator for running a benchmark tests that loops the reactor.