/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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
"""Tests for Transport implementations.
18
19
Transport implementations tested here are supplied by
20
TransportTestProviderAdapter.
21
"""
22
23
import os
24
from cStringIO import StringIO
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
25
import stat
26
import sys
1530.1.3 by Robert Collins
transport implementations now tested consistently.
27
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
28
from bzrlib import (
29
    osutils,
30
    urlutils,
31
    )
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
32
from bzrlib.errors import (DirectoryNotEmpty, NoSuchFile, FileExists,
1185.85.84 by John Arbash Meinel
[merge] bzr.dev 1573, lots of updates
33
                           LockError, PathError,
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
34
                           TransportNotPossible, ConnectionError,
35
                           InvalidURL)
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
36
from bzrlib.osutils import getcwd
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
37
from bzrlib.tests import TestCaseInTempDir, TestSkipped
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
38
from bzrlib.tests.test_transport import TestTransportImplementation
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
39
from bzrlib.transport import memory
1530.1.3 by Robert Collins
transport implementations now tested consistently.
40
import bzrlib.transport
41
42
43
def _append(fn, txt):
44
    """Append the given text (file-like object) to the supplied filename."""
45
    f = open(fn, 'ab')
1530.1.21 by Robert Collins
Review feedback fixes.
46
    try:
47
        f.write(txt.read())
48
    finally:
49
        f.close()
1530.1.3 by Robert Collins
transport implementations now tested consistently.
50
51
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
52
class TransportTests(TestTransportImplementation):
53
1530.1.3 by Robert Collins
transport implementations now tested consistently.
54
    def check_transport_contents(self, content, transport, relpath):
55
        """Check that transport.get(relpath).read() == content."""
1530.1.21 by Robert Collins
Review feedback fixes.
56
        self.assertEqualDiff(content, transport.get(relpath).read())
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
57
1530.1.3 by Robert Collins
transport implementations now tested consistently.
58
    def assertListRaises(self, excClass, func, *args, **kwargs):
1530.1.21 by Robert Collins
Review feedback fixes.
59
        """Fail unless excClass is raised when the iterator from func is used.
60
        
61
        Many transport functions can return generators this makes sure
1530.1.3 by Robert Collins
transport implementations now tested consistently.
62
        to wrap them in a list() call to make sure the whole generator
63
        is run, and that the proper exception is raised.
64
        """
65
        try:
66
            list(func(*args, **kwargs))
67
        except excClass:
68
            return
69
        else:
70
            if hasattr(excClass,'__name__'): excName = excClass.__name__
71
            else: excName = str(excClass)
72
            raise self.failureException, "%s not raised" % excName
73
74
    def test_has(self):
75
        t = self.get_transport()
76
77
        files = ['a', 'b', 'e', 'g', '%']
78
        self.build_tree(files, transport=t)
79
        self.assertEqual(True, t.has('a'))
80
        self.assertEqual(False, t.has('c'))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
81
        self.assertEqual(True, t.has(urlutils.escape('%')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
82
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])),
83
                [True, True, False, False, True, False, True, False])
84
        self.assertEqual(True, t.has_any(['a', 'b', 'c']))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
