Rev 2524: Add tests around connection reuse. in file:///v/home/vila/src/experimental/reuse.transports/

Vincent Ladeuil v.ladeuil+lp at free.fr
Thu Jun 7 12:22:06 BST 2007


At file:///v/home/vila/src/experimental/reuse.transports/

------------------------------------------------------------
revno: 2524
revision-id: v.ladeuil+lp at free.fr-20070607112203-2c3190a3ppqg9c6m
parent: v.ladeuil+lp at free.fr-20070606142608-i9ufaqewadslf1cn
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: reuse.transports
timestamp: Thu 2007-06-07 13:22:03 +0200
message:
  Add tests around connection reuse.
  
  * bzrlib/transport/__init__.py:
  (ConnectedTransport._update_credentials): New method for
  transports that can authenticate again while keeping the
  connection alive.
  
  * bzrlib/tests/test_transport_implementations.py:
  (TransportTests.test__reuse_for,
  TransportTests.test_reuse_connection_for_various_paths): More
  tests for _reuse_for.
  
  * bzrlib/tests/test_transport.py:
  (TestConnectedTransport.test_connection_sharing_propagate_credentials):
  Add test for _update_credentials.
  (TestReusedTransports.test_reuse_same_transport): More tests.
modified:
  bzrlib/tests/test_transport.py testtransport.py-20050718175618-e5cdb99f4555ddce
  bzrlib/tests/test_transport_implementations.py test_transport_implementations.py-20051227111451-f97c5c7d5c49fce7
  bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
-------------- next part --------------
=== modified file 'bzrlib/tests/test_transport.py'
--- a/bzrlib/tests/test_transport.py	2007-06-06 13:52:02 +0000
+++ b/bzrlib/tests/test_transport.py	2007-06-07 11:22:03 +0000
@@ -546,6 +546,9 @@
         base_url = self._server.get_url()
         # try getting the transport via the regular interface:
         t = get_transport(base_url)
+        # vila--20070607 if the following are commented out the test suite
+        # still pass. Is this really still needed or was it a forgotten
+        # temporary fix ?
         if not isinstance(t, self.transport_class):
             # we did not get the correct transport class type. Override the
             # regular connection behaviour by direct construction.
@@ -680,6 +683,14 @@
         self.assertIs(connection, c._get_connection())
         self.assertIs(password, c._get_credentials())
 
+        # credentials can be updated
+        new_password = 'even more secret'
+        c._update_credentials(new_password)
+        self.assertIs(connection, t._get_connection())
+        self.assertIs(new_password, t._get_credentials())
+        self.assertIs(connection, c._get_connection())
+        self.assertIs(new_password, c._get_credentials())
+
 
 class TestReusedTransports(TestCase):
     """Tests for transport reuse"""
@@ -694,13 +705,13 @@
         t4 = get_transport('http://foo/path', possible_transports=[t3])
         self.assertIs(t3, t4)
 
-        t3 = get_transport('http://foo/path')
-        t4 = get_transport('http://foo/path/', possible_transports=[t3])
-        self.assertIs(t3, t4)
+        t5 = get_transport('http://foo/path')
+        t6 = get_transport('http://foo/path/', possible_transports=[t5])
+        self.assertIs(t5, t6)
 
     def test_don_t_reuse_different_transport(self):
-        t = get_transport('http://foo/path')
-        t2 = get_transport('http://bar/path', possible_transports=[t])
+        t1 = get_transport('http://foo/path')
+        t2 = get_transport('http://bar/path', possible_transports=[t1])
         self.assertIsNot(t, t2)
 
 

=== modified file 'bzrlib/tests/test_transport_implementations.py'
--- a/bzrlib/tests/test_transport_implementations.py	2007-06-06 14:26:08 +0000
+++ b/bzrlib/tests/test_transport_implementations.py	2007-06-07 11:22:03 +0000
@@ -1071,6 +1071,67 @@
         self.assertEquals(t1._host, t2._host)
         self.assertEquals(t1._port, t2._port)
 
