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