blob: 9a67a358b7b0f29abd31f4c3ea2fddcd79fccf64 [file] [log] [blame]
Guido van Rossum39f1b362001-07-10 11:52:38 +00001# Test suite for SocketServer.py
2
Barry Warsaw04f357c2002-07-23 19:04:11 +00003from test import test_support
Neal Norwitzb15ac312006-06-29 04:10:08 +00004from test.test_support import (verbose, verify, TESTFN, TestSkipped,
5 reap_children)
Tim Petersa86f0c12001-09-18 02:18:57 +00006test_support.requires('network')
Guido van Rossum39f1b362001-07-10 11:52:38 +00007
8from SocketServer import *
9import socket
Neal Norwitz909eb122006-06-12 02:13:21 +000010import errno
Guido van Rossum39f1b362001-07-10 11:52:38 +000011import select
12import time
13import threading
14import os
15
16NREQ = 3
17DELAY = 0.5
18
19class MyMixinHandler:
20 def handle(self):
21 time.sleep(DELAY)
22 line = self.rfile.readline()
23 time.sleep(DELAY)
24 self.wfile.write(line)
25
26class MyStreamHandler(MyMixinHandler, StreamRequestHandler):
27 pass
28
29class MyDatagramHandler(MyMixinHandler, DatagramRequestHandler):
30 pass
31
32class MyMixinServer:
33 def serve_a_few(self):
34 for i in range(NREQ):
35 self.handle_request()
36 def handle_error(self, request, client_address):
37 self.close_request(request)
38 self.server_close()
39 raise
40
41teststring = "hello world\n"
42
43def receive(sock, n, timeout=20):
44 r, w, x = select.select([sock], [], [], timeout)
45 if sock in r:
46 return sock.recv(n)
47 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +000048 raise RuntimeError, "timed out on %r" % (sock,)
Guido van Rossum39f1b362001-07-10 11:52:38 +000049
50def testdgram(proto, addr):
51 s = socket.socket(proto, socket.SOCK_DGRAM)
52 s.sendto(teststring, addr)
53 buf = data = receive(s, 100)
54 while data and '\n' not in buf:
55 data = receive(s, 100)
56 buf += data
57 verify(buf == teststring)
58 s.close()
59
60def teststream(proto, addr):
61 s = socket.socket(proto, socket.SOCK_STREAM)
62 s.connect(addr)
Guido van Rossum9bd14012001-10-29 07:18:02 +000063 s.sendall(teststring)
Guido van Rossum39f1b362001-07-10 11:52:38 +000064 buf = data = receive(s, 100)
65 while data and '\n' not in buf:
66 data = receive(s, 100)
67 buf += data
68 verify(buf == teststring)
69 s.close()
70
71class ServerThread(threading.Thread):
72 def __init__(self, addr, svrcls, hdlrcls):
73 threading.Thread.__init__(self)
74 self.__addr = addr
75 self.__svrcls = svrcls
76 self.__hdlrcls = hdlrcls
77 def run(self):
78 class svrcls(MyMixinServer, self.__svrcls):
79 pass
80 if verbose: print "thread: creating server"
81 svr = svrcls(self.__addr, self.__hdlrcls)
Neal Norwitz909eb122006-06-12 02:13:21 +000082 # pull the address out of the server in case it changed
83 # this can happen if another process is using the port
Collin Winter3351aa72007-03-10 14:33:32 +000084 addr = svr.server_address
Neal Norwitz909eb122006-06-12 02:13:21 +000085 if addr:
86 self.__addr = addr
Collin Winter3351aa72007-03-10 14:33:32 +000087 if self.__addr != svr.socket.getsockname():
88 raise RuntimeError('server_address was %s, expected %s' %
89 (self.__addr, svr.socket.getsockname()))
Guido van Rossum39f1b362001-07-10 11:52:38 +000090 if verbose: print "thread: serving three times"
91 svr.serve_a_few()
92 if verbose: print "thread: done"
93
94seed = 0
95def pickport():
96 global seed
97 seed += 1
98 return 10000 + (os.getpid() % 1000)*10 + seed
99
Guido van Rossum05be1a02001-07-10 15:46:34 +0000100host = "localhost"
Guido van Rossum39f1b362001-07-10 11:52:38 +0000101testfiles = []
102def pickaddr(proto):
103 if proto == socket.AF_INET:
104 return (host, pickport())
105 else:
106 fn = TESTFN + str(pickport())
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000107 if os.name == 'os2':
108 # AF_UNIX socket names on OS/2 require a specific prefix
109 # which can't include a drive letter and must also use
110 # backslashes as directory separators
111 if fn[1] == ':':
112 fn = fn[2:]
113 if fn[0] in (os.sep, os.altsep):
114 fn = fn[1:]
115 fn = os.path.join('\socket', fn)
116 if os.sep == '/':
117 fn = fn.replace(os.sep, os.altsep)
118 else:
119 fn = fn.replace(os.altsep, os.sep)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000120 testfiles.append(fn)
121 return fn
122
123def cleanup():
124 for fn in testfiles:
125 try:
126 os.remove(fn)
127 except os.error:
128 pass
129 testfiles[:] = []
130
131def testloop(proto, servers, hdlrcls, testfunc):
132 for svrcls in servers:
133 addr = pickaddr(proto)
134 if verbose:
135 print "ADDR =", addr
136 print "CLASS =", svrcls
137 t = ServerThread(addr, svrcls, hdlrcls)
138 if verbose: print "server created"
139 t.start()
140 if verbose: print "server running"
141 for i in range(NREQ):
142 time.sleep(DELAY)
143 if verbose: print "test client", i
144 testfunc(proto, addr)
145 if verbose: print "waiting for server"
146 t.join()
147 if verbose: print "done"
148
Neal Norwitz909eb122006-06-12 02:13:21 +0000149class ForgivingTCPServer(TCPServer):
150 # prevent errors if another process is using the port we want
151 def server_bind(self):
152 host, default_port = self.server_address
153 # this code shamelessly stolen from test.test_support
154 # the ports were changed to protect the innocent
155 import sys
156 for port in [default_port, 3434, 8798, 23833]:
157 try:
158 self.server_address = host, port
159 TCPServer.server_bind(self)
160 break
161 except socket.error, (err, msg):
162 if err != errno.EADDRINUSE:
163 raise
164 print >>sys.__stderr__, \
165 ' WARNING: failed to listen on port %d, trying another' % port
166
167tcpservers = [ForgivingTCPServer, ThreadingTCPServer]
Andrew MacIntyrec6fff892003-01-02 12:49:00 +0000168if hasattr(os, 'fork') and os.name not in ('os2',):
Guido van Rossum39f1b362001-07-10 11:52:38 +0000169 tcpservers.append(ForkingTCPServer)
170udpservers = [UDPServer, ThreadingUDPServer]
Andrew MacIntyrec6fff892003-01-02 12:49:00 +0000171if hasattr(os, 'fork') and os.name not in ('os2',):
Guido van Rossum39f1b362001-07-10 11:52:38 +0000172 udpservers.append(ForkingUDPServer)
173
174if not hasattr(socket, 'AF_UNIX'):
175 streamservers = []
176 dgramservers = []
177else:
178 class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000179 streamservers = [UnixStreamServer, ThreadingUnixStreamServer]
180 if hasattr(os, 'fork') and os.name not in ('os2',):
181 streamservers.append(ForkingUnixStreamServer)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000182 class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000183 dgramservers = [UnixDatagramServer, ThreadingUnixDatagramServer]
184 if hasattr(os, 'fork') and os.name not in ('os2',):
185 dgramservers.append(ForkingUnixDatagramServer)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000186
Neal Norwitzb476fdf2006-08-15 04:58:28 +0000187def sloppy_cleanup():
188 # See http://python.org/sf/1540386
189 # We need to reap children here otherwise a child from one server
190 # can be left running for the next server and cause a test failure.
191 time.sleep(DELAY)
192 reap_children()
193
Guido van Rossum39f1b362001-07-10 11:52:38 +0000194def testall():
195 testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream)
Neal Norwitzb476fdf2006-08-15 04:58:28 +0000196 sloppy_cleanup()
Guido van Rossum39f1b362001-07-10 11:52:38 +0000197 testloop(socket.AF_INET, udpservers, MyDatagramHandler, testdgram)
Guido van Rossum05be1a02001-07-10 15:46:34 +0000198 if hasattr(socket, 'AF_UNIX'):
Neal Norwitzb476fdf2006-08-15 04:58:28 +0000199 sloppy_cleanup()
Guido van Rossum05be1a02001-07-10 15:46:34 +0000200 testloop(socket.AF_UNIX, streamservers, MyStreamHandler, teststream)
201 # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
202 # client address so this cannot work:
203 ##testloop(socket.AF_UNIX, dgramservers, MyDatagramHandler, testdgram)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000204
Tim Petersa9f6f222001-09-17 23:56:20 +0000205def test_main():
206 import imp
207 if imp.lock_held():
208 # If the import lock is held, the threads will hang.
209 raise TestSkipped("can't run when import lock is held")
210
Guido van Rossum39f1b362001-07-10 11:52:38 +0000211 try:
212 testall()
213 finally:
214 cleanup()
Neal Norwitzb15ac312006-06-29 04:10:08 +0000215 reap_children()
Guido van Rossum39f1b362001-07-10 11:52:38 +0000216
Tim Petersa9f6f222001-09-17 23:56:20 +0000217if __name__ == "__main__":
218 test_main()