~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transport.py

Optimize Tree._iter_changes with specific file_ids

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
21
from cStringIO import StringIO
22
22
 
23
23
import bzrlib
 
24
from bzrlib import urlutils
24
25
from bzrlib.errors import (NoSuchFile, FileExists,
25
26
                           TransportNotPossible,
26
27
                           ConnectionError,
27
28
                           DependencyNotPresent,
28
29
                           UnsupportedProtocol,
 
30
                           PathNotChild,
29
31
                           )
30
32
from bzrlib.tests import TestCase, TestCaseInTempDir
31
 
from bzrlib.transport import (_get_protocol_handlers,
 
33
from bzrlib.transport import (_CoalescedOffset,
 
34
                              _get_protocol_handlers,
32
35
                              _get_transport_modules,
33
36
                              get_transport,
34
37
                              register_lazy_transport,
39
42
from bzrlib.transport.local import LocalTransport
40
43
 
41
44
 
 
45
# TODO: Should possibly split transport-specific tests into their own files.
 
46
 
 
47
 
42
48
class TestTransport(TestCase):
43
49
    """Test the non transport-concrete class functionality."""
44
50
 
98
104
            self.assertTrue(isinstance(t, BackupTransportHandler))
99
105
        finally:
100
106
            _set_protocol_handlers(saved_handlers)
 
107
 
 
108
    def test__combine_paths(self):
 
109
        t = Transport('/')
 
110
        self.assertEqual('/home/sarah/project/foo',
 
111
                         t._combine_paths('/home/sarah', 'project/foo'))
 
112
        self.assertEqual('/etc',
 
113
                         t._combine_paths('/home/sarah', '../../etc'))
 
114
        self.assertEqual('/etc',
 
115
                         t._combine_paths('/home/sarah', '../../../etc'))
 
116
        self.assertEqual('/etc',
 
117
                         t._combine_paths('/home/sarah', '/etc'))
 
118
 
 
119
 
 
120
class TestCoalesceOffsets(TestCase):
 
121
    
 
122
    def check(self, expected, offsets, limit=0, fudge=0):
 
123
        coalesce = Transport._coalesce_offsets
 
124
        exp = [_CoalescedOffset(*x) for x in expected]
 
125
        out = list(coalesce(offsets, limit=limit, fudge_factor=fudge))
 
126
        self.assertEqual(exp, out)
 
127
 
 
128
    def test_coalesce_empty(self):
 
129
        self.check([], [])
 
130
 
 
131
    def test_coalesce_simple(self):
 
132
        self.check([(0, 10, [(0, 10)])], [(0, 10)])
 
133
 
 
134
    def test_coalesce_unrelated(self):
 
135
        self.check([(0, 10, [(0, 10)]),
 
136
                    (20, 10, [(0, 10)]),
 
137
                   ], [(0, 10), (20, 10)])
101
138
            
 
139
    def test_coalesce_unsorted(self):
 
140
        self.check([(20, 10, [(0, 10)]),
 
141
                    (0, 10, [(0, 10)]),
 
142
                   ], [(20, 10), (0, 10)])
 
143
 
 
144
    def test_coalesce_nearby(self):
 
145
        self.check([(0, 20, [(0, 10), (10, 10)])],
 
146
                   [(0, 10), (10, 10)])
 
147
 
 
148
    def test_coalesce_overlapped(self):
 
149
        self.check([(0, 15, [(0, 10), (5, 10)])],
 
150
                   [(0, 10), (5, 10)])
 
151
 
 
152
    def test_coalesce_limit(self):
 
153
        self.check([(10, 50, [(0, 10), (10, 10), (20, 10),
 
154
                              (30, 10), (40, 10)]),
 
155
                    (60, 50, [(0, 10), (10, 10), (20, 10),
 
156
                              (30, 10), (40, 10)]),
 
157
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
 
158
                       (50, 10), (60, 10), (70, 10), (80, 10),
 
159
                       (90, 10), (100, 10)],
 
160
                    limit=5)
 
161
 
 
162
    def test_coalesce_no_limit(self):
 
163
        self.check([(10, 100, [(0, 10), (10, 10), (20, 10),
 
164
                               (30, 10), (40, 10), (50, 10),
 
165
                               (60, 10), (70, 10), (80, 10),
 
166
                               (90, 10)]),
 
167
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
 
168
                       (50, 10), (60, 10), (70, 10), (80, 10),
 
169
                       (90, 10), (100, 10)])
 
170
 
 
171
    def test_coalesce_fudge(self):
 
172
        self.check([(10, 30, [(0, 10), (20, 10)]),
 
173
                    (100, 10, [(0, 10),]),
 
174
                   ], [(10, 10), (30, 10), (100, 10)],
 
175
                   fudge=10
 
176
                  )
 
177
 
102
178
 
103
179
class TestMemoryTransport(TestCase):
104
180
 
108
184
    def test_clone(self):
109
185
        transport = MemoryTransport()
110
186
        self.assertTrue(isinstance(transport, MemoryTransport))
 
187
        self.assertEqual("memory:///", transport.clone("/").base)
111
188
 
112
189
    def test_abspath(self):
113
190
        transport = MemoryTransport()
114
191
        self.assertEqual("memory:///relpath", transport.abspath('relpath'))
115
192
 
116
 
    def test_relpath(self):
117
 
        transport = MemoryTransport()
 
193
    def test_abspath_of_root(self):
 
194
        transport = MemoryTransport()
 
195
        self.assertEqual("memory:///", transport.base)
 
196
        self.assertEqual("memory:///", transport.abspath('/'))
 
197
 
 
198
    def test_abspath_of_relpath_starting_at_root(self):
 
199
        transport = MemoryTransport()
 
200
        self.assertEqual("memory:///foo", transport.abspath('/foo'))
118
201
 
119
202
    def test_append_and_get(self):
120
203
        transport = MemoryTransport()
121
 
        transport.append('path', StringIO('content'))
 
204
        transport.append_bytes('path', 'content')
122
205
        self.assertEqual(transport.get('path').read(), 'content')
123
 
        transport.append('path', StringIO('content'))
 
206
        transport.append_file('path', StringIO('content'))
124
207
        self.assertEqual(transport.get('path').read(), 'contentcontent')
125
208
 
126
209
    def test_put_and_get(self):
127
210
        transport = MemoryTransport()
128
 
        transport.put('path', StringIO('content'))
 
211
        transport.put_file('path', StringIO('content'))
129
212
        self.assertEqual(transport.get('path').read(), 'content')
130
 
        transport.put('path', StringIO('content'))
 
213
        transport.put_bytes('path', 'content')
131
214
        self.assertEqual(transport.get('path').read(), 'content')
132
215
 
133
216
    def test_append_without_dir_fails(self):
134
217
        transport = MemoryTransport()
135
218
        self.assertRaises(NoSuchFile,
136
 
                          transport.append, 'dir/path', StringIO('content'))
 
219
                          transport.append_bytes, 'dir/path', 'content')
137
220
 
138
221
    def test_put_without_dir_fails(self):
139
222
        transport = MemoryTransport()
140
223
        self.assertRaises(NoSuchFile,
141
 
                          transport.put, 'dir/path', StringIO('content'))
 
224
                          transport.put_file, 'dir/path', StringIO('content'))
