Rev 5268: All http tests passing, https failing. in file:///home/vila/src/bzr/experimental/leaking-tests/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Fri Jun 4 12:48:56 BST 2010
At file:///home/vila/src/bzr/experimental/leaking-tests/
------------------------------------------------------------
revno: 5268
revision-id: v.ladeuil+lp at free.fr-20100604114856-7e505v5w40937ya5
parent: v.ladeuil+lp at free.fr-20100603183206-jlk1gjq9egmru3k9
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: http-leaks
timestamp: Fri 2010-06-04 13:48:56 +0200
message:
All http tests passing, https failing.
* bzrlib/tests/test_server.py:
(TestingTCPServerInAThread): Daughter classes prefer to deal
with (host, port) while SocketServer classes use server_address.
* bzrlib/tests/test_http.py:
Fix some refactoring fallouts.
* bzrlib/tests/http_server.py:
(TestingHTTPServerMixin.__init__): Vastly simplified now that we
use TestingTCPServerInAThread.
(HttpServer.__init__, HttpServer.create_server)
(HttpServer.start_server): Simplified to the specifics.
-------------- next part --------------
=== modified file 'bzrlib/tests/http_server.py'
--- a/bzrlib/tests/http_server.py 2010-06-02 14:50:04 +0000
+++ b/bzrlib/tests/http_server.py 2010-06-04 11:48:56 +0000
@@ -325,230 +325,33 @@
# the tests cases.
self.test_case_server = test_case_server
self._home_dir = test_case_server._home_dir
- self.serving = None
- self.is_shut_down = threading.Event()
- # We collect the sockets/threads used by the clients so we can
- # close/join them when shutting down
- self.clients = []
-
- def get_request (self):
- """Get the request and client address from the socket.
- """
- sock, addr = self._get_request()
- self.clients.append([sock, addr])
- return sock, addr
-
- def verify_request(self, request, client_address):
- """Verify the request.
-
- Return True if we should proceed with this request, False if we should
- not even touch a single byte in the socket !
- """
- return self.serving is not None and self.serving.isSet()
-
- def handle_request(self):
- request, client_address = self.get_request()
- try:
- if self.verify_request(request, client_address):
- self.process_request(request, client_address)
- except:
- if self.serving is not None and self.serving.isSet():
- self.handle_error(request, client_address)
- else:
- # Exceptions raised while we shut down are just noise, but feel
- # free to put a breakpoint here if you suspect something
- # else. Such an example is the SSL handshake: it's automatic
- # once we start processing the request but the last connection
- # will close immediately and will not be able to correctly
- # reply.
- pass
- self.close_request(request)
-
- def server_bind(self):
- # The following has been fixed in 2.5 so we need to provide it for
- # older python versions.
- if sys.version < (2, 5):
- self.server_address = self.socket.getsockname()
-
- def serve(self, started):
- self.serving = threading.Event()
- self.serving.set()
- self.is_shut_down.clear()
- if 'threads' in tests.selftest_debug_flags:
- print 'Starting %r' % (self.server_address,)
- # We are listening and ready to accept connections
- started.set()
- while self.serving.isSet():
- if 'threads' in tests.selftest_debug_flags:
- print 'Accepting on %r' % (self.server_address,)
- # Really a connection but the python framework is generic and
- # call them requests
- self.handle_request()
- if 'threads' in tests.selftest_debug_flags:
- print 'Closing %r' % (self.server_address,)
- # Let's close the listening socket
- self.server_close()
- if 'threads' in tests.selftest_debug_flags:
- print 'Closed %r' % (self.server_address,)
- self.is_shut_down.set()
-
- def join_thread(self, thread, timeout=2):
- thread.join(timeout)
- if thread.isAlive():
- # The timeout expired without joining the thread, the thread is
- # therefore stucked and that's a failure as far as the test is
- # concerned. We used to hang here.
- raise AssertionError('thread %s hung' % (thread.name,))
-
- def shutdown_server(self):
- """Stops the serve() loop.
-
- Blocks until the loop has finished. This must be called while serve()
- is running in another thread, or it will deadlock.
- """
- if self.serving is None:
- # If the server wasn't properly started, there is nothing to
- # shutdown.
- return
- # As soon as we stop serving, no more connection are accepted except
- # one to get out of the blocking listen.
- self.serving.clear()
- # The server is listening for a last connection, let's give it:
- last_conn = None
- try:
- last_conn = osutils.connect_socket(self.server_address)
- except socket.error, e:
- # But ignore connection errors as the point is to unblock the
- # server thread, it may happen that it's not blocked or even not
- # started (when something went wrong during test case setup
- # leading to self.setUp() *not* being called but self.tearDown()
- # still being called)
- pass
- # We don't have to wait for the server to shut down to start shutting
- # down the clients, so let's start now.
- for c in self.clients:
- self.shutdown_client(c)
- self.clients = []
- # Now we wait for the thread running serve() to finish
- self.is_shut_down.wait()
- if last_conn is not None:
- # Close the last connection without trying to use it. The server
- # will not process a single byte on that socket to avoid
- # complications (SSL starts with a handshake for example).
- last_conn.close()
-
- def shutdown_client(self, client):
- sock, addr = client[:2]
- self.shutdown_client_socket(sock)
-
- def shutdown_client_socket(self, sock):
- """Properly shutdown a client socket.
-
- Under some circumstances (as in bug #383920), we need to force the
- shutdown as python delays it until gc occur otherwise and the client
- may hang.
-
- This should be called only when no other thread is trying to use the
- socket.
- """
- try:
- # The request process has been completed, the thread is about to
- # die, let's shutdown the socket if we can.
- sock.shutdown(socket.SHUT_RDWR)
- sock.close()
- except (socket.error, select.error), e:
- if e[0] in (errno.EBADF, errno.ENOTCONN):
- # Right, the socket is already down
- pass
- else:
- print 'exception in shutdown_client_socket: %r' % (e,)
- raise
-
-
-class TestingHTTPServer(TestingHTTPServerMixin, SocketServer.TCPServer):
+
+
+class TestingHTTPServer(test_server.TestingTCPServer, TestingHTTPServerMixin):
def __init__(self, server_address, request_handler_class,
test_case_server):
+ test_server.TestingTCPServer.__init__(self, server_address,
+ request_handler_class)
TestingHTTPServerMixin.__init__(self, test_case_server)
- SocketServer.TCPServer.__init__(self, server_address,
- request_handler_class)
-
- def _get_request (self):
- return SocketServer.TCPServer.get_request(self)
-
- def server_bind(self):
- SocketServer.TCPServer.server_bind(self)
- TestingHTTPServerMixin.server_bind(self)
-
-
-class TestingThreadingHTTPServer(TestingHTTPServerMixin,
- SocketServer.ThreadingTCPServer,
- ):
+
+
+class TestingThreadingHTTPServer(test_server.TestingThreadingTCPServer,
+ TestingHTTPServerMixin):
"""A threading HTTP test server for HTTP 1.1.
Since tests can initiate several concurrent connections to the same http
server, we need an independent connection for each of them. We achieve that
by spawning a new thread for each connection.
"""
-
def __init__(self, server_address, request_handler_class,
test_case_server):
+ test_server.TestingThreadingTCPServer.__init__(self, server_address,
+ request_handler_class)
TestingHTTPServerMixin.__init__(self, test_case_server)
- SocketServer.ThreadingTCPServer.__init__(self, server_address,
- request_handler_class)
- # Decides how threads will act upon termination of the main
- # process. This is prophylactic as we should not leave the threads
- # lying around.
- self.daemon_threads = True
-
- def _get_request (self):
- return SocketServer.ThreadingTCPServer.get_request(self)
-
- def process_request_thread(self, started, request, client_address):
- if 'threads' in tests.selftest_debug_flags:
- print 'Processing: %s' % (threading.currentThread().name,)
- started.set()
- SocketServer.ThreadingTCPServer.process_request_thread(
- self, request, client_address)
- # Shutdown the socket as soon as possible, the thread will be joined
- # later if needed during server shutdown thread.
- self.shutdown_client_socket(request)
-
- def process_request(self, request, client_address):
- """Start a new thread to process the request."""
- client = self.clients.pop()
- started = threading.Event()
- t = test_server.ThreadWithException(
- event=started,
- target = self.process_request_thread,
- args = (started, request, client_address))
- t.name = '%s -> %s' % (client_address, self.server_address)
- if 'threads' in tests.selftest_debug_flags:
- print 'Thread for: %s started' % (threading.currentThread().name,)
- client.append(t)
- self.clients.append(client)
- if self.daemon_threads:
- t.setDaemon (1)
- t.start()
- started.wait()
-
- def shutdown_client(self, client):
- TestingHTTPServerMixin.shutdown_client(self, client)
- if len(client) == 3:
- # The thread has been created only if the request is processed but
- # after the connection is inited. This could happen during server
- # shutdown.
- sock, addr, thread = client
- if 'threads' in tests.selftest_debug_flags:
- print 'Try joining: %s' % (thread.name,)
- self.join_thread(thread)
-
- def server_bind(self):
- SocketServer.ThreadingTCPServer.server_bind(self)
- TestingHTTPServerMixin.server_bind(self)
-
-
-class HttpServer(transport.Server):
+
+
+class HttpServer(test_server.TestingTCPServerInAThread):
"""A test server for http transports.
Subclasses can provide a specific request handler.
@@ -576,50 +379,33 @@
:param protocol_version: if specified, will override the protocol
version of the request handler.
"""
- transport.Server.__init__(self)
- self.request_handler = request_handler
+ # Depending on the protocol version, we will create the approriate
+ # server
+ if protocol_version is None:
+ # Use the request handler one
+ proto_vers = request_handler.protocol_version
+ else:
+ # Use our own, it will be used to override the request handler
+ # one too.
+ proto_vers = protocol_version
+ # Get the appropriate server class for the required protocol
+ serv_cls = self.http_server_class.get(proto_vers, None)
+ if serv_cls is None:
+ raise httplib.UnknownProtocol(proto_vers)
self.host = 'localhost'
self.port = 0
- self._httpd = None
- self.protocol_version = protocol_version
+ super(HttpServer, self).__init__((self.host, self.port),
+ serv_cls,
+ request_handler)
+ self.protocol_version = proto_vers
# Allows tests to verify number of GET requests issued
self.GET_request_nb = 0
-
- def create_httpd(self, serv_cls, rhandler_cls):
- return serv_cls((self.host, self.port), self.request_handler, self)
-
- def __repr__(self):
- return "%s(%s:%s)" % \
- (self.__class__.__name__, self.host, self.port)
-
- def _get_httpd(self):
- if self._httpd is None:
- rhandler = self.request_handler
- # Depending on the protocol version, we will create the approriate
- # server
- if self.protocol_version is None:
- # Use the request handler one
- proto_vers = rhandler.protocol_version
- else:
- # Use our own, it will be used to override the request handler
- # one too.
- proto_vers = self.protocol_version
- # Create the appropriate server for the required protocol
- serv_cls = self.http_server_class.get(proto_vers, None)
- if serv_cls is None:
- raise httplib.UnknownProtocol(proto_vers)
- else:
- self._httpd = self.create_httpd(serv_cls, rhandler)
- # Ensure we get the right port and an updated host if needed
- self.host, self.port = self._httpd.server_address
- return self._httpd
-
- def run_server(self, started):
- """Server thread main entry point. """
- server = self._get_httpd()
- self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
- self.host, self.port)
- server.serve(started)
+ self._http_base_url = None
+ self.logs = []
+
+ def create_server(self):
+ return self.server_class(
+ (self.host, self.port), self.request_handler_class, self)
def _get_remote_url(self, path):
path_parts = path.split(os.path.sep)
@@ -654,37 +440,11 @@
backing_transport_server)
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 = test_server.ThreadWithException(
- event=started, target=self.run_server, args=(started,))
- self._http_thread.start()
- # Wait for the server thread to start (i.e release the lock)
- started.wait()
- 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."""
- if self._httpd is not None:
- # The server has been started successfully, shut it down now
- self._httpd.shutdown_server()
- 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,)
+ super(HttpServer, self).start_server()
+ self._http_base_url = '%s://%s:%s/' % (
+ self._url_protocol, self.host, self.port)
def get_url(self):
"""See bzrlib.transport.Server.get_url."""
=== modified file 'bzrlib/tests/test_http.py'
--- a/bzrlib/tests/test_http.py 2010-06-02 13:01:24 +0000
+++ b/bzrlib/tests/test_http.py 2010-06-04 11:48:56 +0000
@@ -308,25 +308,20 @@
protocol_version = 'HTTP/0.1'
- server = http_server.HttpServer(BogusRequestHandler)
- try:
- self.assertRaises(httplib.UnknownProtocol, server.start_server)
- except:
- server.stop_server()
- self.fail('HTTP Server creation did not raise UnknownProtocol')
+ self.assertRaises(httplib.UnknownProtocol,
+ http_server.HttpServer, BogusRequestHandler)
def test_force_invalid_protocol(self):
- server = http_server.HttpServer(protocol_version='HTTP/0.1')
- self.addCleanup(server.stop_server)
- self.assertRaises(httplib.UnknownProtocol, server.start_server)
+ self.assertRaises(httplib.UnknownProtocol,
+ http_server.HttpServer, protocol_version='HTTP/0.1')
def test_server_start_and_stop(self):
server = http_server.HttpServer()
self.addCleanup(server.stop_server)
server.start_server()
- self.assertTrue(server._httpd is not None)
- self.assertTrue(server._httpd.serving is not None)
- self.assertTrue(server._httpd.serving.isSet())
+ self.assertTrue(server.server is not None)
+ self.assertTrue(server.server.serving is not None)
+ self.assertTrue(server.server.serving.isSet())
def test_create_http_server_one_zero(self):
class RequestHandlerOneZero(http_server.TestingHTTPRequestHandler):
@@ -335,7 +330,7 @@
server = http_server.HttpServer(RequestHandlerOneZero)
self.start_server(server)
- self.assertIsInstance(server._httpd, http_server.TestingHTTPServer)
+ self.assertIsInstance(server.server, http_server.TestingHTTPServer)
def test_create_http_server_one_one(self):
class RequestHandlerOneOne(http_server.TestingHTTPRequestHandler):
@@ -344,7 +339,7 @@
server = http_server.HttpServer(RequestHandlerOneOne)
self.start_server(server)
- self.assertIsInstance(server._httpd,
+ self.assertIsInstance(server.server,
http_server.TestingThreadingHTTPServer)
def test_create_http_server_force_one_one(self):
@@ -355,7 +350,7 @@
server = http_server.HttpServer(RequestHandlerOneZero,
protocol_version='HTTP/1.1')
self.start_server(server)
- self.assertIsInstance(server._httpd,
+ self.assertIsInstance(server.server,
http_server.TestingThreadingHTTPServer)
def test_create_http_server_force_one_zero(self):
@@ -366,7 +361,7 @@
server = http_server.HttpServer(RequestHandlerOneOne,
protocol_version='HTTP/1.0')
self.start_server(server)
- self.assertIsInstance(server._httpd,
+ self.assertIsInstance(server.server,
http_server.TestingHTTPServer)
@@ -1792,7 +1787,7 @@
self.assertEqual(expected_reply_body, reply_body)
def test_smart_http_server_post_request_handler(self):
- httpd = self.get_readonly_server()._get_httpd()
+ httpd = self.get_readonly_server().server
socket = SampleSocket(
'POST /.bzr/smart %s \r\n' % self._protocol_version
@@ -1838,6 +1833,7 @@
t.get_smart_medium().send_http_smart_request,
'whatever')
+
class Test_redirected_to(tests.TestCase):
def test_redirected_to_subdir(self):
=== modified file 'bzrlib/tests/test_server.py'
--- a/bzrlib/tests/test_server.py 2010-06-03 18:32:06 +0000
+++ b/bzrlib/tests/test_server.py 2010-06-04 11:48:56 +0000
@@ -347,6 +347,7 @@
def handle_error(self, request, client_address):
# Stop serving and re-raise the last exception seen
self.serving.clear()
+ self.sibling_class.handle_error(self, request, client_address)
raise
# The following methods are called by the main thread
@@ -458,14 +459,14 @@
def __init__(self, server_address, server_class, request_handler_class):
self.server_class = server_class
self.request_handler_class = request_handler_class
- self.server_address = server_address
+ self.host, self.port = server_address
self.server = None
def __repr__(self):
- return "%s%r" % (self.__class__.__name__, self.server_address)
+ return "%s(%s:%s)" % (self.__class__.__name__, self.host, self.port)
def create_server(self):
- return self.server_class(self.server_address,
+ return self.server_class((self.host, self.port),
self.request_handler_class)
def start_server(self):
@@ -476,8 +477,8 @@
# Wait for the server thread to start (i.e release the lock)
self.server.started.wait()
# Get the real address, especially the port
- self.server_address = self.server.server_address
- self._server_thread.name = self.server_address
+ self.host, self.port = self.server.server_address
+ self._server_thread.name = '(%s:%s)' % (self.host, self.port)
# If an exception occured during the server start, it will get raised,
# otherwise, the server is blocked on its accept() call.
self._server_thread.pending_exception()
@@ -499,7 +500,7 @@
# The server is listening for a last connection, let's give it:
last_conn = None
try:
- last_conn = osutils.connect_socket(self.server.server_address)
+ last_conn = osutils.connect_socket((self.host, self.port))
except socket.error, e:
# But ignore connection errors as the point is to unblock the
# server thread, it may happen that it's not blocked or even
More information about the bazaar-commits
mailing list