blob: 4a70e59ba4f23e1d3cbfc874bf6514bd267f49cc [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
Neal Norwitz909eb122006-06-12 02:13:21 +00005import errno
Georg Brandl61fdd712008-02-02 11:05:00 +00006import imp
Jeffrey Yasskin180997b2008-02-28 05:53:18 +00007import os
Guido van Rossum39f1b362001-07-10 11:52:38 +00008import select
Jeffrey Yasskin180997b2008-02-28 05:53:18 +00009import signal
10import socket
11import tempfile
Guido van Rossum39f1b362001-07-10 11:52:38 +000012import threading
Jeffrey Yasskin180997b2008-02-28 05:53:18 +000013import time
Georg Brandl61fdd712008-02-02 11:05:00 +000014import unittest
15import SocketServer
16
17import test.test_support
18from test.test_support import reap_children, verbose, TestSkipped
19from test.test_support import TESTFN as TEST_FILE
20
21test.test_support.requires("network")
Guido van Rossum39f1b362001-07-10 11:52:38 +000022
23NREQ = 3
Georg Brandl61fdd712008-02-02 11:05:00 +000024TEST_STR = "hello world\n"
25HOST = "localhost"
26
27HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
28HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
29
Guido van Rossum39f1b362001-07-10 11:52:38 +000030
Guido van Rossum39f1b362001-07-10 11:52:38 +000031def receive(sock, n, timeout=20):
32 r, w, x = select.select([sock], [], [], timeout)
33 if sock in r:
34 return sock.recv(n)
35 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +000036 raise RuntimeError, "timed out on %r" % (sock,)
Guido van Rossum39f1b362001-07-10 11:52:38 +000037
Amaury Forgeot d'Arc72a65762008-02-03 23:57:24 +000038if HAVE_UNIX_SOCKETS:
39 class ForkingUnixStreamServer(SocketServer.ForkingMixIn,
40 SocketServer.UnixStreamServer):
41 pass
Georg Brandl61fdd712008-02-02 11:05:00 +000042
Amaury Forgeot d'Arc72a65762008-02-03 23:57:24 +000043 class ForkingUnixDatagramServer(SocketServer.ForkingMixIn,
44 SocketServer.UnixDatagramServer):
45 pass
Georg Brandl61fdd712008-02-02 11:05:00 +000046
47
48class MyMixinServer:
49 def serve_a_few(self):
50 for i in range(NREQ):
51 self.handle_request()
52
53 def handle_error(self, request, client_address):
54 self.close_request(request)
55 self.server_close()
56 raise
57
Guido van Rossum39f1b362001-07-10 11:52:38 +000058
59class ServerThread(threading.Thread):
60 def __init__(self, addr, svrcls, hdlrcls):
61 threading.Thread.__init__(self)
62 self.__addr = addr
63 self.__svrcls = svrcls
64 self.__hdlrcls = hdlrcls
Guido van Rossumb1bb01e2007-04-04 17:43:02 +000065 self.ready = threading.Event()
Georg Brandl61fdd712008-02-02 11:05:00 +000066
Guido van Rossum39f1b362001-07-10 11:52:38 +000067 def run(self):
68 class svrcls(MyMixinServer, self.__svrcls):
69 pass
70 if verbose: print "thread: creating server"
71 svr = svrcls(self.__addr, self.__hdlrcls)
Jeffrey Yasskin180997b2008-02-28 05:53:18 +000072 # We had the OS pick a port, so pull the real address out of
73 # the server.
74 self.addr = svr.server_address
75 self.port = self.addr[1]
76 if self.addr != svr.socket.getsockname():
77 raise RuntimeError('server_address was %s, expected %s' %
78 (self.addr, svr.socket.getsockname()))
Guido van Rossumb1bb01e2007-04-04 17:43:02 +000079 self.ready.set()
Guido van Rossum39f1b362001-07-10 11:52:38 +000080 if verbose: print "thread: serving three times"
81 svr.serve_a_few()
82 if verbose: print "thread: done"
83
Guido van Rossum39f1b362001-07-10 11:52:38 +000084
Georg Brandl61fdd712008-02-02 11:05:00 +000085class SocketServerTest(unittest.TestCase):
86 """Test all socket servers."""
Guido van Rossum39f1b362001-07-10 11:52:38 +000087
Georg Brandl61fdd712008-02-02 11:05:00 +000088 def setUp(self):
Jeffrey Yasskin180997b2008-02-28 05:53:18 +000089 signal.alarm(20) # Kill deadlocks after 20 seconds.
Georg Brandl61fdd712008-02-02 11:05:00 +000090 self.port_seed = 0
91 self.test_files = []
Neal Norwitzb476fdf2006-08-15 04:58:28 +000092
Georg Brandl61fdd712008-02-02 11:05:00 +000093 def tearDown(self):
94 reap_children()
95
96 for fn in self.test_files:
97 try:
98 os.remove(fn)
99 except os.error:
100 pass
101 self.test_files[:] = []
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000102 signal.alarm(0) # Didn't deadlock.
Georg Brandl61fdd712008-02-02 11:05:00 +0000103
104 def pickaddr(self, proto):
105 if proto == socket.AF_INET:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000106 return (HOST, 0)
Georg Brandl61fdd712008-02-02 11:05:00 +0000107 else:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000108 # XXX: We need a way to tell AF_UNIX to pick its own name
109 # like AF_INET provides port==0.
110 dir = None
111 if os.name == 'os2':
112 dir = '\socket'
113 fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
Georg Brandl61fdd712008-02-02 11:05:00 +0000114 if os.name == 'os2':
115 # AF_UNIX socket names on OS/2 require a specific prefix
116 # which can't include a drive letter and must also use
117 # backslashes as directory separators
118 if fn[1] == ':':
119 fn = fn[2:]
120 if fn[0] in (os.sep, os.altsep):
121 fn = fn[1:]
Georg Brandl61fdd712008-02-02 11:05:00 +0000122 if os.sep == '/':
123 fn = fn.replace(os.sep, os.altsep)
124 else:
125 fn = fn.replace(os.altsep, os.sep)
126 self.test_files.append(fn)
127 return fn
128
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000129 def run_server(self, svrcls, hdlrbase, testfunc):
130 class MyHandler(hdlrbase):
131 def handle(self):
132 line = self.rfile.readline()
133 self.wfile.write(line)
134
135 addr = self.pickaddr(svrcls.address_family)
136 if verbose:
137 print "ADDR =", addr
138 print "CLASS =", svrcls
139 t = ServerThread(addr, svrcls, MyHandler)
140 if verbose: print "server created"
141 t.start()
142 if verbose: print "server running"
143 t.ready.wait(10)
144 self.assert_(t.ready.isSet(),
145 "%s not ready within a reasonable time" % svrcls)
146 addr = t.addr
147 for i in range(NREQ):
148 if verbose: print "test client", i
149 testfunc(svrcls.address_family, addr)
150 if verbose: print "waiting for server"
151 t.join()
152 if verbose: print "done"
Georg Brandl61fdd712008-02-02 11:05:00 +0000153
154 def stream_examine(self, proto, addr):
155 s = socket.socket(proto, socket.SOCK_STREAM)
156 s.connect(addr)
157 s.sendall(TEST_STR)
158 buf = data = receive(s, 100)
159 while data and '\n' not in buf:
160 data = receive(s, 100)
161 buf += data
162 self.assertEquals(buf, TEST_STR)
163 s.close()
164
165 def dgram_examine(self, proto, addr):
166 s = socket.socket(proto, socket.SOCK_DGRAM)
167 s.sendto(TEST_STR, addr)
168 buf = data = receive(s, 100)
169 while data and '\n' not in buf:
170 data = receive(s, 100)
171 buf += data
172 self.assertEquals(buf, TEST_STR)
173 s.close()
174
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000175 def test_TCPServer(self):
176 self.run_server(SocketServer.TCPServer,
177 SocketServer.StreamRequestHandler,
178 self.stream_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000179
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000180 def test_ThreadingTCPServer(self):
181 self.run_server(SocketServer.ThreadingTCPServer,
182 SocketServer.StreamRequestHandler,
183 self.stream_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000184
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000185 if HAVE_FORKING:
186 def test_ThreadingTCPServer(self):
187 self.run_server(SocketServer.ForkingTCPServer,
188 SocketServer.StreamRequestHandler,
189 self.stream_examine)
190
191 if HAVE_UNIX_SOCKETS:
192 def test_UnixStreamServer(self):
193 self.run_server(SocketServer.UnixStreamServer,
194 SocketServer.StreamRequestHandler,
195 self.stream_examine)
196
197 def test_ThreadingUnixStreamServer(self):
198 self.run_server(SocketServer.ThreadingUnixStreamServer,
199 SocketServer.StreamRequestHandler,
200 self.stream_examine)
201
Georg Brandl61fdd712008-02-02 11:05:00 +0000202 if HAVE_FORKING:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000203 def test_ForkingUnixStreamServer(self):
204 self.run_server(ForkingUnixStreamServer,
205 SocketServer.StreamRequestHandler,
206 self.stream_examine)
207
208 def test_UDPServer(self):
209 self.run_server(SocketServer.UDPServer,
210 SocketServer.DatagramRequestHandler,
211 self.dgram_examine)
212
213 def test_ThreadingUDPServer(self):
214 self.run_server(SocketServer.ThreadingUDPServer,
215 SocketServer.DatagramRequestHandler,
216 self.dgram_examine)
217
218 if HAVE_FORKING:
219 def test_ForkingUDPServer(self):
220 self.run_server(SocketServer.ForkingUDPServer,
221 SocketServer.DatagramRequestHandler,
222 self.dgram_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000223
224 # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
225 # client address so this cannot work:
226
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000227 # if HAVE_UNIX_SOCKETS:
228 # def test_UnixDatagramServer(self):
229 # self.run_server(SocketServer.UnixDatagramServer,
230 # SocketServer.DatagramRequestHandler,
231 # self.dgram_examine)
232 #
233 # def test_ThreadingUnixDatagramServer(self):
234 # self.run_server(SocketServer.ThreadingUnixDatagramServer,
235 # SocketServer.DatagramRequestHandler,
236 # self.dgram_examine)
237 #
Georg Brandl61fdd712008-02-02 11:05:00 +0000238 # if HAVE_FORKING:
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000239 # def test_ForkingUnixDatagramServer(self):
240 # self.run_server(SocketServer.ForkingUnixDatagramServer,
241 # SocketServer.DatagramRequestHandler,
242 # self.dgram_examine)
Georg Brandl61fdd712008-02-02 11:05:00 +0000243
Guido van Rossum39f1b362001-07-10 11:52:38 +0000244
Tim Petersa9f6f222001-09-17 23:56:20 +0000245def test_main():
Tim Petersa9f6f222001-09-17 23:56:20 +0000246 if imp.lock_held():
Georg Brandl61fdd712008-02-02 11:05:00 +0000247 # If the import lock is held, the threads will hang
Tim Petersa9f6f222001-09-17 23:56:20 +0000248 raise TestSkipped("can't run when import lock is held")
249
Georg Brandl61fdd712008-02-02 11:05:00 +0000250 test.test_support.run_unittest(SocketServerTest)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000251
Tim Petersa9f6f222001-09-17 23:56:20 +0000252if __name__ == "__main__":
253 test_main()
Jeffrey Yasskin180997b2008-02-28 05:53:18 +0000254 signal.alarm(3) # Shutdown shouldn't take more than 3 seconds.