You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_protocols.py 7.3KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Test cases for twisted.protocols package.
  5. """
  6. from twisted.trial import unittest
  7. from twisted.protocols import wire, portforward
  8. from twisted.python.compat import iterbytes
  9. from twisted.internet import reactor, defer, address, protocol
  10. from twisted.test import proto_helpers
  11. class WireTests(unittest.TestCase):
  12. """
  13. Test wire protocols.
  14. """
  15. def test_echo(self):
  16. """
  17. Test wire.Echo protocol: send some data and check it send it back.
  18. """
  19. t = proto_helpers.StringTransport()
  20. a = wire.Echo()
  21. a.makeConnection(t)
  22. a.dataReceived(b"hello")
  23. a.dataReceived(b"world")
  24. a.dataReceived(b"how")
  25. a.dataReceived(b"are")
  26. a.dataReceived(b"you")
  27. self.assertEqual(t.value(), b"helloworldhowareyou")
  28. def test_who(self):
  29. """
  30. Test wire.Who protocol.
  31. """
  32. t = proto_helpers.StringTransport()
  33. a = wire.Who()
  34. a.makeConnection(t)
  35. self.assertEqual(t.value(), b"root\r\n")
  36. def test_QOTD(self):
  37. """
  38. Test wire.QOTD protocol.
  39. """
  40. t = proto_helpers.StringTransport()
  41. a = wire.QOTD()
  42. a.makeConnection(t)
  43. self.assertEqual(t.value(),
  44. b"An apple a day keeps the doctor away.\r\n")
  45. def test_discard(self):
  46. """
  47. Test wire.Discard protocol.
  48. """
  49. t = proto_helpers.StringTransport()
  50. a = wire.Discard()
  51. a.makeConnection(t)
  52. a.dataReceived(b"hello")
  53. a.dataReceived(b"world")
  54. a.dataReceived(b"how")
  55. a.dataReceived(b"are")
  56. a.dataReceived(b"you")
  57. self.assertEqual(t.value(), b"")
  58. class TestableProxyClientFactory(portforward.ProxyClientFactory):
  59. """
  60. Test proxy client factory that keeps the last created protocol instance.
  61. @ivar protoInstance: the last instance of the protocol.
  62. @type protoInstance: L{portforward.ProxyClient}
  63. """
  64. def buildProtocol(self, addr):
  65. """
  66. Create the protocol instance and keeps track of it.
  67. """
  68. proto = portforward.ProxyClientFactory.buildProtocol(self, addr)
  69. self.protoInstance = proto
  70. return proto
  71. class TestableProxyFactory(portforward.ProxyFactory):
  72. """
  73. Test proxy factory that keeps the last created protocol instance.
  74. @ivar protoInstance: the last instance of the protocol.
  75. @type protoInstance: L{portforward.ProxyServer}
  76. @ivar clientFactoryInstance: client factory used by C{protoInstance} to
  77. create forward connections.
  78. @type clientFactoryInstance: L{TestableProxyClientFactory}
  79. """
  80. def buildProtocol(self, addr):
  81. """
  82. Create the protocol instance, keeps track of it, and makes it use
  83. C{clientFactoryInstance} as client factory.
  84. """
  85. proto = portforward.ProxyFactory.buildProtocol(self, addr)
  86. self.clientFactoryInstance = TestableProxyClientFactory()
  87. # Force the use of this specific instance
  88. proto.clientProtocolFactory = lambda: self.clientFactoryInstance
  89. self.protoInstance = proto
  90. return proto
  91. class PortforwardingTests(unittest.TestCase):
  92. """
  93. Test port forwarding.
  94. """
  95. def setUp(self):
  96. self.serverProtocol = wire.Echo()
  97. self.clientProtocol = protocol.Protocol()
  98. self.openPorts = []
  99. def tearDown(self):
  100. try:
  101. self.proxyServerFactory.protoInstance.transport.loseConnection()
  102. except AttributeError:
  103. pass
  104. try:
  105. pi = self.proxyServerFactory.clientFactoryInstance.protoInstance
  106. pi.transport.loseConnection()
  107. except AttributeError:
  108. pass
  109. try:
  110. self.clientProtocol.transport.loseConnection()
  111. except AttributeError:
  112. pass
  113. try:
  114. self.serverProtocol.transport.loseConnection()
  115. except AttributeError:
  116. pass
  117. return defer.gatherResults(
  118. [defer.maybeDeferred(p.stopListening) for p in self.openPorts])
  119. def test_portforward(self):
  120. """
  121. Test port forwarding through Echo protocol.
  122. """
  123. realServerFactory = protocol.ServerFactory()
  124. realServerFactory.protocol = lambda: self.serverProtocol
  125. realServerPort = reactor.listenTCP(0, realServerFactory,
  126. interface='127.0.0.1')
  127. self.openPorts.append(realServerPort)
  128. self.proxyServerFactory = TestableProxyFactory('127.0.0.1',
  129. realServerPort.getHost().port)
  130. proxyServerPort = reactor.listenTCP(0, self.proxyServerFactory,
  131. interface='127.0.0.1')
  132. self.openPorts.append(proxyServerPort)
  133. nBytes = 1000
  134. received = []
  135. d = defer.Deferred()
  136. def testDataReceived(data):
  137. received.extend(iterbytes(data))
  138. if len(received) >= nBytes:
  139. self.assertEqual(b''.join(received), b'x' * nBytes)
  140. d.callback(None)
  141. self.clientProtocol.dataReceived = testDataReceived
  142. def testConnectionMade():
  143. self.clientProtocol.transport.write(b'x' * nBytes)
  144. self.clientProtocol.connectionMade = testConnectionMade
  145. clientFactory = protocol.ClientFactory()
  146. clientFactory.protocol = lambda: self.clientProtocol
  147. reactor.connectTCP(
  148. '127.0.0.1', proxyServerPort.getHost().port, clientFactory)
  149. return d
  150. def test_registerProducers(self):
  151. """
  152. The proxy client registers itself as a producer of the proxy server and
  153. vice versa.
  154. """
  155. # create a ProxyServer instance
  156. addr = address.IPv4Address('TCP', '127.0.0.1', 0)
  157. server = portforward.ProxyFactory('127.0.0.1', 0).buildProtocol(addr)
  158. # set the reactor for this test
  159. reactor = proto_helpers.MemoryReactor()
  160. server.reactor = reactor
  161. # make the connection
  162. serverTransport = proto_helpers.StringTransport()
  163. server.makeConnection(serverTransport)
  164. # check that the ProxyClientFactory is connecting to the backend
  165. self.assertEqual(len(reactor.tcpClients), 1)
  166. # get the factory instance and check it's the one we expect
  167. host, port, clientFactory, timeout, _ = reactor.tcpClients[0]
  168. self.assertIsInstance(clientFactory, portforward.ProxyClientFactory)
  169. # Connect it
  170. client = clientFactory.buildProtocol(addr)
  171. clientTransport = proto_helpers.StringTransport()
  172. client.makeConnection(clientTransport)
  173. # check that the producers are registered
  174. self.assertIs(clientTransport.producer, serverTransport)
  175. self.assertIs(serverTransport.producer, clientTransport)
  176. # check the streaming attribute in both transports
  177. self.assertTrue(clientTransport.streaming)
  178. self.assertTrue(serverTransport.streaming)
  179. class StringTransportTests(unittest.TestCase):
  180. """
  181. Test L{proto_helpers.StringTransport} helper behaviour.
  182. """
  183. def test_noUnicode(self):
  184. """
  185. Test that L{proto_helpers.StringTransport} doesn't accept unicode data.
  186. """
  187. s = proto_helpers.StringTransport()
  188. self.assertRaises(TypeError, s.write, u'foo')