/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/http_server.py

Cleanup and refactor the server shutdown.

* bzrlib/tests/http_server.py:
(TestingHTTPServerMixin): Implement a proper server() method able
to clean after itself and interruptible by calling shutdown() from
another thread.
(HttpServer._get_httpd): The server has already got the address
from the socket, just get it from there.
(HttpServer._http_start): Delegate the service to the server
itself.
(HttpServer.tearDown): Call server.shutdown() since that's more
appropriate.

Show diffs side-by-side

added added

removed removed

Lines of Context:
317
317
        # the tests cases.
318
318
        self.test_case_server = test_case_server
319
319
        self._home_dir = test_case_server._home_dir
320
 
 
321
 
    def tearDown(self):
322
 
         """Called to clean-up the server.
323
 
 
324
 
         Since the server may be (surely is, even) in a blocking listen, we
325
 
         shutdown its socket before closing it.
326
 
         """
327
 
         # The server is listening for a last connection, let's give it:
328
 
         try:
329
 
             fake_conn = socket.create_connection(self.server_address)
330
 
             fake_conn.close()
331
 
         except socket.error, e:
332
 
             # But ignore connection errors as the point is to unblock the
333
 
             # server thread, it may happen that it's not blocked or even not
334
 
             # started (when something went wrong during test case setup
335
 
             # leading to self.setUp() *not* being called but self.tearDown()
336
 
             # still being called)
337
 
             pass
338
 
 
339
 
 
340
 
class TestingHTTPServer(SocketServer.TCPServer, TestingHTTPServerMixin):
 
320
        self.serving = False
 
321
        self.is_shut_down = threading.Event()
 
322
 
 
323
    def serve(self):
 
324
        self.serving = True
 
325
        self.is_shut_down.clear()
 
326
        while self.serving:
 
327
            try:
 
328
                # Really a connection but the python framework is generic and
 
329
                # call them requests
 
330
                self.handle_request()
 
331
            except socket.timeout:
 
332
                pass
 
333
            except (socket.error, select.error), e:
 
334
               if e[0] == errno.EBADF:
 
335
                   # Starting with python-2.6, handle_request may raise socket
 
336
                   # or select exceptions when the server is shut down as we
 
337
                   # do.
 
338
                   pass
 
339
               else:
 
340
                   raise
 
341
        # Let's close the listening socket
 
342
        self.server_close()
 
343
        self.is_shut_down.set()
 
344
 
 
345
    def shutdown(self):
 
346
        """Stops the serve() loop.
 
347
 
 
348
        Blocks until the loop has finished. This must be called while serve()
 
349
        is running in another thread, or it will deadlock.
 
350
        """
 
351
        if not self.serving:
 
352
            return
 
353
        self.serving = False
 
354
        # The server is listening for a last connection, let's give it:
 
355
        try:
 
356
            fake_conn = socket.create_connection(self.server_address)
 
357
            fake_conn.close()
 
358
        except socket.error, e:
 
359
            # But ignore connection errors as the point is to unblock the
 
360
            # server thread, it may happen that it's not blocked or even not
 
361
            # started (when something went wrong during test case setup
 
362
            # leading to self.setUp() *not* being called but self.tearDown()
 
363
            # still being called)
 
364
            pass
 
365
        self.is_shut_down.wait()
 
366
 
 
367
 
 
368
class TestingHTTPServer(TestingHTTPServerMixin, SocketServer.TCPServer):
341
369
 
342
370
    def __init__(self, server_address, request_handler_class,
343
371
                 test_case_server):
346
374
                                        request_handler_class)
347
375
 
348
376
 
349
 
class TestingThreadingHTTPServer(SocketServer.ThreadingTCPServer,
350
 
                                 TestingHTTPServerMixin):
 
377
class TestingThreadingHTTPServer(TestingHTTPServerMixin,
 
378
                                 SocketServer.ThreadingTCPServer,
 
379
                                 ):
351
380
    """A threading HTTP test server for HTTP 1.1.
352
381
 
353
382
    Since tests can initiate several concurrent connections to the same http
445
474
                raise httplib.UnknownProtocol(proto_vers)
446
475
            else:
447
476
                self._httpd = self.create_httpd(serv_cls, rhandler)
448
 
            host, self.port = self._httpd.socket.getsockname()
 
477
            # Ensure we get the right port
 
478
            host, self.port = self._httpd.server_address
449
479
        return self._httpd
450
480
 
451
481
    def _http_start(self):
452
482
        """Server thread main entry point. """
453
 
        self._http_running = False
 
483
        server = None
454
484
        try:
455
485
            try:
456
 
                httpd = self._get_httpd()
 
486
                server = self._get_httpd()
457
487
                self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
458
488
                                                       self.host, self.port)
459
 
                self._http_running = True
460
489
            except:
461
490
                # Whatever goes wrong, we save the exception for the main
462
491
                # thread. Note that since we are running in a thread, no signal
469
498
 
470
499
        # From now on, exceptions are taken care of by the
471
500
        # SocketServer.BaseServer or the request handler.
472
 
        while self._http_running:
473
 
            try:
474
 
                # Really an HTTP connection but the python framework is generic
475
 
                # and call them requests
476
 
                httpd.handle_request()
477
 
            except socket.timeout:
478
 
                pass
479
 
            except (socket.error, select.error), e:
480
 
               if e[0] == errno.EBADF:
481
 
                   # Starting with python-2.6, handle_request may raise socket
482
 
                   # or select exceptions when the server is shut down (as we
483
 
                   # do).
484
 
                   pass
485
 
               else:
486
 
                   raise
487
 
        if self._httpd is not None:
488
 
            # Let the server properly close the listening socket
489
 
            self._httpd.server_close()
 
501
        if server is not None:
 
502
            server.serve()
490
503
 
491
504
    def _get_remote_url(self, path):
492
505
        path_parts = path.split(os.path.sep)
543
556
    def tearDown(self):
544
557
        """See bzrlib.transport.Server.tearDown."""
545
558
        self._http_running = False
546
 
        self._httpd.tearDown()
 
559
        self._httpd.shutdown()
547
560
        self._http_thread.join()
548
561
 
549
562
    def get_url(self):