/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: v.ladeuil+lp at free
  • Date: 2006-10-12 14:29:32 UTC
  • mto: (2145.1.1 keepalive)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: v.ladeuil+lp@free.fr-20061012142932-7221fe16d2b48fa3
Shuffle http related test code. Hopefully it ends up at the right place :)

* bzrlib/tests/HttpServer.py: 
New file. bzrlib.tests.ChrootedTestCase use HttpServer. So the
class can't be defined in bzrlib.tests.HTTPUtils because it
creates a circular dependency (bzrlib.tests.HTTPUtils needs to
import bzrlib.tests).

* bzrlib/transport/http/_urllib.py: 
Transfer test server definition to bzrlib.tests.HttpServer. Clean
up imports.

* bzrlib/transport/http/_pycurl.py: 
Transfer test server definition to bzrlib.tests.HttpServer. Clean
up imports.

* bzrlib/transport/http/__init__.py: 
Transfer all test related code to either bzrlib.tests.HttpServer
and bzrlib.tests.HTTPUtils.
Fix all use of TransportNotPossible and InvalidURL by prefixing it
by 'errors.' (this seems to be the preferred way in the rest of
bzr).
Get rid of unused imports.

* bzrlib/tests/test_transport.py:
(ReadonlyDecoratorTransportTest.test_local_parameters,
FakeNFSDecoratorTests.test_http_parameters): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

* bzrlib/tests/test_sftp_transport.py:
(set_test_transport_to_sftp): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

* bzrlib/tests/test_selftest.py:
(TestTestCaseWithTransport.test_get_readonly_url_http): Use
HttpServer from bzrlib.tests.HttpServer instead of
bzrlib.transport.http.

* bzrlib/tests/test_repository.py: 
Does *not* use HttpServer.

* bzrlib/tests/test_http.py: 
Build on top of bzrlib.tests.HttpServer and bzrlib.tests.HTTPUtils
instead of bzrlib.transport.http.

