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

  • Committer: John Arbash Meinel
  • Date: 2006-10-18 04:45:50 UTC
  • mto: This revision was merged to the branch mainline in revision 2087.
  • Revision ID: john@arbash-meinel.com-20061018044550-f9522fe99ba15a70
Don't check plugins for copyright or license

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
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
 
21
from cStringIO import StringIO
 
22
 
 
23
import bzrlib
 
24
from bzrlib.errors import (NoSuchFile, FileExists,
 
25
                           TransportNotPossible,
 
26
                           ConnectionError,
 
27
                           DependencyNotPresent,
 
28
                           UnsupportedProtocol,
 
29
                           )
 
30
from bzrlib.tests import TestCase, TestCaseInTempDir
 
31
from bzrlib.transport import (_CoalescedOffset,
 
32
                              _get_protocol_handlers,
 
33
                              _get_transport_modules,
 
34
                              get_transport,
 
35
                              register_lazy_transport,
 
36
                              _set_protocol_handlers,
 
37
                              Transport,
 
38
                              )
 
39
from bzrlib.transport.memory import MemoryTransport
 
40
from bzrlib.transport.local import LocalTransport
 
41
 
 
42
 
 
43
class TestTransport(TestCase):
 
44
    """Test the non transport-concrete class functionality."""
 
45
 
 
46
    def test__get_set_protocol_handlers(self):
 
47
        handlers = _get_protocol_handlers()
 
48
        self.assertNotEqual({}, handlers)
 
49
        try:
 
50
            _set_protocol_handlers({})
 
51
            self.assertEqual({}, _get_protocol_handlers())
 
52
        finally:
 
53
            _set_protocol_handlers(handlers)
 
54
 
 
55
    def test_get_transport_modules(self):
 
56
        handlers = _get_protocol_handlers()
 
57
        class SampleHandler(object):
 
58
            """I exist, isnt that enough?"""
 
59
        try:
 
60
            my_handlers = {}
 
61
            _set_protocol_handlers(my_handlers)
 
62
            register_lazy_transport('foo', 'bzrlib.tests.test_transport', 'TestTransport.SampleHandler')
 
63
            register_lazy_transport('bar', 'bzrlib.tests.test_transport', 'TestTransport.SampleHandler')
 
64
            self.assertEqual([SampleHandler.__module__],
 
65
                             _get_transport_modules())
 
66
        finally:
 
67
            _set_protocol_handlers(handlers)
 
68
 
 
69
    def test_transport_dependency(self):
 
70
        """Transport with missing dependency causes no error"""
 
71
        saved_handlers = _get_protocol_handlers()
 
72
        try:
 
73
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
 
74
                    'BadTransportHandler')
 
75
            try:
 
76
                get_transport('foo://fooserver/foo')
 
77
            except UnsupportedProtocol, e:
 
78
                e_str = str(e)
 
79
                self.assertEquals('Unsupported protocol'
 
80
                                  ' for url "foo://fooserver/foo":'
 
81
                                  ' Unable to import library "some_lib":'
 
82
                                  ' testing missing dependency', str(e))
 
83
            else:
 
84
                self.fail('Did not raise UnsupportedProtocol')
 
85
        finally:
 
86
            # restore original values
 
87
            _set_protocol_handlers(saved_handlers)
 
88
            
 
89
    def test_transport_fallback(self):
 
90
        """Transport with missing dependency causes no error"""
 
91
        saved_handlers = _get_protocol_handlers()
 
92
        try:
 
93
            _set_protocol_handlers({})
 
94
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
 
95
                    'BackupTransportHandler')
 
96
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
 
97
                    'BadTransportHandler')
 
98
            t = get_transport('foo://fooserver/foo')
 
99
            self.assertTrue(isinstance(t, BackupTransportHandler))
 
100
        finally:
 
101
            _set_protocol_handlers(saved_handlers)
 