85
        self.assertEqual(False, t.has_any(['c', 'd', 'f', urlutils.escape('%%')]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
86
        self.assertEqual(list(t.has_multi(iter(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']))),
87
                [True, True, False, False, True, False, True, False])
88
        self.assertEqual(False, t.has_any(['c', 'c', 'c']))
89
        self.assertEqual(True, t.has_any(['b', 'b', 'b']))
90
91
    def test_get(self):
92
        t = self.get_transport()
93
94
        files = ['a', 'b', 'e', 'g']
95
        contents = ['contents of a\n',
96
                    'contents of b\n',
97
                    'contents of e\n',
98
                    'contents of g\n',
99
                    ]
1551.2.39 by abentley
Fix line endings in tests
100
        self.build_tree(files, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
101
        self.check_transport_contents('contents of a\n', t, 'a')
102
        content_f = t.get_multi(files)
103
        for content, f in zip(contents, content_f):
104
            self.assertEqual(content, f.read())
105
106
        content_f = t.get_multi(iter(files))
107
        for content, f in zip(contents, content_f):
108
            self.assertEqual(content, f.read())
109
110
        self.assertRaises(NoSuchFile, t.get, 'c')
111
        self.assertListRaises(NoSuchFile, t.get_multi, ['a', 'b', 'c'])
112
        self.assertListRaises(NoSuchFile, t.get_multi, iter(['a', 'b', 'c']))
113
114
    def test_put(self):
115
        t = self.get_transport()
116
117
        if t.is_readonly():
118
            self.assertRaises(TransportNotPossible,
119
                    t.put, 'a', 'some text for a\n')
120
            return
121
122
        t.put('a', StringIO('some text for a\n'))
123
        self.failUnless(t.has('a'))
124
        self.check_transport_contents('some text for a\n', t, 'a')
125
        # Make sure 'has' is updated
126
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e'])),
127
                [True, False, False, False, False])
128
        # Put also replaces contents
129
        self.assertEqual(t.put_multi([('a', StringIO('new\ncontents for\na\n')),
130
                                      ('d', StringIO('contents\nfor d\n'))]),
131
                         2)
132
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e'])),
133
                [True, False, False, True, False])
134
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
135
        self.check_transport_contents('contents\nfor d\n', t, 'd')
136
137
        self.assertEqual(
138
            t.put_multi(iter([('a', StringIO('diff\ncontents for\na\n')),
139
                              ('d', StringIO('another contents\nfor d\n'))])),
140
                        2)
141
        self.check_transport_contents('diff\ncontents for\na\n', t, 'a')
142
        self.check_transport_contents('another contents\nfor d\n', t, 'd')
143
144
        self.assertRaises(NoSuchFile,
145
                          t.put, 'path/doesnt/exist/c', 'contents')
146
1946.1.1 by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put'
147
    def test_non_atomic_put(self):
148
        t = self.get_transport()
149
150
        if t.is_readonly():
151
            self.assertRaises(TransportNotPossible,
152
                    t.non_atomic_put, 'a', StringIO('some text for a\n'))
153
            return
154
155
        self.failIf(t.has('a'))
156
        t.non_atomic_put('a', StringIO('some text for a\n'))
157
        self.failUnless(t.has('a'))
158
        self.check_transport_contents('some text for a\n', t, 'a')
159
        # Put also replaces contents
160
        t.non_atomic_put('a', StringIO('new\ncontents for\na\n'))
161
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
162
163
        # Make sure we can create another file
164
        t.non_atomic_put('d', StringIO('contents for\nd\n'))
165
        # And overwrite 'a' with empty contents
166
        t.non_atomic_put('a', StringIO(''))
167
        self.check_transport_contents('contents for\nd\n', t, 'd')
168
        self.check_transport_contents('', t, 'a')
169
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
170
        self.assertRaises(NoSuchFile, t.non_atomic_put, 'no/such/path',
171
                                       StringIO('contents\n'))
172
        # Now test the create_parent flag
173
        self.assertRaises(NoSuchFile, t.non_atomic_put, 'dir/a',
174
                                       StringIO('contents\n'))
175
        self.failIf(t.has('dir/a'))
176
        t.non_atomic_put('dir/a', StringIO('contents for dir/a\n'),
177
                         create_parent_dir=True)
178
        self.check_transport_contents('contents for dir/a\n', t, 'dir/a')
179
        
180
        # But we still get NoSuchFile if we can't make the parent dir
181
        self.assertRaises(NoSuchFile, t.non_atomic_put, 'not/there/a',
182
                                       StringIO('contents\n'))
183
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
184
    def test_put_permissions(self):
185
        t = self.get_transport()
186
187
        if t.is_readonly():
188
            return
1711.4.32 by John Arbash Meinel
Skip permission tests on win32 no modebits
189
        if not t._can_roundtrip_unix_modebits():
190
            # Can't roundtrip, so no need to run this test
191
            return
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
192
        t.put('mode644', StringIO('test text\n'), mode=0644)
1530.1.21 by Robert Collins
Review feedback fixes.
193
        self.assertTransportMode(t, 'mode644', 0644)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
194
        t.put('mode666', StringIO('test text\n'), mode=0666)
1530.1.21 by Robert Collins
Review feedback fixes.
195
        self.assertTransportMode(t, 'mode666', 0666)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
196
        t.put('mode600', StringIO('test text\n'), mode=0600)
1530.1.21 by Robert Collins
Review feedback fixes.
197
        self.assertTransportMode(t, 'mode600', 0600)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
198
        # Yes, you can put a file such that it becomes readonly
199
        t.put('mode400', StringIO('test text\n'), mode=0400)
1530.1.21 by Robert Collins
Review feedback fixes.
200
        self.assertTransportMode(t, 'mode400', 0400)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
201
        t.put_multi([('mmode644', StringIO('text\n'))], mode=0644)
1530.1.21 by Robert Collins
Review feedback fixes.
202
        self.assertTransportMode(t, 'mmode644', 0644)
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
203
204
        # The default permissions should be based on the current umask
205
        umask = osutils.get_umask()
206
        t.put('nomode', StringIO('test text\n'), mode=None)
207
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
208
        
1946.1.3 by John Arbash Meinel
Add tests for permissions
209
    def test_non_atomic_put_permissions(self):
210
        t = self.get_transport()
211
212
        if t.is_readonly():
213
            return
214
        if not t._can_roundtrip_unix_modebits():
215
            # Can't roundtrip, so no need to run this test
216
            return
217
        t.non_atomic_put('mode644', StringIO('test text\n'), mode=0644)
218
        self.assertTransportMode(t, 'mode644', 0644)
219
        t.non_atomic_put('mode666', StringIO('test text\n'), mode=0666)
220
        self.assertTransportMode(t, 'mode666', 0666)
221
        t.non_atomic_put('mode600', StringIO('test text\n'), mode=0600)
222
        self.assertTransportMode(t, 'mode600', 0600)
223
        # Yes, you can non_atomic_put a file such that it becomes readonly
224
        t.non_atomic_put('mode400', StringIO('test text\n'), mode=0400)
225
        self.assertTransportMode(t, 'mode400', 0400)
226
227
        # The default permissions should be based on the current umask
228
        umask = osutils.get_umask()
229
        t.non_atomic_put('nomode', StringIO('test text\n'), mode=None)
230
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
231
        
1530.1.3 by Robert Collins
transport implementations now tested consistently.
232
    def test_mkdir(self):
233
        t = self.get_transport()
234
235
        if t.is_readonly():
236
            # cannot mkdir on readonly transports. We're not testing for 
237
            # cache coherency because cache behaviour is not currently
238
            # defined for the transport interface.
239
            self.assertRaises(TransportNotPossible, t.mkdir, '.')
240
            self.assertRaises(TransportNotPossible, t.mkdir, 'new_dir')
241
            self.assertRaises(TransportNotPossible, t.mkdir_multi, ['new_dir'])
242
            self.assertRaises(TransportNotPossible, t.mkdir, 'path/doesnt/exist')
243
            return
244
        # Test mkdir
245
        t.mkdir('dir_a')
246
        self.assertEqual(t.has('dir_a'), True)
247
        self.assertEqual(t.has('dir_b'), False)
248
249
        t.mkdir('dir_b')
250
        self.assertEqual(t.has('dir_b'), True)
251
252
        t.mkdir_multi(['dir_c', 'dir_d'])
253
254
        t.mkdir_multi(iter(['dir_e', 'dir_f']))
255
        self.assertEqual(list(t.has_multi(
256
            ['dir_a', 'dir_b', 'dir_c', 'dir_q',
257
             'dir_d', 'dir_e', 'dir_f', 'dir_b'])),
258
            [True, True, True, False,
259
             True, True, True, True])
260
261
        # we were testing that a local mkdir followed by a transport
262
        # mkdir failed thusly, but given that we * in one process * do not
263
        # concurrently fiddle with disk dirs and then use transport to do 
264
        # things, the win here seems marginal compared to the constraint on
265
        # the interface. RBC 20051227
266
        t.mkdir('dir_g')
267
        self.assertRaises(FileExists, t.mkdir, 'dir_g')
268
269
        # Test get/put in sub-directories
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
270
        self.assertEqual(2, 
1530.1.3 by Robert Collins
transport implementations now tested consistently.
271
            t.put_multi([('dir_a/a', StringIO('contents of dir_a/a')),
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
272
                         ('dir_b/b', StringIO('contents of dir_b/b'))]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
273
        self.check_transport_contents('contents of dir_a/a', t, 'dir_a/a')
274
        self.check_transport_contents('contents of dir_b/b', t, 'dir_b/b')
275
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
276
        # mkdir of a dir with an absent parent
277
        self.assertRaises(NoSuchFile, t.mkdir, 'missing/dir')
278
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
279
    def test_mkdir_permissions(self):
280
        t = self.get_transport()
281
        if t.is_readonly():
282
            return
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
283
        if not t._can_roundtrip_unix_modebits():
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
284
            # no sense testing on this transport
285
            return
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
286
        # Test mkdir with a mode
287
        t.mkdir('dmode755', mode=0755)
1530.1.21 by Robert Collins
Review feedback fixes.
288
        self.assertTransportMode(t, 'dmode755', 0755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
289
        t.mkdir('dmode555', mode=0555)
1530.1.21 by Robert Collins
Review feedback fixes.
290
        self.assertTransportMode(t, 'dmode555', 0555)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
291
        t.mkdir('dmode777', mode=0777)
1530.1.21 by Robert Collins
Review feedback fixes.
292
        self.assertTransportMode(t, 'dmode777', 0777)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
293
        t.mkdir('dmode700', mode=0700)
1530.1.21 by Robert Collins
Review feedback fixes.
294
        self.assertTransportMode(t, 'dmode700', 0700)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
295
        t.mkdir_multi(['mdmode755'], mode=0755)
1530.1.21 by Robert Collins
Review feedback fixes.
296
        self.assertTransportMode(t, 'mdmode755', 0755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
297
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
298
        # Default mode should be based on umask
299
        umask = osutils.get_umask()
300
        t.mkdir('dnomode', mode=None)
301
        self.assertTransportMode(t, 'dnomode', 0777 & ~umask)
302
1530.1.3 by Robert Collins
transport implementations now tested consistently.
303
    def test_copy_to(self):
1534.4.21 by Robert Collins
Extend the copy_to tests to smoke test server-to-same-server copies to catch optimised code paths, and fix sftps optimised code path by removing dead code.
304
        # FIXME: test:   same server to same server (partly done)
305
        # same protocol two servers
306
        # and    different protocols (done for now except for MemoryTransport.
307
        # - RBC 20060122
1530.1.3 by Robert Collins
transport implementations now tested consistently.
308
        from bzrlib.transport.memory import MemoryTransport
1534.4.21 by Robert Collins
Extend the copy_to tests to smoke test server-to-same-server copies to catch optimised code paths, and fix sftps optimised code path by removing dead code.
309
310
        def simple_copy_files(transport_from, transport_to):
311
            files = ['a', 'b', 'c', 'd']
312
            self.build_tree(files, transport=transport_from)
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
313
            self.assertEqual(4, transport_from.copy_to(files, transport_to))
1534.4.21 by Robert Collins
Extend the copy_to tests to smoke test server-to-same-server copies to catch optimised code paths, and fix sftps optimised code path by removing dead code.
314
            for f in files:
315
                self.check_transport_contents(transport_to.get(f).read(),
316
                                              transport_from, f)
317
1530.1.3 by Robert Collins
transport implementations now tested consistently.
318
        t = self.get_transport()
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
319
        temp_transport = MemoryTransport('memory:///')
1534.4.21 by Robert Collins
Extend the copy_to tests to smoke test server-to-same-server copies to catch optimised code paths, and fix sftps optimised code path by removing dead code.
320
        simple_copy_files(t, temp_transport)
321
        if not t.is_readonly():
322
            t.mkdir('copy_to_simple')
323
            t2 = t.clone('copy_to_simple')
324
            simple_copy_files(t, t2)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
325
326
327
        # Test that copying into a missing directory raises
328
        # NoSuchFile
329
        if t.is_readonly():
1530.1.21 by Robert Collins
Review feedback fixes.
330
            self.build_tree(['e/', 'e/f'])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
331
        else:
332
            t.mkdir('e')
333
            t.put('e/f', StringIO('contents of e'))
334
        self.assertRaises(NoSuchFile, t.copy_to, ['e/f'], temp_transport)
335
        temp_transport.mkdir('e')
336
        t.copy_to(['e/f'], temp_transport)
337
338
        del temp_transport
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
339
        temp_transport = MemoryTransport('memory:///')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
340
341
        files = ['a', 'b', 'c', 'd']
342
        t.copy_to(iter(files), temp_transport)
343
        for f in files:
344
            self.check_transport_contents(temp_transport.get(f).read(),
345
                                          t, f)
346
        del temp_transport
347
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
348
        for mode in (0666, 0644, 0600, 0400):
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
349
            temp_transport = MemoryTransport("memory:///")
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
350
            t.copy_to(files, temp_transport, mode=mode)
351
            for f in files:
1530.1.21 by Robert Collins
Review feedback fixes.
352
                self.assertTransportMode(temp_transport, f, mode)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
353
1530.1.3 by Robert Collins
transport implementations now tested consistently.
354
    def test_append(self):
355
        t = self.get_transport()
356
357
        if t.is_readonly():
358
            open('a', 'wb').write('diff\ncontents for\na\n')
359
            open('b', 'wb').write('contents\nfor b\n')
360
        else:
361
            t.put_multi([
362
                    ('a', StringIO('diff\ncontents for\na\n')),
363
                    ('b', StringIO('contents\nfor b\n'))
364
                    ])
365
366
        if t.is_readonly():
367
            self.assertRaises(TransportNotPossible,
368
                    t.append, 'a', 'add\nsome\nmore\ncontents\n')
369
            _append('a', StringIO('add\nsome\nmore\ncontents\n'))
370
        else:
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
371
            self.assertEqual(20,
372
                t.append('a', StringIO('add\nsome\nmore\ncontents\n')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
373
374
        self.check_transport_contents(
375
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
376
            t, 'a')
377
378
        if t.is_readonly():
379
            self.assertRaises(TransportNotPossible,
380
                    t.append_multi,
381
                        [('a', 'and\nthen\nsome\nmore\n'),
382
                         ('b', 'some\nmore\nfor\nb\n')])
383
            _append('a', StringIO('and\nthen\nsome\nmore\n'))
384
            _append('b', StringIO('some\nmore\nfor\nb\n'))
385
        else:
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
386
            self.assertEqual((43, 15), 
387
                t.append_multi([('a', StringIO('and\nthen\nsome\nmore\n')),
388
                                ('b', StringIO('some\nmore\nfor\nb\n'))]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
389
        self.check_transport_contents(
390
            'diff\ncontents for\na\n'
391
            'add\nsome\nmore\ncontents\n'
392
            'and\nthen\nsome\nmore\n',
393
            t, 'a')
394
        self.check_transport_contents(
395
                'contents\nfor b\n'
396
                'some\nmore\nfor\nb\n',
397
                t, 'b')
398
399
        if t.is_readonly():
400
            _append('a', StringIO('a little bit more\n'))
401
            _append('b', StringIO('from an iterator\n'))
402
        else:
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
403
            self.assertEqual((62, 31),
404
                t.append_multi(iter([('a', StringIO('a little bit more\n')),
405
                                     ('b', StringIO('from an iterator\n'))])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
406
        self.check_transport_contents(
407
            'diff\ncontents for\na\n'
408
            'add\nsome\nmore\ncontents\n'
409
            'and\nthen\nsome\nmore\n'
410
            'a little bit more\n',
411
            t, 'a')
412
        self.check_transport_contents(
413
                'contents\nfor b\n'
414
                'some\nmore\nfor\nb\n'
415
                'from an iterator\n',
416
                t, 'b')
417
418
        if t.is_readonly():
419
            _append('c', StringIO('some text\nfor a missing file\n'))
420
            _append('a', StringIO('some text in a\n'))
421
            _append('d', StringIO('missing file r\n'))
422
        else:
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
423
            self.assertEqual(0,
424
                t.append('c', StringIO('some text\nfor a missing file\n')))
425
            self.assertEqual((80, 0),
426
                t.append_multi([('a', StringIO('some text in a\n')),
427
                                ('d', StringIO('missing file r\n'))]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
428
        self.check_transport_contents(
429
            'diff\ncontents for\na\n'
430
            'add\nsome\nmore\ncontents\n'
431
            'and\nthen\nsome\nmore\n'
432
            'a little bit more\n'
433
            'some text in a\n',
434
            t, 'a')
435
        self.check_transport_contents('some text\nfor a missing file\n',
436
                                      t, 'c')
437
        self.check_transport_contents('missing file r\n', t, 'd')
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
438
        
439
        # a file with no parent should fail..
440
        if not t.is_readonly():
441
            self.assertRaises(NoSuchFile,
442
                              t.append, 'missing/path', 
443
                              StringIO('content'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
444
445
    def test_append_file(self):
446
        t = self.get_transport()
447
448
        contents = [
449
            ('f1', StringIO('this is a string\nand some more stuff\n')),
450
            ('f2', StringIO('here is some text\nand a bit more\n')),
451
            ('f3', StringIO('some text for the\nthird file created\n')),
452
            ('f4', StringIO('this is a string\nand some more stuff\n')),
453
            ('f5', StringIO('here is some text\nand a bit more\n')),
454
            ('f6', StringIO('some text for the\nthird file created\n'))
455
        ]
456
        
457
        if t.is_readonly():
458
            for f, val in contents:
459
                open(f, 'wb').write(val.read())
460
        else:
461
            t.put_multi(contents)
462
463
        a1 = StringIO('appending to\none\n')
464
        if t.is_readonly():
465
            _append('f1', a1)
466
        else:
467
            t.append('f1', a1)
468
469
        del a1
470
471
        self.check_transport_contents(
472
                'this is a string\nand some more stuff\n'
473
                'appending to\none\n',
474
                t, 'f1')
475
476
        a2 = StringIO('adding more\ntext to two\n')
477
        a3 = StringIO('some garbage\nto put in three\n')
478
479
        if t.is_readonly():
480
            _append('f2', a2)
481
            _append('f3', a3)
482
        else:
483
            t.append_multi([('f2', a2), ('f3', a3)])
484
485
        del a2, a3
486
487
        self.check_transport_contents(
488
                'here is some text\nand a bit more\n'
489
                'adding more\ntext to two\n',
490
                t, 'f2')
491
        self.check_transport_contents( 
492
                'some text for the\nthird file created\n'
493
                'some garbage\nto put in three\n',
494
                t, 'f3')
495
496
        # Test that an actual file object can be used with put
497
        a4 = t.get('f1')
498
        if t.is_readonly():
499
            _append('f4', a4)
500
        else:
501
            t.append('f4', a4)
502
503
        del a4
504
505
        self.check_transport_contents(
506
                'this is a string\nand some more stuff\n'
507
                'this is a string\nand some more stuff\n'
508
                'appending to\none\n',
509
                t, 'f4')
510
511
        a5 = t.get('f2')
512
        a6 = t.get('f3')
513
        if t.is_readonly():
514
            _append('f5', a5)
515
            _append('f6', a6)
516
        else:
517
            t.append_multi([('f5', a5), ('f6', a6)])
518
519
        del a5, a6
520
521
        self.check_transport_contents(
522
                'here is some text\nand a bit more\n'
523
                'here is some text\nand a bit more\n'
524
                'adding more\ntext to two\n',
525
                t, 'f5')
526
        self.check_transport_contents(
527
                'some text for the\nthird file created\n'
528
                'some text for the\nthird file created\n'
529
                'some garbage\nto put in three\n',
530
                t, 'f6')
531
532
        a5 = t.get('f2')
533
        a6 = t.get('f2')
534
        a7 = t.get('f3')
535
        if t.is_readonly():
536
            _append('c', a5)
537
            _append('a', a6)
538
            _append('d', a7)
539
        else:
540
            t.append('c', a5)
541
            t.append_multi([('a', a6), ('d', a7)])
542
        del a5, a6, a7
543
        self.check_transport_contents(t.get('f2').read(), t, 'c')
544
        self.check_transport_contents(t.get('f3').read(), t, 'd')
545
1666.1.6 by Robert Collins
Make knit the default format.
546
    def test_append_mode(self):
547
        # check append accepts a mode
548
        t = self.get_transport()
549
        if t.is_readonly():
550
            return
551
        t.append('f', StringIO('f'), mode=None)
552
        
1530.1.3 by Robert Collins
transport implementations now tested consistently.
553
    def test_delete(self):
554
        # TODO: Test Transport.delete
555
        t = self.get_transport()
556
557
        # Not much to do with a readonly transport
558
        if t.is_readonly():
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
559
            self.assertRaises(TransportNotPossible, t.delete, 'missing')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
560
            return
561
562
        t.put('a', StringIO('a little bit of text\n'))
563
        self.failUnless(t.has('a'))
564
        t.delete('a')
565
        self.failIf(t.has('a'))
566
567
        self.assertRaises(NoSuchFile, t.delete, 'a')
568
569
        t.put('a', StringIO('a text\n'))
570
        t.put('b', StringIO('b text\n'))
571
        t.put('c', StringIO('c text\n'))
572
        self.assertEqual([True, True, True],
573
                list(t.has_multi(['a', 'b', 'c'])))
574
        t.delete_multi(['a', 'c'])
575
        self.assertEqual([False, True, False],
576
                list(t.has_multi(['a', 'b', 'c'])))
577
        self.failIf(t.has('a'))
578
        self.failUnless(t.has('b'))
579
        self.failIf(t.has('c'))
580
581
        self.assertRaises(NoSuchFile,
582
                t.delete_multi, ['a', 'b', 'c'])
583
584
        self.assertRaises(NoSuchFile,
585
                t.delete_multi, iter(['a', 'b', 'c']))
586
587
        t.put('a', StringIO('another a text\n'))
588
        t.put('c', StringIO('another c text\n'))
589
        t.delete_multi(iter(['a', 'b', 'c']))
590
591
        # We should have deleted everything
592
        # SftpServer creates control files in the
593
        # working directory, so we can just do a
594
        # plain "listdir".
595
        # self.assertEqual([], os.listdir('.'))
596
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
597
    def test_rmdir(self):
598
        t = self.get_transport()
599
        # Not much to do with a readonly transport
600
        if t.is_readonly():
601
            self.assertRaises(TransportNotPossible, t.rmdir, 'missing')
602
            return
603
        t.mkdir('adir')
604
        t.mkdir('adir/bdir')
605
        t.rmdir('adir/bdir')
606
        self.assertRaises(NoSuchFile, t.stat, 'adir/bdir')
607
        t.rmdir('adir')
608
        self.assertRaises(NoSuchFile, t.stat, 'adir')
609
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
610
    def test_rmdir_not_empty(self):
611
        """Deleting a non-empty directory raises an exception
612
        
613
        sftp (and possibly others) don't give us a specific "directory not
614
        empty" exception -- we can just see that the operation failed.
615
        """
616
        t = self.get_transport()
617
        if t.is_readonly():
618
            return
619
        t.mkdir('adir')
620
        t.mkdir('adir/bdir')
621
        self.assertRaises(PathError, t.rmdir, 'adir')
622
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
623
    def test_rename_dir_succeeds(self):
624
        t = self.get_transport()
625
        if t.is_readonly():
626
            raise TestSkipped("transport is readonly")
627
        t.mkdir('adir')
628
        t.mkdir('adir/asubdir')
629
        t.rename('adir', 'bdir')
630
        self.assertTrue(t.has('bdir/asubdir'))
631
        self.assertFalse(t.has('adir'))
632
633
    def test_rename_dir_nonempty(self):
634
        """Attempting to replace a nonemtpy directory should fail"""
635
        t = self.get_transport()
636
        if t.is_readonly():
637
            raise TestSkipped("transport is readonly")
638
        t.mkdir('adir')
639
        t.mkdir('adir/asubdir')
640
        t.mkdir('bdir')
641
        t.mkdir('bdir/bsubdir')
642
        self.assertRaises(PathError, t.rename, 'bdir', 'adir')
643
        # nothing was changed so it should still be as before
644
        self.assertTrue(t.has('bdir/bsubdir'))
645
        self.assertFalse(t.has('adir/bdir'))
646
        self.assertFalse(t.has('adir/bsubdir'))
647
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
648
    def test_delete_tree(self):
649
        t = self.get_transport()
650
651
        # Not much to do with a readonly transport
652
        if t.is_readonly():
653
            self.assertRaises(TransportNotPossible, t.delete_tree, 'missing')
654
            return
655
656
        # and does it like listing ?
657
        t.mkdir('adir')
658
        try:
659
            t.delete_tree('adir')
660
        except TransportNotPossible:
661
            # ok, this transport does not support delete_tree
662
            return
663
        
664
        # did it delete that trivial case?
665
        self.assertRaises(NoSuchFile, t.stat, 'adir')
666
667
        self.build_tree(['adir/',
668
                         'adir/file', 
669
                         'adir/subdir/', 
670
                         'adir/subdir/file', 
671
                         'adir/subdir2/',
672
                         'adir/subdir2/file',
673
                         ], transport=t)
674
675
        t.delete_tree('adir')
676
        # adir should be gone now.
677
        self.assertRaises(NoSuchFile, t.stat, 'adir')
678
1530.1.3 by Robert Collins
transport implementations now tested consistently.
679
    def test_move(self):
680
        t = self.get_transport()
681
682
        if t.is_readonly():
683
            return
684
685
        # TODO: I would like to use os.listdir() to
686
        # make sure there are no extra files, but SftpServer
687
        # creates control files in the working directory
688
        # perhaps all of this could be done in a subdirectory
689
690
        t.put('a', StringIO('a first file\n'))
691
        self.assertEquals([True, False], list(t.has_multi(['a', 'b'])))
692
693
        t.move('a', 'b')
694
        self.failUnless(t.has('b'))
695
        self.failIf(t.has('a'))
696
697
        self.check_transport_contents('a first file\n', t, 'b')
698
        self.assertEquals([False, True], list(t.has_multi(['a', 'b'])))
699
700
        # Overwrite a file
701
        t.put('c', StringIO('c this file\n'))
702
        t.move('c', 'b')
703
        self.failIf(t.has('c'))
704
        self.check_transport_contents('c this file\n', t, 'b')
705
706
        # TODO: Try to write a test for atomicity
707
        # TODO: Test moving into a non-existant subdirectory
708
        # TODO: Test Transport.move_multi
709
710
    def test_copy(self):
711
        t = self.get_transport()
712
713
        if t.is_readonly():
714
            return
715
716
        t.put('a', StringIO('a file\n'))
717
        t.copy('a', 'b')
718
        self.check_transport_contents('a file\n', t, 'b')
719
720
        self.assertRaises(NoSuchFile, t.copy, 'c', 'd')
721
        os.mkdir('c')
722
        # What should the assert be if you try to copy a
723
        # file over a directory?
724
        #self.assertRaises(Something, t.copy, 'a', 'c')
725
        t.put('d', StringIO('text in d\n'))
726
        t.copy('d', 'b')
727
        self.check_transport_contents('text in d\n', t, 'b')
728
729
        # TODO: test copy_multi
730
731
    def test_connection_error(self):
732
        """ConnectionError is raised when connection is impossible"""
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
733
        try:
734
            url = self._server.get_bogus_url()
735
        except NotImplementedError:
736
            raise TestSkipped("Transport %s has no bogus URL support." %
737
                              self._server.__class__)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
738
        try:
1711.2.42 by John Arbash Meinel
enable bogus_url support for SFTP tests
739
            t = bzrlib.transport.get_transport(url)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
740
            t.get('.bzr/branch')
741
        except (ConnectionError, NoSuchFile), e:
742
            pass
743
        except (Exception), e:
1786.1.27 by John Arbash Meinel
Fix up the http transports so that tests pass with the new configuration.
744
            self.fail('Wrong exception thrown (%s.%s): %s' 
745
                        % (e.__class__.__module__, e.__class__.__name__, e))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
746
        else:
1707.3.11 by John Arbash Meinel
fixing more tests.
747
            self.fail('Did not get the expected ConnectionError or NoSuchFile.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
748
749
    def test_stat(self):
750
        # TODO: Test stat, just try once, and if it throws, stop testing
751
        from stat import S_ISDIR, S_ISREG
752
753
        t = self.get_transport()
754
755
        try:
756
            st = t.stat('.')
757
        except TransportNotPossible, e:
758
            # This transport cannot stat
759
            return
760
761
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e']
762
        sizes = [14, 0, 16, 0, 18] 
1551.2.39 by abentley
Fix line endings in tests
763
        self.build_tree(paths, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
764
765
        for path, size in zip(paths, sizes):
766
            st = t.stat(path)
767
            if path.endswith('/'):
768
                self.failUnless(S_ISDIR(st.st_mode))
769
                # directory sizes are meaningless
770
            else:
771
                self.failUnless(S_ISREG(st.st_mode))
772
                self.assertEqual(size, st.st_size)
773
774
        remote_stats = list(t.stat_multi(paths))
775
        remote_iter_stats = list(t.stat_multi(iter(paths)))
776
777
        self.assertRaises(NoSuchFile, t.stat, 'q')
778
        self.assertRaises(NoSuchFile, t.stat, 'b/a')
779
780
        self.assertListRaises(NoSuchFile, t.stat_multi, ['a', 'c', 'd'])
781
        self.assertListRaises(NoSuchFile, t.stat_multi, iter(['a', 'c', 'd']))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
782
        self.build_tree(['subdir/', 'subdir/file'], transport=t)
783
        subdir = t.clone('subdir')
784
        subdir.stat('./file')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
785
        subdir.stat('.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
786
787
    def test_list_dir(self):
788
        # TODO: Test list_dir, just try once, and if it throws, stop testing
789
        t = self.get_transport()
790
        
791
        if not t.listable():
792
            self.assertRaises(TransportNotPossible, t.list_dir, '.')
793
            return
794
795
        def sorted_list(d):
796
            l = list(t.list_dir(d))
797
            l.sort()
798
            return l
799
800
        # SftpServer creates control files in the working directory
801
        # so lets move down a directory to avoid those.
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
802
        if not t.is_readonly():
803
            t.mkdir('wd')
804
        else:
805
            os.mkdir('wd')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
806
        t = t.clone('wd')
807
808
        self.assertEqual([], sorted_list(u'.'))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
809
        # c2 is precisely one letter longer than c here to test that
810
        # suffixing is not confused.
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
811
        if not t.is_readonly():
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
812
            self.build_tree(['a', 'b', 'c/', 'c/d', 'c/e', 'c2/'], transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
813
        else:
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
814
            self.build_tree(['wd/a', 'wd/b', 'wd/c/', 'wd/c/d', 'wd/c/e', 'wd/c2/'])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
815
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
816
        self.assertEqual([u'a', u'b', u'c', u'c2'], sorted_list(u'.'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
817
        self.assertEqual([u'd', u'e'], sorted_list(u'c'))
818
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
819
        if not t.is_readonly():
820
            t.delete('c/d')
821
            t.delete('b')
822
        else:
823
            os.unlink('wd/c/d')
824
            os.unlink('wd/b')
825
            
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
826
        self.assertEqual([u'a', u'c', u'c2'], sorted_list('.'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
827
        self.assertEqual([u'e'], sorted_list(u'c'))
828
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
829
        self.assertListRaises(PathError, t.list_dir, 'q')
830
        self.assertListRaises(PathError, t.list_dir, 'c/f')
831
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
832
833
    def test_clone(self):
834
        # TODO: Test that clone moves up and down the filesystem
835
        t1 = self.get_transport()
836
837
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
838
839
        self.failUnless(t1.has('a'))
840
        self.failUnless(t1.has('b/c'))
841
        self.failIf(t1.has('c'))
842
843
        t2 = t1.clone('b')
844
        self.assertEqual(t1.base + 'b/', t2.base)
845
846
        self.failUnless(t2.has('c'))
847
        self.failIf(t2.has('a'))
848
849
        t3 = t2.clone('..')
850
        self.failUnless(t3.has('a'))
851
        self.failIf(t3.has('c'))
852
853
        self.failIf(t1.has('b/d'))
854
        self.failIf(t2.has('d'))
855
        self.failIf(t3.has('b/d'))
856
857
        if t1.is_readonly():
858
            open('b/d', 'wb').write('newfile\n')
859
        else:
860
            t2.put('d', StringIO('newfile\n'))
861
862
        self.failUnless(t1.has('b/d'))
863
        self.failUnless(t2.has('d'))
864
        self.failUnless(t3.has('b/d'))
865
866
    def test_relpath(self):
867
        t = self.get_transport()
868
        self.assertEqual('', t.relpath(t.base))
869
        # base ends with /
870
        self.assertEqual('', t.relpath(t.base[:-1]))
871
        # subdirs which dont exist should still give relpaths.
872
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
873
        # trailing slash should be the same.
874
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
875
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
876
    def test_relpath_at_root(self):
877
        t = self.get_transport()
878
        # clone all the way to the top
879
        new_transport = t.clone('..')
880
        while new_transport.base != t.base:
881
            t = new_transport
882
            new_transport = t.clone('..')
883
        # we must be able to get a relpath below the root
884
        self.assertEqual('', t.relpath(t.base))
885
        # and a deeper one should work too
886
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
887
1530.1.3 by Robert Collins
transport implementations now tested consistently.
888
    def test_abspath(self):
889
        # smoke test for abspath. Corner cases for backends like unix fs's
890
        # that have aliasing problems like symlinks should go in backend
891
        # specific test cases.
892
        transport = self.get_transport()
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
893
        
894
        # disabled because some transports might normalize urls in generating
895
        # the abspath - eg http+pycurl-> just http -- mbp 20060308 
1530.1.3 by Robert Collins
transport implementations now tested consistently.
896
        self.assertEqual(transport.base + 'relpath',
897
                         transport.abspath('relpath'))
898
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
899
    def test_local_abspath(self):
900
        transport = self.get_transport()
901
        try:
902
            p = transport.local_abspath('.')
903
        except TransportNotPossible:
904
            pass # This is not a local transport
905
        else:
906
            self.assertEqual(getcwd(), p)
907
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
908
    def test_abspath_at_root(self):
909
        t = self.get_transport()
910
        # clone all the way to the top
911
        new_transport = t.clone('..')
912
        while new_transport.base != t.base:
913
            t = new_transport
914
            new_transport = t.clone('..')
915
        # we must be able to get a abspath of the root when we ask for
916
        # t.abspath('..') - this due to our choice that clone('..')
917
        # should return the root from the root, combined with the desire that
918
        # the url from clone('..') and from abspath('..') should be the same.
919
        self.assertEqual(t.base, t.abspath('..'))
920
        # '' should give us the root
921
        self.assertEqual(t.base, t.abspath(''))
922
        # and a path should append to the url
923
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
924
1530.1.3 by Robert Collins
transport implementations now tested consistently.
925
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
926
        transport = self.get_transport()
927
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
928
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
929
                              transport.iter_files_recursive)
930
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
931
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
932
                         'isolated/dir/',
933
                         'isolated/dir/foo',
934
                         'isolated/dir/bar',
935
                         'isolated/bar'],
936
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
937
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
938
        # nb the directories are not converted
939
        self.assertEqual(paths,
940
                    set(['isolated/dir/foo',
941
                         'isolated/dir/bar',
942
                         'isolated/bar']))
943
        sub_transport = transport.clone('isolated')
944
        paths = set(sub_transport.iter_files_recursive())
1530.1.3 by Robert Collins
transport implementations now tested consistently.
945
        self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
946
947
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
948
        """Test that we can read/write files with Unicode names."""
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
949
        t = self.get_transport()
950
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
951
        # With FAT32 and certain encodings on win32
952
        # '\xe5' and '\xe4' actually map to the same file
953
        # adding a suffix kicks in the 'preserving but insensitive'
954
        # route, and maintains the right files
955
        files = [u'\xe5.1', # a w/ circle iso-8859-1
956
                 u'\xe4.2', # a w/ dots iso-8859-1
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
957
                 u'\u017d', # Z with umlat iso-8859-2
958
                 u'\u062c', # Arabic j
959
                 u'\u0410', # Russian A
960
                 u'\u65e5', # Kanji person
961
                ]
962
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
963
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
964
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
965
        except UnicodeError:
966
            raise TestSkipped("cannot handle unicode paths in current encoding")
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
967
968
        # A plain unicode string is not a valid url
969
        for fname in files:
970
            self.assertRaises(InvalidURL, t.get, fname)
971
972
        for fname in files:
973
            fname_utf8 = fname.encode('utf-8')
974
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
975
            self.check_transport_contents(contents, t, urlutils.escape(fname))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
976
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
977
    def test_connect_twice_is_same_content(self):
978
        # check that our server (whatever it is) is accessable reliably
979
        # via get_transport and multiple connections share content.
980
        transport = self.get_transport()
981
        if transport.is_readonly():
982
            return
983
        transport.put('foo', StringIO('bar'))
984
        transport2 = self.get_transport()
985
        self.check_transport_contents('bar', transport2, 'foo')
986
        # its base should be usable.
987
        transport2 = bzrlib.transport.get_transport(transport.base)
988
        self.check_transport_contents('bar', transport2, 'foo')
989
990
        # now opening at a relative url should give use a sane result:
991
        transport.mkdir('newdir')
992
        transport2 = bzrlib.transport.get_transport(transport.base + "newdir")
993
        transport2 = transport2.clone('..')
994
        self.check_transport_contents('bar', transport2, 'foo')
995
996
    def test_lock_write(self):
997
        transport = self.get_transport()
998
        if transport.is_readonly():
999
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
1000
            return
1001
        transport.put('lock', StringIO())
1002
        lock = transport.lock_write('lock')
1003
        # TODO make this consistent on all platforms:
1004
        # self.assertRaises(LockError, transport.lock_write, 'lock')
1005
        lock.unlock()
1006
1007
    def test_lock_read(self):
1008
        transport = self.get_transport()
1009
        if transport.is_readonly():
1010
            file('lock', 'w').close()
1011
        else:
1012
            transport.put('lock', StringIO())
1013
        lock = transport.lock_read('lock')
1014
        # TODO make this consistent on all platforms:
1015
        # self.assertRaises(LockError, transport.lock_read, 'lock')
1016
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
1017
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
1018
    def test_readv(self):
1019
        transport = self.get_transport()
1020
        if transport.is_readonly():
1021
            file('a', 'w').write('0123456789')
1022
        else:
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1023
            transport.put('a', StringIO('0123456789'))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1024
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1025
        d = list(transport.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
1026
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1027
        self.assertEqual(d[1], (1, '1'))
1028
        self.assertEqual(d[2], (3, '34'))
1029
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1030
1864.5.2 by John Arbash Meinel
always read in sorted order, and return in requested order, but only cache what is currently out of order
1031
    def test_readv_out_of_order(self):
1032
        transport = self.get_transport()
1033
        if transport.is_readonly():
1034
            file('a', 'w').write('0123456789')
1035
        else:
1036
            transport.put('a', StringIO('01234567890'))
1037
1038
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
1039
        self.assertEqual(d[0], (1, '1'))
1040
        self.assertEqual(d[1], (9, '9'))
1041
        self.assertEqual(d[2], (0, '0'))
1042
        self.assertEqual(d[3], (3, '34'))