tests: kill all tpool workers in LimitedTestCase
Fixes GH-41 https://github.com/eventlet/eventlet/issues/41
This commit is contained in:

committed by
Sergey Shepelev

parent
5e40ef4bc3
commit
dfc08f7947
@@ -12,7 +12,7 @@ import unittest
|
|||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import debug, hubs
|
from eventlet import debug, hubs, tpool
|
||||||
|
|
||||||
|
|
||||||
# convenience for importers
|
# convenience for importers
|
||||||
@@ -178,15 +178,8 @@ class LimitedTestCase(unittest.TestCase):
|
|||||||
signal.signal(signal.SIGALRM, self.previous_alarm[0])
|
signal.signal(signal.SIGALRM, self.previous_alarm[0])
|
||||||
signal.alarm(self.previous_alarm[1])
|
signal.alarm(self.previous_alarm[1])
|
||||||
|
|
||||||
try:
|
tpool.killall()
|
||||||
hub = hubs.get_hub()
|
verify_hub_empty()
|
||||||
num_readers = len(hub.get_readers())
|
|
||||||
num_writers = len(hub.get_writers())
|
|
||||||
assert num_readers == num_writers == 0
|
|
||||||
except AssertionError:
|
|
||||||
print "ERROR: Hub not empty"
|
|
||||||
print debug.format_hub_timers()
|
|
||||||
print debug.format_hub_listeners()
|
|
||||||
|
|
||||||
def assert_less_than(self, a,b,msg=None):
|
def assert_less_than(self, a,b,msg=None):
|
||||||
if msg:
|
if msg:
|
||||||
|
@@ -34,6 +34,8 @@ def mysql_requirement(_f):
|
|||||||
|
|
||||||
class MySQLdbTester(LimitedTestCase):
|
class MySQLdbTester(LimitedTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
super(MySQLdbTester, self).setUp()
|
||||||
|
|
||||||
self._auth = get_database_auth()['MySQLdb']
|
self._auth = get_database_auth()['MySQLdb']
|
||||||
self.create_db()
|
self.create_db()
|
||||||
self.connection = None
|
self.connection = None
|
||||||
@@ -51,6 +53,8 @@ class MySQLdbTester(LimitedTestCase):
|
|||||||
self.connection.close()
|
self.connection.close()
|
||||||
self.drop_db()
|
self.drop_db()
|
||||||
|
|
||||||
|
super(MySQLdbTester, self).tearDown()
|
||||||
|
|
||||||
@skip_unless(mysql_requirement)
|
@skip_unless(mysql_requirement)
|
||||||
def create_db(self):
|
def create_db(self):
|
||||||
auth = self._auth.copy()
|
auth = self._auth.copy()
|
||||||
|
@@ -195,15 +195,10 @@ class _TestBase(LimitedTestCase):
|
|||||||
super(_TestBase, self).tearDown()
|
super(_TestBase, self).tearDown()
|
||||||
|
|
||||||
def spawn_server(self, **kwargs):
|
def spawn_server(self, **kwargs):
|
||||||
"""Spawns a new wsgi server with the given arguments.
|
"""Spawns a new wsgi server with the given arguments using
|
||||||
Sets self.port to the port of the server, and self.killer is the greenlet
|
:meth:`spawn_thread`.
|
||||||
running it.
|
|
||||||
|
|
||||||
Kills any previously-running server."""
|
|
||||||
eventlet.sleep(0) # give previous server a chance to start
|
|
||||||
if self.killer:
|
|
||||||
greenthread.kill(self.killer)
|
|
||||||
|
|
||||||
|
Sets self.port to the port of the server"""
|
||||||
new_kwargs = dict(max_size=128,
|
new_kwargs = dict(max_size=128,
|
||||||
log=self.logfile,
|
log=self.logfile,
|
||||||
site=self.site)
|
site=self.site)
|
||||||
@@ -213,9 +208,19 @@ class _TestBase(LimitedTestCase):
|
|||||||
new_kwargs['sock'] = eventlet.listen(('localhost', 0))
|
new_kwargs['sock'] = eventlet.listen(('localhost', 0))
|
||||||
|
|
||||||
self.port = new_kwargs['sock'].getsockname()[1]
|
self.port = new_kwargs['sock'].getsockname()[1]
|
||||||
self.killer = eventlet.spawn_n(
|
self.spawn_thread(wsgi.server, **new_kwargs)
|
||||||
wsgi.server,
|
|
||||||
**new_kwargs)
|
def spawn_thread(self, target, **kwargs):
|
||||||
|
"""Spawns a new greenthread using specified target and arguments.
|
||||||
|
|
||||||
|
Kills any previously-running server and sets self.killer to the
|
||||||
|
greenthread running the target.
|
||||||
|
"""
|
||||||
|
eventlet.sleep(0) # give previous server a chance to start
|
||||||
|
if self.killer:
|
||||||
|
greenthread.kill(self.killer)
|
||||||
|
|
||||||
|
self.killer = eventlet.spawn_n(target, **kwargs)
|
||||||
|
|
||||||
def set_site(self):
|
def set_site(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -1104,12 +1109,15 @@ class TestHttpd(_TestBase):
|
|||||||
return
|
return
|
||||||
log = StringIO()
|
log = StringIO()
|
||||||
# first thing the server does is try to log the IP it's bound to
|
# first thing the server does is try to log the IP it's bound to
|
||||||
|
|
||||||
def run_server():
|
def run_server():
|
||||||
try:
|
try:
|
||||||
server = wsgi.server(sock=sock, log=log, site=Site())
|
wsgi.server(sock=sock, log=log, site=Site())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
log.write('broked')
|
log.write('broked')
|
||||||
eventlet.spawn_n(run_server)
|
|
||||||
|
self.spawn_thread(run_server)
|
||||||
|
|
||||||
logval = log.getvalue()
|
logval = log.getvalue()
|
||||||
while not logval:
|
while not logval:
|
||||||
eventlet.sleep(0.0)
|
eventlet.sleep(0.0)
|
||||||
|
@@ -22,20 +22,19 @@ server / client accept() conn - ExplodingConnectionWrap
|
|||||||
V V V
|
V V V
|
||||||
connection makefile() file objects - ExplodingSocketFile <-- these raise
|
connection makefile() file objects - ExplodingSocketFile <-- these raise
|
||||||
"""
|
"""
|
||||||
# This code relies on a subclass of unittest.TestCase, but is NOT a test.
|
|
||||||
# Should NOT be run by nose to avoid potential monkeypatch contamination.
|
|
||||||
# - Not just @skipped; nose must not consider this a test at all:
|
|
||||||
__test__ = False
|
|
||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
from cStringIO import StringIO
|
|
||||||
|
|
||||||
import tests.wsgi_test
|
import tests.wsgi_test
|
||||||
|
|
||||||
|
|
||||||
|
# no standard tests in this file, ignore
|
||||||
|
__test__ = False
|
||||||
|
|
||||||
|
|
||||||
# This test might make you wince
|
# This test might make you wince
|
||||||
class NaughtySocketAcceptWrap(object):
|
class NaughtySocketAcceptWrap(object):
|
||||||
# server's socket.accept(); patches resulting connection sockets
|
# server's socket.accept(); patches resulting connection sockets
|
||||||
@@ -114,50 +113,51 @@ class ExplodingSocketFile(socket._fileobject):
|
|||||||
return super(self.__class__, self).readline(*args, **kwargs)
|
return super(self.__class__, self).readline(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
for debug in (False, True):
|
if __name__ == '__main__':
|
||||||
print "SEPERATOR_SENTINEL"
|
for debug in (False, True):
|
||||||
print "debug set to: %s" % debug
|
print "SEPERATOR_SENTINEL"
|
||||||
|
print "debug set to: %s" % debug
|
||||||
|
|
||||||
server_sock = eventlet.listen(('localhost', 0))
|
server_sock = eventlet.listen(('localhost', 0))
|
||||||
server_addr = server_sock.getsockname()
|
server_addr = server_sock.getsockname()
|
||||||
sock_wrap = NaughtySocketAcceptWrap(server_sock)
|
sock_wrap = NaughtySocketAcceptWrap(server_sock)
|
||||||
|
|
||||||
eventlet.spawn_n(
|
eventlet.spawn_n(
|
||||||
eventlet.wsgi.server,
|
eventlet.wsgi.server,
|
||||||
debug=debug,
|
debug=debug,
|
||||||
log=sys.stdout,
|
log=sys.stdout,
|
||||||
max_size=128,
|
max_size=128,
|
||||||
site=tests.wsgi_test.Site(),
|
site=tests.wsgi_test.Site(),
|
||||||
sock=server_sock,
|
sock=server_sock,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
# req #1 - normal
|
|
||||||
sock1 = eventlet.connect(server_addr)
|
|
||||||
sock1.settimeout(0.1)
|
|
||||||
fd1 = sock1.makefile('rw')
|
|
||||||
fd1.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
|
||||||
fd1.flush()
|
|
||||||
tests.wsgi_test.read_http(sock1)
|
|
||||||
|
|
||||||
# let the server socket ops catch up, set bomb
|
|
||||||
eventlet.sleep(0)
|
|
||||||
print "arming..."
|
|
||||||
sock_wrap.arm()
|
|
||||||
|
|
||||||
# req #2 - old conn, post-arm - timeout
|
|
||||||
fd1.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
|
||||||
fd1.flush()
|
|
||||||
try:
|
try:
|
||||||
|
# req #1 - normal
|
||||||
|
sock1 = eventlet.connect(server_addr)
|
||||||
|
sock1.settimeout(0.1)
|
||||||
|
fd1 = sock1.makefile('rw')
|
||||||
|
fd1.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd1.flush()
|
||||||
tests.wsgi_test.read_http(sock1)
|
tests.wsgi_test.read_http(sock1)
|
||||||
assert False, 'Expected ConnectionClosed exception'
|
|
||||||
except tests.wsgi_test.ConnectionClosed:
|
|
||||||
pass
|
|
||||||
|
|
||||||
fd1.close()
|
# let the server socket ops catch up, set bomb
|
||||||
sock1.close()
|
eventlet.sleep(0)
|
||||||
finally:
|
print "arming..."
|
||||||
# reset streams, then output trapped tracebacks
|
sock_wrap.arm()
|
||||||
sock_wrap.unwrap()
|
|
||||||
# check output asserts in tests.wsgi_test.TestHttpd
|
# req #2 - old conn, post-arm - timeout
|
||||||
# test_143_server_connection_timeout_exception
|
fd1.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd1.flush()
|
||||||
|
try:
|
||||||
|
tests.wsgi_test.read_http(sock1)
|
||||||
|
assert False, 'Expected ConnectionClosed exception'
|
||||||
|
except tests.wsgi_test.ConnectionClosed:
|
||||||
|
pass
|
||||||
|
|
||||||
|
fd1.close()
|
||||||
|
sock1.close()
|
||||||
|
finally:
|
||||||
|
# reset streams, then output trapped tracebacks
|
||||||
|
sock_wrap.unwrap()
|
||||||
|
# check output asserts in tests.wsgi_test.TestHttpd
|
||||||
|
# test_143_server_connection_timeout_exception
|
||||||
|
Reference in New Issue
Block a user