blob: 658056c968401ce3811dc156d900580860588b14 [file] [log] [blame]
Christian Heimes292d3512008-02-03 16:51:08 +00001"""
2Test suite for SocketServer.py.
3"""
Guido van Rossum39f1b362001-07-10 11:52:38 +00004
Christian Heimes70e7ea22008-02-28 20:02:27 +00005import contextlib
Thomas Wouters0e3f5912006-08-11 14:57:12 +00006import errno
Christian Heimes292d3512008-02-03 16:51:08 +00007import imp
Christian Heimes9e7f1d22008-02-28 12:27:11 +00008import os
Guido van Rossum39f1b362001-07-10 11:52:38 +00009import select
Christian Heimes9e7f1d22008-02-28 12:27:11 +000010import signal
11import socket
12import tempfile
Guido van Rossum39f1b362001-07-10 11:52:38 +000013import threading
Christian Heimes9e7f1d22008-02-28 12:27:11 +000014import time
Christian Heimes292d3512008-02-03 16:51:08 +000015import unittest
16import SocketServer
17
18import test.test_support
19from test.test_support import reap_children, verbose, TestSkipped
20from test.test_support import TESTFN as TEST_FILE
21
22test.test_support.requires("network")
Guido van Rossum39f1b362001-07-10 11:52:38 +000023
24NREQ = 3
Christian Heimes292d3512008-02-03 16:51:08 +000025TEST_STR = b"hello world\n"
26HOST = "localhost"
27
28HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
29HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
30
Guido van Rossum39f1b362001-07-10 11:52:38 +000031
Christian Heimes292d3512008-02-03 16:51:08 +000032def receive(sock, n, timeout=20):
33 r, w, x = select.select([sock], [], [], timeout)
34 if sock in r:
35 return sock.recv(n)
36 else:
37 raise RuntimeError("timed out on %r" % (sock,))
38
Christian Heimes15ebc882008-02-04 18:48:49 +000039if HAVE_UNIX_SOCKETS:
40 class ForkingUnixStreamServer(SocketServer.ForkingMixIn,
41 SocketServer.UnixStreamServer):
42 pass
Christian Heimes292d3512008-02-03 16:51:08 +000043
Christian Heimes15ebc882008-02-04 18:48:49 +000044 class ForkingUnixDatagramServer(SocketServer.ForkingMixIn,
45 SocketServer.UnixDatagramServer):
46 pass
Christian Heimes292d3512008-02-03 16:51:08 +000047
48
Guido van Rossum39f1b362001-07-10 11:52:38 +000049class MyMixinServer:
50 def serve_a_few(self):
51 for i in range(NREQ):
52 self.handle_request()
Christian Heimes292d3512008-02-03 16:51:08 +000053
Guido van Rossum39f1b362001-07-10 11:52:38 +000054 def handle_error(self, request, client_address):
55 self.close_request(request)
56 self.server_close()
57 raise
58
Guido van Rossum39f1b362001-07-10 11:52:38 +000059def receive(sock, n, timeout=20):
60 r, w, x = select.select([sock], [], [], timeout)
61 if sock in r:
62 return sock.recv(n)
63 else:
Collin Winter3add4d72007-08-29 23:37:32 +000064 raise RuntimeError("timed out on %r" % (sock,))
Guido van Rossum39f1b362001-07-10 11:52:38 +000065
66def testdgram(proto, addr):
67 s = socket.socket(proto, socket.SOCK_DGRAM)
68 s.sendto(teststring, addr)
69 buf = data = receive(s, 100)
Guido van Rossum15863ea2007-08-03 19:03:39 +000070 while data and b'\n' not in buf:
Guido van Rossum39f1b362001-07-10 11:52:38 +000071 data = receive(s, 100)
72 buf += data
73 verify(buf == teststring)
74 s.close()
75
76def teststream(proto, addr):
77 s = socket.socket(proto, socket.SOCK_STREAM)
78 s.connect(addr)
Guido van Rossum9bd14012001-10-29 07:18:02 +000079 s.sendall(teststring)
Guido van Rossum39f1b362001-07-10 11:52:38 +000080 buf = data = receive(s, 100)
Guido van Rossum15863ea2007-08-03 19:03:39 +000081 while data and b'\n' not in buf:
Guido van Rossum39f1b362001-07-10 11:52:38 +000082 data = receive(s, 100)
83 buf += data
84 verify(buf == teststring)
85 s.close()
86
87class ServerThread(threading.Thread):
88 def __init__(self, addr, svrcls, hdlrcls):
89 threading.Thread.__init__(self)
90 self.__addr = addr
91 self.__svrcls = svrcls
92 self.__hdlrcls = hdlrcls
Guido van Rossumd8faa362007-04-27 19:54:29 +000093 self.ready = threading.Event()
Christian Heimes292d3512008-02-03 16:51:08 +000094
Guido van Rossum39f1b362001-07-10 11:52:38 +000095 def run(self):
96 class svrcls(MyMixinServer, self.__svrcls):
97 pass
Guido van Rossumbe19ed72007-02-09 05:37:30 +000098 if verbose: print("thread: creating server")
Guido van Rossum39f1b362001-07-10 11:52:38 +000099 svr = svrcls(self.__addr, self.__hdlrcls)
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000100 # We had the OS pick a port, so pull the real address out of
101 # the server.
102 self.addr = svr.server_address
103 self.port = self.addr[1]
104 if self.addr != svr.socket.getsockname():
105 raise RuntimeError('server_address was %s, expected %s' %
106 (self.addr, svr.socket.getsockname()))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000107 self.ready.set()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000108 if verbose: print("thread: serving three times")
Guido van Rossum39f1b362001-07-10 11:52:38 +0000109 svr.serve_a_few()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000110 if verbose: print("thread: done")
Guido van Rossum39f1b362001-07-10 11:52:38 +0000111
Guido van Rossum39f1b362001-07-10 11:52:38 +0000112
Christian Heimes70e7ea22008-02-28 20:02:27 +0000113@contextlib.contextmanager
114def simple_subprocess(testcase):
115 pid = os.fork()
116 if pid == 0:
117 # Don't throw an exception; it would be caught by the test harness.
118 os._exit(72)
119 yield None
120 pid2, status = os.waitpid(pid, 0)
121 testcase.assertEquals(pid2, pid)
122 testcase.assertEquals(72 << 8, status)
123
124
Christian Heimes292d3512008-02-03 16:51:08 +0000125class SocketServerTest(unittest.TestCase):
126 """Test all socket servers."""
Guido van Rossum39f1b362001-07-10 11:52:38 +0000127
Christian Heimes292d3512008-02-03 16:51:08 +0000128 def setUp(self):
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000129 signal.alarm(20) # Kill deadlocks after 20 seconds.
Christian Heimes292d3512008-02-03 16:51:08 +0000130 self.port_seed = 0
131 self.test_files = []
Guido van Rossum39f1b362001-07-10 11:52:38 +0000132
Christian Heimes292d3512008-02-03 16:51:08 +0000133 def tearDown(self):
Christian Heimes292d3512008-02-03 16:51:08 +0000134 reap_children()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000135
Christian Heimes292d3512008-02-03 16:51:08 +0000136 for fn in self.test_files:
137 try:
138 os.remove(fn)
139 except os.error:
140 pass
141 self.test_files[:] = []
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000142 signal.alarm(0) # Didn't deadlock.
Christian Heimes292d3512008-02-03 16:51:08 +0000143
144 def pickaddr(self, proto):
145 if proto == socket.AF_INET:
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000146 return (HOST, 0)
Christian Heimes292d3512008-02-03 16:51:08 +0000147 else:
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000148 # XXX: We need a way to tell AF_UNIX to pick its own name
149 # like AF_INET provides port==0.
150 dir = None
151 if os.name == 'os2':
152 dir = '\socket'
153 fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
Christian Heimes292d3512008-02-03 16:51:08 +0000154 if os.name == 'os2':
155 # AF_UNIX socket names on OS/2 require a specific prefix
156 # which can't include a drive letter and must also use
157 # backslashes as directory separators
158 if fn[1] == ':':
159 fn = fn[2:]
160 if fn[0] in (os.sep, os.altsep):
161 fn = fn[1:]
Christian Heimes292d3512008-02-03 16:51:08 +0000162 if os.sep == '/':
163 fn = fn.replace(os.sep, os.altsep)
164 else:
165 fn = fn.replace(os.altsep, os.sep)
166 self.test_files.append(fn)
167 return fn
168
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000169
170 def run_server(self, svrcls, hdlrbase, testfunc):
171 class MyHandler(hdlrbase):
172 def handle(self):
173 line = self.rfile.readline()
174 self.wfile.write(line)
175
176 addr = self.pickaddr(svrcls.address_family)
177 if verbose:
178 print("ADDR =", addr)
179 print("CLASS =", svrcls)
180 t = ServerThread(addr, svrcls, MyHandler)
181 if verbose: print("server created")
182 t.start()
183 if verbose: print("server running")
184 t.ready.wait(10)
185 self.assert_(t.ready.isSet(),
186 "%s not ready within a reasonable time" % svrcls)
187 addr = t.addr
188 for i in range(NREQ):
189 if verbose: print("test client", i)
190 testfunc(svrcls.address_family, addr)
191 if verbose: print("waiting for server")
192 t.join()
193 if verbose: print("done")
Christian Heimes292d3512008-02-03 16:51:08 +0000194
195 def stream_examine(self, proto, addr):
196 s = socket.socket(proto, socket.SOCK_STREAM)
197 s.connect(addr)
198 s.sendall(TEST_STR)
199 buf = data = receive(s, 100)
Christian Heimesfdb6bb52008-02-03 17:32:13 +0000200 while data and b'\n' not in buf:
Christian Heimes292d3512008-02-03 16:51:08 +0000201 data = receive(s, 100)
202 buf += data
203 self.assertEquals(buf, TEST_STR)
204 s.close()
205
206 def dgram_examine(self, proto, addr):
207 s = socket.socket(proto, socket.SOCK_DGRAM)
208 s.sendto(TEST_STR, addr)
209 buf = data = receive(s, 100)
Christian Heimesfdb6bb52008-02-03 17:32:13 +0000210 while data and b'\n' not in buf:
Christian Heimes292d3512008-02-03 16:51:08 +0000211 data = receive(s, 100)
212 buf += data
213 self.assertEquals(buf, TEST_STR)
214 s.close()
215
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000216 def test_TCPServer(self):
217 self.run_server(SocketServer.TCPServer,
218 SocketServer.StreamRequestHandler,
219 self.stream_examine)
Christian Heimes292d3512008-02-03 16:51:08 +0000220
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000221 def test_ThreadingTCPServer(self):
222 self.run_server(SocketServer.ThreadingTCPServer,
223 SocketServer.StreamRequestHandler,
224 self.stream_examine)
Christian Heimes292d3512008-02-03 16:51:08 +0000225
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000226 if HAVE_FORKING:
Christian Heimes70e7ea22008-02-28 20:02:27 +0000227 def test_ForkingTCPServer(self):
228 with simple_subprocess(self):
229 self.run_server(SocketServer.ForkingTCPServer,
230 SocketServer.StreamRequestHandler,
231 self.stream_examine)
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000232
233 if HAVE_UNIX_SOCKETS:
234 def test_UnixStreamServer(self):
235 self.run_server(SocketServer.UnixStreamServer,
236 SocketServer.StreamRequestHandler,
237 self.stream_examine)
238
239 def test_ThreadingUnixStreamServer(self):
240 self.run_server(SocketServer.ThreadingUnixStreamServer,
241 SocketServer.StreamRequestHandler,
242 self.stream_examine)
243
Christian Heimes292d3512008-02-03 16:51:08 +0000244 if HAVE_FORKING:
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000245 def test_ForkingUnixStreamServer(self):
Christian Heimes70e7ea22008-02-28 20:02:27 +0000246 with simple_subprocess(self):
247 self.run_server(ForkingUnixStreamServer,
248 SocketServer.StreamRequestHandler,
249 self.stream_examine)
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000250
251 def test_UDPServer(self):
252 self.run_server(SocketServer.UDPServer,
253 SocketServer.DatagramRequestHandler,
254 self.dgram_examine)
255
256 def test_ThreadingUDPServer(self):
257 self.run_server(SocketServer.ThreadingUDPServer,
258 SocketServer.DatagramRequestHandler,
259 self.dgram_examine)
260
261 if HAVE_FORKING:
262 def test_ForkingUDPServer(self):
Christian Heimes70e7ea22008-02-28 20:02:27 +0000263 with simple_subprocess(self):
264 self.run_server(SocketServer.ForkingUDPServer,
265 SocketServer.DatagramRequestHandler,
266 self.dgram_examine)
Christian Heimes292d3512008-02-03 16:51:08 +0000267
268 # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
269 # client address so this cannot work:
270
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000271 # if HAVE_UNIX_SOCKETS:
272 # def test_UnixDatagramServer(self):
273 # self.run_server(SocketServer.UnixDatagramServer,
274 # SocketServer.DatagramRequestHandler,
275 # self.dgram_examine)
276 #
277 # def test_ThreadingUnixDatagramServer(self):
278 # self.run_server(SocketServer.ThreadingUnixDatagramServer,
279 # SocketServer.DatagramRequestHandler,
280 # self.dgram_examine)
281 #
Christian Heimes292d3512008-02-03 16:51:08 +0000282 # if HAVE_FORKING:
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000283 # def test_ForkingUnixDatagramServer(self):
284 # self.run_server(SocketServer.ForkingUnixDatagramServer,
285 # SocketServer.DatagramRequestHandler,
286 # self.dgram_examine)
Christian Heimes292d3512008-02-03 16:51:08 +0000287
Guido van Rossum39f1b362001-07-10 11:52:38 +0000288
Tim Petersa9f6f222001-09-17 23:56:20 +0000289def test_main():
Tim Petersa9f6f222001-09-17 23:56:20 +0000290 if imp.lock_held():
Christian Heimes292d3512008-02-03 16:51:08 +0000291 # If the import lock is held, the threads will hang
Tim Petersa9f6f222001-09-17 23:56:20 +0000292 raise TestSkipped("can't run when import lock is held")
293
Christian Heimes292d3512008-02-03 16:51:08 +0000294 test.test_support.run_unittest(SocketServerTest)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000295
Tim Petersa9f6f222001-09-17 23:56:20 +0000296if __name__ == "__main__":
297 test_main()
Christian Heimes9e7f1d22008-02-28 12:27:11 +0000298 signal.alarm(3) # Shutdown shouldn't take more than 3 seconds.