142
225
 
143
226
    def test_get_missing(self):
144
227
        transport = MemoryTransport()
150
233
 
151
234
    def test_has_present(self):
152
235
        transport = MemoryTransport()
153
 
        transport.append('foo', StringIO('content'))
 
236
        transport.append_bytes('foo', 'content')
154
237
        self.assertEquals(True, transport.has('foo'))
155
238
 
 
239
    def test_list_dir(self):
 
240
        transport = MemoryTransport()
 
241
        transport.put_bytes('foo', 'content')
 
242
        transport.mkdir('dir')
 
243
        transport.put_bytes('dir/subfoo', 'content')
 
244
        transport.put_bytes('dirlike', 'content')
 
245
 
 
246
        self.assertEquals(['dir', 'dirlike', 'foo'], sorted(transport.list_dir('.')))
 
247
        self.assertEquals(['subfoo'], sorted(transport.list_dir('dir')))
 
248
 
156
249
    def test_mkdir(self):
157
250
        transport = MemoryTransport()
158
251
        transport.mkdir('dir')
159
 
        transport.append('dir/path', StringIO('content'))
 
252
        transport.append_bytes('dir/path', 'content')
160
253
        self.assertEqual(transport.get('dir/path').read(), 'content')
161
254
 
162
255
    def test_mkdir_missing_parent(self):
178
271
    def test_iter_files_recursive(self):
179
272
        transport = MemoryTransport()
180
273
        transport.mkdir('dir')
181
 
        transport.put('dir/foo', StringIO('content'))
182
 
        transport.put('dir/bar', StringIO('content'))
183
 
        transport.put('bar', StringIO('content'))
 
274
        transport.put_bytes('dir/foo', 'content')
 
275
        transport.put_bytes('dir/bar', 'content')
 
276
        transport.put_bytes('bar', 'content')
184
277
        paths = set(transport.iter_files_recursive())
185
278
        self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
186
279
 
187
280
    def test_stat(self):