102
 
 
103
    def test__combine_paths(self):
 
104
        t = Transport('/')
 
105
        self.assertEqual('/home/sarah/project/foo',
 
106
                         t._combine_paths('/home/sarah', 'project/foo'))
 
107
        self.assertEqual('/etc',
 
108
                         t._combine_paths('/home/sarah', '../../etc'))
 
109
        self.assertEqual('/etc',
 
110
                         t._combine_paths('/home/sarah', '../../../etc'))
 
111
        self.assertEqual('/etc',
 
112
                         t._combine_paths('/home/sarah', '/etc'))
 
113
 
 
114
 
 
115
class TestCoalesceOffsets(TestCase):
 
116
    
 
117
    def check(self, expected, offsets, limit=0, fudge=0):
 
118
        coalesce = Transport._coalesce_offsets
 
119
        exp = [_CoalescedOffset(*x) for x in expected]
 
120
        out = list(coalesce(offsets, limit=limit, fudge_factor=fudge))
 
121
        self.assertEqual(exp, out)
 
122
 
 
123
    def test_coalesce_empty(self):
 
124
        self.check([], [])
 
125
 
 
126
    def test_coalesce_simple(self):
 
127
        self.check([(0, 10, [(0, 10)])], [(0, 10)])
 
128
 
 
129
    def test_coalesce_unrelated(self):
 
130
        self.check([(0, 10, [(0, 10)]),
 
131
                    (20, 10, [(0, 10)]),
 
132
                   ], [(0, 10), (20, 10)])
 
133
            
 
134
    def test_coalesce_unsorted(self):
 
135
        self.check([(20, 10, [(0, 10)]),
 
136
                    (0, 10, [(0, 10)]),
 
137
                   ], [(20, 10), (0, 10)])
 
138
 
 
139
    def test_coalesce_nearby(self):
 
140
        self.check([(0, 20, [(0, 10), (10, 10)])],
 
141
                   [(0, 10), (10, 10)])
 
142
 
 
143
    def test_coalesce_overlapped(self):
 
144
        self.check([(0, 15, [(0, 10), (5, 10)])],
 
145
                   [(0, 10), (5, 10)])
 
146
 
 
147
    def test_coalesce_limit(self):
 
148
        self.check([(10, 50, [(0, 10), (10, 10), (20, 10),
 
149
                              (30, 10), (40, 10)]),
 
150
                    (60, 50, [(0, 10), (10, 10), (20, 10),
 
151
                              (30, 10), (40, 10)]),
 
152
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
 
153
                       (50, 10), (60, 10), (70, 10), (80, 10),
 
154
                       (90, 10), (100, 10)],
 
155
                    limit=5)
 
156
 
 
157
    def test_coalesce_no_limit(self):
 
158
        self.check([(10, 100, [(0, 10), (10, 10), (20, 10),
 
159
                               (30, 10), (40, 10), (50, 10),
 
160
                               (60, 10), (70, 10), (80, 10),
 
161
                               (90, 10)]),
 
162
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
 
163
                       (50, 10), (60, 10), (70, 10), (80, 10),
 
164
                       (90, 10), (100, 10)])
 
165
 
 
166
    def test_coalesce_fudge(self):
 
167
        self.check([(10, 30, [(0, 10), (20, 10)]),
 
168
                    (100, 10, [(0, 10),]),
 
169
                   ], [(10, 10), (30, 10), (100, 10)],
 
170
                   fudge=10
 
171
                  )
 
172
 
 
173
 
 
174
class TestMemoryTransport(TestCase):
 
175
 
 
176
    def test_get_transport(self):
 
177
        MemoryTransport()
 
178
 
 
179
    def test_clone(self):
 
180
        transport = MemoryTransport()
 
181
        self.assertTrue(isinstance(transport, MemoryTransport))
 
182
        self.assertEqual("memory:///", transport.clone("/").base)
 
