Kaydet (Commit) 61fdd71a authored tarafından Georg Brandl's avatar Georg Brandl

Rewrite test_socketserver as unittest, written for GHOP by Benjamin Petersen.

üst bbc4fc29
# Test suite for SocketServer.py """
Test suite for SocketServer.py.
"""
from test import test_support import os
from test.test_support import (verbose, verify, TESTFN, TestSkipped,
reap_children)
test_support.requires('network')
from SocketServer import *
import socket import socket
import errno import errno
import imp
import select import select
import time import time
import threading import threading
import os from functools import wraps
import unittest
import SocketServer
import test.test_support
from test.test_support import reap_children, verbose, TestSkipped
from test.test_support import TESTFN as TEST_FILE
test.test_support.requires("network")
NREQ = 3 NREQ = 3
DELAY = 0.5 DELAY = 0.5
TEST_STR = "hello world\n"
HOST = "localhost"
HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
HAVE_FORKING = hasattr(os, "fork") and os.name != "os2"
class MyMixinHandler: class MyMixinHandler:
def handle(self): def handle(self):
...@@ -23,50 +35,41 @@ class MyMixinHandler: ...@@ -23,50 +35,41 @@ class MyMixinHandler:
time.sleep(DELAY) time.sleep(DELAY)
self.wfile.write(line) self.wfile.write(line)
class MyStreamHandler(MyMixinHandler, StreamRequestHandler):
def receive(sock, n, timeout=20):
r, w, x = select.select([sock], [], [], timeout)
if sock in r:
return sock.recv(n)
else:
raise RuntimeError, "timed out on %r" % (sock,)
class MyStreamHandler(MyMixinHandler, SocketServer.StreamRequestHandler):
pass
class MyDatagramHandler(MyMixinHandler,
SocketServer.DatagramRequestHandler):
pass pass
class MyDatagramHandler(MyMixinHandler, DatagramRequestHandler): class ForkingUnixStreamServer(SocketServer.ForkingMixIn,
SocketServer.UnixStreamServer):
pass pass
class ForkingUnixDatagramServer(SocketServer.ForkingMixIn,
SocketServer.UnixDatagramServer):
pass
class MyMixinServer: class MyMixinServer:
def serve_a_few(self): def serve_a_few(self):
for i in range(NREQ): for i in range(NREQ):
self.handle_request() self.handle_request()
def handle_error(self, request, client_address): def handle_error(self, request, client_address):
self.close_request(request) self.close_request(request)
self.server_close() self.server_close()
raise raise
teststring = "hello world\n"
def receive(sock, n, timeout=20):
r, w, x = select.select([sock], [], [], timeout)
if sock in r:
return sock.recv(n)
else:
raise RuntimeError, "timed out on %r" % (sock,)
def testdgram(proto, addr):
s = socket.socket(proto, socket.SOCK_DGRAM)
s.sendto(teststring, addr)
buf = data = receive(s, 100)
while data and '\n' not in buf:
data = receive(s, 100)
buf += data
verify(buf == teststring)
s.close()
def teststream(proto, addr):
s = socket.socket(proto, socket.SOCK_STREAM)
s.connect(addr)
s.sendall(teststring)
buf = data = receive(s, 100)
while data and '\n' not in buf:
data = receive(s, 100)
buf += data
verify(buf == teststring)
s.close()
class ServerThread(threading.Thread): class ServerThread(threading.Thread):
def __init__(self, addr, svrcls, hdlrcls): def __init__(self, addr, svrcls, hdlrcls):
...@@ -75,6 +78,7 @@ class ServerThread(threading.Thread): ...@@ -75,6 +78,7 @@ class ServerThread(threading.Thread):
self.__svrcls = svrcls self.__svrcls = svrcls
self.__hdlrcls = hdlrcls self.__hdlrcls = hdlrcls
self.ready = threading.Event() self.ready = threading.Event()
def run(self): def run(self):
class svrcls(MyMixinServer, self.__svrcls): class svrcls(MyMixinServer, self.__svrcls):
pass pass
...@@ -93,19 +97,52 @@ class ServerThread(threading.Thread): ...@@ -93,19 +97,52 @@ class ServerThread(threading.Thread):
svr.serve_a_few() svr.serve_a_few()
if verbose: print "thread: done" if verbose: print "thread: done"
seed = 0
def pickport():
global seed
seed += 1
return 10000 + (os.getpid() % 1000)*10 + seed
host = "localhost" class ForgivingTCPServer(SocketServer.TCPServer):
testfiles = [] # prevent errors if another process is using the port we want
def pickaddr(proto): def server_bind(self):
host, default_port = self.server_address
# this code shamelessly stolen from test.test_support
# the ports were changed to protect the innocent
import sys
for port in [default_port, 3434, 8798, 23833]:
try:
self.server_address = host, port
SocketServer.TCPServer.server_bind(self)
break
except socket.error, (err, msg):
if err != errno.EADDRINUSE:
raise
print >> sys.__stderr__, \
"WARNING: failed to listen on port %d, trying another: " % port
class SocketServerTest(unittest.TestCase):
"""Test all socket servers."""
def setUp(self):
self.port_seed = 0
self.test_files = []
def tearDown(self):
reap_children()
for fn in self.test_files:
try:
os.remove(fn)
except os.error:
pass
self.test_files[:] = []
def pickport(self):
self.port_seed += 1
return 10000 + (os.getpid() % 1000)*10 + self.port_seed
def pickaddr(self, proto):
if proto == socket.AF_INET: if proto == socket.AF_INET:
return (host, pickport()) return (HOST, self.pickport())
else: else:
fn = TESTFN + str(pickport()) fn = TEST_FILE + str(self.pickport())
if os.name == 'os2': if os.name == 'os2':
# AF_UNIX socket names on OS/2 require a specific prefix # AF_UNIX socket names on OS/2 require a specific prefix
# which can't include a drive letter and must also use # which can't include a drive letter and must also use
...@@ -119,20 +156,12 @@ def pickaddr(proto): ...@@ -119,20 +156,12 @@ def pickaddr(proto):
fn = fn.replace(os.sep, os.altsep) fn = fn.replace(os.sep, os.altsep)
else: else:
fn = fn.replace(os.altsep, os.sep) fn = fn.replace(os.altsep, os.sep)
testfiles.append(fn) self.test_files.append(fn)
return fn return fn
def cleanup(): def run_servers(self, proto, servers, hdlrcls, testfunc):
for fn in testfiles:
try:
os.remove(fn)
except os.error:
pass
testfiles[:] = []
def testloop(proto, servers, hdlrcls, testfunc):
for svrcls in servers: for svrcls in servers:
addr = pickaddr(proto) addr = self.pickaddr(proto)
if verbose: if verbose:
print "ADDR =", addr print "ADDR =", addr
print "CLASS =", svrcls print "CLASS =", svrcls
...@@ -142,82 +171,84 @@ def testloop(proto, servers, hdlrcls, testfunc): ...@@ -142,82 +171,84 @@ def testloop(proto, servers, hdlrcls, testfunc):
if verbose: print "server running" if verbose: print "server running"
for i in range(NREQ): for i in range(NREQ):
t.ready.wait(10*DELAY) t.ready.wait(10*DELAY)
if not t.ready.isSet(): self.assert_(t.ready.isSet(),
raise RuntimeError("Server not ready within a reasonable time") "Server not ready within a reasonable time")
if verbose: print "test client", i if verbose: print "test client", i
testfunc(proto, addr) testfunc(proto, addr)
if verbose: print "waiting for server" if verbose: print "waiting for server"
t.join() t.join()
if verbose: print "done" if verbose: print "done"
class ForgivingTCPServer(TCPServer): def stream_examine(self, proto, addr):
# prevent errors if another process is using the port we want s = socket.socket(proto, socket.SOCK_STREAM)
def server_bind(self): s.connect(addr)
host, default_port = self.server_address s.sendall(TEST_STR)
# this code shamelessly stolen from test.test_support buf = data = receive(s, 100)
# the ports were changed to protect the innocent while data and '\n' not in buf:
import sys data = receive(s, 100)
for port in [default_port, 3434, 8798, 23833]: buf += data
try: self.assertEquals(buf, TEST_STR)
self.server_address = host, port s.close()
TCPServer.server_bind(self)
break def dgram_examine(self, proto, addr):
except socket.error, (err, msg): s = socket.socket(proto, socket.SOCK_DGRAM)
if err != errno.EADDRINUSE: s.sendto(TEST_STR, addr)
raise buf = data = receive(s, 100)
print >>sys.__stderr__, \ while data and '\n' not in buf:
' WARNING: failed to listen on port %d, trying another' % port data = receive(s, 100)
buf += data
tcpservers = [ForgivingTCPServer, ThreadingTCPServer] self.assertEquals(buf, TEST_STR)
if hasattr(os, 'fork') and os.name not in ('os2',): s.close()
tcpservers.append(ForkingTCPServer)
udpservers = [UDPServer, ThreadingUDPServer] def test_TCPServers(self):
if hasattr(os, 'fork') and os.name not in ('os2',): # Test SocketServer.TCPServer
udpservers.append(ForkingUDPServer) servers = [ForgivingTCPServer, SocketServer.ThreadingTCPServer]
if HAVE_FORKING:
if not hasattr(socket, 'AF_UNIX'): servers.append(SocketServer.ForkingTCPServer)
streamservers = [] self.run_servers(socket.AF_INET, servers,
dgramservers = [] MyStreamHandler, self.stream_examine)
else:
class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass def test_UDPServers(self):
streamservers = [UnixStreamServer, ThreadingUnixStreamServer] # Test SocketServer.UPDServer
if hasattr(os, 'fork') and os.name not in ('os2',): servers = [SocketServer.UDPServer,
streamservers.append(ForkingUnixStreamServer) SocketServer.ThreadingUDPServer]
class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass if HAVE_FORKING:
dgramservers = [UnixDatagramServer, ThreadingUnixDatagramServer] servers.append(SocketServer.ForkingUDPServer)
if hasattr(os, 'fork') and os.name not in ('os2',): self.run_servers(socket.AF_INET, servers, MyDatagramHandler,
dgramservers.append(ForkingUnixDatagramServer) self.dgram_examine)
def sloppy_cleanup(): def test_stream_servers(self):
# See http://python.org/sf/1540386 # Test SocketServer's stream servers
# We need to reap children here otherwise a child from one server if not HAVE_UNIX_SOCKETS:
# can be left running for the next server and cause a test failure. return
time.sleep(DELAY) servers = [SocketServer.UnixStreamServer,
reap_children() SocketServer.ThreadingUnixStreamServer]
if HAVE_FORKING:
servers.append(ForkingUnixStreamServer)
self.run_servers(socket.AF_UNIX, servers, MyStreamHandler,
self.stream_examine)
def testall():
testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream)
sloppy_cleanup()
testloop(socket.AF_INET, udpservers, MyDatagramHandler, testdgram)
if hasattr(socket, 'AF_UNIX'):
sloppy_cleanup()
testloop(socket.AF_UNIX, streamservers, MyStreamHandler, teststream)
# Alas, on Linux (at least) recvfrom() doesn't return a meaningful # Alas, on Linux (at least) recvfrom() doesn't return a meaningful
# client address so this cannot work: # client address so this cannot work:
##testloop(socket.AF_UNIX, dgramservers, MyDatagramHandler, testdgram)
# def test_dgram_servers(self):
# # Test SocketServer.UnixDatagramServer
# if not HAVE_UNIX_SOCKETS:
# return
# servers = [SocketServer.UnixDatagramServer,
# SocketServer.ThreadingUnixDatagramServer]
# if HAVE_FORKING:
# servers.append(ForkingUnixDatagramServer)
# self.run_servers(socket.AF_UNIX, servers, MyDatagramHandler,
# self.dgram_examine)
def test_main(): def test_main():
import imp
if imp.lock_held(): if imp.lock_held():
# If the import lock is held, the threads will hang. # If the import lock is held, the threads will hang
raise TestSkipped("can't run when import lock is held") raise TestSkipped("can't run when import lock is held")
reap_children() test.test_support.run_unittest(SocketServerTest)
try:
testall()
finally:
cleanup()
reap_children()
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment