/Lib/test/test_socketserver.py

http://unladen-swallow.googlecode.com/ · Python · 256 lines · 183 code · 38 blank · 35 comment · 37 complexity · 7b5ab8cb1d9eb70fc750f7e55514319e MD5 · raw file

  1. """
  2. Test suite for SocketServer.py.
  3. """
  4. import contextlib
  5. import errno
  6. import imp
  7. import os
  8. import select
  9. import signal
  10. import socket
  11. import tempfile
  12. import threading
  13. import time
  14. import unittest
  15. import SocketServer
  16. import test.test_support
  17. from test.test_support import reap_children, verbose, TestSkipped
  18. from test.test_support import TESTFN as TEST_FILE
  19. test.test_support.requires("network")
  20. TEST_STR = "hello world\n"
  21. HOST = test.test_support.HOST
  22. HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
  23. HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
  24. def signal_alarm(n):
  25. """Call signal.alarm when it exists (i.e. not on Windows)."""
  26. if hasattr(signal, 'alarm'):
  27. signal.alarm(n)
  28. def receive(sock, n, timeout=20):
  29. r, w, x = select.select([sock], [], [], timeout)
  30. if sock in r:
  31. return sock.recv(n)
  32. else:
  33. raise RuntimeError, "timed out on %r" % (sock,)
  34. if HAVE_UNIX_SOCKETS:
  35. class ForkingUnixStreamServer(SocketServer.ForkingMixIn,
  36. SocketServer.UnixStreamServer):
  37. pass
  38. class ForkingUnixDatagramServer(SocketServer.ForkingMixIn,
  39. SocketServer.UnixDatagramServer):
  40. pass
  41. @contextlib.contextmanager
  42. def simple_subprocess(testcase):
  43. pid = os.fork()
  44. if pid == 0:
  45. # Don't throw an exception; it would be caught by the test harness.
  46. os._exit(72)
  47. yield None
  48. pid2, status = os.waitpid(pid, 0)
  49. testcase.assertEquals(pid2, pid)
  50. testcase.assertEquals(72 << 8, status)
  51. class SocketServerTest(unittest.TestCase):
  52. """Test all socket servers."""
  53. def setUp(self):
  54. signal_alarm(20) # Kill deadlocks after 20 seconds.
  55. self.port_seed = 0
  56. self.test_files = []
  57. def tearDown(self):
  58. signal_alarm(0) # Didn't deadlock.
  59. reap_children()
  60. for fn in self.test_files:
  61. try:
  62. os.remove(fn)
  63. except os.error:
  64. pass
  65. self.test_files[:] = []
  66. def pickaddr(self, proto):
  67. if proto == socket.AF_INET:
  68. return (HOST, 0)
  69. else:
  70. # XXX: We need a way to tell AF_UNIX to pick its own name
  71. # like AF_INET provides port==0.
  72. dir = None
  73. if os.name == 'os2':
  74. dir = '\socket'
  75. fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
  76. if os.name == 'os2':
  77. # AF_UNIX socket names on OS/2 require a specific prefix
  78. # which can't include a drive letter and must also use
  79. # backslashes as directory separators
  80. if fn[1] == ':':
  81. fn = fn[2:]
  82. if fn[0] in (os.sep, os.altsep):
  83. fn = fn[1:]
  84. if os.sep == '/':
  85. fn = fn.replace(os.sep, os.altsep)
  86. else:
  87. fn = fn.replace(os.altsep, os.sep)
  88. self.test_files.append(fn)
  89. return fn
  90. def make_server(self, addr, svrcls, hdlrbase):
  91. class MyServer(svrcls):
  92. def handle_error(self, request, client_address):
  93. self.close_request(request)
  94. self.server_close()
  95. raise
  96. class MyHandler(hdlrbase):
  97. def handle(self):
  98. line = self.rfile.readline()
  99. self.wfile.write(line)
  100. if verbose: print "creating server"
  101. server = MyServer(addr, MyHandler)
  102. self.assertEquals(server.server_address, server.socket.getsockname())
  103. return server
  104. def run_server(self, svrcls, hdlrbase, testfunc):
  105. server = self.make_server(self.pickaddr(svrcls.address_family),
  106. svrcls, hdlrbase)
  107. # We had the OS pick a port, so pull the real address out of
  108. # the server.
  109. addr = server.server_address
  110. if verbose:
  111. print "server created"
  112. print "ADDR =", addr
  113. print "CLASS =", svrcls
  114. t = threading.Thread(
  115. name='%s serving' % svrcls,
  116. target=server.serve_forever,
  117. # Short poll interval to make the test finish quickly.
  118. # Time between requests is short enough that we won't wake
  119. # up spuriously too many times.
  120. kwargs={'poll_interval':0.01})
  121. t.daemon = True # In case this function raises.
  122. t.start()
  123. if verbose: print "server running"
  124. for i in range(3):
  125. if verbose: print "test client", i
  126. testfunc(svrcls.address_family, addr)
  127. if verbose: print "waiting for server"
  128. server.shutdown()
  129. t.join()
  130. if verbose: print "done"
  131. def stream_examine(self, proto, addr):
  132. s = socket.socket(proto, socket.SOCK_STREAM)
  133. s.connect(addr)
  134. s.sendall(TEST_STR)
  135. buf = data = receive(s, 100)
  136. while data and '\n' not in buf:
  137. data = receive(s, 100)
  138. buf += data
  139. self.assertEquals(buf, TEST_STR)
  140. s.close()
  141. def dgram_examine(self, proto, addr):
  142. s = socket.socket(proto, socket.SOCK_DGRAM)
  143. s.sendto(TEST_STR, addr)
  144. buf = data = receive(s, 100)
  145. while data and '\n' not in buf:
  146. data = receive(s, 100)
  147. buf += data
  148. self.assertEquals(buf, TEST_STR)
  149. s.close()
  150. def test_TCPServer(self):
  151. self.run_server(SocketServer.TCPServer,
  152. SocketServer.StreamRequestHandler,
  153. self.stream_examine)
  154. def test_ThreadingTCPServer(self):
  155. self.run_server(SocketServer.ThreadingTCPServer,
  156. SocketServer.StreamRequestHandler,
  157. self.stream_examine)
  158. if HAVE_FORKING:
  159. def test_ForkingTCPServer(self):
  160. with simple_subprocess(self):
  161. self.run_server(SocketServer.ForkingTCPServer,
  162. SocketServer.StreamRequestHandler,
  163. self.stream_examine)
  164. if HAVE_UNIX_SOCKETS:
  165. def test_UnixStreamServer(self):
  166. self.run_server(SocketServer.UnixStreamServer,
  167. SocketServer.StreamRequestHandler,
  168. self.stream_examine)
  169. def test_ThreadingUnixStreamServer(self):
  170. self.run_server(SocketServer.ThreadingUnixStreamServer,
  171. SocketServer.StreamRequestHandler,
  172. self.stream_examine)
  173. if HAVE_FORKING:
  174. def test_ForkingUnixStreamServer(self):
  175. with simple_subprocess(self):
  176. self.run_server(ForkingUnixStreamServer,
  177. SocketServer.StreamRequestHandler,
  178. self.stream_examine)
  179. def test_UDPServer(self):
  180. self.run_server(SocketServer.UDPServer,
  181. SocketServer.DatagramRequestHandler,
  182. self.dgram_examine)
  183. def test_ThreadingUDPServer(self):
  184. self.run_server(SocketServer.ThreadingUDPServer,
  185. SocketServer.DatagramRequestHandler,
  186. self.dgram_examine)
  187. if HAVE_FORKING:
  188. def test_ForkingUDPServer(self):
  189. with simple_subprocess(self):
  190. self.run_server(SocketServer.ForkingUDPServer,
  191. SocketServer.DatagramRequestHandler,
  192. self.dgram_examine)
  193. # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
  194. # client address so this cannot work:
  195. # if HAVE_UNIX_SOCKETS:
  196. # def test_UnixDatagramServer(self):
  197. # self.run_server(SocketServer.UnixDatagramServer,
  198. # SocketServer.DatagramRequestHandler,
  199. # self.dgram_examine)
  200. #
  201. # def test_ThreadingUnixDatagramServer(self):
  202. # self.run_server(SocketServer.ThreadingUnixDatagramServer,
  203. # SocketServer.DatagramRequestHandler,
  204. # self.dgram_examine)
  205. #
  206. # if HAVE_FORKING:
  207. # def test_ForkingUnixDatagramServer(self):
  208. # self.run_server(SocketServer.ForkingUnixDatagramServer,
  209. # SocketServer.DatagramRequestHandler,
  210. # self.dgram_examine)
  211. def test_main():
  212. if imp.lock_held():
  213. # If the import lock is held, the threads will hang
  214. raise TestSkipped("can't run when import lock is held")
  215. test.test_support.run_unittest(SocketServerTest)
  216. if __name__ == "__main__":
  217. test_main()
  218. signal_alarm(3) # Shutdown shouldn't take more than 3 seconds.