From dfc08f79471c588bcfb8e217194f08e80c193858 Mon Sep 17 00:00:00 2001 From: Jakub Stasiak Date: Mon, 29 Jul 2013 23:40:03 +0100 Subject: [PATCH] tests: kill all tpool workers in LimitedTestCase Fixes GH-41 https://github.com/eventlet/eventlet/issues/41 --- tests/__init__.py | 13 ++--- tests/mysqldb_test.py | 4 ++ tests/wsgi_test.py | 34 ++++++++----- tests/wsgi_test_conntimeout.py | 92 +++++++++++++++++----------------- 4 files changed, 74 insertions(+), 69 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 43e558a..9fbfaf4 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -12,7 +12,7 @@ import unittest import warnings import eventlet -from eventlet import debug, hubs +from eventlet import debug, hubs, tpool # convenience for importers @@ -178,15 +178,8 @@ class LimitedTestCase(unittest.TestCase): signal.signal(signal.SIGALRM, self.previous_alarm[0]) signal.alarm(self.previous_alarm[1]) - try: - hub = hubs.get_hub() - 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() + tpool.killall() + verify_hub_empty() def assert_less_than(self, a,b,msg=None): if msg: diff --git a/tests/mysqldb_test.py b/tests/mysqldb_test.py index f6f45cf..a1455b6 100644 --- a/tests/mysqldb_test.py +++ b/tests/mysqldb_test.py @@ -34,6 +34,8 @@ def mysql_requirement(_f): class MySQLdbTester(LimitedTestCase): def setUp(self): + super(MySQLdbTester, self).setUp() + self._auth = get_database_auth()['MySQLdb'] self.create_db() self.connection = None @@ -51,6 +53,8 @@ class MySQLdbTester(LimitedTestCase): self.connection.close() self.drop_db() + super(MySQLdbTester, self).tearDown() + @skip_unless(mysql_requirement) def create_db(self): auth = self._auth.copy() diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py index a30baa3..3bbbd2f 100644 --- a/tests/wsgi_test.py +++ b/tests/wsgi_test.py @@ -195,15 +195,10 @@ class _TestBase(LimitedTestCase): super(_TestBase, self).tearDown() def spawn_server(self, **kwargs): - """Spawns a new wsgi server with the given arguments. - Sets self.port to the port of the server, and self.killer is the greenlet - running it. - - Kills any previously-running server.""" - eventlet.sleep(0) # give previous server a chance to start - if self.killer: - greenthread.kill(self.killer) + """Spawns a new wsgi server with the given arguments using + :meth:`spawn_thread`. + Sets self.port to the port of the server""" new_kwargs = dict(max_size=128, log=self.logfile, site=self.site) @@ -213,9 +208,19 @@ class _TestBase(LimitedTestCase): new_kwargs['sock'] = eventlet.listen(('localhost', 0)) self.port = new_kwargs['sock'].getsockname()[1] - self.killer = eventlet.spawn_n( - wsgi.server, - **new_kwargs) + self.spawn_thread(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): raise NotImplementedError @@ -1104,12 +1109,15 @@ class TestHttpd(_TestBase): return log = StringIO() # first thing the server does is try to log the IP it's bound to + def run_server(): try: - server = wsgi.server(sock=sock, log=log, site=Site()) + wsgi.server(sock=sock, log=log, site=Site()) except ValueError: log.write('broked') - eventlet.spawn_n(run_server) + + self.spawn_thread(run_server) + logval = log.getvalue() while not logval: eventlet.sleep(0.0) diff --git a/tests/wsgi_test_conntimeout.py b/tests/wsgi_test_conntimeout.py index bf3fb30..b89d47f 100644 --- a/tests/wsgi_test_conntimeout.py +++ b/tests/wsgi_test_conntimeout.py @@ -22,20 +22,19 @@ server / client accept() conn - ExplodingConnectionWrap V V V 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 socket import sys -from cStringIO import StringIO import tests.wsgi_test +# no standard tests in this file, ignore +__test__ = False + + # This test might make you wince class NaughtySocketAcceptWrap(object): # server's socket.accept(); patches resulting connection sockets @@ -114,50 +113,51 @@ class ExplodingSocketFile(socket._fileobject): return super(self.__class__, self).readline(*args, **kwargs) -for debug in (False, True): - print "SEPERATOR_SENTINEL" - print "debug set to: %s" % debug +if __name__ == '__main__': + for debug in (False, True): + print "SEPERATOR_SENTINEL" + print "debug set to: %s" % debug - server_sock = eventlet.listen(('localhost', 0)) - server_addr = server_sock.getsockname() - sock_wrap = NaughtySocketAcceptWrap(server_sock) + server_sock = eventlet.listen(('localhost', 0)) + server_addr = server_sock.getsockname() + sock_wrap = NaughtySocketAcceptWrap(server_sock) - eventlet.spawn_n( - eventlet.wsgi.server, - debug=debug, - log=sys.stdout, - max_size=128, - site=tests.wsgi_test.Site(), - sock=server_sock, - ) + eventlet.spawn_n( + eventlet.wsgi.server, + debug=debug, + log=sys.stdout, + max_size=128, + site=tests.wsgi_test.Site(), + 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: + # 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) - 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 + # 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: + 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