/brz/remove-bazaar

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