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