1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
-
- """
- Tests for L{twisted.application} and its interaction with
- L{twisted.persisted.sob}.
- """
-
-
- import copy
- import os
- import pickle
- from io import StringIO
-
- try:
- import asyncio
- except ImportError:
- asyncio = None # type: ignore[assignment]
-
- from unittest import skipIf
-
- from twisted.application import app, internet, reactors, service
- from twisted.application.internet import backoffPolicy
- from twisted.internet import defer, interfaces, protocol, reactor
- from twisted.persisted import sob
- from twisted.plugins import twisted_reactors
- from twisted.protocols import basic, wire
- from twisted.python import usage
- from twisted.python.runtime import platformType
- from twisted.python.test.modules_helpers import TwistedModulesMixin
- from twisted.test.proto_helpers import MemoryReactor
- from twisted.trial.unittest import SkipTest, TestCase
-
-
- class Dummy:
- processName = None
-
-
- class ServiceTests(TestCase):
- def testName(self):
- s = service.Service()
- s.setName("hello")
- self.assertEqual(s.name, "hello")
-
- def testParent(self):
- s = service.Service()
- p = service.MultiService()
- s.setServiceParent(p)
- self.assertEqual(list(p), [s])
- self.assertEqual(s.parent, p)
-
- def testApplicationAsParent(self):
- s = service.Service()
- p = service.Application("")
- s.setServiceParent(p)
- self.assertEqual(list(service.IServiceCollection(p)), [s])
- self.assertEqual(s.parent, service.IServiceCollection(p))
-
- def testNamedChild(self):
- s = service.Service()
- p = service.MultiService()
- s.setName("hello")
- s.setServiceParent(p)
- self.assertEqual(list(p), [s])
- self.assertEqual(s.parent, p)
- self.assertEqual(p.getServiceNamed("hello"), s)
-
- def testDoublyNamedChild(self):
- s = service.Service()
- p = service.MultiService()
- s.setName("hello")
- s.setServiceParent(p)
- self.assertRaises(RuntimeError, s.setName, "lala")
-
- def testDuplicateNamedChild(self):
- s = service.Service()
- p = service.MultiService()
- s.setName("hello")
- s.setServiceParent(p)
- s = service.Service()
- s.setName("hello")
- self.assertRaises(RuntimeError, s.setServiceParent, p)
-
- def testDisowning(self):
- s = service.Service()
- p = service.MultiService()
- s.setServiceParent(p)
- self.assertEqual(list(p), [s])
- self.assertEqual(s.parent, p)
- s.disownServiceParent()
- self.assertEqual(list(p), [])
- self.assertIsNone(s.parent)
-
- def testRunning(self):
- s = service.Service()
- self.assertFalse(s.running)
- s.startService()
- self.assertTrue(s.running)
- s.stopService()
- self.assertFalse(s.running)
-
- def testRunningChildren1(self):
- s = service.Service()
- p = service.MultiService()
- s.setServiceParent(p)
- self.assertFalse(s.running)
- self.assertFalse(p.running)
- p.startService()
- self.assertTrue(s.running)
- self.assertTrue(p.running)
- p.stopService()
- self.assertFalse(s.running)
- self.assertFalse(p.running)
-
- def testRunningChildren2(self):
- s = service.Service()
-
- def checkRunning():
- self.assertTrue(s.running)
-
- t = service.Service()
- t.stopService = checkRunning
- t.startService = checkRunning
- p = service.MultiService()
- s.setServiceParent(p)
- t.setServiceParent(p)
- p.startService()
- p.stopService()
-
- def testAddingIntoRunning(self):
- p = service.MultiService()
- p.startService()
- s = service.Service()
- self.assertFalse(s.running)
- s.setServiceParent(p)
- self.assertTrue(s.running)
- s.disownServiceParent()
- self.assertFalse(s.running)
-
- def testPrivileged(self):
- s = service.Service()
-
- def pss():
- s.privilegedStarted = 1
-
- s.privilegedStartService = pss
- s1 = service.Service()
- p = service.MultiService()
- s.setServiceParent(p)
- s1.setServiceParent(p)
- p.privilegedStartService()
- self.assertTrue(s.privilegedStarted)
-
- def testCopying(self):
- s = service.Service()
- s.startService()
- s1 = copy.copy(s)
- self.assertFalse(s1.running)
- self.assertTrue(s.running)
-
-
- if hasattr(os, "getuid"):
- curuid = os.getuid()
- curgid = os.getgid()
- else:
- curuid = curgid = 0
-
-
- class ProcessTests(TestCase):
- def testID(self):
- p = service.Process(5, 6)
- self.assertEqual(p.uid, 5)
- self.assertEqual(p.gid, 6)
-
- def testDefaults(self):
- p = service.Process(5)
- self.assertEqual(p.uid, 5)
- self.assertIsNone(p.gid)
- p = service.Process(gid=5)
- self.assertIsNone(p.uid)
- self.assertEqual(p.gid, 5)
- p = service.Process()
- self.assertIsNone(p.uid)
- self.assertIsNone(p.gid)
-
- def testProcessName(self):
- p = service.Process()
- self.assertIsNone(p.processName)
- p.processName = "hello"
- self.assertEqual(p.processName, "hello")
-
-
- class InterfacesTests(TestCase):
- def testService(self):
- self.assertTrue(service.IService.providedBy(service.Service()))
-
- def testMultiService(self):
- self.assertTrue(service.IService.providedBy(service.MultiService()))
- self.assertTrue(service.IServiceCollection.providedBy(service.MultiService()))
-
- def testProcess(self):
- self.assertTrue(service.IProcess.providedBy(service.Process()))
-
-
- class ApplicationTests(TestCase):
- def testConstructor(self):
- service.Application("hello")
- service.Application("hello", 5)
- service.Application("hello", 5, 6)
-
- def testProcessComponent(self):
- a = service.Application("hello")
- self.assertIsNone(service.IProcess(a).uid)
- self.assertIsNone(service.IProcess(a).gid)
- a = service.Application("hello", 5)
- self.assertEqual(service.IProcess(a).uid, 5)
- self.assertIsNone(service.IProcess(a).gid)
- a = service.Application("hello", 5, 6)
- self.assertEqual(service.IProcess(a).uid, 5)
- self.assertEqual(service.IProcess(a).gid, 6)
-
- def testServiceComponent(self):
- a = service.Application("hello")
- self.assertIs(service.IService(a), service.IServiceCollection(a))
- self.assertEqual(service.IService(a).name, "hello")
- self.assertIsNone(service.IService(a).parent)
-
- def testPersistableComponent(self):
- a = service.Application("hello")
- p = sob.IPersistable(a)
- self.assertEqual(p.style, "pickle")
- self.assertEqual(p.name, "hello")
- self.assertIs(p.original, a)
-
-
- class LoadingTests(TestCase):
- def test_simpleStoreAndLoad(self):
- a = service.Application("hello")
- p = sob.IPersistable(a)
- for style in "source pickle".split():
- p.setStyle(style)
- p.save()
- a1 = service.loadApplication("hello.ta" + style[0], style)
- self.assertEqual(service.IService(a1).name, "hello")
- with open("hello.tac", "w") as f:
- f.writelines(
- [
- "from twisted.application import service\n",
- "application = service.Application('hello')\n",
- ]
- )
- a1 = service.loadApplication("hello.tac", "python")
- self.assertEqual(service.IService(a1).name, "hello")
-
-
- class AppSupportTests(TestCase):
- def testPassphrase(self):
- self.assertIsNone(app.getPassphrase(0))
-
- def testLoadApplication(self):
- """
- Test loading an application file in different dump format.
- """
- a = service.Application("hello")
- baseconfig = {"file": None, "source": None, "python": None}
- for style in "source pickle".split():
- config = baseconfig.copy()
- config[{"pickle": "file"}.get(style, style)] = "helloapplication"
- sob.IPersistable(a).setStyle(style)
- sob.IPersistable(a).save(filename="helloapplication")
- a1 = app.getApplication(config, None)
- self.assertEqual(service.IService(a1).name, "hello")
- config = baseconfig.copy()
- config["python"] = "helloapplication"
- with open("helloapplication", "w") as f:
- f.writelines(
- [
- "from twisted.application import service\n",
- "application = service.Application('hello')\n",
- ]
- )
- a1 = app.getApplication(config, None)
- self.assertEqual(service.IService(a1).name, "hello")
-
- def test_convertStyle(self):
- appl = service.Application("lala")
- for instyle in "source pickle".split():
- for outstyle in "source pickle".split():
- sob.IPersistable(appl).setStyle(instyle)
- sob.IPersistable(appl).save(filename="converttest")
- app.convertStyle(
- "converttest", instyle, None, "converttest.out", outstyle, 0
- )
- appl2 = service.loadApplication("converttest.out", outstyle)
- self.assertEqual(service.IService(appl2).name, "lala")
-
- def test_startApplication(self):
- appl = service.Application("lala")
- app.startApplication(appl, 0)
- self.assertTrue(service.IService(appl).running)
-
-
- class Foo(basic.LineReceiver):
- def connectionMade(self):
- self.transport.write(b"lalala\r\n")
-
- def lineReceived(self, line):
- self.factory.line = line
- self.transport.loseConnection()
-
- def connectionLost(self, reason):
- self.factory.d.callback(self.factory.line)
-
-
- class DummyApp:
- processName = None
-
- def addService(self, service):
- self.services[service.name] = service
-
- def removeService(self, service):
- del self.services[service.name]
-
-
- class TimerTarget:
- def __init__(self):
- self.l = []
-
- def append(self, what):
- self.l.append(what)
-
-
- class TestEcho(wire.Echo):
- def connectionLost(self, reason):
- self.d.callback(True)
-
-
- class InternetTests(TestCase):
- def testTCP(self):
- s = service.MultiService()
- s.startService()
- factory = protocol.ServerFactory()
- factory.protocol = TestEcho
- TestEcho.d = defer.Deferred()
- t = internet.TCPServer(0, factory)
- t.setServiceParent(s)
- num = t._port.getHost().port
- factory = protocol.ClientFactory()
- factory.d = defer.Deferred()
- factory.protocol = Foo
- factory.line = None
- internet.TCPClient("127.0.0.1", num, factory).setServiceParent(s)
- factory.d.addCallback(self.assertEqual, b"lalala")
- factory.d.addCallback(lambda x: s.stopService())
- factory.d.addCallback(lambda x: TestEcho.d)
- return factory.d
-
- def test_UDP(self):
- """
- Test L{internet.UDPServer} with a random port: starting the service
- should give it valid port, and stopService should free it so that we
- can start a server on the same port again.
- """
- if not interfaces.IReactorUDP(reactor, None):
- raise SkipTest("This reactor does not support UDP sockets")
- p = protocol.DatagramProtocol()
- t = internet.UDPServer(0, p)
- t.startService()
- num = t._port.getHost().port
- self.assertNotEqual(num, 0)
-
- def onStop(ignored):
- t = internet.UDPServer(num, p)
- t.startService()
- return t.stopService()
-
- return defer.maybeDeferred(t.stopService).addCallback(onStop)
-
- def testPrivileged(self):
- factory = protocol.ServerFactory()
- factory.protocol = TestEcho
- TestEcho.d = defer.Deferred()
- t = internet.TCPServer(0, factory)
- t.privileged = 1
- t.privilegedStartService()
- num = t._port.getHost().port
- factory = protocol.ClientFactory()
- factory.d = defer.Deferred()
- factory.protocol = Foo
- factory.line = None
- c = internet.TCPClient("127.0.0.1", num, factory)
- c.startService()
- factory.d.addCallback(self.assertEqual, b"lalala")
- factory.d.addCallback(lambda x: c.stopService())
- factory.d.addCallback(lambda x: t.stopService())
- factory.d.addCallback(lambda x: TestEcho.d)
- return factory.d
-
- def testConnectionGettingRefused(self):
- factory = protocol.ServerFactory()
- factory.protocol = wire.Echo
- t = internet.TCPServer(0, factory)
- t.startService()
- num = t._port.getHost().port
- t.stopService()
- d = defer.Deferred()
- factory = protocol.ClientFactory()
- factory.clientConnectionFailed = lambda *args: d.callback(None)
- c = internet.TCPClient("127.0.0.1", num, factory)
- c.startService()
- return d
-
- @skipIf(
- not interfaces.IReactorUNIX(reactor, None),
- "This reactor does not support UNIX domain sockets",
- )
- def testUNIX(self):
- # FIXME: This test is far too dense. It needs comments.
- # -- spiv, 2004-11-07
- s = service.MultiService()
- s.startService()
- factory = protocol.ServerFactory()
- factory.protocol = TestEcho
- TestEcho.d = defer.Deferred()
- t = internet.UNIXServer("echo.skt", factory)
- t.setServiceParent(s)
- factory = protocol.ClientFactory()
- factory.protocol = Foo
- factory.d = defer.Deferred()
- factory.line = None
- internet.UNIXClient("echo.skt", factory).setServiceParent(s)
- factory.d.addCallback(self.assertEqual, b"lalala")
- factory.d.addCallback(lambda x: s.stopService())
- factory.d.addCallback(lambda x: TestEcho.d)
- factory.d.addCallback(self._cbTestUnix, factory, s)
- return factory.d
-
- def _cbTestUnix(self, ignored, factory, s):
- TestEcho.d = defer.Deferred()
- factory.line = None
- factory.d = defer.Deferred()
- s.startService()
- factory.d.addCallback(self.assertEqual, b"lalala")
- factory.d.addCallback(lambda x: s.stopService())
- factory.d.addCallback(lambda x: TestEcho.d)
- return factory.d
-
- @skipIf(
- not interfaces.IReactorUNIX(reactor, None),
- "This reactor does not support UNIX domain sockets",
- )
- def testVolatile(self):
- factory = protocol.ServerFactory()
- factory.protocol = wire.Echo
- t = internet.UNIXServer("echo.skt", factory)
- t.startService()
- self.failIfIdentical(t._port, None)
- t1 = copy.copy(t)
- self.assertIsNone(t1._port)
- t.stopService()
- self.assertIsNone(t._port)
- self.assertFalse(t.running)
-
- factory = protocol.ClientFactory()
- factory.protocol = wire.Echo
- t = internet.UNIXClient("echo.skt", factory)
- t.startService()
- self.failIfIdentical(t._connection, None)
- t1 = copy.copy(t)
- self.assertIsNone(t1._connection)
- t.stopService()
- self.assertIsNone(t._connection)
- self.assertFalse(t.running)
-
- @skipIf(
- not interfaces.IReactorUNIX(reactor, None),
- "This reactor does not support UNIX domain sockets",
- )
- def testStoppingServer(self):
- factory = protocol.ServerFactory()
- factory.protocol = wire.Echo
- t = internet.UNIXServer("echo.skt", factory)
- t.startService()
- t.stopService()
- self.assertFalse(t.running)
- factory = protocol.ClientFactory()
- d = defer.Deferred()
- factory.clientConnectionFailed = lambda *args: d.callback(None)
- reactor.connectUNIX("echo.skt", factory)
- return d
-
- def testPickledTimer(self):
- target = TimerTarget()
- t0 = internet.TimerService(1, target.append, "hello")
- t0.startService()
- s = pickle.dumps(t0)
- t0.stopService()
-
- t = pickle.loads(s)
- self.assertFalse(t.running)
-
- def testBrokenTimer(self):
- d = defer.Deferred()
- t = internet.TimerService(1, lambda: 1 // 0)
- oldFailed = t._failed
-
- def _failed(why):
- oldFailed(why)
- d.callback(None)
-
- t._failed = _failed
- t.startService()
- d.addCallback(lambda x: t.stopService)
- d.addCallback(
- lambda x: self.assertEqual(
- [ZeroDivisionError],
- [o.value.__class__ for o in self.flushLoggedErrors(ZeroDivisionError)],
- )
- )
- return d
-
- def test_everythingThere(self):
- """
- L{twisted.application.internet} dynamically defines a set of
- L{service.Service} subclasses that in general have corresponding
- reactor.listenXXX or reactor.connectXXX calls.
- """
- trans = ["TCP", "UNIX", "SSL", "UDP", "UNIXDatagram", "Multicast"]
- for tran in trans[:]:
- if not getattr(interfaces, "IReactor" + tran)(reactor, None):
- trans.remove(tran)
- for tran in trans:
- for side in ["Server", "Client"]:
- if tran == "Multicast" and side == "Client":
- continue
- if tran == "UDP" and side == "Client":
- continue
- self.assertTrue(hasattr(internet, tran + side))
- method = getattr(internet, tran + side).method
- prefix = {"Server": "listen", "Client": "connect"}[side]
- self.assertTrue(
- hasattr(reactor, prefix + method)
- or (prefix == "connect" and method == "UDP")
- )
- o = getattr(internet, tran + side)()
- self.assertEqual(service.IService(o), o)
-
- def test_importAll(self):
- """
- L{twisted.application.internet} dynamically defines L{service.Service}
- subclasses. This test ensures that the subclasses exposed by C{__all__}
- are valid attributes of the module.
- """
- for cls in internet.__all__:
- self.assertTrue(
- hasattr(internet, cls),
- f"{cls} not importable from twisted.application.internet",
- )
-
- def test_reactorParametrizationInServer(self):
- """
- L{internet._AbstractServer} supports a C{reactor} keyword argument
- that can be used to parametrize the reactor used to listen for
- connections.
- """
- reactor = MemoryReactor()
-
- factory = object()
- t = internet.TCPServer(1234, factory, reactor=reactor)
- t.startService()
- self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory))
-
- def test_reactorParametrizationInClient(self):
- """
- L{internet._AbstractClient} supports a C{reactor} keyword arguments
- that can be used to parametrize the reactor used to create new client
- connections.
- """
- reactor = MemoryReactor()
-
- factory = protocol.ClientFactory()
- t = internet.TCPClient("127.0.0.1", 1234, factory, reactor=reactor)
- t.startService()
- self.assertEqual(reactor.tcpClients.pop()[:3], ("127.0.0.1", 1234, factory))
-
- def test_reactorParametrizationInServerMultipleStart(self):
- """
- Like L{test_reactorParametrizationInServer}, but stop and restart the
- service and check that the given reactor is still used.
- """
- reactor = MemoryReactor()
-
- factory = protocol.Factory()
- t = internet.TCPServer(1234, factory, reactor=reactor)
- t.startService()
- self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory))
- t.stopService()
- t.startService()
- self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory))
-
- def test_reactorParametrizationInClientMultipleStart(self):
- """
- Like L{test_reactorParametrizationInClient}, but stop and restart the
- service and check that the given reactor is still used.
- """
- reactor = MemoryReactor()
-
- factory = protocol.ClientFactory()
- t = internet.TCPClient("127.0.0.1", 1234, factory, reactor=reactor)
- t.startService()
- self.assertEqual(reactor.tcpClients.pop()[:3], ("127.0.0.1", 1234, factory))
- t.stopService()
- t.startService()
- self.assertEqual(reactor.tcpClients.pop()[:3], ("127.0.0.1", 1234, factory))
-
-
- class TimerBasicTests(TestCase):
- def testTimerRuns(self):
- d = defer.Deferred()
- self.t = internet.TimerService(1, d.callback, "hello")
- self.t.startService()
- d.addCallback(self.assertEqual, "hello")
- d.addCallback(lambda x: self.t.stopService())
- d.addCallback(lambda x: self.assertFalse(self.t.running))
- return d
-
- def tearDown(self):
- return self.t.stopService()
-
- def testTimerRestart(self):
- # restart the same TimerService
- d1 = defer.Deferred()
- d2 = defer.Deferred()
- work = [(d2, "bar"), (d1, "foo")]
-
- def trigger():
- d, arg = work.pop()
- d.callback(arg)
-
- self.t = internet.TimerService(1, trigger)
- self.t.startService()
-
- def onFirstResult(result):
- self.assertEqual(result, "foo")
- return self.t.stopService()
-
- def onFirstStop(ignored):
- self.assertFalse(self.t.running)
- self.t.startService()
- return d2
-
- def onSecondResult(result):
- self.assertEqual(result, "bar")
- self.t.stopService()
-
- d1.addCallback(onFirstResult)
- d1.addCallback(onFirstStop)
- d1.addCallback(onSecondResult)
- return d1
-
- def testTimerLoops(self):
- l = []
-
- def trigger(data, number, d):
- l.append(data)
- if len(l) == number:
- d.callback(l)
-
- d = defer.Deferred()
- self.t = internet.TimerService(0.01, trigger, "hello", 10, d)
- self.t.startService()
- d.addCallback(self.assertEqual, ["hello"] * 10)
- d.addCallback(lambda x: self.t.stopService())
- return d
-
-
- class FakeReactor(reactors.Reactor):
- """
- A fake reactor with a hooked install method.
- """
-
- def __init__(self, install, *args, **kwargs):
- """
- @param install: any callable that will be used as install method.
- @type install: C{callable}
- """
- reactors.Reactor.__init__(self, *args, **kwargs)
- self.install = install
-
-
- class PluggableReactorTests(TwistedModulesMixin, TestCase):
- """
- Tests for the reactor discovery/inspection APIs.
- """
-
- def setUp(self):
- """
- Override the L{reactors.getPlugins} function, normally bound to
- L{twisted.plugin.getPlugins}, in order to control which
- L{IReactorInstaller} plugins are seen as available.
-
- C{self.pluginResults} can be customized and will be used as the
- result of calls to C{reactors.getPlugins}.
- """
- self.pluginCalls = []
- self.pluginResults = []
- self.originalFunction = reactors.getPlugins
- reactors.getPlugins = self._getPlugins
-
- def tearDown(self):
- """
- Restore the original L{reactors.getPlugins}.
- """
- reactors.getPlugins = self.originalFunction
-
- def _getPlugins(self, interface, package=None):
- """
- Stand-in for the real getPlugins method which records its arguments
- and returns a fixed result.
- """
- self.pluginCalls.append((interface, package))
- return list(self.pluginResults)
-
- def test_getPluginReactorTypes(self):
- """
- Test that reactor plugins are returned from L{getReactorTypes}
- """
- name = "fakereactortest"
- package = __name__ + ".fakereactor"
- description = "description"
- self.pluginResults = [reactors.Reactor(name, package, description)]
- reactorTypes = reactors.getReactorTypes()
-
- self.assertEqual(self.pluginCalls, [(reactors.IReactorInstaller, None)])
-
- for r in reactorTypes:
- if r.shortName == name:
- self.assertEqual(r.description, description)
- break
- else:
- self.fail("Reactor plugin not present in getReactorTypes() result")
-
- def test_reactorInstallation(self):
- """
- Test that L{reactors.Reactor.install} loads the correct module and
- calls its install attribute.
- """
- installed = []
-
- def install():
- installed.append(True)
-
- fakeReactor = FakeReactor(install, "fakereactortest", __name__, "described")
- modules = {"fakereactortest": fakeReactor}
- self.replaceSysModules(modules)
- installer = reactors.Reactor("fakereactor", "fakereactortest", "described")
- installer.install()
- self.assertEqual(installed, [True])
-
- def test_installReactor(self):
- """
- Test that the L{reactors.installReactor} function correctly installs
- the specified reactor.
- """
- installed = []
-
- def install():
- installed.append(True)
-
- name = "fakereactortest"
- package = __name__
- description = "description"
- self.pluginResults = [FakeReactor(install, name, package, description)]
- reactors.installReactor(name)
- self.assertEqual(installed, [True])
-
- def test_installReactorReturnsReactor(self):
- """
- Test that the L{reactors.installReactor} function correctly returns
- the installed reactor.
- """
- reactor = object()
-
- def install():
- from twisted import internet
-
- self.patch(internet, "reactor", reactor)
-
- name = "fakereactortest"
- package = __name__
- description = "description"
- self.pluginResults = [FakeReactor(install, name, package, description)]
- installed = reactors.installReactor(name)
- self.assertIs(installed, reactor)
-
- def test_installReactorMultiplePlugins(self):
- """
- Test that the L{reactors.installReactor} function correctly installs
- the specified reactor when there are multiple reactor plugins.
- """
- installed = []
-
- def install():
- installed.append(True)
-
- name = "fakereactortest"
- package = __name__
- description = "description"
- fakeReactor = FakeReactor(install, name, package, description)
- otherReactor = FakeReactor(lambda: None, "otherreactor", package, description)
- self.pluginResults = [otherReactor, fakeReactor]
- reactors.installReactor(name)
- self.assertEqual(installed, [True])
-
- def test_installNonExistentReactor(self):
- """
- Test that L{reactors.installReactor} raises L{reactors.NoSuchReactor}
- when asked to install a reactor which it cannot find.
- """
- self.pluginResults = []
- self.assertRaises(
- reactors.NoSuchReactor, reactors.installReactor, "somereactor"
- )
-
- def test_installNotAvailableReactor(self):
- """
- Test that L{reactors.installReactor} raises an exception when asked to
- install a reactor which doesn't work in this environment.
- """
-
- def install():
- raise ImportError("Missing foo bar")
-
- name = "fakereactortest"
- package = __name__
- description = "description"
- self.pluginResults = [FakeReactor(install, name, package, description)]
- self.assertRaises(ImportError, reactors.installReactor, name)
-
- def test_reactorSelectionMixin(self):
- """
- Test that the reactor selected is installed as soon as possible, ie
- when the option is parsed.
- """
- executed = []
- INSTALL_EVENT = "reactor installed"
- SUBCOMMAND_EVENT = "subcommands loaded"
-
- class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin):
- @property
- def subCommands(self):
- executed.append(SUBCOMMAND_EVENT)
- return [("subcommand", None, lambda: self, "test subcommand")]
-
- def install():
- executed.append(INSTALL_EVENT)
-
- self.pluginResults = [
- FakeReactor(install, "fakereactortest", __name__, "described")
- ]
-
- options = ReactorSelectionOptions()
- options.parseOptions(["--reactor", "fakereactortest", "subcommand"])
- self.assertEqual(executed[0], INSTALL_EVENT)
- self.assertEqual(executed.count(INSTALL_EVENT), 1)
- self.assertEqual(options["reactor"], "fakereactortest")
-
- def test_reactorSelectionMixinNonExistent(self):
- """
- Test that the usage mixin exits when trying to use a non existent
- reactor (the name not matching to any reactor), giving an error
- message.
- """
-
- class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin):
- pass
-
- self.pluginResults = []
-
- options = ReactorSelectionOptions()
- options.messageOutput = StringIO()
- e = self.assertRaises(
- usage.UsageError,
- options.parseOptions,
- ["--reactor", "fakereactortest", "subcommand"],
- )
- self.assertIn("fakereactortest", e.args[0])
- self.assertIn("help-reactors", e.args[0])
-
- def test_reactorSelectionMixinNotAvailable(self):
- """
- Test that the usage mixin exits when trying to use a reactor not
- available (the reactor raises an error at installation), giving an
- error message.
- """
-
- class ReactorSelectionOptions(usage.Options, app.ReactorSelectionMixin):
- pass
-
- message = "Missing foo bar"
-
- def install():
- raise ImportError(message)
-
- name = "fakereactortest"
- package = __name__
- description = "description"
- self.pluginResults = [FakeReactor(install, name, package, description)]
-
- options = ReactorSelectionOptions()
- options.messageOutput = StringIO()
- e = self.assertRaises(
- usage.UsageError,
- options.parseOptions,
- ["--reactor", "fakereactortest", "subcommand"],
- )
- self.assertIn(message, e.args[0])
- self.assertIn("help-reactors", e.args[0])
-
-
- class HelpReactorsTests(TestCase):
- """
- --help-reactors lists the available reactors
- """
-
- def setUp(self):
- """
- Get the text from --help-reactors
- """
- self.options = app.ReactorSelectionMixin()
- self.options.messageOutput = StringIO()
- self.assertRaises(SystemExit, self.options.opt_help_reactors)
- self.message = self.options.messageOutput.getvalue()
-
- @skipIf(asyncio, "Not applicable, asyncio is available")
- def test_lacksAsyncIO(self):
- """
- --help-reactors should NOT display the asyncio reactor on Python < 3.4
- """
- self.assertIn(twisted_reactors.asyncio.description, self.message)
- self.assertIn("!" + twisted_reactors.asyncio.shortName, self.message)
-
- @skipIf(not asyncio, "asyncio library not available")
- def test_hasAsyncIO(self):
- """
- --help-reactors should display the asyncio reactor on Python >= 3.4
- """
- self.assertIn(twisted_reactors.asyncio.description, self.message)
- self.assertNotIn("!" + twisted_reactors.asyncio.shortName, self.message)
-
- @skipIf(platformType != "win32", "Test only applicable on Windows")
- def test_iocpWin32(self):
- """
- --help-reactors should display the iocp reactor on Windows
- """
- self.assertIn(twisted_reactors.iocp.description, self.message)
- self.assertNotIn("!" + twisted_reactors.iocp.shortName, self.message)
-
- @skipIf(platformType == "win32", "Test not applicable on Windows")
- def test_iocpNotWin32(self):
- """
- --help-reactors should NOT display the iocp reactor on Windows
- """
- self.assertIn(twisted_reactors.iocp.description, self.message)
- self.assertIn("!" + twisted_reactors.iocp.shortName, self.message)
-
- def test_onlySupportedReactors(self):
- """
- --help-reactors with only supported reactors
- """
-
- def getReactorTypes():
- yield twisted_reactors.default
-
- options = app.ReactorSelectionMixin()
- options._getReactorTypes = getReactorTypes
- options.messageOutput = StringIO()
- self.assertRaises(SystemExit, options.opt_help_reactors)
- message = options.messageOutput.getvalue()
- self.assertNotIn("reactors not available", message)
-
-
- class BackoffPolicyTests(TestCase):
- """
- Tests of L{twisted.application.internet.backoffPolicy}
- """
-
- def test_calculates_correct_values(self):
- """
- Test that L{backoffPolicy()} calculates expected values
- """
- pol = backoffPolicy(1.0, 60.0, 1.5, jitter=lambda: 1)
- self.assertAlmostEqual(pol(0), 2)
- self.assertAlmostEqual(pol(1), 2.5)
- self.assertAlmostEqual(pol(10), 58.6650390625)
- self.assertEqual(pol(20), 61)
- self.assertEqual(pol(100), 61)
-
- def test_does_not_overflow_on_high_attempts(self):
- """
- L{backoffPolicy()} does not fail for large values of the attempt
- parameter. In previous versions, this test failed when attempt was
- larger than 1750.
-
- See https://twistedmatrix.com/trac/ticket/9476
- """
- pol = backoffPolicy(1.0, 60.0, 1.5, jitter=lambda: 1)
- self.assertEqual(pol(1751), 61)
- self.assertEqual(pol(1000000), 61)
-
- def test_does_not_overflow_with_large_factor_value(self):
- """
- Even with unusual parameters, any L{OverflowError} within
- L{backoffPolicy()} will be caught and L{maxDelay} will be returned
- instead
- """
- pol = backoffPolicy(1.0, 60.0, 1e10, jitter=lambda: 1)
- self.assertEqual(pol(1751), 61)
|