/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/test_smart_transport.py

  • Committer: Robert Collins
  • Date: 2007-03-25 08:59:56 UTC
  • mto: (2376.3.1 integration)
  • mto: This revision was merged to the branch mainline in revision 2401.
  • Revision ID: robertc@robertcollins.net-20070325085956-my8jv7cifqzyltyz
New SmartServer hooks facility. There are two initial hooks documented
in bzrlib.transport.smart.SmartServerHooks. The two initial hooks allow
plugins to execute code upon server startup and shutdown.
(Robert Collins).

SmartServer in standalone mode will now close its listening socket
when it stops, rather than waiting for garbage collection. This primarily
fixes test suite hangs when a test tries to connect to a shutdown server.
It may also help improve behaviour when dealing with a server running
on a specific port (rather than dynamically assigned ports).
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
808
808
        self.server = smart.SmartTCPServer(self.backing_transport)
809
809
        self.server.start_background_thread()
810
810
        self.transport = smart.SmartTCPTransport(self.server.get_url())
 
811
        self.addCleanup(self.tearDownServer)
811
812
 
812
 
    def tearDown(self):
 
813
    def tearDownServer(self):
813
814
        if getattr(self, 'transport', None):
814
815
            self.transport.disconnect()
 
816
            del self.transport
815
817
        if getattr(self, 'server', None):
816
818
            self.server.stop_background_thread()
817
 
        super(SmartTCPTests, self).tearDown()
818
 
        
 
819
            del self.server
 
820
 
 
821
 
 
822
class TestServerSocketUsage(SmartTCPTests):
 
823
 
 
824
    def test_server_closes_listening_sock_on_shutdown(self):
 
825
        """The server should close its listening socket when its stopped."""
 
826
        self.setUpServer()
 
827
        # clean up the server and initial transport (which wont have connected)
 
828
        server = self.server
 
829
        # force a connection, which uses the listening socket to synchronise
 
830
        # with the server thread, so that when we shut it down it has already
 
831
        # executed the 'self._should_terminate = False' line in the server
 
832
        # method.
 
833
        self.transport.has('.')
 
834
        self.tearDownServer()
 
835
        # make a new connection to break out the inner loop in the server.
 
836
        transport = smart.SmartTCPTransport(server.get_url())
 
837
        # force the connection
 
838
        transport.has('.')
 
839
        # and close it.
 
840
        transport.disconnect()
 
841
        del transport
 
842
        while server._server_thread.isAlive():
 
843
            # this is fugly: we should have an event for the server we can
 
844
            # wait for.
 
845
            import time; time.sleep(0.001)
 
846
        # if the listening socket has closed, we should get a BADFD error
 
847
        # when connecting, rather than a hang.
 
848
        transport = smart.SmartTCPTransport(server.get_url())
 
849
        self.assertRaises(errors.ConnectionError, transport.has, '.')
 
850
 
819
851
 
820
852
class WritableEndToEndTests(SmartTCPTests):
821
853
    """Client to server tests that require a writable transport."""
901
933
        self.setUpServer(readonly=True)
902
934
        self.assertRaises(errors.TransportNotPossible, self.transport.mkdir,
903
935
            'foo')
904
 
        
 
936
 
 
937
 
 
938
class TestServerHooks(SmartTCPTests):
 
939
 
 
940
    def capture_server_call(self, backing_url, public_url):
 
941
        """Record a server_started|stopped hook firing."""
 
942
        self.hook_calls.append((backing_url, public_url))
 
943
 
 
944
    def test_server_started_hook(self):
 
945
        """The server_started hook fires when the server is started."""
 
946
        self.hook_calls = []
 
947
        smart.SmartTCPServer.hooks.install_hook('server_started',
 
948
            self.capture_server_call)
 
949
        self.setUpServer()
 
950
        # at this point, the server will be starting a thread up.
 
951
        # there is no indicator at the moment, so bodge it by doing a request.
 
952
        self.transport.has('.')
 
953
        self.assertEqual([(self.backing_transport.base, self.transport.base)],
 
954
            self.hook_calls)
 
955
 
 
956
    def test_server_stopped_hook_simple(self):
 
957
        """The server_stopped hook fires when the server is stopped."""
 
958
        self.hook_calls = []
 
959
        smart.SmartTCPServer.hooks.install_hook('server_stopped',
 
960
            self.capture_server_call)
 
961
        self.setUpServer()
 
962
        result = [(self.backing_transport.base, self.transport.base)]
 
963
        # check the stopping message isn't emitted up front, this also
 
964
        # has the effect of synchronising with the server, so that
 
965
        # when we shut it down it has already executed the 
 
966
        # 'self._should_terminate = False' line in the server method.
 
967
        self.transport.has('.')
 
968
        self.assertEqual([], self.hook_calls)
 
969
        # clean up the server
 
970
        server = self.server
 
971
        self.tearDownServer()
 
972
        # make a new connection to break out the inner loop in the server.
 
973
        transport = smart.SmartTCPTransport(result[0][1])
 
974
        transport.has('.')
 
975
        transport.disconnect()
 
976
        del transport
 
977
        while server._server_thread.isAlive():
 
978
            # this is fugly: we should have an event for the server we can
 
979
            # wait for.
 
980
            import time; time.sleep(0.001)
 
981
        self.assertEqual(result, self.hook_calls)
 
982
 
 
983
# TODO: test that when the server suffers an exception that it calls the
 
984
# server-stopped hook.
 
985
 
905
986
 
906
987
class SmartServerRequestHandlerTests(tests.TestCaseWithTransport):
907
988
    """Test that call directly into the handler logic, bypassing the network."""