18
18
from cStringIO import StringIO
24
21
from bzrlib import (
31
from bzrlib.directory_service import directories
32
from bzrlib.transport import (
42
import bzrlib.transport.trace
43
from bzrlib.tests import (
26
from bzrlib.errors import (DependencyNotPresent,
34
from bzrlib.tests import TestCase, TestCaseInTempDir
35
from bzrlib.transport import (_clear_protocol_handlers,
38
_get_protocol_handlers,
39
_set_protocol_handlers,
40
_get_transport_modules,
43
register_lazy_transport,
44
register_transport_proto,
47
from bzrlib.transport.chroot import ChrootServer
48
from bzrlib.transport.memory import MemoryTransport
49
from bzrlib.transport.local import (LocalTransport,
50
EmulatedWin32LocalTransport)
49
53
# TODO: Should possibly split transport-specific tests into their own files.
52
class TestTransport(tests.TestCase):
56
class TestTransport(TestCase):
53
57
"""Test the non transport-concrete class functionality."""
55
59
def test__get_set_protocol_handlers(self):
56
handlers = transport._get_protocol_handlers()
57
self.assertNotEqual([], handlers.keys())
58
transport._clear_protocol_handlers()
59
self.addCleanup(transport._set_protocol_handlers, handlers)
60
self.assertEqual([], transport._get_protocol_handlers().keys())
60
handlers = _get_protocol_handlers()
61
self.assertNotEqual([], handlers.keys( ))
63
_clear_protocol_handlers()
64
self.assertEqual([], _get_protocol_handlers().keys())
66
_set_protocol_handlers(handlers)
62
68
def test_get_transport_modules(self):
63
handlers = transport._get_protocol_handlers()
64
self.addCleanup(transport._set_protocol_handlers, handlers)
69
handlers = _get_protocol_handlers()
65
70
# don't pollute the current handlers
66
transport._clear_protocol_handlers()
71
_clear_protocol_handlers()
68
72
class SampleHandler(object):
69
73
"""I exist, isnt that enough?"""
70
transport._clear_protocol_handlers()
71
transport.register_transport_proto('foo')
72
transport.register_lazy_transport('foo',
73
'bzrlib.tests.test_transport',
74
'TestTransport.SampleHandler')
75
transport.register_transport_proto('bar')
76
transport.register_lazy_transport('bar',
77
'bzrlib.tests.test_transport',
78
'TestTransport.SampleHandler')
79
self.assertEqual([SampleHandler.__module__,
80
'bzrlib.transport.chroot',
81
'bzrlib.transport.pathfilter'],
82
transport._get_transport_modules())
75
_clear_protocol_handlers()
76
register_transport_proto('foo')
77
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
78
'TestTransport.SampleHandler')
79
register_transport_proto('bar')
80
register_lazy_transport('bar', 'bzrlib.tests.test_transport',
81
'TestTransport.SampleHandler')
82
self.assertEqual([SampleHandler.__module__,
83
'bzrlib.transport.chroot'],
84
_get_transport_modules())
86
_set_protocol_handlers(handlers)
84
88
def test_transport_dependency(self):
85
89
"""Transport with missing dependency causes no error"""
86
saved_handlers = transport._get_protocol_handlers()
87
self.addCleanup(transport._set_protocol_handlers, saved_handlers)
90
saved_handlers = _get_protocol_handlers()
88
91
# don't pollute the current handlers
89
transport._clear_protocol_handlers()
90
transport.register_transport_proto('foo')
91
transport.register_lazy_transport(
92
'foo', 'bzrlib.tests.test_transport', 'BadTransportHandler')
92
_clear_protocol_handlers()
94
transport.get_transport_from_url('foo://fooserver/foo')
95
except errors.UnsupportedProtocol, e:
97
self.assertEquals('Unsupported protocol'
98
' for url "foo://fooserver/foo":'
99
' Unable to import library "some_lib":'
100
' testing missing dependency', str(e))
102
self.fail('Did not raise UnsupportedProtocol')
94
register_transport_proto('foo')
95
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
96
'BadTransportHandler')
98
get_transport('foo://fooserver/foo')
99
except UnsupportedProtocol, e:
101
self.assertEquals('Unsupported protocol'
102
' for url "foo://fooserver/foo":'
103
' Unable to import library "some_lib":'
104
' testing missing dependency', str(e))
106
self.fail('Did not raise UnsupportedProtocol')
108
# restore original values
109
_set_protocol_handlers(saved_handlers)
104
111
def test_transport_fallback(self):
105
112
"""Transport with missing dependency causes no error"""
106
saved_handlers = transport._get_protocol_handlers()
107
self.addCleanup(transport._set_protocol_handlers, saved_handlers)
108
transport._clear_protocol_handlers()
109
transport.register_transport_proto('foo')
110
transport.register_lazy_transport(
111
'foo', 'bzrlib.tests.test_transport', 'BackupTransportHandler')
112
transport.register_lazy_transport(
113
'foo', 'bzrlib.tests.test_transport', 'BadTransportHandler')
114
t = transport.get_transport_from_url('foo://fooserver/foo')
115
self.assertTrue(isinstance(t, BackupTransportHandler))
113
saved_handlers = _get_protocol_handlers()
115
_clear_protocol_handlers()
116
register_transport_proto('foo')
117
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
118
'BackupTransportHandler')
119
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
120
'BadTransportHandler')
121
t = get_transport('foo://fooserver/foo')
122
self.assertTrue(isinstance(t, BackupTransportHandler))
124
_set_protocol_handlers(saved_handlers)
117
126
def test_ssh_hints(self):
118
127
"""Transport ssh:// should raise an error pointing out bzr+ssh://"""
120
transport.get_transport_from_url('ssh://fooserver/foo')
121
except errors.UnsupportedProtocol, e:
129
get_transport('ssh://fooserver/foo')
130
except UnsupportedProtocol, e:
123
132
self.assertEquals('Unsupported protocol'
124
133
' for url "ssh://fooserver/foo":'
125
' bzr supports bzr+ssh to operate over ssh,'
126
' use "bzr+ssh://fooserver/foo".',
134
' bzr supports bzr+ssh to operate over ssh, use "bzr+ssh://fooserver/foo".',
129
137
self.fail('Did not raise UnsupportedProtocol')
131
139
def test_LateReadError(self):
132
140
"""The LateReadError helper should raise on read()."""
133
a_file = transport.LateReadError('a path')
141
a_file = LateReadError('a path')
136
except errors.ReadError, error:
144
except ReadError, error:
137
145
self.assertEqual('a path', error.path)
138
self.assertRaises(errors.ReadError, a_file.read, 40)
146
self.assertRaises(ReadError, a_file.read, 40)
149
def test__combine_paths(self):
151
self.assertEqual('/home/sarah/project/foo',
152
t._combine_paths('/home/sarah', 'project/foo'))
153
self.assertEqual('/etc',
154
t._combine_paths('/home/sarah', '../../etc'))
155
self.assertEqual('/etc',
156
t._combine_paths('/home/sarah', '../../../etc'))
157
self.assertEqual('/etc',
158
t._combine_paths('/home/sarah', '/etc'))
141
160
def test_local_abspath_non_local_transport(self):
142
161
# the base implementation should throw
143
t = memory.MemoryTransport()
162
t = MemoryTransport()
144
163
e = self.assertRaises(errors.NotLocalUrl, t.local_abspath, 't')
145
164
self.assertEqual('memory:///t is not a local path.', str(e))
148
class TestCoalesceOffsets(tests.TestCase):
167
class TestCoalesceOffsets(TestCase):
150
169
def check(self, expected, offsets, limit=0, max_size=0, fudge=0):
151
coalesce = transport.Transport._coalesce_offsets
152
exp = [transport._CoalescedOffset(*x) for x in expected]
170
coalesce = Transport._coalesce_offsets
171
exp = [_CoalescedOffset(*x) for x in expected]
153
172
out = list(coalesce(offsets, limit=limit, fudge_factor=fudge,
154
173
max_size=max_size))
155
174
self.assertEqual(exp, out)
201
220
def test_coalesce_fudge(self):
202
221
self.check([(10, 30, [(0, 10), (20, 10)]),
203
(100, 10, [(0, 10)]),
222
(100, 10, [(0, 10),]),
204
223
], [(10, 10), (30, 10), (100, 10)],
207
226
def test_coalesce_max_size(self):
208
227
self.check([(10, 20, [(0, 10), (10, 10)]),
209
228
(30, 50, [(0, 50)]),
210
229
# If one range is above max_size, it gets its own coalesced
212
(100, 80, [(0, 80)]),],
231
(100, 80, [(0, 80),]),],
213
232
[(10, 10), (20, 10), (30, 50), (100, 80)],
216
236
def test_coalesce_no_max_size(self):
217
self.check([(10, 170, [(0, 10), (10, 10), (20, 50), (70, 100)])],
237
self.check([(10, 170, [(0, 10), (10, 10), (20, 50), (70, 100)]),],
218
238
[(10, 10), (20, 10), (30, 50), (80, 100)],
221
241
def test_coalesce_default_limit(self):
222
242
# By default we use a 100MB max size.
223
ten_mb = 10 * 1024 * 1024
224
self.check([(0, 10 * ten_mb, [(i * ten_mb, ten_mb) for i in range(10)]),
243
ten_mb = 10*1024*1024
244
self.check([(0, 10*ten_mb, [(i*ten_mb, ten_mb) for i in range(10)]),
225
245
(10*ten_mb, ten_mb, [(0, ten_mb)])],
226
246
[(i*ten_mb, ten_mb) for i in range(11)])
227
self.check([(0, 11 * ten_mb, [(i * ten_mb, ten_mb) for i in range(11)])],
228
[(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)],
229
249
max_size=1*1024*1024*1024)
232
class TestMemoryServer(tests.TestCase):
234
def test_create_server(self):
235
server = memory.MemoryServer()
236
server.start_server()
237
url = server.get_url()
238
self.assertTrue(url in transport.transport_list_registry)
239
t = transport.get_transport_from_url(url)
242
self.assertFalse(url in transport.transport_list_registry)
243
self.assertRaises(errors.UnsupportedProtocol,
244
transport.get_transport, url)
247
class TestMemoryTransport(tests.TestCase):
252
class TestMemoryTransport(TestCase):
249
254
def test_get_transport(self):
250
memory.MemoryTransport()
252
257
def test_clone(self):
253
t = memory.MemoryTransport()
254
self.assertTrue(isinstance(t, memory.MemoryTransport))
255
self.assertEqual("memory:///", t.clone("/").base)
258
transport = MemoryTransport()
259
self.assertTrue(isinstance(transport, MemoryTransport))
260
self.assertEqual("memory:///", transport.clone("/").base)
257
262
def test_abspath(self):
258
t = memory.MemoryTransport()
259
self.assertEqual("memory:///relpath", t.abspath('relpath'))
263
transport = MemoryTransport()
264
self.assertEqual("memory:///relpath", transport.abspath('relpath'))
261
266
def test_abspath_of_root(self):
262
t = memory.MemoryTransport()
263
self.assertEqual("memory:///", t.base)
264
self.assertEqual("memory:///", t.abspath('/'))
267
transport = MemoryTransport()
268
self.assertEqual("memory:///", transport.base)
269
self.assertEqual("memory:///", transport.abspath('/'))
266
271
def test_abspath_of_relpath_starting_at_root(self):
267
t = memory.MemoryTransport()
268
self.assertEqual("memory:///foo", t.abspath('/foo'))
272
transport = MemoryTransport()
273
self.assertEqual("memory:///foo", transport.abspath('/foo'))
270
275
def test_append_and_get(self):
271
t = memory.MemoryTransport()
272
t.append_bytes('path', 'content')
273
self.assertEqual(t.get('path').read(), 'content')
274
t.append_file('path', StringIO('content'))
275
self.assertEqual(t.get('path').read(), 'contentcontent')
276
transport = MemoryTransport()
277
transport.append_bytes('path', 'content')
278
self.assertEqual(transport.get('path').read(), 'content')
279
transport.append_file('path', StringIO('content'))
280
self.assertEqual(transport.get('path').read(), 'contentcontent')
277
282
def test_put_and_get(self):
278
t = memory.MemoryTransport()
279
t.put_file('path', StringIO('content'))
280
self.assertEqual(t.get('path').read(), 'content')
281
t.put_bytes('path', 'content')
282
self.assertEqual(t.get('path').read(), 'content')
283
transport = MemoryTransport()
284
transport.put_file('path', StringIO('content'))
285
self.assertEqual(transport.get('path').read(), 'content')
286
transport.put_bytes('path', 'content')
287
self.assertEqual(transport.get('path').read(), 'content')
284
289
def test_append_without_dir_fails(self):
285
t = memory.MemoryTransport()
286
self.assertRaises(errors.NoSuchFile,
287
t.append_bytes, 'dir/path', 'content')
290
transport = MemoryTransport()
291
self.assertRaises(NoSuchFile,
292
transport.append_bytes, 'dir/path', 'content')
289
294
def test_put_without_dir_fails(self):
290
t = memory.MemoryTransport()
291
self.assertRaises(errors.NoSuchFile,
292
t.put_file, 'dir/path', StringIO('content'))
295
transport = MemoryTransport()
296
self.assertRaises(NoSuchFile,
297
transport.put_file, 'dir/path', StringIO('content'))
294
299
def test_get_missing(self):
295
transport = memory.MemoryTransport()
296
self.assertRaises(errors.NoSuchFile, transport.get, 'foo')
300
transport = MemoryTransport()
301
self.assertRaises(NoSuchFile, transport.get, 'foo')
298
303
def test_has_missing(self):
299
t = memory.MemoryTransport()
300
self.assertEquals(False, t.has('foo'))
304
transport = MemoryTransport()
305
self.assertEquals(False, transport.has('foo'))
302
307
def test_has_present(self):
303
t = memory.MemoryTransport()
304
t.append_bytes('foo', 'content')
305
self.assertEquals(True, t.has('foo'))
308
transport = MemoryTransport()
309
transport.append_bytes('foo', 'content')
310
self.assertEquals(True, transport.has('foo'))
307
312
def test_list_dir(self):
308
t = memory.MemoryTransport()
309
t.put_bytes('foo', 'content')
311
t.put_bytes('dir/subfoo', 'content')
312
t.put_bytes('dirlike', 'content')
313
transport = MemoryTransport()
314
transport.put_bytes('foo', 'content')
315
transport.mkdir('dir')
316
transport.put_bytes('dir/subfoo', 'content')
317
transport.put_bytes('dirlike', 'content')
314
self.assertEquals(['dir', 'dirlike', 'foo'], sorted(t.list_dir('.')))
315
self.assertEquals(['subfoo'], sorted(t.list_dir('dir')))
319
self.assertEquals(['dir', 'dirlike', 'foo'], sorted(transport.list_dir('.')))
320
self.assertEquals(['subfoo'], sorted(transport.list_dir('dir')))
317
322
def test_mkdir(self):
318
t = memory.MemoryTransport()
320
t.append_bytes('dir/path', 'content')
321
self.assertEqual(t.get('dir/path').read(), 'content')
323
transport = MemoryTransport()
324
transport.mkdir('dir')
325
transport.append_bytes('dir/path', 'content')
326
self.assertEqual(transport.get('dir/path').read(), 'content')
323
328
def test_mkdir_missing_parent(self):
324
t = memory.MemoryTransport()
325
self.assertRaises(errors.NoSuchFile, t.mkdir, 'dir/dir')
329
transport = MemoryTransport()
330
self.assertRaises(NoSuchFile,
331
transport.mkdir, 'dir/dir')
327
333
def test_mkdir_twice(self):
328
t = memory.MemoryTransport()
330
self.assertRaises(errors.FileExists, t.mkdir, 'dir')
334
transport = MemoryTransport()
335
transport.mkdir('dir')
336
self.assertRaises(FileExists, transport.mkdir, 'dir')
332
338
def test_parameters(self):
333
t = memory.MemoryTransport()
334
self.assertEqual(True, t.listable())
335
self.assertEqual(False, t.is_readonly())
339
transport = MemoryTransport()
340
self.assertEqual(True, transport.listable())
341
self.assertEqual(False, transport.is_readonly())
337
343
def test_iter_files_recursive(self):
338
t = memory.MemoryTransport()
340
t.put_bytes('dir/foo', 'content')
341
t.put_bytes('dir/bar', 'content')
342
t.put_bytes('bar', 'content')
343
paths = set(t.iter_files_recursive())
344
transport = MemoryTransport()
345
transport.mkdir('dir')
346
transport.put_bytes('dir/foo', 'content')
347
transport.put_bytes('dir/bar', 'content')
348
transport.put_bytes('bar', 'content')
349
paths = set(transport.iter_files_recursive())
344
350
self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
346
352
def test_stat(self):
347
t = memory.MemoryTransport()
348
t.put_bytes('foo', 'content')
349
t.put_bytes('bar', 'phowar')
350
self.assertEqual(7, t.stat('foo').st_size)
351
self.assertEqual(6, t.stat('bar').st_size)
354
class ChrootDecoratorTransportTest(tests.TestCase):
353
transport = MemoryTransport()
354
transport.put_bytes('foo', 'content')
355
transport.put_bytes('bar', 'phowar')
356
self.assertEqual(7, transport.stat('foo').st_size)
357
self.assertEqual(6, transport.stat('bar').st_size)
360
class ChrootDecoratorTransportTest(TestCase):
355
361
"""Chroot decoration specific tests."""
357
363
def test_abspath(self):
358
364
# The abspath is always relative to the chroot_url.
359
server = chroot.ChrootServer(
360
transport.get_transport_from_url('memory:///foo/bar/'))
361
self.start_server(server)
362
t = transport.get_transport_from_url(server.get_url())
363
self.assertEqual(server.get_url(), t.abspath('/'))
365
server = ChrootServer(get_transport('memory:///foo/bar/'))
367
transport = get_transport(server.get_url())
368
self.assertEqual(server.get_url(), transport.abspath('/'))
365
subdir_t = t.clone('subdir')
366
self.assertEqual(server.get_url(), subdir_t.abspath('/'))
370
subdir_transport = transport.clone('subdir')
371
self.assertEqual(server.get_url(), subdir_transport.abspath('/'))
368
374
def test_clone(self):
369
server = chroot.ChrootServer(
370
transport.get_transport_from_url('memory:///foo/bar/'))
371
self.start_server(server)
372
t = transport.get_transport_from_url(server.get_url())
375
server = ChrootServer(get_transport('memory:///foo/bar/'))
377
transport = get_transport(server.get_url())
373
378
# relpath from root and root path are the same
374
relpath_cloned = t.clone('foo')
375
abspath_cloned = t.clone('/foo')
379
relpath_cloned = transport.clone('foo')
380
abspath_cloned = transport.clone('/foo')
376
381
self.assertEqual(server, relpath_cloned.server)
377
382
self.assertEqual(server, abspath_cloned.server)
379
385
def test_chroot_url_preserves_chroot(self):
380
386
"""Calling get_transport on a chroot transport's base should produce a
401
407
This is so that it is not possible to escape a chroot by doing::
402
408
url = chroot_transport.base
403
409
parent_url = urlutils.join(url, '..')
404
new_t = transport.get_transport_from_url(parent_url)
410
new_transport = get_transport(parent_url)
406
server = chroot.ChrootServer(
407
transport.get_transport_from_url('memory:///path/'))
408
self.start_server(server)
409
t = transport.get_transport_from_url(server.get_url())
412
server = ChrootServer(get_transport('memory:///path/'))
414
transport = get_transport(server.get_url())
410
415
self.assertRaises(
411
errors.InvalidURLJoin, urlutils.join, t.base, '..')
414
class TestChrootServer(tests.TestCase):
416
InvalidURLJoin, urlutils.join, transport.base, '..')
420
class ChrootServerTest(TestCase):
416
422
def test_construct(self):
417
backing_transport = memory.MemoryTransport()
418
server = chroot.ChrootServer(backing_transport)
423
backing_transport = MemoryTransport()
424
server = ChrootServer(backing_transport)
419
425
self.assertEqual(backing_transport, server.backing_transport)
421
427
def test_setUp(self):
422
backing_transport = memory.MemoryTransport()
423
server = chroot.ChrootServer(backing_transport)
424
server.start_server()
425
self.addCleanup(server.stop_server)
426
self.assertTrue(server.scheme
427
in transport._get_protocol_handlers().keys())
428
backing_transport = MemoryTransport()
429
server = ChrootServer(backing_transport)
431
self.assertTrue(server.scheme in _get_protocol_handlers().keys())
429
def test_stop_server(self):
430
backing_transport = memory.MemoryTransport()
431
server = chroot.ChrootServer(backing_transport)
432
server.start_server()
434
self.assertFalse(server.scheme
435
in transport._get_protocol_handlers().keys())
433
def test_tearDown(self):
434
backing_transport = MemoryTransport()
435
server = ChrootServer(backing_transport)
438
self.assertFalse(server.scheme in _get_protocol_handlers().keys())
437
440
def test_get_url(self):
438
backing_transport = memory.MemoryTransport()
439
server = chroot.ChrootServer(backing_transport)
440
server.start_server()
441
self.addCleanup(server.stop_server)
441
backing_transport = MemoryTransport()
442
server = ChrootServer(backing_transport)
442
444
self.assertEqual('chroot-%d:///' % id(server), server.get_url())
445
class PathFilteringDecoratorTransportTest(tests.TestCase):
446
"""Pathfilter decoration specific tests."""
448
def test_abspath(self):
449
# The abspath is always relative to the base of the backing transport.
450
server = pathfilter.PathFilteringServer(
451
transport.get_transport_from_url('memory:///foo/bar/'),
453
server.start_server()
454
t = transport.get_transport_from_url(server.get_url())
455
self.assertEqual(server.get_url(), t.abspath('/'))
457
subdir_t = t.clone('subdir')
458
self.assertEqual(server.get_url(), subdir_t.abspath('/'))
461
def make_pf_transport(self, filter_func=None):
462
"""Make a PathFilteringTransport backed by a MemoryTransport.
464
:param filter_func: by default this will be a no-op function. Use this
465
parameter to override it."""
466
if filter_func is None:
467
filter_func = lambda x: x
468
server = pathfilter.PathFilteringServer(
469
transport.get_transport_from_url('memory:///foo/bar/'), filter_func)
470
server.start_server()
471
self.addCleanup(server.stop_server)
472
return transport.get_transport_from_url(server.get_url())
474
def test__filter(self):
475
# _filter (with an identity func as filter_func) always returns
476
# paths relative to the base of the backing transport.
477
t = self.make_pf_transport()
478
self.assertEqual('foo', t._filter('foo'))
479
self.assertEqual('foo/bar', t._filter('foo/bar'))
480
self.assertEqual('', t._filter('..'))
481
self.assertEqual('', t._filter('/'))
482
# The base of the pathfiltering transport is taken into account too.
483
t = t.clone('subdir1/subdir2')
484
self.assertEqual('subdir1/subdir2/foo', t._filter('foo'))
485
self.assertEqual('subdir1/subdir2/foo/bar', t._filter('foo/bar'))
486
self.assertEqual('subdir1', t._filter('..'))
487
self.assertEqual('', t._filter('/'))
489
def test_filter_invocation(self):
493
filter_log.append(path)
495
t = self.make_pf_transport(filter)
497
self.assertEqual(['abc'], filter_log)
499
t.clone('abc').has('xyz')
500
self.assertEqual(['abc/xyz'], filter_log)
503
self.assertEqual(['abc'], filter_log)
505
def test_clone(self):
506
t = self.make_pf_transport()
507
# relpath from root and root path are the same
508
relpath_cloned = t.clone('foo')
509
abspath_cloned = t.clone('/foo')
510
self.assertEqual(t.server, relpath_cloned.server)
511
self.assertEqual(t.server, abspath_cloned.server)
513
def test_url_preserves_pathfiltering(self):
514
"""Calling get_transport on a pathfiltered transport's base should
515
produce a transport with exactly the same behaviour as the original
516
pathfiltered transport.
518
This is so that it is not possible to escape (accidentally or
519
otherwise) the filtering by doing::
520
url = filtered_transport.base
521
parent_url = urlutils.join(url, '..')
522
new_t = transport.get_transport_from_url(parent_url)
524
t = self.make_pf_transport()
525
new_t = transport.get_transport_from_url(t.base)
526
self.assertEqual(t.server, new_t.server)
527
self.assertEqual(t.base, new_t.base)
530
class ReadonlyDecoratorTransportTest(tests.TestCase):
448
class ReadonlyDecoratorTransportTest(TestCase):
531
449
"""Readonly decoration specific tests."""
533
451
def test_local_parameters(self):
452
import bzrlib.transport.readonly as readonly
534
453
# connect to . in readonly mode
535
t = readonly.ReadonlyTransportDecorator('readonly+.')
536
self.assertEqual(True, t.listable())
537
self.assertEqual(True, t.is_readonly())
454
transport = readonly.ReadonlyTransportDecorator('readonly+.')
455
self.assertEqual(True, transport.listable())
456
self.assertEqual(True, transport.is_readonly())
539
458
def test_http_parameters(self):
540
459
from bzrlib.tests.http_server import HttpServer
460
import bzrlib.transport.readonly as readonly
541
461
# connect to '.' via http which is not listable
542
462
server = HttpServer()
543
self.start_server(server)
544
t = transport.get_transport_from_url('readonly+' + server.get_url())
545
self.assertIsInstance(t, readonly.ReadonlyTransportDecorator)
546
self.assertEqual(False, t.listable())
547
self.assertEqual(True, t.is_readonly())
550
class FakeNFSDecoratorTests(tests.TestCaseInTempDir):
465
transport = get_transport('readonly+' + server.get_url())
466
self.failUnless(isinstance(transport,
467
readonly.ReadonlyTransportDecorator))
468
self.assertEqual(False, transport.listable())
469
self.assertEqual(True, transport.is_readonly())
474
class FakeNFSDecoratorTests(TestCaseInTempDir):
551
475
"""NFS decorator specific tests."""
553
477
def get_nfs_transport(self, url):
478
import bzrlib.transport.fakenfs as fakenfs
554
479
# connect to url with nfs decoration
555
480
return fakenfs.FakeNFSTransportDecorator('fakenfs+' + url)
557
482
def test_local_parameters(self):
558
483
# the listable and is_readonly parameters
559
484
# are not changed by the fakenfs decorator
560
t = self.get_nfs_transport('.')
561
self.assertEqual(True, t.listable())
562
self.assertEqual(False, t.is_readonly())
485
transport = self.get_nfs_transport('.')
486
self.assertEqual(True, transport.listable())
487
self.assertEqual(False, transport.is_readonly())
564
489
def test_http_parameters(self):
565
490
# the listable and is_readonly parameters
677
class TestTransportFromPath(tests.TestCaseInTempDir):
679
def test_with_path(self):
680
t = transport.get_transport_from_path(self.test_dir)
681
self.assertIsInstance(t, local.LocalTransport)
682
self.assertEquals(t.base.rstrip("/"),
683
urlutils.local_path_to_url(self.test_dir))
685
def test_with_url(self):
686
t = transport.get_transport_from_path("file:")
687
self.assertIsInstance(t, local.LocalTransport)
688
self.assertEquals(t.base.rstrip("/"),
689
urlutils.local_path_to_url(os.path.join(self.test_dir, "file:")))
692
class TestTransportFromUrl(tests.TestCaseInTempDir):
694
def test_with_path(self):
695
self.assertRaises(errors.InvalidURL, transport.get_transport_from_url,
698
def test_with_url(self):
699
url = urlutils.local_path_to_url(self.test_dir)
700
t = transport.get_transport_from_url(url)
701
self.assertIsInstance(t, local.LocalTransport)
702
self.assertEquals(t.base.rstrip("/"), url)
704
def test_with_url_and_segment_parameters(self):
705
url = urlutils.local_path_to_url(self.test_dir)+",branch=foo"
706
t = transport.get_transport_from_url(url)
707
self.assertIsInstance(t, local.LocalTransport)
708
self.assertEquals(t.base.rstrip("/"), url)
709
with open(os.path.join(self.test_dir, "afile"), 'w') as f:
711
self.assertTrue(t.has("afile"))
714
class TestLocalTransports(tests.TestCase):
612
class TestLocalTransports(TestCase):
716
614
def test_get_transport_from_abspath(self):
717
615
here = osutils.abspath('.')
718
t = transport.get_transport(here)
719
self.assertIsInstance(t, local.LocalTransport)
616
t = get_transport(here)
617
self.assertIsInstance(t, LocalTransport)
720
618
self.assertEquals(t.base, urlutils.local_path_to_url(here) + '/')
722
620
def test_get_transport_from_relpath(self):
723
621
here = osutils.abspath('.')
724
t = transport.get_transport('.')
725
self.assertIsInstance(t, local.LocalTransport)
622
t = get_transport('.')
623
self.assertIsInstance(t, LocalTransport)
726
624
self.assertEquals(t.base, urlutils.local_path_to_url('.') + '/')
728
626
def test_get_transport_from_local_url(self):
729
627
here = osutils.abspath('.')
730
628
here_url = urlutils.local_path_to_url(here) + '/'
731
t = transport.get_transport(here_url)
732
self.assertIsInstance(t, local.LocalTransport)
629
t = get_transport(here_url)
630
self.assertIsInstance(t, LocalTransport)
733
631
self.assertEquals(t.base, here_url)
735
633
def test_local_abspath(self):
736
634
here = osutils.abspath('.')
737
t = transport.get_transport(here)
635
t = get_transport(here)
738
636
self.assertEquals(t.local_abspath(''), here)
741
class TestLocalTransportWriteStream(tests.TestCaseWithTransport):
743
def test_local_fdatasync_calls_fdatasync(self):
744
"""Check fdatasync on a stream tries to flush the data to the OS.
746
We can't easily observe the external effect but we can at least see
750
fdatasync = getattr(os, 'fdatasync', sentinel)
751
if fdatasync is sentinel:
752
raise tests.TestNotApplicable('fdatasync not supported')
753
t = self.get_transport('.')
754
calls = self.recordCalls(os, 'fdatasync')
755
w = t.open_write_stream('out')
758
with open('out', 'rb') as f:
759
# Should have been flushed.
760
self.assertEquals(f.read(), 'foo')
761
self.assertEquals(len(calls), 1, calls)
764
class TestWin32LocalTransport(tests.TestCase):
639
class TestWin32LocalTransport(TestCase):
766
641
def test_unc_clone_to_root(self):
767
642
# Win32 UNC path like \\HOST\path
768
643
# clone to root should stop at least at \\HOST part
770
t = local.EmulatedWin32LocalTransport('file://HOST/path/to/some/dir/')
645
t = EmulatedWin32LocalTransport('file://HOST/path/to/some/dir/')
771
646
for i in xrange(4):
772
647
t = t.clone('..')
773
648
self.assertEquals(t.base, 'file://HOST/')
776
651
self.assertEquals(t.base, 'file://HOST/')
779
class TestConnectedTransport(tests.TestCase):
654
class TestConnectedTransport(TestCase):
780
655
"""Tests for connected to remote server transports"""
782
657
def test_parse_url(self):
783
t = transport.ConnectedTransport(
784
'http://simple.example.com/home/source')
785
self.assertEquals(t._parsed_url.host, 'simple.example.com')
786
self.assertEquals(t._parsed_url.port, None)
787
self.assertEquals(t._parsed_url.path, '/home/source/')
788
self.assertTrue(t._parsed_url.user is None)
789
self.assertTrue(t._parsed_url.password is None)
658
t = ConnectedTransport('http://simple.example.com/home/source')
659
self.assertEquals(t._host, 'simple.example.com')
660
self.assertEquals(t._port, None)
661
self.assertEquals(t._path, '/home/source/')
662
self.failUnless(t._user is None)
663
self.failUnless(t._password is None)
791
665
self.assertEquals(t.base, 'http://simple.example.com/home/source/')
793
667
def test_parse_url_with_at_in_user(self):
795
t = transport.ConnectedTransport('ftp://user@host.com@www.host.com/')
796
self.assertEquals(t._parsed_url.user, 'user@host.com')
669
t = ConnectedTransport('ftp://user@host.com@www.host.com/')
670
self.assertEquals(t._user, 'user@host.com')
798
672
def test_parse_quoted_url(self):
799
t = transport.ConnectedTransport(
800
'http://ro%62ey:h%40t@ex%41mple.com:2222/path')
801
self.assertEquals(t._parsed_url.host, 'exAmple.com')
802
self.assertEquals(t._parsed_url.port, 2222)
803
self.assertEquals(t._parsed_url.user, 'robey')
804
self.assertEquals(t._parsed_url.password, 'h@t')
805
self.assertEquals(t._parsed_url.path, '/path/')
673
t = ConnectedTransport('http://ro%62ey:h%40t@ex%41mple.com:2222/path')
674
self.assertEquals(t._host, 'exAmple.com')
675
self.assertEquals(t._port, 2222)
676
self.assertEquals(t._user, 'robey')
677
self.assertEquals(t._password, 'h@t')
678
self.assertEquals(t._path, '/path/')
807
680
# Base should not keep track of the password
808
self.assertEquals(t.base, 'http://ro%62ey@ex%41mple.com:2222/path/')
681
self.assertEquals(t.base, 'http://robey@exAmple.com:2222/path/')
810
683
def test_parse_invalid_url(self):
811
684
self.assertRaises(errors.InvalidURL,
812
transport.ConnectedTransport,
813
686
'sftp://lily.org:~janneke/public/bzr/gub')
815
688
def test_relpath(self):
816
t = transport.ConnectedTransport('sftp://user@host.com/abs/path')
689
t = ConnectedTransport('sftp://user@host.com/abs/path')
818
self.assertEquals(t.relpath('sftp://user@host.com/abs/path/sub'),
691
self.assertEquals(t.relpath('sftp://user@host.com/abs/path/sub'), 'sub')
820
692
self.assertRaises(errors.PathNotChild, t.relpath,
821
693
'http://user@host.com/abs/path/sub')
822
694
self.assertRaises(errors.PathNotChild, t.relpath,
861
733
self.assertIs(new_password, c._get_credentials())
864
class TestReusedTransports(tests.TestCase):
736
class TestReusedTransports(TestCase):
865
737
"""Tests for transport reuse"""
867
739
def test_reuse_same_transport(self):
868
740
possible_transports = []
869
t1 = transport.get_transport_from_url('http://foo/',
870
possible_transports=possible_transports)
741
t1 = get_transport('http://foo/',
742
possible_transports=possible_transports)
871
743
self.assertEqual([t1], possible_transports)
872
t2 = transport.get_transport_from_url('http://foo/',
873
possible_transports=[t1])
744
t2 = get_transport('http://foo/', possible_transports=[t1])
874
745
self.assertIs(t1, t2)
876
747
# Also check that final '/' are handled correctly
877
t3 = transport.get_transport_from_url('http://foo/path/')
878
t4 = transport.get_transport_from_url('http://foo/path',
879
possible_transports=[t3])
748
t3 = get_transport('http://foo/path/')
749
t4 = get_transport('http://foo/path', possible_transports=[t3])
880
750
self.assertIs(t3, t4)
882
t5 = transport.get_transport_from_url('http://foo/path')
883
t6 = transport.get_transport_from_url('http://foo/path/',
884
possible_transports=[t5])
752
t5 = get_transport('http://foo/path')
753
t6 = get_transport('http://foo/path/', possible_transports=[t5])
885
754
self.assertIs(t5, t6)
887
756
def test_don_t_reuse_different_transport(self):
888
t1 = transport.get_transport_from_url('http://foo/path')
889
t2 = transport.get_transport_from_url('http://bar/path',
890
possible_transports=[t1])
757
t1 = get_transport('http://foo/path')
758
t2 = get_transport('http://bar/path', possible_transports=[t1])
891
759
self.assertIsNot(t1, t2)
894
class TestTransportTrace(tests.TestCase):
762
class TestTransportTrace(TestCase):
896
def test_decorator(self):
897
t = transport.get_transport_from_url('trace+memory://')
765
transport = get_transport('trace+memory://')
898
766
self.assertIsInstance(
899
t, bzrlib.transport.trace.TransportTraceDecorator)
767
transport, bzrlib.transport.trace.TransportTraceDecorator)
901
769
def test_clone_preserves_activity(self):
902
t = transport.get_transport_from_url('trace+memory://')
904
self.assertTrue(t is not t2)
905
self.assertTrue(t._activity is t2._activity)
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)
907
775
# the following specific tests are for the operations that have made use of
908
776
# logging in tests; we could test every single operation but doing that
909
777
# still won't cause a test failure when the top level Transport API
910
778
# changes; so there is little return doing that.
911
779
def test_get(self):
912
t = transport.get_transport_from_url('trace+memory:///')
913
t.put_bytes('foo', 'barish')
780
transport = get_transport('trace+memory:///')
781
transport.put_bytes('foo', 'barish')
915
783
expected_result = []
916
784
# put_bytes records the bytes, not the content to avoid memory
918
786
expected_result.append(('put_bytes', 'foo', 6, None))
919
787
# get records the file name only.
920
788
expected_result.append(('get', 'foo'))
921
self.assertEqual(expected_result, t._activity)
789
self.assertEqual(expected_result, transport._activity)
923
791
def test_readv(self):
924
t = transport.get_transport_from_url('trace+memory:///')
925
t.put_bytes('foo', 'barish')
926
list(t.readv('foo', [(0, 1), (3, 2)],
927
adjust_for_latency=True, upper_limit=6))
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,
928
796
expected_result = []
929
797
# put_bytes records the bytes, not the content to avoid memory
931
799
expected_result.append(('put_bytes', 'foo', 6, None))
932
800
# readv records the supplied offset request
933
801
expected_result.append(('readv', 'foo', [(0, 1), (3, 2)], True, 6))
934
self.assertEqual(expected_result, t._activity)
937
class TestSSHConnections(tests.TestCaseWithTransport):
939
def test_bzr_connect_to_bzr_ssh(self):
940
"""get_transport of a bzr+ssh:// behaves correctly.
942
bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
944
# This test actually causes a bzr instance to be invoked, which is very
945
# expensive: it should be the only such test in the test suite.
946
# A reasonable evolution for this would be to simply check inside
947
# check_channel_exec_request that the command is appropriate, and then
948
# satisfy requests in-process.
949
self.requireFeature(features.paramiko)
950
# SFTPFullAbsoluteServer has a get_url method, and doesn't
951
# override the interface (doesn't change self._vendor).
952
# Note that this does encryption, so can be slow.
953
from bzrlib.tests import stub_sftp
955
# Start an SSH server
956
self.command_executed = []
957
# XXX: This is horrible -- we define a really dumb SSH server that
958
# executes commands, and manage the hooking up of stdin/out/err to the
959
# SSH channel ourselves. Surely this has already been implemented
963
class StubSSHServer(stub_sftp.StubServer):
967
def check_channel_exec_request(self, channel, command):
968
self.test.command_executed.append(command)
969
proc = subprocess.Popen(
970
command, shell=True, stdin=subprocess.PIPE,
971
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
973
# XXX: horribly inefficient, not to mention ugly.
974
# Start a thread for each of stdin/out/err, and relay bytes
975
# from the subprocess to channel and vice versa.
976
def ferry_bytes(read, write, close):
985
(channel.recv, proc.stdin.write, proc.stdin.close),
986
(proc.stdout.read, channel.sendall, channel.close),
987
(proc.stderr.read, channel.sendall_stderr, channel.close)]
989
for read, write, close in file_functions:
990
t = threading.Thread(
991
target=ferry_bytes, args=(read, write, close))
997
ssh_server = stub_sftp.SFTPFullAbsoluteServer(StubSSHServer)
998
# We *don't* want to override the default SSH vendor: the detected one
1001
# FIXME: I don't understand the above comment, SFTPFullAbsoluteServer
1002
# inherits from SFTPServer which forces the SSH vendor to
1003
# ssh.ParamikoVendor(). So it's forced, not detected. --vila 20100623
1004
self.start_server(ssh_server)
1005
port = ssh_server.port
1007
if sys.platform == 'win32':
1008
bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
1010
bzr_remote_path = self.get_bzr_path()
1011
self.overrideEnv('BZR_REMOTE_PATH', bzr_remote_path)
1013
# Access the branch via a bzr+ssh URL. The BZR_REMOTE_PATH environment
1014
# variable is used to tell bzr what command to run on the remote end.
1015
path_to_branch = osutils.abspath('.')
1016
if sys.platform == 'win32':
1017
# On Windows, we export all drives as '/C:/, etc. So we need to
1018
# prefix a '/' to get the right path.
1019
path_to_branch = '/' + path_to_branch
1020
url = 'bzr+ssh://fred:secret@localhost:%d%s' % (port, path_to_branch)
1021
t = transport.get_transport(url)
1022
self.permit_url(t.base)
1026
['%s serve --inet --directory=/ --allow-writes' % bzr_remote_path],
1027
self.command_executed)
1028
# Make sure to disconnect, so that the remote process can stop, and we
1029
# can cleanup. Then pause the test until everything is shutdown
1030
t._client._medium.disconnect()
1033
# First wait for the subprocess
1035
# And the rest are threads
1036
for t in started[1:]:
1040
class TestUnhtml(tests.TestCase):
1042
"""Tests for unhtml_roughly"""
1044
def test_truncation(self):
1045
fake_html = "<p>something!\n" * 1000
1046
result = http.unhtml_roughly(fake_html)
1047
self.assertEquals(len(result), 1000)
1048
self.assertStartsWith(result, " something!")
1051
class SomeDirectory(object):
1053
def look_up(self, name, url):
1057
class TestLocationToUrl(tests.TestCase):
1059
def get_base_location(self):
1060
path = osutils.abspath('/foo/bar')
1061
if path.startswith('/'):
1062
url = 'file://%s' % (path,)
1064
# On Windows, abspaths start with the drive letter, so we have to
1065
# add in the extra '/'
1066
url = 'file:///%s' % (path,)
1069
def test_regular_url(self):
1070
self.assertEquals("file://foo", location_to_url("file://foo"))
1072
def test_directory(self):
1073
directories.register("bar:", SomeDirectory, "Dummy directory")
1074
self.addCleanup(directories.remove, "bar:")
1075
self.assertEquals("http://bar", location_to_url("bar:"))
1077
def test_unicode_url(self):
1078
self.assertRaises(errors.InvalidURL, location_to_url,
1079
"http://fo/\xc3\xaf".decode("utf-8"))
1081
def test_unicode_path(self):
1082
path, url = self.get_base_location()
1083
location = path + "\xc3\xaf".decode("utf-8")
1085
self.assertEquals(url, location_to_url(location))
1087
def test_path(self):
1088
path, url = self.get_base_location()
1089
self.assertEquals(url, location_to_url(path))
1091
def test_relative_file_url(self):
1092
self.assertEquals(urlutils.local_path_to_url(".") + "/bar",
1093
location_to_url("file:bar"))
1095
def test_absolute_file_url(self):
1096
self.assertEquals("file:///bar", location_to_url("file:/bar"))
802
self.assertEqual(expected_result, transport._activity)