183
 
 
184
    def test_abspath(self):
 
185
        transport = MemoryTransport()
 
186
        self.assertEqual("memory:///relpath", transport.abspath('relpath'))
 
187
 
 
188
    def test_abspath_of_root(self):
 
189
        transport = MemoryTransport()
 
190
        self.assertEqual("memory:///", transport.base)
 
191
        self.assertEqual("memory:///", transport.abspath('/'))
 
192
 
 
193
    def test_abspath_of_relpath_starting_at_root(self):
 
194
        transport = MemoryTransport()
 
195
        self.assertEqual("memory:///foo", transport.abspath('/foo'))
 
196
 
 
197
    def test_append_and_get(self):
 
198
        transport = MemoryTransport()
 
199
        transport.append_bytes('path', 'content')
 
200
        self.assertEqual(transport.get('path').read(), 'content')
 
201
        transport.append_file('path', StringIO('content'))
 
202
        self.assertEqual(transport.get('path').read(), 'contentcontent')
 
203
 
 
204
    def test_put_and_get(self):
 
205
        transport = MemoryTransport()
 
206
        transport.put_file('path', StringIO('content'))
 
207
        self.assertEqual(transport.get('path').read(), 'content')
 
208
        transport.put_bytes('path', 'content')
 
209
        self.assertEqual(transport.get('path').read(), 'content')
 
210
 
 
211
    def test_append_without_dir_fails(self):
 
212
        transport = MemoryTransport()
 
213
        self.assertRaises(NoSuchFile,
 
214
                          transport.append_bytes, 'dir/path', 'content')
 
215
 
 
216
    def test_put_without_dir_fails(self):
 
217
        transport = MemoryTransport()
 
218
        self.assertRaises(NoSuchFile,
 
219
                          transport.put_file, 'dir/path', StringIO('content'))
 
220
 
 
221
    def test_get_missing(self):
 
222
        transport = MemoryTransport()
 
223
        self.assertRaises(NoSuchFile, transport.get, 'foo')
 
224
 
 
225
    def test_has_missing(self):
 
226
        transport = MemoryTransport()
 
227
        self.assertEquals(False, transport.has('foo'))
 
228
 
 
229
    def test_has_present(self):
 
230
        transport = MemoryTransport()
 
231
        transport.append_bytes('foo', 'content')
 
232
        self.assertEquals(True, transport.has('foo'))
 
233
 
 
234
    def test_mkdir(self):
 
235
        transport = MemoryTransport()
 
236
        transport.mkdir('dir')
 
237
        transport.append_bytes('dir/path', 'content')
 
238
        self.assertEqual(transport.get('dir/path').read(), 'content')
 
239
 
 
240
    def test_mkdir_missing_parent(self):
 
241
        transport = MemoryTransport()
 
242
        self.assertRaises(NoSuchFile,
 
243
                          transport.mkdir, 'dir/dir')
 
244
 
 
245
    def test_mkdir_twice(self):
 
246
        transport = MemoryTransport()
 
247
        transport.mkdir('dir')
 
248
        self.assertRaises(FileExists, transport.mkdir, 'dir')
 
249
 
 
250
    def test_parameters(self):
 
251
        transport = MemoryTransport()
 
252
        self.assertEqual(True, transport.listable())
 
253
        self.assertEqual(False, transport.should_cache())
 
254
        self.assertEqual(False, transport.is_readonly())
 
255
 
 
256
    def test_iter_files_recursive(self):
 
257
        transport = MemoryTransport()
 
258
        transport.mkdir('dir')
 
259
        transport.put_bytes('dir/foo', 'content')
 
260
        transport.put_bytes('dir/bar', 'content')
 
261
        transport.put_bytes('bar', 'content')
 
262
        paths = set(transport.iter_files_recursive())
 
263
        self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
 
264
 
 
265
    def test_stat(self):
 
266
        transport = MemoryTransport()
 