188
281
        transport = MemoryTransport()
189
 
        transport.put('foo', StringIO('content'))
190
 
        transport.put('bar', StringIO('phowar'))
 
282
        transport.put_bytes('foo', 'content')
 
283
        transport.put_bytes('bar', 'phowar')
191
284
        self.assertEqual(7, transport.stat('foo').st_size)
192
285
        self.assertEqual(6, transport.stat('bar').st_size)
193
286
 
194
 
        
 
287
 
 
288
class ChrootDecoratorTransportTest(TestCase):
 
289
    """Chroot decoration specific tests."""
 
290
 
 
291
    def test_construct(self):
 
292
        from bzrlib.transport import chroot
 
293
        transport = chroot.ChrootTransportDecorator('chroot+memory:///pathA/')
 
294
        self.assertEqual('memory:///pathA/', transport.chroot_url)
 
295
 
 
296
        transport = chroot.ChrootTransportDecorator(
 
297
            'chroot+memory:///path/B', chroot='memory:///path/')
 
298
        self.assertEqual('memory:///path/', transport.chroot_url)
 
299
 
 
300
    def test_append_file(self):
 
301
        transport = get_transport('chroot+memory:///foo/bar')
 
302
        self.assertRaises(PathNotChild, transport.append_file, '/foo', None)
 
303
 
 
304
    def test_append_bytes(self):
 
305
        transport = get_transport('chroot+memory:///foo/bar')
 
306
        self.assertRaises(PathNotChild, transport.append_bytes, '/foo', 'bytes')
 
307
 
 
308
    def test_clone(self):
 
309
        transport = get_transport('chroot+memory:///foo/bar')
 
310
        self.assertRaises(PathNotChild, transport.clone, '/foo')
 
311
 
 
312
    def test_delete(self):
 
313
        transport = get_transport('chroot+memory:///foo/bar')
 
314
        self.assertRaises(PathNotChild, transport.delete, '/foo')
 
315
 
 
316
    def test_delete_tree(self):
 
317
        transport = get_transport('chroot+memory:///foo/bar')
 
318
        self.assertRaises(PathNotChild, transport.delete_tree, '/foo')
 
319
 
 
320
    def test_get(self):
 
321
        transport = get_transport('chroot+memory:///foo/bar')
 
322
        self.assertRaises(PathNotChild, transport.get, '/foo')
 
323
 
 
324
    def test_get_bytes(self):
 
325
        transport = get_transport('chroot+memory:///foo/bar')
 
326
        self.assertRaises(PathNotChild, transport.get_bytes, '/foo')
 
327
 
 
328
    def test_has(self):
 
329
        transport = get_transport('chroot+memory:///foo/bar')
 
330
        self.assertRaises(PathNotChild, transport.has, '/foo')
 
331
 
 
332
    def test_list_dir(self):
 
333
        transport = get_transport('chroot+memory:///foo/bar')
 
334
        self.assertRaises(PathNotChild, transport.list_dir, '/foo')
 
335
 
 
336
    def test_lock_read(self):
 
337
        transport = get_transport('chroot+memory:///foo/bar')
 
338
        self.assertRaises(PathNotChild, transport.lock_read, '/foo')
 
339
 
 
340
    def test_lock_write(self):
 
341
        transport = get_transport('chroot+memory:///foo/bar')
 
342
        self.assertRaises(PathNotChild, transport.lock_write, '/foo')
 
343
 
 
344
    def test_mkdir(self):
 
345
        transport = get_transport('chroot+memory:///foo/bar')
 
346
        self.assertRaises(PathNotChild, transport.mkdir, '/foo')
 
347
 
 
348
    def test_put_bytes(self):
 
349
        transport = get_transport('chroot+memory:///foo/bar')
 
350
        self.assertRaises(PathNotChild, transport.put_bytes, '/foo', 'bytes')
 
351
 
 
352
    def test_put_file(self):
 
353
        transport = get_transport('chroot+memory:///foo/bar')
 
354
        self.assertRaises(PathNotChild, transport.put_file, '/foo', None)
 
355
 
 
356
    def test_rename(self):
 
357
        transport = get_transport('chroot+memory:///foo/bar')
 
358
        self.assertRaises(PathNotChild, transport.rename, '/aaa', 'bbb')
 
359
        self.assertRaises(PathNotChild, transport.rename, 'ccc', '/d')
 
360
 
 
361
    def test_rmdir(self):
 
362
        transport = get_transport('chroot+memory:///foo/bar')
 
363
        self.assertRaises(PathNotChild, transport.rmdir, '/foo')
 
364
 
 
365
    def test_stat(self):
 
