~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transport.py

  • Committer: Ian Clatworthy
  • Date: 2009-09-09 11:43:10 UTC
  • mto: (4634.37.2 prepare-2.0)
  • mto: This revision was merged to the branch mainline in revision 4689.
  • Revision ID: ian.clatworthy@canonical.com-20090909114310-glw7tv76i5gnx9pt
put rules back in Makefile supporting plain-style docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
 
18
 
import os
19
 
import sys
20
 
import stat
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
21
18
from cStringIO import StringIO
22
19
 
23
20
import bzrlib
24
21
from bzrlib import (
25
22
    errors,
 
23
    osutils,
26
24
    urlutils,
27
25
    )
28
 
from bzrlib.errors import (ConnectionError,
29
 
                           DependencyNotPresent,
 
26
from bzrlib.errors import (DependencyNotPresent,
30
27
                           FileExists,
31
28
                           InvalidURLJoin,
32
29
                           NoSuchFile,
33
30
                           PathNotChild,
34
 
                           TransportNotPossible,
35
 
                           ConnectionError,
36
 
                           DependencyNotPresent,
37
31
                           ReadError,
38
32
                           UnsupportedProtocol,
39
33
                           )
40
34
from bzrlib.tests import TestCase, TestCaseInTempDir
41
 
from bzrlib.transport import (_CoalescedOffset,
 
35
from bzrlib.transport import (_clear_protocol_handlers,
 
36
                              _CoalescedOffset,
42
37
                              ConnectedTransport,
43
38
                              _get_protocol_handlers,
44
39
                              _set_protocol_handlers,
47
42
                              LateReadError,
48
43
                              register_lazy_transport,
49
44
                              register_transport_proto,
50
 
                              _clear_protocol_handlers,
51
45
                              Transport,
52
46
                              )
53
47
from bzrlib.transport.chroot import ChrootServer
73
67
 
74
68
    def test_get_transport_modules(self):
75
69
        handlers = _get_protocol_handlers()
 
70
        # don't pollute the current handlers
 
71
        _clear_protocol_handlers()
76
72
        class SampleHandler(object):
77
73
            """I exist, isnt that enough?"""
78
74
        try:
79
75
            _clear_protocol_handlers()
80
76
            register_transport_proto('foo')
81
 
            register_lazy_transport('foo', 'bzrlib.tests.test_transport', 'TestTransport.SampleHandler')
 
77
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
 
78
                                    'TestTransport.SampleHandler')
82
79
            register_transport_proto('bar')
83
 
            register_lazy_transport('bar', 'bzrlib.tests.test_transport', 'TestTransport.SampleHandler')
84
 
            self.assertEqual([SampleHandler.__module__, 'bzrlib.transport.chroot'],
 
80
            register_lazy_transport('bar', 'bzrlib.tests.test_transport',
 
81
                                    'TestTransport.SampleHandler')
 
82
            self.assertEqual([SampleHandler.__module__,
 
83
                              'bzrlib.transport.chroot'],
85
84
                             _get_transport_modules())
86
85
        finally:
87
86
            _set_protocol_handlers(handlers)
89
88
    def test_transport_dependency(self):
90
89
        """Transport with missing dependency causes no error"""
91
90
        saved_handlers = _get_protocol_handlers()
 
91
        # don't pollute the current handlers
 
92
        _clear_protocol_handlers()
92
93
        try:
93
94
            register_transport_proto('foo')
94
95
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
106
107
        finally:
107
108
            # restore original values
108
109
            _set_protocol_handlers(saved_handlers)
109
 
            
 
110
 
110
111
    def test_transport_fallback(self):
111
112
        """Transport with missing dependency causes no error"""
112
113
        saved_handlers = _get_protocol_handlers()
122
123
        finally:
123
124
            _set_protocol_handlers(saved_handlers)
124
125
 
 
126
    def test_ssh_hints(self):
 
127
        """Transport ssh:// should raise an error pointing out bzr+ssh://"""
 
128
        try:
 
129
            get_transport('ssh://fooserver/foo')
 
130
        except UnsupportedProtocol, e:
 
131
            e_str = str(e)
 
132
            self.assertEquals('Unsupported protocol'
 
133
                              ' for url "ssh://fooserver/foo":'
 
134
                              ' bzr supports bzr+ssh to operate over ssh, use "bzr+ssh://fooserver/foo".',
 
135
                              str(e))
 
136
        else:
 
137
            self.fail('Did not raise UnsupportedProtocol')
 
138
 
125
139
    def test_LateReadError(self):
126
140
        """The LateReadError helper should raise on read()."""
127
141
        a_file = LateReadError('a path')
151
165
 
152
166
 
153
167
class TestCoalesceOffsets(TestCase):
154
 
    
155
 
    def check(self, expected, offsets, limit=0, fudge=0):
 
168
 
 
169
    def check(self, expected, offsets, limit=0, max_size=0, fudge=0):
156
170
        coalesce = Transport._coalesce_offsets
157
171
        exp = [_CoalescedOffset(*x) for x in expected]
158
 
        out = list(coalesce(offsets, limit=limit, fudge_factor=fudge))
 
172
        out = list(coalesce(offsets, limit=limit, fudge_factor=fudge,
 
173
                            max_size=max_size))
159
174
        self.assertEqual(exp, out)
160
175
 
161
176
    def test_coalesce_empty(self):
168
183
        self.check([(0, 10, [(0, 10)]),
169
184
                    (20, 10, [(0, 10)]),
170
185
                   ], [(0, 10), (20, 10)])
171
 
            
 
186
 
172
187
    def test_coalesce_unsorted(self):
173
188
        self.check([(20, 10, [(0, 10)]),
174
189
                    (0, 10, [(0, 10)]),
179
194
                   [(0, 10), (10, 10)])
180
195
 
181
196
    def test_coalesce_overlapped(self):
182
 
        self.check([(0, 15, [(0, 10), (5, 10)])],
183
 
                   [(0, 10), (5, 10)])
 
197
        self.assertRaises(ValueError,
 
198
            self.check, [(0, 15, [(0, 10), (5, 10)])],
 
199
                        [(0, 10), (5, 10)])
184
200
 
185
201
    def test_coalesce_limit(self):
186
202
        self.check([(10, 50, [(0, 10), (10, 10), (20, 10),
207
223
                   ], [(10, 10), (30, 10), (100, 10)],
208
224
                   fudge=10
209
225
                  )
 
226
    def test_coalesce_max_size(self):
 
227
        self.check([(10, 20, [(0, 10), (10, 10)]),
 
228
                    (30, 50, [(0, 50)]),
 
229
                    # If one range is above max_size, it gets its own coalesced
 
230
                    # offset
 
231
                    (100, 80, [(0, 80),]),],
 
232
                   [(10, 10), (20, 10), (30, 50), (100, 80)],
 
233
                   max_size=50
 
234
                  )
 
235
 
 
236
    def test_coalesce_no_max_size(self):
 
237
        self.check([(10, 170, [(0, 10), (10, 10), (20, 50), (70, 100)]),],
 
238
                   [(10, 10), (20, 10), (30, 50), (80, 100)],
 
239
                  )
 
240
 
 
241
    def test_coalesce_default_limit(self):
 
242
        # By default we use a 100MB max size.
 
243
        ten_mb = 10*1024*1024
 
244
        self.check([(0, 10*ten_mb, [(i*ten_mb, ten_mb) for i in range(10)]),
 
245
                    (10*ten_mb, ten_mb, [(0, ten_mb)])],
 
246
                   [(i*ten_mb, ten_mb) for i in range(11)])
 
247
        self.check([(0, 11*ten_mb, [(i*ten_mb, ten_mb) for i in range(11)]),],
 
248
                   [(i*ten_mb, ten_mb) for i in range(11)],
 
249
                   max_size=1*1024*1024*1024)
210
250
 
211
251
 
212
252
class TestMemoryTransport(TestCase):
341
381
        self.assertEqual(server, relpath_cloned.server)
342
382
        self.assertEqual(server, abspath_cloned.server)
343
383
        server.tearDown()
344
 
    
 
384
 
345
385
    def test_chroot_url_preserves_chroot(self):
346
386
        """Calling get_transport on a chroot transport's base should produce a
347
387
        transport with exactly the same behaviour as the original chroot
359
399
        self.assertEqual(transport.server, new_transport.server)
360
400
        self.assertEqual(transport.base, new_transport.base)
361
401
        server.tearDown()
362
 
        
 
402
 
363
403
    def test_urljoin_preserves_chroot(self):
364
404
        """Using urlutils.join(url, '..') on a chroot URL should not produce a
365
405
        URL that escapes the intended chroot.
416
456
        self.assertEqual(True, transport.is_readonly())
417
457
 
418
458
    def test_http_parameters(self):
419
 
        from bzrlib.tests.HttpServer import HttpServer
 
459
        from bzrlib.tests.http_server import HttpServer
420
460
        import bzrlib.transport.readonly as readonly
421
 
        # connect to . via http which is not listable
 
461
        # connect to '.' via http which is not listable
422
462
        server = HttpServer()
423
463
        server.setUp()
424
464
        try:
449
489
    def test_http_parameters(self):
450
490
        # the listable and is_readonly parameters
451
491
        # are not changed by the fakenfs decorator
452
 
        from bzrlib.tests.HttpServer import HttpServer
453
 
        # connect to . via http which is not listable
 
492
        from bzrlib.tests.http_server import HttpServer
 
493
        # connect to '.' via http which is not listable
454
494
        server = HttpServer()
455
495
        server.setUp()
456
496
        try:
524
564
 
525
565
class TestTransportImplementation(TestCaseInTempDir):
526
566
    """Implementation verification for transports.
527
 
    
 
567
 
528
568
    To verify a transport we need a server factory, which is a callable
529
569
    that accepts no parameters and returns an implementation of
530
570
    bzrlib.transport.Server.
531
 
    
 
571
 
532
572
    That Server is then used to construct transport instances and test
533
573
    the transport via loopback activity.
534
574
 
535
 
    Currently this assumes that the Transport object is connected to the 
536
 
    current working directory.  So that whatever is done 
537
 
    through the transport, should show up in the working 
 
575
    Currently this assumes that the Transport object is connected to the
 
576
    current working directory.  So that whatever is done
 
577
    through the transport, should show up in the working
538
578
    directory, and vice-versa. This is a bug, because its possible to have
539
 
    URL schemes which provide access to something that may not be 
540
 
    result in storage on the local disk, i.e. due to file system limits, or 
 
579
    URL schemes which provide access to something that may not be
 
580
    result in storage on the local disk, i.e. due to file system limits, or
541
581
    due to it being a database or some other non-filesystem tool.
542
582
 
543
583
    This also tests to make sure that the functions work with both
544
584
    generators and lists (assuming iter(list) is effectively a generator)
545
585
    """
546
 
    
 
586
 
547
587
    def setUp(self):
548
588
        super(TestTransportImplementation, self).setUp()
549
589
        self._server = self.transport_server()
572
612
class TestLocalTransports(TestCase):
573
613
 
574
614
    def test_get_transport_from_abspath(self):
575
 
        here = os.path.abspath('.')
 
615
        here = osutils.abspath('.')
576
616
        t = get_transport(here)
577
617
        self.assertIsInstance(t, LocalTransport)
578
618
        self.assertEquals(t.base, urlutils.local_path_to_url(here) + '/')
579
619
 
580
620
    def test_get_transport_from_relpath(self):
581
 
        here = os.path.abspath('.')
 
621
        here = osutils.abspath('.')
582
622
        t = get_transport('.')
583
623
        self.assertIsInstance(t, LocalTransport)
584
624
        self.assertEquals(t.base, urlutils.local_path_to_url('.') + '/')
585
625
 
586
626
    def test_get_transport_from_local_url(self):
587
 
        here = os.path.abspath('.')
 
627
        here = osutils.abspath('.')
588
628
        here_url = urlutils.local_path_to_url(here) + '/'
589
629
        t = get_transport(here_url)
590
630
        self.assertIsInstance(t, LocalTransport)
591
631
        self.assertEquals(t.base, here_url)
592
632
 
593
633
    def test_local_abspath(self):
594
 
        here = os.path.abspath('.')
 
634
        here = osutils.abspath('.')
595
635
        t = get_transport(here)
596
636
        self.assertEquals(t.local_abspath(''), here)
597
637
 
615
655
    """Tests for connected to remote server transports"""
616
656
 
617
657
    def test_parse_url(self):
618
 
        t = ConnectedTransport('sftp://simple.example.com/home/source')
 
658
        t = ConnectedTransport('http://simple.example.com/home/source')
619
659
        self.assertEquals(t._host, 'simple.example.com')
620
660
        self.assertEquals(t._port, None)
621
661
        self.assertEquals(t._path, '/home/source/')
622
662
        self.failUnless(t._user is None)
623
663
        self.failUnless(t._password is None)
624
664
 
625
 
        self.assertEquals(t.base, 'sftp://simple.example.com/home/source/')
 
665
        self.assertEquals(t.base, 'http://simple.example.com/home/source/')
 
666
 
 
667
    def test_parse_url_with_at_in_user(self):
 
668
        # Bug 228058
 
669
        t = ConnectedTransport('ftp://user@host.com@www.host.com/')
 
670
        self.assertEquals(t._user, 'user@host.com')
626
671
 
627
672
    def test_parse_quoted_url(self):
628
673
        t = ConnectedTransport('http://ro%62ey:h%40t@ex%41mple.com:2222/path')
661
706
        self.assertEquals(t.relpath('sftp://host.com/dev/%path/sub'), 'sub')
662
707
 
663
708
    def test_connection_sharing_propagate_credentials(self):
664
 
        t = ConnectedTransport('foo://user@host.com/abs/path')
 
709
        t = ConnectedTransport('ftp://user@host.com/abs/path')
 
710
        self.assertEquals('user', t._user)
 
711
        self.assertEquals('host.com', t._host)
665
712
        self.assertIs(None, t._get_connection())
666
713
        self.assertIs(None, t._password)
667
714
        c = t.clone('subdir')
668
 
        self.assertEquals(None, c._get_connection())
 
715
        self.assertIs(None, c._get_connection())
669
716
        self.assertIs(None, t._password)
670
717
 
671
718
        # Simulate the user entering a password
712
759
        self.assertIsNot(t1, t2)
713
760
 
714
761
 
715
 
def get_test_permutations():
716
 
    """Return transport permutations to be used in testing.
717
 
 
718
 
    This module registers some transports, but they're only for testing
719
 
    registration.  We don't really want to run all the transport tests against
720
 
    them.
721
 
    """
722
 
    return []
 
762
class TestTransportTrace(TestCase):
 
763
 
 
764
    def test_get(self):
 
765
        transport = get_transport('trace+memory://')
 
766
        self.assertIsInstance(
 
767
            transport, bzrlib.transport.trace.TransportTraceDecorator)
 
768
 
 
769
    def test_clone_preserves_activity(self):
 
770
        transport = get_transport('trace+memory://')
 
771
        transport2 = transport.clone('.')
 
772
        self.assertTrue(transport is not transport2)
 
773
        self.assertTrue(transport._activity is transport2._activity)
 
774
 
 
775
    # the following specific tests are for the operations that have made use of
 
776
    # logging in tests; we could test every single operation but doing that
 
777
    # still won't cause a test failure when the top level Transport API
 
778
    # changes; so there is little return doing that.
 
779
    def test_get(self):
 
780
        transport = get_transport('trace+memory:///')
 
781
        transport.put_bytes('foo', 'barish')
 
782
        transport.get('foo')
 
783
        expected_result = []
 
784
        # put_bytes records the bytes, not the content to avoid memory
 
785
        # pressure.
 
786
        expected_result.append(('put_bytes', 'foo', 6, None))
 
787
        # get records the file name only.
 
788
        expected_result.append(('get', 'foo'))
 
789
        self.assertEqual(expected_result, transport._activity)
 
790
 
 
791
    def test_readv(self):
 
792
        transport = get_transport('trace+memory:///')
 
793
        transport.put_bytes('foo', 'barish')
 
794
        list(transport.readv('foo', [(0, 1), (3, 2)], adjust_for_latency=True,
 
795
            upper_limit=6))
 
796
        expected_result = []
 
797
        # put_bytes records the bytes, not the content to avoid memory
 
798
        # pressure.
 
799
        expected_result.append(('put_bytes', 'foo', 6, None))
 
800
        # readv records the supplied offset request
 
801
        expected_result.append(('readv', 'foo', [(0, 1), (3, 2)], True, 6))
 
802
        self.assertEqual(expected_result, transport._activity)