267
        transport.put_bytes('foo', 'content')
 
268
        transport.put_bytes('bar', 'phowar')
 
269
        self.assertEqual(7, transport.stat('foo').st_size)
 
270
        self.assertEqual(6, transport.stat('bar').st_size)
 
271
 
 
272
        
 
273
class ReadonlyDecoratorTransportTest(TestCase):
 
274
    """Readonly decoration specific tests."""
 
275
 
 
276
    def test_local_parameters(self):
 
277
        import bzrlib.transport.readonly as readonly
 
278
        # connect to . in readonly mode
 
279
        transport = readonly.ReadonlyTransportDecorator('readonly+.')
 
280
        self.assertEqual(True, transport.listable())
 
281
        self.assertEqual(False, transport.should_cache())
 
282
        self.assertEqual(True, transport.is_readonly())
 
283
 
 
284
    def test_http_parameters(self):
 
285
        import bzrlib.transport.readonly as readonly
 
286
        from bzrlib.transport.http import HttpServer
 
287
        # connect to . via http which is not listable
 
288
        server = HttpServer()
 
289
        server.setUp()
 
290
        try:
 
291
            transport = get_transport('readonly+' + server.get_url())
 
292
            self.failUnless(isinstance(transport,
 
293
                                       readonly.ReadonlyTransportDecorator))
 
294
            self.assertEqual(False, transport.listable())
 
295
            self.assertEqual(True, transport.should_cache())
 
296
            self.assertEqual(True, transport.is_readonly())
 
297
        finally:
 
298
            server.tearDown()
 
299
 
 
300
 
 
301
class FakeNFSDecoratorTests(TestCaseInTempDir):
 
302
    """NFS decorator specific tests."""
 
303
 
 
304
    def get_nfs_transport(self, url):
 
305
        import bzrlib.transport.fakenfs as fakenfs
 
306
        # connect to url with nfs decoration
 
307
        return fakenfs.FakeNFSTransportDecorator('fakenfs+' + url)
 
308
 
 
309
    def test_local_parameters(self):
 
310
        # the listable, should_cache and is_readonly parameters
 
311
        # are not changed by the fakenfs decorator
 
312
        transport = self.get_nfs_transport('.')
 
313
        self.assertEqual(True, transport.listable())
 
314
        self.assertEqual(False, transport.should_cache())
 
315
        self.assertEqual(False, transport.is_readonly())
 
316
 
 
317
    def test_http_parameters(self):
 
318
        # the listable, should_cache and is_readonly parameters
 
319
        # are not changed by the fakenfs decorator
 
320
        from bzrlib.transport.http import HttpServer
 
321
        # connect to . via http which is not listable
 
322
        server = HttpServer()
 
323
        server.setUp()
 
324
        try:
 
325
            transport = self.get_nfs_transport(server.get_url())
 
326
            self.assertIsInstance(
 
327
                transport, bzrlib.transport.fakenfs.FakeNFSTransportDecorator)
 
328
            self.assertEqual(False, transport.listable())
 
329
            self.assertEqual(True, transport.should_cache())
 
330
            self.assertEqual(True, transport.is_readonly())
 
331
        finally:
 
332
            server.tearDown()
 
333
 
 
334
    def test_fakenfs_server_default(self):
 
335
        # a FakeNFSServer() should bring up a local relpath server for itself
 
336
        import bzrlib.transport.fakenfs as fakenfs
 
337
        server = fakenfs.FakeNFSServer()
 
338
        server.setUp()
 
339
        try:
 
340
            # the server should be a relpath localhost server
 
341
            self.assertEqual(server.get_url(), 'fakenfs+.')
 
342
            # and we should be able to get a transport for it
 
343
            transport = get_transport(server.get_url())
 
344
            # which must be a FakeNFSTransportDecorator instance.
 
345
            self.assertIsInstance(
 
346
                transport, fakenfs.FakeNFSTransportDecorator)
 