* bzrlib/tests/test_bzrdir.py:
(ChrootedTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/branch_implementations/test_http.py:
(HTTPBranchTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/branch_implementations/test_branch.py:
(ChrootedTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/__init__.py:
(ChrootedTestCase.setUp): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2004, 2005, 2006 by 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
 
 
110
 
 
111
class TestCoalesceOffsets(TestCase):
 
112
    
 
113
    def check(self, expected, offsets, limit=0, fudge=0):
 
114
        coalesce = Transport._coalesce_offsets
 
115
        exp = [_CoalescedOffset(*x) for x in expected]
 
116
        out = list(coalesce(offsets, limit=limit, fudge_factor=fudge))
 
117
        self.assertEqual(exp, out)
 
118
 
 
119
    def test_coalesce_empty(self):
 
120
        self.check([], [])
 
121
 
 
122
    def test_coalesce_simple(self):
 
123
        self.check([(0, 10, [(0, 10)])], [(0, 10)])
 
124
 
 
125
    def test_coalesce_unrelated(self):
 
126
        self.check([(0, 10, [(0, 10)]),
 
127
                    (20, 10, [(0, 10)]),
 
128
                   ], [(0, 10), (20, 10)])
 
129
            
 
130
    def test_coalesce_unsorted(self):
 
131
        self.check([(20, 10, [(0, 10)]),
 
132
                    (0, 10, [(0, 10)]),
 
133
                   ], [(20, 10), (0, 10)])
 
134
 
 
135
    def test_coalesce_nearby(self):
 
136
        self.check([(0, 20, [(0, 10), (10, 10)])],
 
137
                   [(0, 10), (10, 10)])
 
138
 
 
139
    def test_coalesce_overlapped(self):
 
140
        self.check([(0, 15, [(0, 10), (5, 10)])],
 
141
                   [(0, 10), (5, 10)])
 
142
 
 
143
    def test_coalesce_limit(self):
 
144
        self.check([(10, 50, [(0, 10), (10, 10), (20, 10),
 
145
                              (30, 10), (40, 10)]),
 
146
                    (60, 50, [(0, 10), (10, 10), (20, 10),
 
147
                              (30, 10), (40, 10)]),
 
148
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
 
149
                       (50, 10), (60, 10), (70, 10), (80, 10),
 
150
                       (90, 10), (100, 10)],
 
151
                    limit=5)
 
152
 
 
153
    def test_coalesce_no_limit(self):
 
154
        self.check([(10, 100, [(0, 10), (10, 10), (20, 10),
 
155
                               (30, 10), (40, 10), (50, 10),
 
156
                               (60, 10), (70, 10), (80, 10),
 
157
                               (90, 10)]),
 
158
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
 
159
                       (50, 10), (60, 10), (70, 10), (80, 10),
 
160
                       (90, 10), (100, 10)])
 
161
 
 
162
    def test_coalesce_fudge(self):
 
163
        self.check([(10, 30, [(0, 10), (20, 10)]),
 
164
                    (100, 10, [(0, 10),]),
 
165
                   ], [(10, 10), (30, 10), (100, 10)],
 
166
                   fudge=10
 
167
                  )
 
168
 
 
169
 
 
170
class TestMemoryTransport(TestCase):
 
171
 
 
172
    def test_get_transport(self):
 
173
        MemoryTransport()
 
174
 
 
175
    def test_clone(self):
 
176
        transport = MemoryTransport()
 
177
        self.assertTrue(isinstance(transport, MemoryTransport))
 
178
        self.assertEqual("memory:///", transport.clone("/").base)
 
179
 
 
180
    def test_abspath(self):
 
181
        transport = MemoryTransport()
 
182
        self.assertEqual("memory:///relpath", transport.abspath('relpath'))
 
183
 
 
184
    def test_abspath_of_root(self):
 
185
        transport = MemoryTransport()
 
186
        self.assertEqual("memory:///", transport.base)
 
187
        self.assertEqual("memory:///", transport.abspath('/'))
 
188
 
 
189
    def test_relpath(self):
 
190
        transport = MemoryTransport()
 
191
 
 
192
    def test_append_and_get(self):
 
193
        transport = MemoryTransport()
 
194
        transport.append_bytes('path', 'content')
 
195
        self.assertEqual(transport.get('path').read(), 'content')
 
196
        transport.append_file('path', StringIO('content'))
 
197
        self.assertEqual(transport.get('path').read(), 'contentcontent')
 
198
 
 
199
    def test_put_and_get(self):
 
200
        transport = MemoryTransport()
 
201
        transport.put_file('path', StringIO('content'))
 
202
        self.assertEqual(transport.get('path').read(), 'content')
 
203
        transport.put_bytes('path', 'content')
 
204
        self.assertEqual(transport.get('path').read(), 'content')
 
205
 
 
206
    def test_append_without_dir_fails(self):
 
207
        transport = MemoryTransport()
 
208
        self.assertRaises(NoSuchFile,
 
209
                          transport.append_bytes, 'dir/path', 'content')
 
210
 
 
211
    def test_put_without_dir_fails(self):
 
212
        transport = MemoryTransport()
 
213
        self.assertRaises(NoSuchFile,
 
214
                          transport.put_file, 'dir/path', StringIO('content'))
 
215
 
 
216
    def test_get_missing(self):
 
217
        transport = MemoryTransport()
 
218
        self.assertRaises(NoSuchFile, transport.get, 'foo')
 
219
 
 
220
    def test_has_missing(self):
 
221
        transport = MemoryTransport()
 
222
        self.assertEquals(False, transport.has('foo'))
 
223
 
 
224
    def test_has_present(self):
 
225
        transport = MemoryTransport()
 
226
        transport.append_bytes('foo', 'content')
 
227
        self.assertEquals(True, transport.has('foo'))
 
228
 
 
229
    def test_mkdir(self):
 
230
        transport = MemoryTransport()
 
231
        transport.mkdir('dir')
 
232
        transport.append_bytes('dir/path', 'content')
 
233
        self.assertEqual(transport.get('dir/path').read(), 'content')
 
234
 
 
235
    def test_mkdir_missing_parent(self):
 
236
        transport = MemoryTransport()
 
237
        self.assertRaises(NoSuchFile,
 
238
                          transport.mkdir, 'dir/dir')
 
239
 
 
240
    def test_mkdir_twice(self):
 
241
        transport = MemoryTransport()
 
242
        transport.mkdir('dir')
 
243
        self.assertRaises(FileExists, transport.mkdir, 'dir')
 
244
 
 
245
    def test_parameters(self):
 
246
        transport = MemoryTransport()
 
247
        self.assertEqual(True, transport.listable())
 
248
        self.assertEqual(False, transport.should_cache())
 
249
        self.assertEqual(False, transport.is_readonly())
 
250
 
 
251
    def test_iter_files_recursive(self):
 
252
        transport = MemoryTransport()
 
253
        transport.mkdir('dir')
 
254
        transport.put_bytes('dir/foo', 'content')
 
255
        transport.put_bytes('dir/bar', 'content')
 
256
        transport.put_bytes('bar', 'content')
 
257
        paths = set(transport.iter_files_recursive())
 
258
        self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
 
259
 
 
260
    def test_stat(self):
 
261
        transport = MemoryTransport()
 
262
        transport.put_bytes('foo', 'content')
 
263
        transport.put_bytes('bar', 'phowar')
 
264
        self.assertEqual(7, transport.stat('foo').st_size)
 
265
        self.assertEqual(6, transport.stat('bar').st_size)
 
266
 
 
267
        
 
268
class ReadonlyDecoratorTransportTest(TestCase):
 
269
    """Readonly decoration specific tests."""
 
270
 
 
271
    def test_local_parameters(self):
 
272
        import bzrlib.transport.readonly as readonly
 
273
        # connect to . in readonly mode
 
274
        transport = readonly.ReadonlyTransportDecorator('readonly+.')
 
275
        self.assertEqual(True, transport.listable())
 
276
        self.assertEqual(False, transport.should_cache())
 
277
        self.assertEqual(True, transport.is_readonly())
 
278
 
 
279
    def test_http_parameters(self):
 
280
        from bzrlib.tests.HttpServer import HttpServer
 
281
        import bzrlib.transport.readonly as readonly
 
282
        # connect to . via http which is not listable
 
283
        server = HttpServer()
 
284
        server.setUp()
 
285
        try:
 
286
            transport = get_transport('readonly+' + server.get_url())
 
287
            self.failUnless(isinstance(transport,
 
288
                                       readonly.ReadonlyTransportDecorator))
 
289
            self.assertEqual(False, transport.listable())
 
290
            self.assertEqual(True, transport.should_cache())
 
291
            self.assertEqual(True, transport.is_readonly())
 
292
        finally:
 
293
            server.tearDown()
 
294
 
 
295
 
 
296
class FakeNFSDecoratorTests(TestCaseInTempDir):
 
297
    """NFS decorator specific tests."""
 
298
 
 
299
    def get_nfs_transport(self, url):
 
300
        import bzrlib.transport.fakenfs as fakenfs
 
301
        # connect to url with nfs decoration
 
302
        return fakenfs.FakeNFSTransportDecorator('fakenfs+' + url)
 
303
 
 
304
    def test_local_parameters(self):
 
305
        # the listable, should_cache and is_readonly parameters
 
306
        # are not changed by the fakenfs decorator
 
307
        transport = self.get_nfs_transport('.')
 
308
        self.assertEqual(True, transport.listable())
 
309
        self.assertEqual(False, transport.should_cache())
 
310
        self.assertEqual(False, transport.is_readonly())
 
311
 
 
312
    def test_http_parameters(self):
 
313
        # the listable, should_cache and is_readonly parameters
 
314
        # are not changed by the fakenfs decorator
 
315
        from bzrlib.tests.HttpServer import HttpServer
 
316
        # connect to . via http which is not listable
 
317
        server = HttpServer()
 
318
        server.setUp()
 
319
        try:
 
320
            transport = self.get_nfs_transport(server.get_url())
 
321
            self.assertIsInstance(
 
322
                transport, bzrlib.transport.fakenfs.FakeNFSTransportDecorator)
 
323
            self.assertEqual(False, transport.listable())
 
324
            self.assertEqual(True, transport.should_cache())
 
325
            self.assertEqual(True, transport.is_readonly())
 
326
        finally:
 
327
            server.tearDown()
 
328
 
 
329
    def test_fakenfs_server_default(self):
 
330
        # a FakeNFSServer() should bring up a local relpath server for itself
 
331
        import bzrlib.transport.fakenfs as fakenfs
 
332
        server = fakenfs.FakeNFSServer()
 
333
        server.setUp()
 
334
        try:
 
335
            # the server should be a relpath localhost server
 
336
            self.assertEqual(server.get_url(), 'fakenfs+.')
 
337
            # and we should be able to get a transport for it
 
338
            transport = get_transport(server.get_url())
 
339
            # which must be a FakeNFSTransportDecorator instance.
 
340
            self.assertIsInstance(
 
341
                transport, fakenfs.FakeNFSTransportDecorator)
 
342
        finally:
 
343
            server.tearDown()
 
344
 
 
345
    def test_fakenfs_rename_semantics(self):
 
346
        # a FakeNFS transport must mangle the way rename errors occur to
 
347
        # look like NFS problems.
 
348
        transport = self.get_nfs_transport('.')
 
349
        self.build_tree(['from/', 'from/foo', 'to/', 'to/bar'],
 
350
                        transport=transport)
 
351
        self.assertRaises(bzrlib.errors.ResourceBusy,
 
352
                          transport.rename, 'from', 'to')
 
353
 
 
354
 
 
355
class FakeVFATDecoratorTests(TestCaseInTempDir):
 
356
    """Tests for simulation of VFAT restrictions"""
 
357
 
 
358
    def get_vfat_transport(self, url):
 
359
        """Return vfat-backed transport for test directory"""
 
360
        from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
 
361
        return FakeVFATTransportDecorator('vfat+' + url)
 
362
 
 
363
    def test_transport_creation(self):
 
364
        from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
 
365
        transport = self.get_vfat_transport('.')
 
366
        self.assertIsInstance(transport, FakeVFATTransportDecorator)
 
367
 
 
368
    def test_transport_mkdir(self):
 
369
        transport = self.get_vfat_transport('.')
 
370
        transport.mkdir('HELLO')
 
371
        self.assertTrue(transport.has('hello'))
 
372
        self.assertTrue(transport.has('Hello'))
 
373
 
 
374
    def test_forbidden_chars(self):
 
375
        transport = self.get_vfat_transport('.')
 
376
        self.assertRaises(ValueError, transport.has, "<NU>")
 
377
 
 
378
 
 
379
class BadTransportHandler(Transport):
 
380
    def __init__(self, base_url):
 
381
        raise DependencyNotPresent('some_lib', 'testing missing dependency')
 
382
 
 
383
 
 
384
class BackupTransportHandler(Transport):
 
385
    """Test transport that works as a backup for the BadTransportHandler"""
 
386
    pass
 
387
 
 
388
 
 
389
class TestTransportImplementation(TestCaseInTempDir):
 
390
    """Implementation verification for transports.
 
391
    
 
392
    To verify a transport we need a server factory, which is a callable
 
393
    that accepts no parameters and returns an implementation of
 
394
    bzrlib.transport.Server.
 
395
    
 
396
    That Server is then used to construct transport instances and test
 
397
    the transport via loopback activity.
 
398
 
 
399
    Currently this assumes that the Transport object is connected to the 
 
400
    current working directory.  So that whatever is done 
 
401
    through the transport, should show up in the working 
 
402
    directory, and vice-versa. This is a bug, because its possible to have
 
403
    URL schemes which provide access to something that may not be 
 
404
    result in storage on the local disk, i.e. due to file system limits, or 
 
405
    due to it being a database or some other non-filesystem tool.
 
406
 
 
407
    This also tests to make sure that the functions work with both
 
408
    generators and lists (assuming iter(list) is effectively a generator)
 
409
    """
 
410
    
 
411
    def setUp(self):
 
412
        super(TestTransportImplementation, self).setUp()
 
413
        self._server = self.transport_server()
 
414
        self._server.setUp()
 
415
 
 
416
    def tearDown(self):
 
417
        super(TestTransportImplementation, self).tearDown()
 
418
        self._server.tearDown()
 
419
        
 
420
    def get_transport(self):
 
421
        """Return a connected transport to the local directory."""
 
422
        base_url = self._server.get_url()
 
423
        # try getting the transport via the regular interface:
 
424
        t = get_transport(base_url)
 
425
        if not isinstance(t, self.transport_class):
 
426
            # we did not get the correct transport class type. Override the
 
427
            # regular connection behaviour by direct construction.
 
428
            t = self.transport_class(base_url)
 
429
        return t