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