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