366
        transport = get_transport('chroot+memory:///foo/bar')
 
367
        self.assertRaises(PathNotChild, transport.stat, '/foo')
 
368
 
 
369
 
195
370
class ReadonlyDecoratorTransportTest(TestCase):
196
371
    """Readonly decoration specific tests."""
197
372
 
204
379
        self.assertEqual(True, transport.is_readonly())
205
380
 
206
381
    def test_http_parameters(self):
 
382
        from bzrlib.tests.HttpServer import HttpServer
207
383
        import bzrlib.transport.readonly as readonly
208
 
        from bzrlib.transport.http import HttpServer
209
384
        # connect to . via http which is not listable
210
385
        server = HttpServer()
211
386
        server.setUp()
239
414
    def test_http_parameters(self):
240
415
        # the listable, should_cache and is_readonly parameters
241
416
        # are not changed by the fakenfs decorator
242
 
        from bzrlib.transport.http import HttpServer
 
417
        from bzrlib.tests.HttpServer import HttpServer
243
418
        # connect to . via http which is not listable
244
419
        server = HttpServer()
245
420
        server.setUp()
259
434
        server = fakenfs.FakeNFSServer()
260
435
        server.setUp()
261
436
        try:
262
 
            # the server should be a relpath localhost server
263
 
            self.assertEqual(server.get_url(), 'fakenfs+.')
 
437
            # the url should be decorated appropriately
 
438
            self.assertStartsWith(server.get_url(), 'fakenfs+')
264
439
            # and we should be able to get a transport for it
265
440
            transport = get_transport(server.get_url())
266
441
            # which must be a FakeNFSTransportDecorator instance.
311
486
class BackupTransportHandler(Transport):
312
487
    """Test transport that works as a backup for the BadTransportHandler"""
313
488
    pass
 
489
 
 
490
 
 
491
class TestTransportImplementation(TestCaseInTempDir):
 
492
    """Implementation verification for transports.
 
493
    
 
494
    To verify a transport we need a server factory, which is a callable
 
495
    that accepts no parameters and returns an implementation of
 
496
    bzrlib.transport.Server.
 
497
    
 
498
    That Server is then used to construct transport instances and test
 
499
    the transport via loopback activity.
 
500
 
 
501
    Currently this assumes that the Transport object is connected to the 
 
502
    current working directory.  So that whatever is done 
 
503
    through the transport, should show up in the working 
 
504
    directory, and vice-versa. This is a bug, because its possible to have
 
505
    URL schemes which provide access to something that may not be 
 
506
    result in storage on the local disk, i.e. due to file system limits, or 
 
507
    due to it being a database or some other non-filesystem tool.
 
508
 
 
509
    This also tests to make sure that the functions work with both
 
510
    generators and lists (assuming iter(list) is effectively a generator)
 
511
    """
 
512
    
 
513
    def setUp(self):
 
514
        super(TestTransportImplementation, self).setUp()
 
515
        self._server = self.transport_server()
 
516
        self._server.setUp()
 
517
 
 
518
    def tearDown(self):
 
519
        super(TestTransportImplementation, self).tearDown()
 
520
        self._server.tearDown()
 
521
        
 
522
    def get_transport(self):
 
523
        """Return a connected transport to the local directory."""
 
524
        base_url = self._server.get_url()
 
525
        # try getting the transport via the regular interface:
 
526
        t = get_transport(base_url)
 
527
        if not isinstance(t, self.transport_class):
 
528
            # we did not get the correct transport class type. Override the
 
529
            # regular connection behaviour by direct construction.
 
530
            t = self.transport_class(base_url)
 
531
        return t
 
532
 
 
533
 
 
534
class TestLocalTransports(TestCase):
 
535
 
 
536
    def test_get_transport_from_abspath(self):
 
537
        here = os.path.abspath('.')
 
538
        t = get_transport(here)
 
539
        self.assertIsInstance(t, LocalTransport)
 
540
        self.assertEquals(t.base, urlutils.local_path_to_url(here) + '/')
 
541
 
 
542
    def test_get_transport_from_relpath(self):
 
543
        here = os.path.abspath('.')
 
544
        t = get_transport('.')
 
545
        self.assertIsInstance(t, LocalTransport)
 
546
        self.assertEquals(t.base, urlutils.local_path_to_url('.') + '/')
 
547
 
 
548
    def test_get_transport_from_local_url(self):
 
549
        here = os.path.abspath('.')
 
550
        here_url = urlutils.local_path_to_url(here) + '/'
 
551
        t = get_transport(here_url)
 
552
        self.assertIsInstance(t, LocalTransport)
 
553
        self.assertEquals(t.base, here_url)