Rev 3114: Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually). in file:///v/home/vila/src/bzr/bugs/175524/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Mon Dec 17 10:16:21 GMT 2007
At file:///v/home/vila/src/bzr/bugs/175524/
------------------------------------------------------------
revno: 3114
revision-id:v.ladeuil+lp at free.fr-20071217101617-zsszx3y00yj25dd2
parent: v.ladeuil+lp at free.fr-20071217085652-p4m867lxku62pmsn
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 175524
timestamp: Mon 2007-12-17 11:16:17 +0100
message:
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
* bzrlib/tests/http_server.py:
(TestingHTTPServerWrapper): Introduce a wrapper to allow different
subclasses for servers while keeping the common parts in a single
place.
(TestingHTTPServer): The 1.0 server.
(TestingThreadingHTTPServer): The 1.1 server.
modified:
bzrlib/tests/http_server.py httpserver.py-20061012142527-m1yxdj1xazsf8d7s-1
-------------- next part --------------
=== modified file 'bzrlib/tests/http_server.py'
--- a/bzrlib/tests/http_server.py 2007-12-17 08:56:52 +0000
+++ b/bzrlib/tests/http_server.py 2007-12-17 10:16:17 +0000
@@ -23,6 +23,7 @@
import re
import SimpleHTTPServer
import socket
+import SocketServer
import sys
import threading
import time
@@ -268,26 +269,77 @@
return path
-class TestingHTTPServer(BaseHTTPServer.HTTPServer):
-
- def __init__(self, server_address, request_handler_class,
- test_case_server):
- BaseHTTPServer.HTTPServer.__init__(self, server_address,
- request_handler_class)
+class TestingHTTPServerWrapper(object):
+ """Isolate the wrapper itself to make the server use transparent.
+
+ Daughter classes can override any method and/or directly call the _server
+ methods.
+ """
+
+ def __init__(self, server_class, test_case_server,
+ server_address, request_handler_class):
+ self._server = server_class(server_address, request_handler_class)
# test_case_server can be used to communicate between the
# tests and the server (or the request handler and the
# server), allowing dynamic behaviors to be defined from
# the tests cases.
- self.test_case_server = test_case_server
+ self._server.test_case_server = test_case_server
+
+ def __getattr__(self, name):
+ return getattr(self._server, name)
+
+ def server_bind(self):
+ """Override server_bind to store the server name."""
+ self._server.server_bind()
+ host, port = self._server.socket.getsockname()[:2]
+ self._server.server_name = socket.getfqdn(host)
+ self._server.server_port = port
def server_close(self):
- """Called to clean-up the server.
-
- Since the server may be in a blocking read, we shutdown the socket
- before closing it.
- """
- self.socket.shutdown(socket.SHUT_RDWR)
- BaseHTTPServer.HTTPServer.server_close(self)
+ """Called to clean-up the server.
+
+ Since the server may be (surely is, even) in a blocking listen, we
+ shutdown its socket before closing it.
+ """
+ # Note that is this executed as part of the implicit tear down in the
+ # main thread while the server runs in its own thread. The clean way
+ # to tear down the server will be to instruct him to stop accepting
+ # connections and wait for the current connection to end naturally. To
+ # end the connection naturally, the http transports should close their
+ # socket when they do not need to talk to the server anymore. We
+ # don't want to impose such a constraint on the http transports (and
+ # we can't anyway ;). So we must tear down here, from the main thread,
+ # when the test have ended. Note that since the server is in a
+ # blocking operation and since python use select internally, shutting
+ # down the socket is reliable and relatively clean.
+ self._server.socket.shutdown(socket.SHUT_RDWR)
+ # Let the server properly close the socket
+ self._server.server_close()
+
+class TestingHTTPServer(TestingHTTPServerWrapper):
+
+ def __init__(self, server_address, request_handler_class, test_case_server):
+ super(TestingHTTPServer, self).__init__(
+ SocketServer.TCPServer, test_case_server,
+ server_address, request_handler_class)
+
+
+class TestingThreadingHTTPServer(TestingHTTPServerWrapper):
+ """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):
+ super(TestingThreadingHTTPServer, self).__init__(
+ SocketServer.ThreadingTCPServer, test_case_server,
+ 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._server.daemon_threads = True
class HttpServer(transport.Server):
@@ -315,9 +367,8 @@
def _get_httpd(self):
if self._httpd is None:
- self._httpd = TestingHTTPServer((self.host, self.port),
- self.request_handler,
- self)
+ self._httpd = TestingHTTPServer(
+ (self.host, self.port), self.request_handler, self)
host, self.port = self._httpd.socket.getsockname()
return self._httpd
More information about the bazaar-commits
mailing list