blob: 93165470f922adc594064c3b5688594047cea0f7 [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
4from test.test_support import verbose, verify, TESTFN, TestSkipped
Tim Petersa86f0c12001-09-18 02:18:57 +00005test_support.requires('network')
Guido van Rossum39f1b362001-07-10 11:52:38 +00006
7from SocketServer import *
8import socket
Neal Norwitz909eb122006-06-12 02:13:21 +00009import errno
Guido van Rossum39f1b362001-07-10 11:52:38 +000010import select
11import time
12import threading
13import os
14
15NREQ = 3
16DELAY = 0.5
17
18class MyMixinHandler:
19 def handle(self):
20 time.sleep(DELAY)
21 line = self.rfile.readline()
22 time.sleep(DELAY)
23 self.wfile.write(line)
24
25class MyStreamHandler(MyMixinHandler, StreamRequestHandler):
26 pass
27
28class MyDatagramHandler(MyMixinHandler, DatagramRequestHandler):
29 pass
30
31class MyMixinServer:
32 def serve_a_few(self):
33 for i in range(NREQ):
34 self.handle_request()
35 def handle_error(self, request, client_address):
36 self.close_request(request)
37 self.server_close()
38 raise
39
40teststring = "hello world\n"
41
42def receive(sock, n, timeout=20):
43 r, w, x = select.select([sock], [], [], timeout)
44 if sock in r:
45 return sock.recv(n)
46 else:
Walter Dörwald70a6b492004-02-12 17:35:32 +000047 raise RuntimeError, "timed out on %r" % (sock,)
Guido van Rossum39f1b362001-07-10 11:52:38 +000048
49def testdgram(proto, addr):
50 s = socket.socket(proto, socket.SOCK_DGRAM)
51 s.sendto(teststring, addr)
52 buf = data = receive(s, 100)
53 while data and '\n' not in buf:
54 data = receive(s, 100)
55 buf += data
56 verify(buf == teststring)
57 s.close()
58
59def teststream(proto, addr):
60 s = socket.socket(proto, socket.SOCK_STREAM)
61 s.connect(addr)
Guido van Rossum9bd14012001-10-29 07:18:02 +000062 s.sendall(teststring)
Guido van Rossum39f1b362001-07-10 11:52:38 +000063 buf = data = receive(s, 100)
64 while data and '\n' not in buf:
65 data = receive(s, 100)
66 buf += data
67 verify(buf == teststring)
68 s.close()
69
70class ServerThread(threading.Thread):
71 def __init__(self, addr, svrcls, hdlrcls):
72 threading.Thread.__init__(self)
73 self.__addr = addr
74 self.__svrcls = svrcls
75 self.__hdlrcls = hdlrcls
76 def run(self):
77 class svrcls(MyMixinServer, self.__svrcls):
78 pass
79 if verbose: print "thread: creating server"
80 svr = svrcls(self.__addr, self.__hdlrcls)
Neal Norwitz909eb122006-06-12 02:13:21 +000081 # pull the address out of the server in case it changed
82 # this can happen if another process is using the port
83 addr = getattr(svr, 'server_address')
84 if addr:
85 self.__addr = addr
Guido van Rossum39f1b362001-07-10 11:52:38 +000086 if verbose: print "thread: serving three times"
87 svr.serve_a_few()
88 if verbose: print "thread: done"
89
90seed = 0
91def pickport():
92 global seed
93 seed += 1
94 return 10000 + (os.getpid() % 1000)*10 + seed
95
Guido van Rossum05be1a02001-07-10 15:46:34 +000096host = "localhost"
Guido van Rossum39f1b362001-07-10 11:52:38 +000097testfiles = []
98def pickaddr(proto):
99 if proto == socket.AF_INET:
100 return (host, pickport())
101 else:
102 fn = TESTFN + str(pickport())
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000103 if os.name == 'os2':
104 # AF_UNIX socket names on OS/2 require a specific prefix
105 # which can't include a drive letter and must also use
106 # backslashes as directory separators
107 if fn[1] == ':':
108 fn = fn[2:]
109 if fn[0] in (os.sep, os.altsep):
110 fn = fn[1:]
111 fn = os.path.join('\socket', fn)
112 if os.sep == '/':
113 fn = fn.replace(os.sep, os.altsep)
114 else:
115 fn = fn.replace(os.altsep, os.sep)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000116 testfiles.append(fn)
117 return fn
118
119def cleanup():
120 for fn in testfiles:
121 try:
122 os.remove(fn)
123 except os.error:
124 pass
125 testfiles[:] = []
126
127def testloop(proto, servers, hdlrcls, testfunc):
128 for svrcls in servers:
129 addr = pickaddr(proto)
130 if verbose:
131 print "ADDR =", addr
132 print "CLASS =", svrcls
133 t = ServerThread(addr, svrcls, hdlrcls)
134 if verbose: print "server created"
135 t.start()
136 if verbose: print "server running"
137 for i in range(NREQ):
138 time.sleep(DELAY)
139 if verbose: print "test client", i
140 testfunc(proto, addr)
141 if verbose: print "waiting for server"
142 t.join()
143 if verbose: print "done"
144
Neal Norwitz909eb122006-06-12 02:13:21 +0000145class ForgivingTCPServer(TCPServer):
146 # prevent errors if another process is using the port we want
147 def server_bind(self):
148 host, default_port = self.server_address
149 # this code shamelessly stolen from test.test_support
150 # the ports were changed to protect the innocent
151 import sys
152 for port in [default_port, 3434, 8798, 23833]:
153 try:
154 self.server_address = host, port
155 TCPServer.server_bind(self)
156 break
157 except socket.error, (err, msg):
158 if err != errno.EADDRINUSE:
159 raise
160 print >>sys.__stderr__, \
161 ' WARNING: failed to listen on port %d, trying another' % port
162
163tcpservers = [ForgivingTCPServer, ThreadingTCPServer]
Andrew MacIntyrec6fff892003-01-02 12:49:00 +0000164if hasattr(os, 'fork') and os.name not in ('os2',):
Guido van Rossum39f1b362001-07-10 11:52:38 +0000165 tcpservers.append(ForkingTCPServer)
166udpservers = [UDPServer, ThreadingUDPServer]
Andrew MacIntyrec6fff892003-01-02 12:49:00 +0000167if hasattr(os, 'fork') and os.name not in ('os2',):
Guido van Rossum39f1b362001-07-10 11:52:38 +0000168 udpservers.append(ForkingUDPServer)
169
170if not hasattr(socket, 'AF_UNIX'):
171 streamservers = []
172 dgramservers = []
173else:
174 class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000175 streamservers = [UnixStreamServer, ThreadingUnixStreamServer]
176 if hasattr(os, 'fork') and os.name not in ('os2',):
177 streamservers.append(ForkingUnixStreamServer)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000178 class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000179 dgramservers = [UnixDatagramServer, ThreadingUnixDatagramServer]
180 if hasattr(os, 'fork') and os.name not in ('os2',):
181 dgramservers.append(ForkingUnixDatagramServer)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000182
183def testall():
184 testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream)
185 testloop(socket.AF_INET, udpservers, MyDatagramHandler, testdgram)
Guido van Rossum05be1a02001-07-10 15:46:34 +0000186 if hasattr(socket, 'AF_UNIX'):
187 testloop(socket.AF_UNIX, streamservers, MyStreamHandler, teststream)
188 # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
189 # client address so this cannot work:
190 ##testloop(socket.AF_UNIX, dgramservers, MyDatagramHandler, testdgram)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000191
Tim Petersa9f6f222001-09-17 23:56:20 +0000192def test_main():
193 import imp
194 if imp.lock_held():
195 # If the import lock is held, the threads will hang.
196 raise TestSkipped("can't run when import lock is held")
197
Guido van Rossum39f1b362001-07-10 11:52:38 +0000198 try:
199 testall()
200 finally:
201 cleanup()
202
Tim Petersa9f6f222001-09-17 23:56:20 +0000203if __name__ == "__main__":
204 test_main()