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