|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
-
- """
- Tests for L{twisted.test.iosim}.
- """
-
-
- from zope.interface import implementer
-
- from twisted.internet.interfaces import IPushProducer
- from twisted.internet.protocol import Protocol
- from twisted.test.iosim import FakeTransport, connect
- from twisted.trial.unittest import TestCase
-
-
- class FakeTransportTests(TestCase):
- """
- Tests for L{FakeTransport}.
- """
-
- def test_connectionSerial(self):
- """
- Each L{FakeTransport} receives a serial number that uniquely identifies
- it.
- """
- a = FakeTransport(object(), True)
- b = FakeTransport(object(), False)
- self.assertIsInstance(a.serial, int)
- self.assertIsInstance(b.serial, int)
- self.assertNotEqual(a.serial, b.serial)
-
- def test_writeSequence(self):
- """
- L{FakeTransport.writeSequence} will write a sequence of L{bytes} to the
- transport.
- """
- a = FakeTransport(object(), False)
-
- a.write(b"a")
- a.writeSequence([b"b", b"c", b"d"])
-
- self.assertEqual(b"".join(a.stream), b"abcd")
-
- def test_writeAfterClose(self):
- """
- L{FakeTransport.write} will accept writes after transport was closed,
- but the data will be silently discarded.
- """
- a = FakeTransport(object(), False)
- a.write(b"before")
- a.loseConnection()
- a.write(b"after")
-
- self.assertEqual(b"".join(a.stream), b"before")
-
-
- @implementer(IPushProducer)
- class StrictPushProducer:
- """
- An L{IPushProducer} implementation which produces nothing but enforces
- preconditions on its state transition methods.
- """
-
- _state = "running"
-
- def stopProducing(self):
- if self._state == "stopped":
- raise ValueError("Cannot stop already-stopped IPushProducer")
- self._state = "stopped"
-
- def pauseProducing(self):
- if self._state != "running":
- raise ValueError(f"Cannot pause {self._state} IPushProducer")
- self._state = "paused"
-
- def resumeProducing(self):
- if self._state != "paused":
- raise ValueError(f"Cannot resume {self._state} IPushProducer")
- self._state = "running"
-
-
- class StrictPushProducerTests(TestCase):
- """
- Tests for L{StrictPushProducer}.
- """
-
- def _initial(self):
- """
- @return: A new L{StrictPushProducer} which has not been through any state
- changes.
- """
- return StrictPushProducer()
-
- def _stopped(self):
- """
- @return: A new, stopped L{StrictPushProducer}.
- """
- producer = StrictPushProducer()
- producer.stopProducing()
- return producer
-
- def _paused(self):
- """
- @return: A new, paused L{StrictPushProducer}.
- """
- producer = StrictPushProducer()
- producer.pauseProducing()
- return producer
-
- def _resumed(self):
- """
- @return: A new L{StrictPushProducer} which has been paused and resumed.
- """
- producer = StrictPushProducer()
- producer.pauseProducing()
- producer.resumeProducing()
- return producer
-
- def assertStopped(self, producer):
- """
- Assert that the given producer is in the stopped state.
-
- @param producer: The producer to verify.
- @type producer: L{StrictPushProducer}
- """
- self.assertEqual(producer._state, "stopped")
-
- def assertPaused(self, producer):
- """
- Assert that the given producer is in the paused state.
-
- @param producer: The producer to verify.
- @type producer: L{StrictPushProducer}
- """
- self.assertEqual(producer._state, "paused")
-
- def assertRunning(self, producer):
- """
- Assert that the given producer is in the running state.
-
- @param producer: The producer to verify.
- @type producer: L{StrictPushProducer}
- """
- self.assertEqual(producer._state, "running")
-
- def test_stopThenStop(self):
- """
- L{StrictPushProducer.stopProducing} raises L{ValueError} if called when
- the producer is stopped.
- """
- self.assertRaises(ValueError, self._stopped().stopProducing)
-
- def test_stopThenPause(self):
- """
- L{StrictPushProducer.pauseProducing} raises L{ValueError} if called when
- the producer is stopped.
- """
- self.assertRaises(ValueError, self._stopped().pauseProducing)
-
- def test_stopThenResume(self):
- """
- L{StrictPushProducer.resumeProducing} raises L{ValueError} if called when
- the producer is stopped.
- """
- self.assertRaises(ValueError, self._stopped().resumeProducing)
-
- def test_pauseThenStop(self):
- """
- L{StrictPushProducer} is stopped if C{stopProducing} is called on a paused
- producer.
- """
- producer = self._paused()
- producer.stopProducing()
- self.assertStopped(producer)
-
- def test_pauseThenPause(self):
- """
- L{StrictPushProducer.pauseProducing} raises L{ValueError} if called on a
- paused producer.
- """
- producer = self._paused()
- self.assertRaises(ValueError, producer.pauseProducing)
-
- def test_pauseThenResume(self):
- """
- L{StrictPushProducer} is resumed if C{resumeProducing} is called on a
- paused producer.
- """
- producer = self._paused()
- producer.resumeProducing()
- self.assertRunning(producer)
-
- def test_resumeThenStop(self):
- """
- L{StrictPushProducer} is stopped if C{stopProducing} is called on a
- resumed producer.
- """
- producer = self._resumed()
- producer.stopProducing()
- self.assertStopped(producer)
-
- def test_resumeThenPause(self):
- """
- L{StrictPushProducer} is paused if C{pauseProducing} is called on a
- resumed producer.
- """
- producer = self._resumed()
- producer.pauseProducing()
- self.assertPaused(producer)
-
- def test_resumeThenResume(self):
- """
- L{StrictPushProducer.resumeProducing} raises L{ValueError} if called on a
- resumed producer.
- """
- producer = self._resumed()
- self.assertRaises(ValueError, producer.resumeProducing)
-
- def test_stop(self):
- """
- L{StrictPushProducer} is stopped if C{stopProducing} is called in the
- initial state.
- """
- producer = self._initial()
- producer.stopProducing()
- self.assertStopped(producer)
-
- def test_pause(self):
- """
- L{StrictPushProducer} is paused if C{pauseProducing} is called in the
- initial state.
- """
- producer = self._initial()
- producer.pauseProducing()
- self.assertPaused(producer)
-
- def test_resume(self):
- """
- L{StrictPushProducer} raises L{ValueError} if C{resumeProducing} is called
- in the initial state.
- """
- producer = self._initial()
- self.assertRaises(ValueError, producer.resumeProducing)
-
-
- class IOPumpTests(TestCase):
- """
- Tests for L{IOPump}.
- """
-
- def _testStreamingProducer(self, mode):
- """
- Connect a couple protocol/transport pairs to an L{IOPump} and then pump
- it. Verify that a streaming producer registered with one of the
- transports does not receive invalid L{IPushProducer} method calls and
- ends in the right state.
-
- @param mode: C{u"server"} to test a producer registered with the
- server transport. C{u"client"} to test a producer registered with
- the client transport.
- """
- serverProto = Protocol()
- serverTransport = FakeTransport(serverProto, isServer=True)
-
- clientProto = Protocol()
- clientTransport = FakeTransport(clientProto, isServer=False)
-
- pump = connect(
- serverProto,
- serverTransport,
- clientProto,
- clientTransport,
- greet=False,
- )
-
- producer = StrictPushProducer()
- victim = {
- "server": serverTransport,
- "client": clientTransport,
- }[mode]
- victim.registerProducer(producer, streaming=True)
-
- pump.pump()
- self.assertEqual("running", producer._state)
-
- def test_serverStreamingProducer(self):
- """
- L{IOPump.pump} does not call C{resumeProducing} on a L{IPushProducer}
- (stream producer) registered with the server transport.
- """
- self._testStreamingProducer(mode="server")
-
- def test_clientStreamingProducer(self):
- """
- L{IOPump.pump} does not call C{resumeProducing} on a L{IPushProducer}
- (stream producer) registered with the client transport.
- """
- self._testStreamingProducer(mode="client")
|