test_iosim.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.test.iosim}.
  5. """
  6. from __future__ import absolute_import, division
  7. from zope.interface import implementer
  8. from twisted.internet.interfaces import IPushProducer
  9. from twisted.internet.protocol import Protocol
  10. from twisted.test.iosim import FakeTransport, connect
  11. from twisted.trial.unittest import TestCase
  12. class FakeTransportTests(TestCase):
  13. """
  14. Tests for L{FakeTransport}.
  15. """
  16. def test_connectionSerial(self):
  17. """
  18. Each L{FakeTransport} receives a serial number that uniquely identifies
  19. it.
  20. """
  21. a = FakeTransport(object(), True)
  22. b = FakeTransport(object(), False)
  23. self.assertIsInstance(a.serial, int)
  24. self.assertIsInstance(b.serial, int)
  25. self.assertNotEqual(a.serial, b.serial)
  26. def test_writeSequence(self):
  27. """
  28. L{FakeTransport.writeSequence} will write a sequence of L{bytes} to the
  29. transport.
  30. """
  31. a = FakeTransport(object(), False)
  32. a.write(b"a")
  33. a.writeSequence([b"b", b"c", b"d"])
  34. self.assertEqual(b"".join(a.stream), b"abcd")
  35. @implementer(IPushProducer)
  36. class StrictPushProducer(object):
  37. """
  38. An L{IPushProducer} implementation which produces nothing but enforces
  39. preconditions on its state transition methods.
  40. """
  41. _state = u"running"
  42. def stopProducing(self):
  43. if self._state == u"stopped":
  44. raise ValueError(u"Cannot stop already-stopped IPushProducer")
  45. self._state = u"stopped"
  46. def pauseProducing(self):
  47. if self._state != u"running":
  48. raise ValueError(
  49. u"Cannot pause {} IPushProducer".format(self._state)
  50. )
  51. self._state = u"paused"
  52. def resumeProducing(self):
  53. if self._state != u"paused":
  54. raise ValueError(
  55. u"Cannot resume {} IPushProducer".format(self._state)
  56. )
  57. self._state = u"running"
  58. class StrictPushProducerTests(TestCase):
  59. """
  60. Tests for L{StrictPushProducer}.
  61. """
  62. def _initial(self):
  63. """
  64. @return: A new L{StrictPushProducer} which has not been through any state
  65. changes.
  66. """
  67. return StrictPushProducer()
  68. def _stopped(self):
  69. """
  70. @return: A new, stopped L{StrictPushProducer}.
  71. """
  72. producer = StrictPushProducer()
  73. producer.stopProducing()
  74. return producer
  75. def _paused(self):
  76. """
  77. @return: A new, paused L{StrictPushProducer}.
  78. """
  79. producer = StrictPushProducer()
  80. producer.pauseProducing()
  81. return producer
  82. def _resumed(self):
  83. """
  84. @return: A new L{StrictPushProducer} which has been paused and resumed.
  85. """
  86. producer = StrictPushProducer()
  87. producer.pauseProducing()
  88. producer.resumeProducing()
  89. return producer
  90. def assertStopped(self, producer):
  91. """
  92. Assert that the given producer is in the stopped state.
  93. @param producer: The producer to verify.
  94. @type producer: L{StrictPushProducer}
  95. """
  96. self.assertEqual(producer._state, u"stopped")
  97. def assertPaused(self, producer):
  98. """
  99. Assert that the given producer is in the paused state.
  100. @param producer: The producer to verify.
  101. @type producer: L{StrictPushProducer}
  102. """
  103. self.assertEqual(producer._state, u"paused")
  104. def assertRunning(self, producer):
  105. """
  106. Assert that the given producer is in the running state.
  107. @param producer: The producer to verify.
  108. @type producer: L{StrictPushProducer}
  109. """
  110. self.assertEqual(producer._state, u"running")
  111. def test_stopThenStop(self):
  112. """
  113. L{StrictPushProducer.stopProducing} raises L{ValueError} if called when
  114. the producer is stopped.
  115. """
  116. self.assertRaises(ValueError, self._stopped().stopProducing)
  117. def test_stopThenPause(self):
  118. """
  119. L{StrictPushProducer.pauseProducing} raises L{ValueError} if called when
  120. the producer is stopped.
  121. """
  122. self.assertRaises(ValueError, self._stopped().pauseProducing)
  123. def test_stopThenResume(self):
  124. """
  125. L{StrictPushProducer.resumeProducing} raises L{ValueError} if called when
  126. the producer is stopped.
  127. """
  128. self.assertRaises(ValueError, self._stopped().resumeProducing)
  129. def test_pauseThenStop(self):
  130. """
  131. L{StrictPushProducer} is stopped if C{stopProducing} is called on a paused
  132. producer.
  133. """
  134. producer = self._paused()
  135. producer.stopProducing()
  136. self.assertStopped(producer)
  137. def test_pauseThenPause(self):
  138. """
  139. L{StrictPushProducer.pauseProducing} raises L{ValueError} if called on a
  140. paused producer.
  141. """
  142. producer = self._paused()
  143. self.assertRaises(ValueError, producer.pauseProducing)
  144. def test_pauseThenResume(self):
  145. """
  146. L{StrictPushProducer} is resumed if C{resumeProducing} is called on a
  147. paused producer.
  148. """
  149. producer = self._paused()
  150. producer.resumeProducing()
  151. self.assertRunning(producer)
  152. def test_resumeThenStop(self):
  153. """
  154. L{StrictPushProducer} is stopped if C{stopProducing} is called on a
  155. resumed producer.
  156. """
  157. producer = self._resumed()
  158. producer.stopProducing()
  159. self.assertStopped(producer)
  160. def test_resumeThenPause(self):
  161. """
  162. L{StrictPushProducer} is paused if C{pauseProducing} is called on a
  163. resumed producer.
  164. """
  165. producer = self._resumed()
  166. producer.pauseProducing()
  167. self.assertPaused(producer)
  168. def test_resumeThenResume(self):
  169. """
  170. L{StrictPushProducer.resumeProducing} raises L{ValueError} if called on a
  171. resumed producer.
  172. """
  173. producer = self._resumed()
  174. self.assertRaises(ValueError, producer.resumeProducing)
  175. def test_stop(self):
  176. """
  177. L{StrictPushProducer} is stopped if C{stopProducing} is called in the
  178. initial state.
  179. """
  180. producer = self._initial()
  181. producer.stopProducing()
  182. self.assertStopped(producer)
  183. def test_pause(self):
  184. """
  185. L{StrictPushProducer} is paused if C{pauseProducing} is called in the
  186. initial state.
  187. """
  188. producer = self._initial()
  189. producer.pauseProducing()
  190. self.assertPaused(producer)
  191. def test_resume(self):
  192. """
  193. L{StrictPushProducer} raises L{ValueError} if C{resumeProducing} is called
  194. in the initial state.
  195. """
  196. producer = self._initial()
  197. self.assertRaises(ValueError, producer.resumeProducing)
  198. class IOPumpTests(TestCase):
  199. """
  200. Tests for L{IOPump}.
  201. """
  202. def _testStreamingProducer(self, mode):
  203. """
  204. Connect a couple protocol/transport pairs to an L{IOPump} and then pump
  205. it. Verify that a streaming producer registered with one of the
  206. transports does not receive invalid L{IPushProducer} method calls and
  207. ends in the right state.
  208. @param mode: C{u"server"} to test a producer registered with the
  209. server transport. C{u"client"} to test a producer registered with
  210. the client transport.
  211. """
  212. serverProto = Protocol()
  213. serverTransport = FakeTransport(serverProto, isServer=True)
  214. clientProto = Protocol()
  215. clientTransport = FakeTransport(clientProto, isServer=False)
  216. pump = connect(
  217. serverProto, serverTransport,
  218. clientProto, clientTransport,
  219. greet=False,
  220. )
  221. producer = StrictPushProducer()
  222. victim = {
  223. u"server": serverTransport,
  224. u"client": clientTransport,
  225. }[mode]
  226. victim.registerProducer(producer, streaming=True)
  227. pump.pump()
  228. self.assertEqual(u"running", producer._state)
  229. def test_serverStreamingProducer(self):
  230. """
  231. L{IOPump.pump} does not call C{resumeProducing} on a L{IPushProducer}
  232. (stream producer) registered with the server transport.
  233. """
  234. self._testStreamingProducer(mode=u"server")
  235. def test_clientStreamingProducer(self):
  236. """
  237. L{IOPump.pump} does not call C{resumeProducing} on a L{IPushProducer}
  238. (stream producer) registered with the client transport.
  239. """
  240. self._testStreamingProducer(mode=u"client")