Rev 5251: Add an event to ThreadWithException that can be shared with the calling thread. in file:///home/vila/src/bzr/experimental/leaking-tests/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Wed May 26 16:26:00 BST 2010
At file:///home/vila/src/bzr/experimental/leaking-tests/
------------------------------------------------------------
revno: 5251
revision-id: v.ladeuil+lp at free.fr-20100526152559-che4hqfn4pwo8s6g
parent: v.ladeuil+lp at free.fr-20100526110529-865s1k26bdj4s9md
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: propagate-exceptions
timestamp: Wed 2010-05-26 17:25:59 +0200
message:
Add an event to ThreadWithException that can be shared with the calling thread.
* bzrlib/tests/test_server.py:
(ThreadWithException.__init__): Add an 'event' parameter that can
be shared with the caller.
(ThreadWithException.run): Sset the event once the exception has
been recorded so we can release the caller and provide the
exception.
(ThreadWithException.join): Properly raise the recorded exception.
* bzrlib/tests/test_http.py:
(TestHTTPServer.test_force_invalid_protocol): Just rely on
assertRaises or we don't get the traceback on error.
(TestHTTPServer.test_server_start_and_stop): Cleanup.
* bzrlib/tests/http_server.py:
(HttpServer._http_start): Simplified.
(HttpServer.start_server): Leave the ThreadWithException do its
work.
(HttpServer.stop_server): Shutdown the server only if it was
started.
-------------- next part --------------
=== modified file 'bzrlib/tests/http_server.py'
--- a/bzrlib/tests/http_server.py 2010-05-25 12:47:13 +0000
+++ b/bzrlib/tests/http_server.py 2010-05-26 15:25:59 +0000
@@ -626,24 +626,10 @@
def _http_start(self, started):
"""Server thread main entry point. """
- server = None
- try:
- server = self._get_httpd()
- self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
- self.host, self.port)
- except:
- # Whatever goes wrong, we save the exception for the main
- # thread. Note that since we are running in a thread, no signal
- # can be received, so we don't care about KeyboardInterrupt.
- self._http_exception = sys.exc_info()
-
- if server is not None:
- # From now on, exceptions are taken care of by the
- # SocketServer.BaseServer or the request handler.
- server.serve(started)
- if not started.isSet():
- # Hmm, something went wrong, but we can release the caller anyway
- started.set()
+ server = self._get_httpd()
+ self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
+ self.host, self.port)
+ server.serve(started)
def _get_remote_url(self, path):
path_parts = path.split(os.path.sep)
@@ -679,35 +665,37 @@
self._home_dir = os.getcwdu()
self._local_path_parts = self._home_dir.split(os.path.sep)
self._http_base_url = None
+ self.logs = []
# Create the server thread
started = threading.Event()
- self._http_thread = threading.Thread(target=self._http_start,
- args = (started,))
+ self._http_thread = test_server.ThreadWithException(
+ event=started, target=self._http_start, args=(started,))
self._http_thread.setDaemon(True)
- self._http_exception = None
self._http_thread.start()
# Wait for the server thread to start (i.e release the lock)
started.wait()
- self._http_thread.name = self._http_base_url
- if 'threads' in tests.selftest_debug_flags:
- print 'Thread started: %s' % (self._http_thread.name,)
-
-
- if self._http_exception is not None:
- # Something went wrong during server start
- exc_class, exc_value, exc_tb = self._http_exception
- raise exc_class, exc_value, exc_tb
- self.logs = []
+ if self._httpd is None:
+ if 'threads' in tests.selftest_debug_flags:
+ print 'Server %s:% start failed ' % (self.host, self.port)
+ else:
+ self._http_thread.name = self._http_base_url
+ if 'threads' in tests.selftest_debug_flags:
+ print 'Thread started: %s' % (self._http_thread.name,)
+
+ # If an exception occured during the server start, it will get raised
+ self._http_thread.join(timeout=0)
def stop_server(self):
"""See bzrlib.transport.Server.tearDown."""
- self._httpd.shutdown()
- if 'threads' in tests.selftest_debug_flags:
- print 'Try joining: %s' % (self._http_thread.name,)
- self._httpd.join_thread(self._http_thread)
- if 'threads' in tests.selftest_debug_flags:
- print 'Thread joined: %s' % (self._http_thread.name,)
+ if self._httpd is not None:
+ # The server has been started successfully, shut it down now
+ self._httpd.shutdown()
+ if 'threads' in tests.selftest_debug_flags:
+ print 'Try joining: %s' % (self._http_thread.name,)
+ self._httpd.join_thread(self._http_thread)
+ if 'threads' in tests.selftest_debug_flags:
+ print 'Thread joined: %s' % (self._http_thread.name,)
def get_url(self):
"""See bzrlib.transport.Server.get_url."""
=== modified file 'bzrlib/tests/test_http.py'
--- a/bzrlib/tests/test_http.py 2010-05-24 01:05:14 +0000
+++ b/bzrlib/tests/test_http.py 2010-05-26 15:25:59 +0000
@@ -340,21 +340,16 @@
def test_force_invalid_protocol(self):
server = http_server.HttpServer(protocol_version='HTTP/0.1')
- try:
- self.assertRaises(httplib.UnknownProtocol, server.start_server)
- except:
- server.stop_server()
- self.fail('HTTP Server creation did not raise UnknownProtocol')
+ self.addCleanup(server.stop_server)
+ self.assertRaises(httplib.UnknownProtocol, server.start_server)
def test_server_start_and_stop(self):
server = http_server.HttpServer()
+ self.addCleanup(server.stop_server)
server.start_server()
- try:
- self.assertTrue(server._httpd is not None)
- self.assertTrue(server._httpd.serving is not None)
- self.assertTrue(server._httpd.serving.isSet())
- finally:
- server.stop_server()
+ self.assertTrue(server._httpd is not None)
+ self.assertTrue(server._httpd.serving is not None)
+ self.assertTrue(server._httpd.serving.isSet())
def test_create_http_server_one_zero(self):
class RequestHandlerOneZero(http_server.TestingHTTPRequestHandler):
=== modified file 'bzrlib/tests/test_server.py'
--- a/bzrlib/tests/test_server.py 2010-05-26 11:05:29 +0000
+++ b/bzrlib/tests/test_server.py 2010-05-26 15:25:59 +0000
@@ -237,15 +237,29 @@
"""
def __init__(self, *args, **kwargs):
+ # There are cases where the calling thread must wait, yet, if an
+ # exception occurs the event should be set so the caller is not
+ # blocked.
+ try:
+ event = kwargs.pop('event')
+ except KeyError:
+ # If the caller didn't pass a specific event, create our own
+ event = threading.Event()
super(ThreadWithException, self).__init__(*args, **kwargs)
+ self.running = event
self.exception = None
def run(self):
"""Overrides Thread.run to capture any exception."""
+ self.running.clear()
try:
super(ThreadWithException, self).run()
except Exception, e:
self.exception = sys.exc_info()
+ finally:
+ # Make sure the calling thread is released
+ self.running.set()
+
def join(self, *args, **kwargs):
"""Overrides Thread.join to raise any exception caught.
@@ -260,7 +274,8 @@
# means it didn't encounter an exception.
super(ThreadWithException, self).join(*args, **kwargs)
if self.exception is not None:
- raise self.exception
+ exc_class, exc_value, exc_tb = self.exception
+ raise exc_class, exc_value, exc_tb
class SmartTCPServer_for_testing(server.SmartTCPServer):
More information about the bazaar-commits
mailing list