15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
from cStringIO import StringIO
24
from bzrlib.errors import (NoSuchFile, FileExists,
30
from bzrlib.tests import TestCase, TestCaseInTempDir
31
from bzrlib.transport import (_get_protocol_handlers,
32
_get_transport_modules,
34
register_lazy_transport,
35
_set_protocol_handlers,
38
from bzrlib.transport.memory import MemoryTransport
39
from bzrlib.transport.local import LocalTransport
42
class TestTransport(TestCase):
43
"""Test the non transport-concrete class functionality."""
45
def test__get_set_protocol_handlers(self):
46
handlers = _get_protocol_handlers()
47
self.assertNotEqual({}, handlers)
49
_set_protocol_handlers({})
50
self.assertEqual({}, _get_protocol_handlers())
52
_set_protocol_handlers(handlers)
54
def test_get_transport_modules(self):
55
handlers = _get_protocol_handlers()
56
class SampleHandler(object):
57
"""I exist, isnt that enough?"""
60
_set_protocol_handlers(my_handlers)
61
register_lazy_transport('foo', 'bzrlib.tests.test_transport', 'TestTransport.SampleHandler')
62
register_lazy_transport('bar', 'bzrlib.tests.test_transport', 'TestTransport.SampleHandler')
63
self.assertEqual([SampleHandler.__module__],
64
_get_transport_modules())
66
_set_protocol_handlers(handlers)
68
def test_transport_dependency(self):
69
"""Transport with missing dependency causes no error"""
70
saved_handlers = _get_protocol_handlers()
72
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
73
'BadTransportHandler')
74
# TODO: jam 20060427 Now we get InvalidURL because it looks like
75
# a URL but we have no support for it.
76
# Is it better to always fall back to LocalTransport?
77
# I think this is a better error than a future NoSuchFile
78
self.assertRaises(InvalidURL, get_transport, 'foo://fooserver/foo')
80
# restore original values
81
_set_protocol_handlers(saved_handlers)
83
def test_transport_fallback(self):
84
"""Transport with missing dependency causes no error"""
85
saved_handlers = _get_protocol_handlers()
87
_set_protocol_handlers({})
88
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
89
'BackupTransportHandler')
90
register_lazy_transport('foo', 'bzrlib.tests.test_transport',
91
'BadTransportHandler')
92
t = get_transport('foo://fooserver/foo')
93
self.assertTrue(isinstance(t, BackupTransportHandler))
95
_set_protocol_handlers(saved_handlers)
98
class TestMemoryTransport(TestCase):
100
def test_get_transport(self):
103
def test_clone(self):
104
transport = MemoryTransport()
105
self.assertTrue(isinstance(transport, MemoryTransport))
107
def test_abspath(self):
108
transport = MemoryTransport()
109
self.assertEqual("memory:///relpath", transport.abspath('relpath'))
111
def test_relpath(self):
112
transport = MemoryTransport()
114
def test_append_and_get(self):
115
transport = MemoryTransport()
116
transport.append('path', StringIO('content'))
117
self.assertEqual(transport.get('path').read(), 'content')
118
transport.append('path', StringIO('content'))
119
self.assertEqual(transport.get('path').read(), 'contentcontent')
121
def test_put_and_get(self):
122
transport = MemoryTransport()
123
transport.put('path', StringIO('content'))
124
self.assertEqual(transport.get('path').read(), 'content')
125
transport.put('path', StringIO('content'))
126
self.assertEqual(transport.get('path').read(), 'content')
128
def test_append_without_dir_fails(self):
129
transport = MemoryTransport()
130
self.assertRaises(NoSuchFile,
131
transport.append, 'dir/path', StringIO('content'))
133
def test_put_without_dir_fails(self):
134
transport = MemoryTransport()
135
self.assertRaises(NoSuchFile,
136
transport.put, 'dir/path', StringIO('content'))
138
def test_get_missing(self):
139
transport = MemoryTransport()
140
self.assertRaises(NoSuchFile, transport.get, 'foo')
142
def test_has_missing(self):
143
transport = MemoryTransport()
144
self.assertEquals(False, transport.has('foo'))
146
def test_has_present(self):
147
transport = MemoryTransport()
148
transport.append('foo', StringIO('content'))
149
self.assertEquals(True, transport.has('foo'))
151
def test_mkdir(self):
152
transport = MemoryTransport()
153
transport.mkdir('dir')
154
transport.append('dir/path', StringIO('content'))
155
self.assertEqual(transport.get('dir/path').read(), 'content')
157
def test_mkdir_missing_parent(self):
158
transport = MemoryTransport()
159
self.assertRaises(NoSuchFile,
160
transport.mkdir, 'dir/dir')
162
def test_mkdir_twice(self):
163
transport = MemoryTransport()
164
transport.mkdir('dir')
165
self.assertRaises(FileExists, transport.mkdir, 'dir')
167
def test_parameters(self):
168
transport = MemoryTransport()
169
self.assertEqual(True, transport.listable())
170
self.assertEqual(False, transport.should_cache())
171
self.assertEqual(False, transport.is_readonly())
173
def test_iter_files_recursive(self):
174
transport = MemoryTransport()
175
transport.mkdir('dir')
176
transport.put('dir/foo', StringIO('content'))
177
transport.put('dir/bar', StringIO('content'))
178
transport.put('bar', StringIO('content'))
179
paths = set(transport.iter_files_recursive())
180
self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
183
transport = MemoryTransport()
184
transport.put('foo', StringIO('content'))
185
transport.put('bar', StringIO('phowar'))
186
self.assertEqual(7, transport.stat('foo').st_size)
187
self.assertEqual(6, transport.stat('bar').st_size)
190
class ReadonlyDecoratorTransportTest(TestCase):
191
"""Readonly decoration specific tests."""
193
def test_local_parameters(self):
194
import bzrlib.transport.readonly as readonly
195
# connect to . in readonly mode
196
transport = readonly.ReadonlyTransportDecorator('readonly+.')
197
self.assertEqual(True, transport.listable())
198
self.assertEqual(False, transport.should_cache())
199
self.assertEqual(True, transport.is_readonly())
201
def test_http_parameters(self):
202
import bzrlib.transport.readonly as readonly
203
from bzrlib.transport.http import HttpServer
204
# connect to . via http which is not listable
205
server = HttpServer()
208
transport = get_transport('readonly+' + server.get_url())
209
self.failUnless(isinstance(transport,
210
readonly.ReadonlyTransportDecorator))
211
self.assertEqual(False, transport.listable())
212
self.assertEqual(True, transport.should_cache())
213
self.assertEqual(True, transport.is_readonly())
218
class FakeNFSDecoratorTests(TestCaseInTempDir):
219
"""NFS decorator specific tests."""
221
def get_nfs_transport(self, url):
222
import bzrlib.transport.fakenfs as fakenfs
223
# connect to url with nfs decoration
224
return fakenfs.FakeNFSTransportDecorator('fakenfs+' + url)
226
def test_local_parameters(self):
227
# the listable, should_cache and is_readonly parameters
228
# are not changed by the fakenfs decorator
229
transport = self.get_nfs_transport('.')
230
self.assertEqual(True, transport.listable())
231
self.assertEqual(False, transport.should_cache())
232
self.assertEqual(False, transport.is_readonly())
234
def test_http_parameters(self):
235
# the listable, should_cache and is_readonly parameters
236
# are not changed by the fakenfs decorator
237
from bzrlib.transport.http import HttpServer
238
# connect to . via http which is not listable
239
server = HttpServer()
242
transport = self.get_nfs_transport(server.get_url())
243
self.assertIsInstance(
244
transport, bzrlib.transport.fakenfs.FakeNFSTransportDecorator)
245
self.assertEqual(False, transport.listable())
246
self.assertEqual(True, transport.should_cache())
247
self.assertEqual(True, transport.is_readonly())
251
def test_fakenfs_server_default(self):
252
# a FakeNFSServer() should bring up a local relpath server for itself
253
import bzrlib.transport.fakenfs as fakenfs
254
server = fakenfs.FakeNFSServer()
257
# the server should be a relpath localhost server
258
self.assertEqual(server.get_url(), 'fakenfs+.')
259
# and we should be able to get a transport for it
260
transport = get_transport(server.get_url())
261
# which must be a FakeNFSTransportDecorator instance.
262
self.assertIsInstance(
263
transport, fakenfs.FakeNFSTransportDecorator)
267
def test_fakenfs_rename_semantics(self):
268
# a FakeNFS transport must mangle the way rename errors occur to
269
# look like NFS problems.
270
transport = self.get_nfs_transport('.')
271
self.build_tree(['from/', 'from/foo', 'to/', 'to/bar'],
273
self.assertRaises(bzrlib.errors.ResourceBusy,
274
transport.rename, 'from', 'to')
277
class FakeVFATDecoratorTests(TestCaseInTempDir):
278
"""Tests for simulation of VFAT restrictions"""
280
def get_vfat_transport(self, url):
281
"""Return vfat-backed transport for test directory"""
282
from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
283
return FakeVFATTransportDecorator('vfat+' + url)
285
def test_transport_creation(self):
286
from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
287
transport = self.get_vfat_transport('.')
288
self.assertIsInstance(transport, FakeVFATTransportDecorator)
290
def test_transport_mkdir(self):
291
transport = self.get_vfat_transport('.')
292
transport.mkdir('HELLO')
293
self.assertTrue(transport.has('hello'))
294
self.assertTrue(transport.has('Hello'))
296
def test_forbidden_chars(self):
297
transport = self.get_vfat_transport('.')
298
self.assertRaises(ValueError, transport.has, "<NU>")
301
class BadTransportHandler(Transport):
302
def __init__(self, base_url):
303
raise DependencyNotPresent('some_lib', 'testing missing dependency')
306
class BackupTransportHandler(Transport):
307
"""Test transport that works as a backup for the BadTransportHandler"""
18
from bzrlib.selftest import TestCaseInTempDir
20
def test_transport(tester, t, readonly=False):
21
"""Test a transport object. Basically, it assumes that the
22
Transport object is connected to the current working directory.
23
So that whatever is done through the transport, should show
24
up in the working directory, and vice-versa.
26
This also tests to make sure that the functions work with both
27
generators and lists (assuming iter(list) is effectively a generator)
30
from bzrlib.transport.local import LocalTransport
33
files = ['a', 'b', 'e', 'g']
34
tester.build_tree(files)
35
tester.assertEqual(t.has('a'), True)
36
tester.assertEqual(t.has('c'), False)
37
tester.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])),
38
[True, True, False, False, True, False, True, False])
39
tester.assertEqual(list(t.has_multi(iter(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']))),
40
[True, True, False, False, True, False, True, False])
43
tester.assertEqual(t.get('a').read(), open('a').read())
44
content_f = t.get_multi(files)
45
for path,f in zip(files, content_f):
46
tester.assertEqual(open(path).read(), f.read())
48
content_f = t.get_multi(iter(files))
49
for path,f in zip(files, content_f):
50
tester.assertEqual(open(path).read(), f.read())
52
tester.assertRaises(NoSuchFile, t.get, 'c')
54
files = list(t.get_multi(['a', 'b', 'c']))
58
tester.fail('Failed to raise NoSuchFile for missing file in get_multi')
60
files = list(t.get_multi(iter(['a', 'b', 'c', 'e'])))
64
tester.fail('Failed to raise NoSuchFile for missing file in get_multi')
68
open('c', 'wb').write('some text for c\n')
70
t.put('c', 'some text for c\n')
71
tester.assert_(os.path.exists('c'))
72
tester.assertEqual(open('c').read(), 'some text for c\n')
73
tester.assertEqual(t.get('c').read(), 'some text for c\n')
74
# Make sure 'has' is updated
75
tester.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])),
76
[True, True, True, False, True, False, True, False])
78
open('a', 'wb').write('new\ncontents for\na\n')
79
open('d', 'wb').write('contents\nfor d\n')
81
# Put also replaces contents
82
tester.assertEqual(t.put_multi([('a', 'new\ncontents for\na\n'),
83
('d', 'contents\nfor d\n')]),
85
tester.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])),
86
[True, True, True, True, True, False, True, False])
87
tester.assertEqual(open('a').read(), 'new\ncontents for\na\n')
88
tester.assertEqual(open('d').read(), 'contents\nfor d\n')
91
open('a', 'wb').write('diff\ncontents for\na\n')
92
open('d', 'wb').write('another contents\nfor d\n')
95
t.put_multi(iter([('a', 'diff\ncontents for\na\n'),
96
('d', 'another contents\nfor d\n')]))
98
tester.assertEqual(open('a').read(), 'diff\ncontents for\na\n')
99
tester.assertEqual(open('d').read(), 'another contents\nfor d\n')
102
tester.assertRaises(NoSuchFile, t.put, 'path/doesnt/exist/c', 'contents')
106
tester.assertEqual(t.has('dir_a'), True)
107
tester.assertEqual(t.has('dir_b'), False)
113
tester.assertEqual(t.has('dir_b'), True)
114
tester.assert_(os.path.isdir('dir_b'))
120
t.mkdir_multi(['dir_c', 'dir_d'])
121
tester.assertEqual(list(t.has_multi(['dir_a', 'dir_b', 'dir_c', 'dir_d', 'dir_e', 'dir_b'])),
122
[True, True, True, True, False, True])
123
for d in ['dir_a', 'dir_b', 'dir_c', 'dir_d']:
124
tester.assert_(os.path.isdir(d))
127
tester.assertRaises(NoSuchFile, t.mkdir, 'path/doesnt/exist')
128
tester.assertRaises(FileExists, t.mkdir, 'dir_a') # Creating a directory again should fail
130
# Make sure the transport recognizes when a
131
# directory is created by other means
132
# Caching Transports will fail, because dir_e was already seen not
133
# to exist. So instead, we will search for a new directory
136
# tester.assertRaises(FileExists, t.mkdir, 'dir_e')
140
tester.assertRaises(FileExists, t.mkdir, 'dir_f')
142
# Test get/put in sub-directories
144
open('dir_a/a', 'wb').write('contents of dir_a/a')
145
open('dir_b/b', 'wb').write('contents of dir_b/b')
148
t.put_multi([('dir_a/a', 'contents of dir_a/a'),
149
('dir_b/b', 'contents of dir_b/b')])
151
for f in ('dir_a/a', 'dir_b/b'):
152
tester.assertEqual(t.get(f).read(), open(f).read())
155
dtmp = tempfile.mkdtemp(dir='.', prefix='test-transport-')
156
dtmp_base = os.path.basename(dtmp)
157
local_t = LocalTransport(dtmp)
159
files = ['a', 'b', 'c', 'd']
160
t.copy_to(files, local_t)
162
tester.assertEquals(open(f).read(), open(os.path.join(dtmp_base, f)).read())
165
# TODO: Make sure all entries support file-like objects as well as strings.
167
class LocalTransportTest(TestCaseInTempDir):
168
def test_local_transport(self):
169
from bzrlib.transport.local import LocalTransport
171
t = LocalTransport('.')
172
test_transport(self, t)
174
class HttpServer(object):
175
"""This just encapsulates spawning and stopping
179
"""This just spawns a separate process to serve files from
180
this directory. Call the .stop() function to kill the
183
from BaseHTTPServer import HTTPServer
184
from SimpleHTTPServer import SimpleHTTPRequestHandler
186
if hasattr(os, 'fork'):
190
else: # How do we handle windows, which doesn't have fork?
191
raise NotImplementedError('At present HttpServer cannot fork on Windows')
193
# We might be able to do something like os.spawn() for the
194
# python executable, and give it a simple script to run.
195
# but then how do we kill it?
198
self.s = HTTPServer(('', 9999), SimpleHTTPRequestHandler)
199
# TODO: Is there something nicer than killing the server when done?
200
self.s.serve_forever()
201
except KeyboardInterrupt:
209
if hasattr(os, 'kill'):
211
os.kill(self.pid, signal.SIGINT)
212
os.waitpid(self.pid, 0)
215
raise NotImplementedError('At present HttpServer cannot stop on Windows')
217
class HttpTransportTest(TestCaseInTempDir):
218
def test_http_transport(self):
219
from bzrlib.transport.http import HttpTransport
223
t = HttpTransport('http://localhost:9999/')
224
test_transport(self, t, readonly=True)