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