test_socket.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for implementations of L{IReactorSocket}.
  5. Generally only tests for failure cases are found here. Success cases for
  6. this interface are tested elsewhere. For example, the success case for
  7. I{AF_INET} is in L{twisted.internet.test.test_tcp}, since that case should
  8. behave exactly the same as L{IReactorTCP.listenTCP}.
  9. """
  10. import errno, socket
  11. from zope.interface import verify
  12. from twisted.python.log import err
  13. from twisted.internet.interfaces import IReactorSocket
  14. from twisted.internet.error import UnsupportedAddressFamily
  15. from twisted.internet.protocol import DatagramProtocol, ServerFactory
  16. from twisted.internet.test.reactormixins import (
  17. ReactorBuilder, needsRunningReactor)
  18. from twisted.python.compat import _PY3
  19. from twisted.python.runtime import platform
  20. class IReactorSocketVerificationTestsBuilder(ReactorBuilder):
  21. """
  22. Builder for testing L{IReactorSocket} implementations for required
  23. methods and method signatures.
  24. L{ReactorBuilder} already runs L{IReactorSocket.providedBy} to
  25. ensure that these tests will only be run on reactor classes that
  26. claim to implement L{IReactorSocket}.
  27. These tests ensure that reactors which claim to provide the
  28. L{IReactorSocket} interface actually have all the required methods
  29. and that those methods have the expected number of arguments.
  30. These tests will be skipped for reactors which do not claim to
  31. provide L{IReactorSocket}.
  32. """
  33. requiredInterfaces = [IReactorSocket]
  34. def test_provider(self):
  35. """
  36. The reactor instance returned by C{buildReactor} provides
  37. L{IReactorSocket}.
  38. """
  39. reactor = self.buildReactor()
  40. self.assertTrue(
  41. verify.verifyObject(IReactorSocket, reactor))
  42. class AdoptStreamPortErrorsTestsBuilder(ReactorBuilder):
  43. """
  44. Builder for testing L{IReactorSocket.adoptStreamPort} implementations.
  45. Generally only tests for failure cases are found here. Success cases for
  46. this interface are tested elsewhere. For example, the success case for
  47. I{AF_INET} is in L{twisted.internet.test.test_tcp}, since that case should
  48. behave exactly the same as L{IReactorTCP.listenTCP}.
  49. """
  50. requiredInterfaces = [IReactorSocket]
  51. def test_invalidDescriptor(self):
  52. """
  53. An implementation of L{IReactorSocket.adoptStreamPort} raises
  54. L{socket.error} if passed an integer which is not associated with a
  55. socket.
  56. """
  57. reactor = self.buildReactor()
  58. probe = socket.socket()
  59. fileno = probe.fileno()
  60. probe.close()
  61. exc = self.assertRaises(
  62. socket.error,
  63. reactor.adoptStreamPort, fileno, socket.AF_INET, ServerFactory())
  64. if platform.isWindows() and _PY3:
  65. self.assertEqual(exc.args[0], errno.WSAENOTSOCK)
  66. else:
  67. self.assertEqual(exc.args[0], errno.EBADF)
  68. def test_invalidAddressFamily(self):
  69. """
  70. An implementation of L{IReactorSocket.adoptStreamPort} raises
  71. L{UnsupportedAddressFamily} if passed an address family it does not
  72. support.
  73. """
  74. reactor = self.buildReactor()
  75. port = socket.socket()
  76. port.bind(("127.0.0.1", 0))
  77. port.listen(1)
  78. self.addCleanup(port.close)
  79. arbitrary = 2 ** 16 + 7
  80. self.assertRaises(
  81. UnsupportedAddressFamily,
  82. reactor.adoptStreamPort, port.fileno(), arbitrary, ServerFactory())
  83. def test_stopOnlyCloses(self):
  84. """
  85. When the L{IListeningPort} returned by
  86. L{IReactorSocket.adoptStreamPort} is stopped using
  87. C{stopListening}, the underlying socket is closed but not
  88. shutdown. This allows another process which still has a
  89. reference to it to continue accepting connections over it.
  90. """
  91. reactor = self.buildReactor()
  92. portSocket = socket.socket()
  93. self.addCleanup(portSocket.close)
  94. portSocket.bind(("127.0.0.1", 0))
  95. portSocket.listen(1)
  96. portSocket.setblocking(False)
  97. # The file descriptor is duplicated by adoptStreamPort
  98. port = reactor.adoptStreamPort(
  99. portSocket.fileno(), portSocket.family, ServerFactory())
  100. d = port.stopListening()
  101. def stopped(ignored):
  102. # Should still be possible to accept a connection on
  103. # portSocket. If it was shutdown, the exception would be
  104. # EINVAL instead.
  105. exc = self.assertRaises(socket.error, portSocket.accept)
  106. if platform.isWindows() and _PY3:
  107. self.assertEqual(exc.args[0], errno.WSAEWOULDBLOCK)
  108. else:
  109. self.assertEqual(exc.args[0], errno.EAGAIN)
  110. d.addCallback(stopped)
  111. d.addErrback(err, "Failed to accept on original port.")
  112. needsRunningReactor(
  113. reactor,
  114. lambda: d.addCallback(lambda ignored: reactor.stop()))
  115. reactor.run()
  116. class AdoptStreamConnectionErrorsTestsBuilder(ReactorBuilder):
  117. """
  118. Builder for testing L{IReactorSocket.adoptStreamConnection}
  119. implementations.
  120. Generally only tests for failure cases are found here. Success cases for
  121. this interface are tested elsewhere. For example, the success case for
  122. I{AF_INET} is in L{twisted.internet.test.test_tcp}, since that case should
  123. behave exactly the same as L{IReactorTCP.listenTCP}.
  124. """
  125. requiredInterfaces = [IReactorSocket]
  126. def test_invalidAddressFamily(self):
  127. """
  128. An implementation of L{IReactorSocket.adoptStreamConnection} raises
  129. L{UnsupportedAddressFamily} if passed an address family it does not
  130. support.
  131. """
  132. reactor = self.buildReactor()
  133. connection = socket.socket()
  134. self.addCleanup(connection.close)
  135. arbitrary = 2 ** 16 + 7
  136. self.assertRaises(
  137. UnsupportedAddressFamily,
  138. reactor.adoptStreamConnection, connection.fileno(), arbitrary,
  139. ServerFactory())
  140. class AdoptDatagramPortErrorsTestsBuilder(ReactorBuilder):
  141. """
  142. Builder for testing L{IReactorSocket.adoptDatagramPort} implementations.
  143. """
  144. requiredInterfaces = [IReactorSocket]
  145. def test_invalidDescriptor(self):
  146. """
  147. An implementation of L{IReactorSocket.adoptDatagramPort} raises
  148. L{socket.error} if passed an integer which is not associated with a
  149. socket.
  150. """
  151. reactor = self.buildReactor()
  152. probe = socket.socket()
  153. fileno = probe.fileno()
  154. probe.close()
  155. exc = self.assertRaises(
  156. socket.error,
  157. reactor.adoptDatagramPort, fileno, socket.AF_INET,
  158. DatagramProtocol())
  159. if platform.isWindows() and _PY3:
  160. self.assertEqual(exc.args[0], errno.WSAENOTSOCK)
  161. else:
  162. self.assertEqual(exc.args[0], errno.EBADF)
  163. def test_invalidAddressFamily(self):
  164. """
  165. An implementation of L{IReactorSocket.adoptDatagramPort} raises
  166. L{UnsupportedAddressFamily} if passed an address family it does not
  167. support.
  168. """
  169. reactor = self.buildReactor()
  170. port = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  171. self.addCleanup(port.close)
  172. arbitrary = 2 ** 16 + 7
  173. self.assertRaises(
  174. UnsupportedAddressFamily,
  175. reactor.adoptDatagramPort, port.fileno(), arbitrary,
  176. DatagramProtocol())
  177. def test_stopOnlyCloses(self):
  178. """
  179. When the L{IListeningPort} returned by
  180. L{IReactorSocket.adoptDatagramPort} is stopped using
  181. C{stopListening}, the underlying socket is closed but not
  182. shutdown. This allows another process which still has a
  183. reference to it to continue reading and writing to it.
  184. """
  185. reactor = self.buildReactor()
  186. portSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  187. self.addCleanup(portSocket.close)
  188. portSocket.bind(("127.0.0.1", 0))
  189. portSocket.setblocking(False)
  190. # The file descriptor is duplicated by adoptDatagramPort
  191. port = reactor.adoptDatagramPort(
  192. portSocket.fileno(), portSocket.family, DatagramProtocol())
  193. d = port.stopListening()
  194. def stopped(ignored):
  195. # Should still be possible to recv on portSocket. If
  196. # it was shutdown, the exception would be EINVAL instead.
  197. exc = self.assertRaises(socket.error, portSocket.recvfrom, 1)
  198. if platform.isWindows() and _PY3:
  199. self.assertEqual(exc.args[0], errno.WSAEWOULDBLOCK)
  200. else:
  201. self.assertEqual(exc.args[0], errno.EAGAIN)
  202. d.addCallback(stopped)
  203. d.addErrback(err, "Failed to read on original port.")
  204. needsRunningReactor(
  205. reactor,
  206. lambda: d.addCallback(lambda ignored: reactor.stop()))
  207. reactor.run()
  208. globals().update(IReactorSocketVerificationTestsBuilder.makeTestCaseClasses())
  209. globals().update(AdoptStreamPortErrorsTestsBuilder.makeTestCaseClasses())
  210. globals().update(AdoptStreamConnectionErrorsTestsBuilder.makeTestCaseClasses())
  211. globals().update(AdoptDatagramPortErrorsTestsBuilder.makeTestCaseClasses())