blob: 92e5d045a85e1836f54c5c447337315b41df6655 [file] [log] [blame]
Georg Brandl61fdd712008-02-02 11:05:00 +00001"""
2Test suite for SocketServer.py.
3"""
Guido van Rossum39f1b362001-07-10 11:52:38 +00004
Jeffrey Yasskin392c159a2008-02-28 18:03:15 +00005import contextlib
Neal Norwitz909eb122006-06-12 02:13:21 +00006import errno
Georg Brandl61fdd712008-02-02 11:05:00 +00007import imp
Jeffrey Yasskin180997b2008-02-28 05:53:18 +00008import os
Guido van Rossum39f1b362001-07-10 11:52:38 +00009import select
Jeffrey Yasskin180997b2008-02-28 05:53:18 +000010import signal
11import socket
12import tempfile
Guido van Rossum39f1b362001-07-10 11:52:38 +000013import threading
Jeffrey Yasskin180997b2008-02-28 05:53:18 +000014import time
Georg Brandl61fdd712008-02-02 11:05:00 +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
Georg Brandl61fdd712008-02-02 11:05:00 +000025TEST_STR = "hello world\n"
26HOST = "localhost"
27
28HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
29HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
30
Jeffrey Yasskinf28896d2008-03-05 06:19:56 +000031def signal_alarm(n):
32 """Call signal.alarm when it exists (i.e. not on Windows)."""
33 if hasattr(signal, 'alarm'):
34 signal.alarm(n)
Guido van Rossum39f1b362001-07-10 11:52:38 +000035
Guido van Rossum39f1b362001-07-10 11:52:38 +000036def receive(sock, n, timeout=20):
37 r, w, x = select.select([sock], [], [], timeout)
38 if sock in r:
39 return sock.recv(n)
40 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +000041 raise RuntimeError, "timed out on %r" % (sock,)
Guido van Rossum39f1b362001-07-10 11:52:38 +000042
Amaury Forgeot d'Arc72a65762008-02-03 23:57:24 +000043if HAVE_UNIX_SOCKETS:
44 class ForkingUnixStreamServer(SocketServer.ForkingMixIn,
45 SocketServer.UnixStreamServer):
46 pass
Georg Brandl61fdd712008-02-02 11:05:00 +000047
Amaury Forgeot d'Arc72a65762008-02-03 23:57:24 +000048 class ForkingUnixDatagramServer(SocketServer.ForkingMixIn,
49 SocketServer.UnixDatagramServer):
50 pass
Georg Brandl61fdd712008-02-02 11:05:00 +000051
52
53class MyMixinServer:
54 def serve_a_few(self):
55 for i in range(NREQ):
56 self.handle_request()
57
58 def handle_error(self, request, client_address):
59 self.close_request(request)
60 self.server_close()
61 raise
62
Guido van Rossum39f1b362001-07-10 11:52:38 +000063
64class ServerThread(threading.Thread):
65 def __init__(self, addr, svrcls, hdlrcls):
66 threading.Thread.__init__(self)
67 self.__addr = addr
68 self.__svrcls = svrcls
69 self.__hdlrcls = hdlrcls
Guido van Rossumb1bb01e2007-04-04 17:43:02 +000070 self.ready = threading.Event()
Georg Brandl61fdd712008-02-02 11:05:00 +000071
Guido van Rossum39f1b362001-07-10 11:52:38 +000072 def run(self):
73 class svrcls(MyMixinServer, self.__svrcls):
74 pass
75 if verbose: print "thread: creating server"
76 svr = svrcls(self.__addr, self.__hdlrcls)
Jeffrey Yasskin180997b2008-02-28 05:53:18 +000077 # We had the OS pick a port, so pull the real address out of
78 # the server.
79 self.addr = svr.server_address
80 self.port = self.addr[1]
81 if self.addr != svr.socket.getsockname():
82 raise RuntimeError('server_address was %s, expected %s' %
83 (self.addr, svr.socket.getsockname()))
Guido van Rossumb1bb01e2007-04-04 17:43:02 +000084 self.ready.set()
Guido van Rossum39f1b362001-07-10 11:52:38 +000085 if verbose: print "thread: serving three times"
86 svr.serve_a_few()
87 if verbose: print "thread: done"
88
Guido van Rossum39f1b362001-07-10 11:52:38 +000089
Jeffrey Yasskin392c159a2008-02-28 18:03:15 +000090@contextlib.contextmanager
91def simple_subprocess(testcase):
92 pid = os.fork()
93 if pid == 0:
94 # Don't throw an exception; it would be caught by the test harness.
95 os._exit(72)
96 yield None
97 pid2, status = os.waitpid(pid, 0)
98 testcase.assertEquals(pid2, pid)
99 testcase.assertEquals(72 << 8, status)
100
101
Georg Brandl61fdd712008-02-02 11:05:00 +0000102class SocketServerTest(unittest.TestCase):
103 """Test all socket servers."""
Guido van Rossum39f1b362001-07-10 11:52:38 +0000104
Georg Brandl61fdd712008-02-02 11:05:00 +0000105 def setUp(self):
Jeffrey Yasskinf28896d2008-03-05 06:19:56 +0000106 signal_alarm(20) # Kill deadlocks after 20 seconds.
Georg Brandl61fdd712008-02-02 11:05:00 +0000107 self.port_seed = 0
108 self.test_files = []
Neal Norwitzb476fdf2006-08-15 04:58:28 +0000109
Georg Brandl61fdd712008-02-02 11:05:00 +0000110 def tearDown(self):
111 reap_children()
112
113 for fn in self.test_files:
114 try:
115 os.remove(fn)
116 except os.error:
117 pass
118 self.test_files[:] = []
Jeffrey Yasskinf28896d2008-03-05 06:19:56 +0000119 signal_alarm(0) # Didn't deadlock.
Georg Brandl61fdd712008-02-02 11:05:00 +0000120
121 def pickaddr(self, proto):
122 if proto == socket.AF_INET:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000123 return (HOST, 0)
Georg Brandl61fdd712008-02-02 11:05:00 +0000124 else:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000125 # XXX: We need a way to tell AF_UNIX to pick its own name
126 # like AF_INET provides port==0.
127 dir = None
128 if os.name == 'os2':
129 dir = '\socket'
130 fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
Georg Brandl61fdd712008-02-02 11:05:00 +0000131 if os.name == 'os2':
132 # AF_UNIX socket names on OS/2 require a specific prefix
133 # which can't include a drive letter and must also use
134 # backslashes as directory separators
135 if fn[1] == ':':
136 fn = fn[2:]
137 if fn[0] in (os.sep, os.altsep):
138 fn = fn[1:]
Georg Brandl61fdd712008-02-02 11:05:00 +0000139 if os.sep == '/':
140 fn = fn.replace(os.sep, os.altsep)
141 else:
142 fn = fn.replace(os.altsep, os.sep)
143 self.test_files.append(fn)
144 return fn
145
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000146 def run_server(self, svrcls, hdlrbase, testfunc):
147 class MyHandler(hdlrbase):
148 def handle(self):
149 line = self.rfile.readline()
150 self.wfile.write(line)
151
152 addr = self.pickaddr(svrcls.address_family)
153 if verbose:
154 print "ADDR =", addr
155 print "CLASS =", svrcls
156 t = ServerThread(addr, svrcls, MyHandler)
157 if verbose: print "server created"
158 t.start()
159 if verbose: print "server running"
160 t.ready.wait(10)
161 self.assert_(t.ready.isSet(),
162 "%s not ready within a reasonable time" % svrcls)
163 addr = t.addr
164 for i in range(NREQ):
165 if verbose: print "test client", i
166 testfunc(svrcls.address_family, addr)
167 if verbose: print "waiting for server"
168 t.join()
169 if verbose: print "done"
Georg Brandl61fdd712008-02-02 11:05:00 +0000170
171 def stream_examine(self, proto, addr):
172 s = socket.socket(proto, socket.SOCK_STREAM)
173 s.connect(addr)
174 s.sendall(TEST_STR)
175 buf = data = receive(s, 100)
176 while data and '\n' not in buf:
177 data = receive(s, 100)
178 buf += data
179 self.assertEquals(buf, TEST_STR)
180 s.close()
181
182 def dgram_examine(self, proto, addr):
183 s = socket.socket(proto, socket.SOCK_DGRAM)
184 s.sendto(TEST_STR, addr)
185 buf = data = receive(s, 100)
186 while data and '\n' not in buf:
187 data = receive(s, 100)
188 buf += data
189 self.assertEquals(buf, TEST_STR)
190 s.close()
191
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000192 def test_TCPServer(self):
193 self.run_server(SocketServer.TCPServer,
194 SocketServer.StreamRequestHandler,
195 self.stream_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000196
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000197 def test_ThreadingTCPServer(self):
198 self.run_server(SocketServer.ThreadingTCPServer,
199 SocketServer.StreamRequestHandler,
200 self.stream_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000201
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000202 if HAVE_FORKING:
Jeffrey Yasskin392c159a2008-02-28 18:03:15 +0000203 def test_ForkingTCPServer(self):
204 with simple_subprocess(self):
205 self.run_server(SocketServer.ForkingTCPServer,
206 SocketServer.StreamRequestHandler,
207 self.stream_examine)
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000208
209 if HAVE_UNIX_SOCKETS:
210 def test_UnixStreamServer(self):
211 self.run_server(SocketServer.UnixStreamServer,
212 SocketServer.StreamRequestHandler,
213 self.stream_examine)
214
215 def test_ThreadingUnixStreamServer(self):
216 self.run_server(SocketServer.ThreadingUnixStreamServer,
217 SocketServer.StreamRequestHandler,
218 self.stream_examine)
219
Georg Brandl61fdd712008-02-02 11:05:00 +0000220 if HAVE_FORKING:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000221 def test_ForkingUnixStreamServer(self):
Jeffrey Yasskin392c159a2008-02-28 18:03:15 +0000222 with simple_subprocess(self):
223 self.run_server(ForkingUnixStreamServer,
224 SocketServer.StreamRequestHandler,
225 self.stream_examine)
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000226
227 def test_UDPServer(self):
228 self.run_server(SocketServer.UDPServer,
229 SocketServer.DatagramRequestHandler,
230 self.dgram_examine)
231
232 def test_ThreadingUDPServer(self):
233 self.run_server(SocketServer.ThreadingUDPServer,
234 SocketServer.DatagramRequestHandler,
235 self.dgram_examine)
236
237 if HAVE_FORKING:
238 def test_ForkingUDPServer(self):
Jeffrey Yasskin392c159a2008-02-28 18:03:15 +0000239 with simple_subprocess(self):
240 self.run_server(SocketServer.ForkingUDPServer,
241 SocketServer.DatagramRequestHandler,
242 self.dgram_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000243
244 # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
245 # client address so this cannot work:
246
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000247 # if HAVE_UNIX_SOCKETS:
248 # def test_UnixDatagramServer(self):
249 # self.run_server(SocketServer.UnixDatagramServer,
250 # SocketServer.DatagramRequestHandler,
251 # self.dgram_examine)
252 #
253 # def test_ThreadingUnixDatagramServer(self):
254 # self.run_server(SocketServer.ThreadingUnixDatagramServer,
255 # SocketServer.DatagramRequestHandler,
256 # self.dgram_examine)
257 #
Georg Brandl61fdd712008-02-02 11:05:00 +0000258 # if HAVE_FORKING:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000259 # def test_ForkingUnixDatagramServer(self):
260 # self.run_server(SocketServer.ForkingUnixDatagramServer,
261 # SocketServer.DatagramRequestHandler,
262 # self.dgram_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000263
Guido van Rossum39f1b362001-07-10 11:52:38 +0000264
Tim Petersa9f6f222001-09-17 23:56:20 +0000265def test_main():
Tim Petersa9f6f222001-09-17 23:56:20 +0000266 if imp.lock_held():
Georg Brandl61fdd712008-02-02 11:05:00 +0000267 # If the import lock is held, the threads will hang
Tim Petersa9f6f222001-09-17 23:56:20 +0000268 raise TestSkipped("can't run when import lock is held")
269
Georg Brandl61fdd712008-02-02 11:05:00 +0000270 test.test_support.run_unittest(SocketServerTest)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000271
Tim Petersa9f6f222001-09-17 23:56:20 +0000272if __name__ == "__main__":
273 test_main()
Jeffrey Yasskinf28896d2008-03-05 06:19:56 +0000274 signal_alarm(3) # Shutdown shouldn't take more than 3 seconds.