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