blob: 3e0c7a47d8e7721f76b5355a10aa9b1b0c392a74 [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
Thomas Wouters0e3f5912006-08-11 14:57:12 +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
Thomas Wouters0e3f5912006-08-11 14:57:12 +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
Guido van Rossum15863ea2007-08-03 19:03:39 +000041teststring = b"hello world\n"
Guido van Rossum39f1b362001-07-10 11:52:38 +000042
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:
Collin Winter3add4d72007-08-29 23:37: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)
Guido van Rossum15863ea2007-08-03 19:03:39 +000054 while data and b'\n' not in buf:
Guido van Rossum39f1b362001-07-10 11:52:38 +000055 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)
Guido van Rossum15863ea2007-08-03 19:03:39 +000065 while data and b'\n' not in buf:
Guido van Rossum39f1b362001-07-10 11:52:38 +000066 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
Guido van Rossumd8faa362007-04-27 19:54:29 +000077 self.ready = threading.Event()
Guido van Rossum39f1b362001-07-10 11:52:38 +000078 def run(self):
79 class svrcls(MyMixinServer, self.__svrcls):
80 pass
Guido van Rossumbe19ed72007-02-09 05:37:30 +000081 if verbose: print("thread: creating server")
Guido van Rossum39f1b362001-07-10 11:52:38 +000082 svr = svrcls(self.__addr, self.__hdlrcls)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000083 # pull the address out of the server in case it changed
84 # this can happen if another process is using the port
Guido van Rossumd8faa362007-04-27 19:54:29 +000085 addr = svr.server_address
Thomas Wouters0e3f5912006-08-11 14:57:12 +000086 if addr:
87 self.__addr = addr
Guido van Rossumd8faa362007-04-27 19:54:29 +000088 if self.__addr != svr.socket.getsockname():
89 raise RuntimeError('server_address was %s, expected %s' %
90 (self.__addr, svr.socket.getsockname()))
91 self.ready.set()
Guido van Rossumbe19ed72007-02-09 05:37:30 +000092 if verbose: print("thread: serving three times")
Guido van Rossum39f1b362001-07-10 11:52:38 +000093 svr.serve_a_few()
Guido van Rossumbe19ed72007-02-09 05:37:30 +000094 if verbose: print("thread: done")
Guido van Rossum39f1b362001-07-10 11:52:38 +000095
96seed = 0
97def pickport():
98 global seed
99 seed += 1
100 return 10000 + (os.getpid() % 1000)*10 + seed
101
Guido van Rossum05be1a02001-07-10 15:46:34 +0000102host = "localhost"
Guido van Rossum39f1b362001-07-10 11:52:38 +0000103testfiles = []
104def pickaddr(proto):
105 if proto == socket.AF_INET:
106 return (host, pickport())
107 else:
108 fn = TESTFN + str(pickport())
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000109 if os.name == 'os2':
110 # AF_UNIX socket names on OS/2 require a specific prefix
111 # which can't include a drive letter and must also use
112 # backslashes as directory separators
113 if fn[1] == ':':
114 fn = fn[2:]
115 if fn[0] in (os.sep, os.altsep):
116 fn = fn[1:]
117 fn = os.path.join('\socket', fn)
118 if os.sep == '/':
119 fn = fn.replace(os.sep, os.altsep)
120 else:
121 fn = fn.replace(os.altsep, os.sep)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000122 testfiles.append(fn)
123 return fn
124
125def cleanup():
126 for fn in testfiles:
127 try:
128 os.remove(fn)
129 except os.error:
130 pass
131 testfiles[:] = []
132
133def testloop(proto, servers, hdlrcls, testfunc):
134 for svrcls in servers:
135 addr = pickaddr(proto)
136 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000137 print("ADDR =", addr)
138 print("CLASS =", svrcls)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000139 t = ServerThread(addr, svrcls, hdlrcls)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000140 if verbose: print("server created")
Guido van Rossum39f1b362001-07-10 11:52:38 +0000141 t.start()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000142 if verbose: print("server running")
Guido van Rossum39f1b362001-07-10 11:52:38 +0000143 for i in range(NREQ):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000144 t.ready.wait(10*DELAY)
145 if not t.ready.isSet():
146 raise RuntimeError("Server not ready within a reasonable time")
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000147 if verbose: print("test client", i)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000148 testfunc(proto, addr)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000149 if verbose: print("waiting for server")
Guido van Rossum39f1b362001-07-10 11:52:38 +0000150 t.join()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000151 if verbose: print("done")
Guido van Rossum39f1b362001-07-10 11:52:38 +0000152
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000153class ForgivingTCPServer(TCPServer):
154 # prevent errors if another process is using the port we want
155 def server_bind(self):
156 host, default_port = self.server_address
157 # this code shamelessly stolen from test.test_support
158 # the ports were changed to protect the innocent
159 import sys
160 for port in [default_port, 3434, 8798, 23833]:
161 try:
162 self.server_address = host, port
163 TCPServer.server_bind(self)
164 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000165 except socket.error as e:
166 (err, msg) = e
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000167 if err != errno.EADDRINUSE:
168 raise
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000169 print(' WARNING: failed to listen on port %d, trying another' % port, file=sys.__stderr__)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000170
171tcpservers = [ForgivingTCPServer, ThreadingTCPServer]
Andrew MacIntyrec6fff892003-01-02 12:49:00 +0000172if hasattr(os, 'fork') and os.name not in ('os2',):
Guido van Rossum39f1b362001-07-10 11:52:38 +0000173 tcpservers.append(ForkingTCPServer)
174udpservers = [UDPServer, ThreadingUDPServer]
Andrew MacIntyrec6fff892003-01-02 12:49:00 +0000175if hasattr(os, 'fork') and os.name not in ('os2',):
Guido van Rossum39f1b362001-07-10 11:52:38 +0000176 udpservers.append(ForkingUDPServer)
177
178if not hasattr(socket, 'AF_UNIX'):
179 streamservers = []
180 dgramservers = []
181else:
182 class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000183 streamservers = [UnixStreamServer, ThreadingUnixStreamServer]
184 if hasattr(os, 'fork') and os.name not in ('os2',):
185 streamservers.append(ForkingUnixStreamServer)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000186 class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
Andrew MacIntyredaedf212004-04-11 12:03:57 +0000187 dgramservers = [UnixDatagramServer, ThreadingUnixDatagramServer]
188 if hasattr(os, 'fork') and os.name not in ('os2',):
189 dgramservers.append(ForkingUnixDatagramServer)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000190
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000191def sloppy_cleanup():
192 # See http://python.org/sf/1540386
193 # We need to reap children here otherwise a child from one server
194 # can be left running for the next server and cause a test failure.
195 time.sleep(DELAY)
196 reap_children()
197
Guido van Rossum39f1b362001-07-10 11:52:38 +0000198def testall():
199 testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000200 sloppy_cleanup()
Guido van Rossum39f1b362001-07-10 11:52:38 +0000201 testloop(socket.AF_INET, udpservers, MyDatagramHandler, testdgram)
Guido van Rossum05be1a02001-07-10 15:46:34 +0000202 if hasattr(socket, 'AF_UNIX'):
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000203 sloppy_cleanup()
Guido van Rossum05be1a02001-07-10 15:46:34 +0000204 testloop(socket.AF_UNIX, streamservers, MyStreamHandler, teststream)
205 # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
206 # client address so this cannot work:
207 ##testloop(socket.AF_UNIX, dgramservers, MyDatagramHandler, testdgram)
Guido van Rossum39f1b362001-07-10 11:52:38 +0000208
Tim Petersa9f6f222001-09-17 23:56:20 +0000209def test_main():
210 import imp
211 if imp.lock_held():
212 # If the import lock is held, the threads will hang.
213 raise TestSkipped("can't run when import lock is held")
214
Neal Norwitz6665cef2007-08-28 06:29:09 +0000215 reap_children()
Guido van Rossum39f1b362001-07-10 11:52:38 +0000216 try:
217 testall()
218 finally:
219 cleanup()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000220 reap_children()
Guido van Rossum39f1b362001-07-10 11:52:38 +0000221
Tim Petersa9f6f222001-09-17 23:56:20 +0000222if __name__ == "__main__":
223 test_main()