+    def test__reuse_for(self):
+        t = self.get_transport()
+        if not isinstance(t, ConnectedTransport):
+            raise TestSkipped("not a connected transport")
+
+        def new_url(scheme=None, user=None, password=None,
+                    host=None, port=None, path=None):
+            """Build a new url from t.base chaging only parts of it.
+
+            Only the parameters different from None will be changed.
+            """
+            if scheme is None: scheme = t._scheme
+            if user is None: user = t._user
+            if password is None: password = t._password
+            if user is None: user = t._user
+            if host is None: host = t._host
+            if port is None: port = t._port
+            if path is None: path = t._path
+            return t._unsplit_url(scheme, user, password, host, port, path)
+
+        self.assertIsNot(t, t._reuse_for(new_url(scheme='foo')))
+        if t._user == 'me':
+            user = 'you'
+        else:
+            user = 'me'
+        self.assertIsNot(t, t._reuse_for(new_url(user=user)))
+        # passwords are not taken into account because:
+        # - it makes no sense to have two different valid passwords for the
+        #   same user
+        # - _password in ConnectedTransport is intended to collect what the
+        #   user specified from the command-line and there are cases where the
+        #   new url can contain no password (if the url was built from an
+        #   existing transport.base for example)
+        # - password are considered part of the credentials provided at
+        #   connection creation time and as such may not be present in the url
+        #   (they may be typed by the user when prompted for example)
+        self.assertIs(t, t._reuse_for(new_url(password='from space')))
+        # We will not connect, we can use a invalid host
+        self.assertIsNot(t, t._reuse_for(new_url(host=t._host + 'bar')))
+        if t._port == 1234:
+            port = 4321
+        else:
+            port = 1234
+        self.assertIsNot(t, t._reuse_for(new_url(port=port)))
+
+    def test_reuse_connection_for_various_paths(self):
+        t = self.get_transport()
+        if not isinstance(t, ConnectedTransport):
+            raise TestSkipped("not a connected transport")
+
+        t.has('surely_not') # Force connection
+        self.assertIsNot(None, t._get_connection())
+
+        subdir = t._reuse_for(t.base + 'whatever/but/deep/down/the/path')
+        self.assertIsNot(t, subdir)
+        self.assertIs(t._get_connection(), subdir._get_connection())
+
+        home = subdir._reuse_for(t.base + 'home')
+        self.assertIs(t._get_connection(), home._get_connection())
+        self.assertIs(subdir._get_connection(), home._get_connection())
+
     def test_clone(self):
         # TODO: Test that clone moves up and down the filesystem
         t1 = self.get_transport()

=== modified file 'bzrlib/transport/__init__.py'
--- a/bzrlib/transport/__init__.py	2007-06-06 14:26:08 +0000
+++ b/bzrlib/transport/__init__.py	2007-06-07 11:22:03 +0000
@@ -1057,7 +1057,9 @@
          self._path) = self._initial_split_url(base)
         if from_transport is not None:
             # Copy the password as it does not appear in base and will be lost
-            # otherwise.
+            # otherwise. It can appear in the _initial_split_url above if the
+            # user provided it on the command line. Otherwise, daughter classes
+            # will prompt the user for one when appropriate.
             self._password = from_transport._password
 
         base = self._unsplit_url(self._scheme,
@@ -1244,6 +1246,19 @@
         (connection, credentials) = self._connection[0]
         return self._connection[0][1]
 
+    def _update_credentials(self, credentials):
+        """Update the credentials of the current connection.
+
+        Some protocols can renegociate the credentials within a connection,
+        this method allows daughter classes to share updated credentials.
+        
+        :param credentials: the updated credentials.
+        """
+        # We don't want to call _set_connection here as we are only updating
+        # the credentials not creating a new connection.
+        (connection, old_credentials) = self._connection[0]
+        self._connection[0] = (connection, credentials)
+
     def _reuse_for(self, other_base):
         """Returns a transport sharing the same connection if possible.
 
@@ -1261,16 +1276,13 @@
         """
         (scheme, user, password, host, port, path) = self._split_url(other_base)
         transport = None
-        # Don't compare passwords, they may be absent from other_base
-        if (scheme,
-            user,
-            host, port) == (self._scheme,
-                            self._user,
-                            self._host, self._port):
+        # Don't compare passwords, they may be absent from other_base or from
+        # self and they don't carry more information than user anyway.
+        if (scheme, user, host, port) == (self._scheme,
+                                          self._user, self._host, self._port):
             if not path.endswith('/'):
                 # This normally occurs at __init__ time, but it's easier to do
-                # it now to avoid positives (creating two transports for the
-                # same base).
+                # it now to avoid creating two transports for the same base.
                 path += '/'
             if self._path  == path:
                 # shortcut, it's really the same transport
@@ -1284,7 +1296,8 @@
 
 
 # jam 20060426 For compatibility we copy the functions here
-# TODO: The should be marked as deprecated
+# TODO: They should be marked as deprecated
+# vila-20070606: How should we do that ?
 urlescape = urlutils.escape
 urlunescape = urlutils.unescape
 # We try to recognize an url lazily (ignoring user, password, etc)



More information about the bazaar-commits mailing list