347
        finally:
 
348
            server.tearDown()
 
349
 
 
350
    def test_fakenfs_rename_semantics(self):
 
351
        # a FakeNFS transport must mangle the way rename errors occur to
 
352
        # look like NFS problems.
 
353
        transport = self.get_nfs_transport('.')
 
354
        self.build_tree(['from/', 'from/foo', 'to/', 'to/bar'],
 
355
                        transport=transport)
 
356
        self.assertRaises(bzrlib.errors.ResourceBusy,
 
357
                          transport.rename, 'from', 'to')
 
358
 
 
359
 
 
360
class FakeVFATDecoratorTests(TestCaseInTempDir):
 
361
    """Tests for simulation of VFAT restrictions"""
 
362
 
 
363
    def get_vfat_transport(self, url):
 
364
        """Return vfat-backed transport for test directory"""
 
365
        from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
 
366
        return FakeVFATTransportDecorator('vfat+' + url)
 
367
 
 
368
    def test_transport_creation(self):
 
369
        from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
 
370
        transport = self.get_vfat_transport('.')
 
371
        self.assertIsInstance(transport, FakeVFATTransportDecorator)
 
372
 
 
373
    def test_transport_mkdir(self):
 
374
        transport = self.get_vfat_transport('.')
 
375
        transport.mkdir('HELLO')
 
376
        self.assertTrue(transport.has('hello'))
 
377
        self.assertTrue(transport.has('Hello'))
 
378
 
 
379
    def test_forbidden_chars(self):
 
380
        transport = self.get_vfat_transport('.')
 
381
        self.assertRaises(ValueError, transport.has, "<NU>")
 
382
 
 
383
 
 
384
class BadTransportHandler(Transport):
 
385
    def __init__(self, base_url):
 
386
        raise DependencyNotPresent('some_lib', 'testing missing dependency')
 
387
 
 
388
 
 
389
class BackupTransportHandler(Transport):
 
390
    """Test transport that works as a backup for the BadTransportHandler"""
 
391
    pass
 
392
 
 
393
 
 
394
class TestTransportImplementation(TestCaseInTempDir):
 
395
    """Implementation verification for transports.
 
396
    
 
397
    To verify a transport we need a server factory, which is a callable
 
398
    that accepts no parameters and returns an implementation of
 
399
    bzrlib.transport.Server.
 
400
    
 
401
    That Server is then used to construct transport instances and test
 
402
    the transport via loopback activity.
 
403
 
 
404
    Currently this assumes that the Transport object is connected to the 
 
405
    current working directory.  So that whatever is done 
 
406
    through the transport, should show up in the working 
 
407
    directory, and vice-versa. This is a bug, because its possible to have
 
408
    URL schemes which provide access to something that may not be 
 
409
    result in storage on the local disk, i.e. due to file system limits, or 
 
410
    due to it being a database or some other non-filesystem tool.
 
411
 
 
412
    This also tests to make sure that the functions work with both
 
413
    generators and lists (assuming iter(list) is effectively a generator)
 
414
    """
 
415
    
 
416
    def setUp(self):
 
417
        super(TestTransportImplementation, self).setUp()
 
418
        self._server = self.transport_server()
 
419
        self._server.setUp()
 
420
 
 
421
    def tearDown(self):
 
422
        super(TestTransportImplementation, self).tearDown()
 
423
        self._server.tearDown()
 
424
        
 
425
    def get_transport(self):
 
426
        """Return a connected transport to the local directory."""
 
427
        base_url = self._server.get_url()
 
428
        # try getting the transport via the regular interface:
 
429
        t = get_transport(base_url)
 
430
        if not isinstance(t, self.transport_class):
 
431
            # we did not get the correct transport class type. Override the
 
432
            # regular connection behaviour by direct construction.
 
433
            t = self.transport_class(base_url)
 
434
        return t