~bzr-pqm/bzr/bzr.dev

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
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
762
    def test_rename_dir_succeeds(self):
763
        t = self.get_transport()
764
        if t.is_readonly():
765
            raise TestSkipped("transport is readonly")
766
        t.mkdir('adir')
767
        t.mkdir('adir/asubdir')
768
        t.rename('adir', 'bdir')
769
        self.assertTrue(t.has('bdir/asubdir'))
770
        self.assertFalse(t.has('adir'))
771
772
    def test_rename_dir_nonempty(self):
773
        """Attempting to replace a nonemtpy directory should fail"""
774
        t = self.get_transport()
775
        if t.is_readonly():
776
            raise TestSkipped("transport is readonly")
777
        t.mkdir('adir')
778
        t.mkdir('adir/asubdir')
779
        t.mkdir('bdir')
780
        t.mkdir('bdir/bsubdir')
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
781
        # any kind of PathError would be OK, though we normally expect
782
        # DirectoryNotEmpty
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
783
        self.assertRaises(PathError, t.rename, 'bdir', 'adir')
784
        # nothing was changed so it should still be as before
785
        self.assertTrue(t.has('bdir/bsubdir'))
786
        self.assertFalse(t.has('adir/bdir'))
787
        self.assertFalse(t.has('adir/bsubdir'))
788
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
789
    def test_delete_tree(self):
790
        t = self.get_transport()
791
792
        # Not much to do with a readonly transport
793
        if t.is_readonly():
794
            self.assertRaises(TransportNotPossible, t.delete_tree, 'missing')
795
            return
796
797
        # and does it like listing ?
798
        t.mkdir('adir')
799
        try:
800
            t.delete_tree('adir')
801
        except TransportNotPossible:
802
            # ok, this transport does not support delete_tree
803
            return
804
        
805
        # did it delete that trivial case?
806
        self.assertRaises(NoSuchFile, t.stat, 'adir')
807
808
        self.build_tree(['adir/',
809
                         'adir/file', 
810
                         'adir/subdir/', 
811
                         'adir/subdir/file', 
812
                         'adir/subdir2/',
813
                         'adir/subdir2/file',
814
                         ], transport=t)
815
816
        t.delete_tree('adir')
817
        # adir should be gone now.
818
        self.assertRaises(NoSuchFile, t.stat, 'adir')
819
1530.1.3 by Robert Collins
transport implementations now tested consistently.
820
    def test_move(self):
821
        t = self.get_transport()
822
823
        if t.is_readonly():
824
            return
825
826
        # TODO: I would like to use os.listdir() to
827
        # make sure there are no extra files, but SftpServer
828
        # creates control files in the working directory
829
        # perhaps all of this could be done in a subdirectory
830
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
831
        t.put_bytes('a', 'a first file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
832
        self.assertEquals([True, False], list(t.has_multi(['a', 'b'])))
833
834
        t.move('a', 'b')
835
        self.failUnless(t.has('b'))
836
        self.failIf(t.has('a'))
837
838
        self.check_transport_contents('a first file\n', t, 'b')
839
        self.assertEquals([False, True], list(t.has_multi(['a', 'b'])))
840
841
        # 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
842
        t.put_bytes('c', 'c this file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
843
        t.move('c', 'b')
844
        self.failIf(t.has('c'))
845
        self.check_transport_contents('c this file\n', t, 'b')
846
847
        # TODO: Try to write a test for atomicity
848
        # TODO: Test moving into a non-existant subdirectory
849
        # TODO: Test Transport.move_multi
850
851
    def test_copy(self):
852
        t = self.get_transport()
853
854
        if t.is_readonly():
855
            return
856
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
857
        t.put_bytes('a', 'a file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
858
        t.copy('a', 'b')
859
        self.check_transport_contents('a file\n', t, 'b')
860
861
        self.assertRaises(NoSuchFile, t.copy, 'c', 'd')
862
        os.mkdir('c')
863
        # What should the assert be if you try to copy a
864
        # file over a directory?
865
        #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
866
        t.put_bytes('d', 'text in d\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
867
        t.copy('d', 'b')
868
        self.check_transport_contents('text in d\n', t, 'b')
869
870
        # TODO: test copy_multi
871
872
    def test_connection_error(self):
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
873
        """ConnectionError is raised when connection is impossible.
874
        
875
        The error may be raised from either the constructor or the first
876
        operation on the transport.
877
        """
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
878
        try:
879
            url = self._server.get_bogus_url()
880
        except NotImplementedError:
881
            raise TestSkipped("Transport %s has no bogus URL support." %
882
                              self._server.__class__)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
883
        # This should be:  but SSH still connects on construction. No COOKIE!
884
        # self.assertRaises((ConnectionError, NoSuchFile), t.get, '.bzr/branch')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
885
        try:
1711.2.42 by John Arbash Meinel
enable bogus_url support for SFTP tests
886
            t = bzrlib.transport.get_transport(url)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
887
            t.get('.bzr/branch')
888
        except (ConnectionError, NoSuchFile), e:
889
            pass
890
        except (Exception), e:
1786.1.27 by John Arbash Meinel
Fix up the http transports so that tests pass with the new configuration.
891
            self.fail('Wrong exception thrown (%s.%s): %s' 
892
                        % (e.__class__.__module__, e.__class__.__name__, e))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
893
        else:
1707.3.11 by John Arbash Meinel
fixing more tests.
894
            self.fail('Did not get the expected ConnectionError or NoSuchFile.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
895
896
    def test_stat(self):
897
        # TODO: Test stat, just try once, and if it throws, stop testing
898
        from stat import S_ISDIR, S_ISREG
899
900
        t = self.get_transport()
901
902
        try:
903
            st = t.stat('.')
904
        except TransportNotPossible, e:
905
            # This transport cannot stat
906
            return
907
908
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e']
909
        sizes = [14, 0, 16, 0, 18] 
1551.2.39 by abentley
Fix line endings in tests
910
        self.build_tree(paths, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
911
912
        for path, size in zip(paths, sizes):
913
            st = t.stat(path)
914
            if path.endswith('/'):
915
                self.failUnless(S_ISDIR(st.st_mode))
916
                # directory sizes are meaningless
917
            else:
918
                self.failUnless(S_ISREG(st.st_mode))
919
                self.assertEqual(size, st.st_size)
920
921
        remote_stats = list(t.stat_multi(paths))
922
        remote_iter_stats = list(t.stat_multi(iter(paths)))
923
924
        self.assertRaises(NoSuchFile, t.stat, 'q')
925
        self.assertRaises(NoSuchFile, t.stat, 'b/a')
926
927
        self.assertListRaises(NoSuchFile, t.stat_multi, ['a', 'c', 'd'])
928
        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.
929
        self.build_tree(['subdir/', 'subdir/file'], transport=t)
930
        subdir = t.clone('subdir')
931
        subdir.stat('./file')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
932
        subdir.stat('.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
933
934
    def test_list_dir(self):
935
        # TODO: Test list_dir, just try once, and if it throws, stop testing
936
        t = self.get_transport()
937
        
938
        if not t.listable():
939
            self.assertRaises(TransportNotPossible, t.list_dir, '.')
940
            return
941
942
        def sorted_list(d):
943
            l = list(t.list_dir(d))
944
            l.sort()
945
            return l
946
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
947
        self.assertEqual([], sorted_list('.'))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
948
        # c2 is precisely one letter longer than c here to test that
949
        # suffixing is not confused.
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
950
        # a%25b checks that quoting is done consistently across transports
951
        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
952
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
953
        if not t.is_readonly():
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
954
            self.build_tree(tree_names, transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
955
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
956
            self.build_tree(tree_names)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
957
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
958
        self.assertEqual(
1959.2.3 by John Arbash Meinel
Remove some unicode string notations
959
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('.'))
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
960
        self.assertEqual(['d', 'e'], sorted_list('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
961
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
962
        if not t.is_readonly():
963
            t.delete('c/d')
964
            t.delete('b')
965
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
966
            os.unlink('c/d')
967
            os.unlink('b')
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
968
            
1959.2.3 by John Arbash Meinel
Remove some unicode string notations
969
        self.assertEqual(['a', 'a%2525b', 'c', 'c2'], sorted_list('.'))
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
970
        self.assertEqual(['e'], sorted_list('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
971
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
972
        self.assertListRaises(PathError, t.list_dir, 'q')
973
        self.assertListRaises(PathError, t.list_dir, 'c/f')
974
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
975
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
976
    def test_list_dir_result_is_url_escaped(self):
977
        t = self.get_transport()
978
        if not t.listable():
979
            raise TestSkipped("transport not listable")
980
981
        if not t.is_readonly():
982
            self.build_tree(['a/', 'a/%'], transport=t)
983
        else:
984
            self.build_tree(['a/', 'a/%'])
985
        
1910.7.2 by Andrew Bennetts
Also assert that list_dir returns plain str objects.
986
        names = list(t.list_dir('a'))
987
        self.assertEqual(['%25'], names)
988
        self.assertIsInstance(names[0], str)
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
989
1530.1.3 by Robert Collins
transport implementations now tested consistently.
990
    def test_clone(self):
991
        # TODO: Test that clone moves up and down the filesystem
992
        t1 = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
993
        if isinstance(t1, chroot.ChrootTransportDecorator):
994
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1530.1.3 by Robert Collins
transport implementations now tested consistently.
995
996
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
997
998
        self.failUnless(t1.has('a'))
999
        self.failUnless(t1.has('b/c'))
1000
        self.failIf(t1.has('c'))
1001
1002
        t2 = t1.clone('b')
1003
        self.assertEqual(t1.base + 'b/', t2.base)
1004
1005
        self.failUnless(t2.has('c'))
1006
        self.failIf(t2.has('a'))
1007
1008
        t3 = t2.clone('..')
1009
        self.failUnless(t3.has('a'))
1010
        self.failIf(t3.has('c'))
1011
1012
        self.failIf(t1.has('b/d'))
1013
        self.failIf(t2.has('d'))
1014
        self.failIf(t3.has('b/d'))
1015
1016
        if t1.is_readonly():
1017
            open('b/d', 'wb').write('newfile\n')
1018
        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
1019
            t2.put_bytes('d', 'newfile\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1020
1021
        self.failUnless(t1.has('b/d'))
1022
        self.failUnless(t2.has('d'))
1023
        self.failUnless(t3.has('b/d'))
1024
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1025
    def test_clone_to_root(self):
1026
        orig_transport = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1027
        if isinstance(orig_transport, chroot.ChrootTransportDecorator):
1028
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1029
        # Repeatedly go up to a parent directory until we're at the root
1030
        # directory of this transport
1031
        root_transport = orig_transport
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1032
        new_transport = root_transport.clone("..")
1033
        # as we are walking up directories, the path must be must be 
1034
        # growing less, except at the top
1035
        self.assertTrue(len(new_transport.base) < len(root_transport.base)
1036
            or new_transport.base == root_transport.base)
1037
        while new_transport.base != root_transport.base:
1038
            root_transport = new_transport
1039
            new_transport = root_transport.clone("..")
1040
            # as we are walking up directories, the path must be must be 
1041
            # growing less, except at the top
1042
            self.assertTrue(len(new_transport.base) < len(root_transport.base)
1043
                or new_transport.base == root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1044
1045
        # Cloning to "/" should take us to exactly the same location.
1046
        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.
1047
        # the abspath of "/" from the original transport should be the same
1048
        # as the base at the root:
1049
        self.assertEqual(orig_transport.abspath("/"), root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1050
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
1051
        # At the root, the URL must still end with / as its a directory
1052
        self.assertEqual(root_transport.base[-1], '/')
1053
1054
    def test_clone_from_root(self):
1055
        """At the root, cloning to a simple dir should just do string append."""
1056
        orig_transport = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1057
        if isinstance(orig_transport, chroot.ChrootTransportDecorator):
1058
            raise TestSkipped("ChrootTransportDecorator disallows clone('/')")
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
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()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1079
        if isinstance(t, chroot.ChrootTransportDecorator):
1080
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1081
        # clone all the way to the top
1082
        new_transport = t.clone('..')
1083
        while new_transport.base != t.base:
1084
            t = new_transport
1085
            new_transport = t.clone('..')
1086
        # we must be able to get a relpath below the root
1087
        self.assertEqual('', t.relpath(t.base))
1088
        # and a deeper one should work too
1089
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
1090
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1091
    def test_abspath(self):
1092
        # smoke test for abspath. Corner cases for backends like unix fs's
1093
        # that have aliasing problems like symlinks should go in backend
1094
        # specific test cases.
1095
        transport = self.get_transport()
2070.5.2 by Andrew Bennetts
Merge from 'memory transport abspath'.
1096
        if isinstance(transport, chroot.ChrootTransportDecorator):
1097
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
1098
        
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1099
        self.assertEqual(transport.base + 'relpath',
1100
                         transport.abspath('relpath'))
1101
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1102
        # This should work without raising an error.
1103
        transport.abspath("/")
1104
1105
        # the abspath of "/" and "/foo/.." should result in the same location
1106
        self.assertEqual(transport.abspath("/"), transport.abspath("/foo/.."))
1107
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
1108
        self.assertEqual(transport.clone("/").abspath('foo'),
1109
                         transport.abspath("/foo"))
1110
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
1111
    def test_local_abspath(self):
1112
        transport = self.get_transport()
1113
        try:
1114
            p = transport.local_abspath('.')
1115
        except TransportNotPossible:
1116
            pass # This is not a local transport
1117
        else:
1118
            self.assertEqual(getcwd(), p)
1119
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1120
    def test_abspath_at_root(self):
1121
        t = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1122
        if isinstance(t, chroot.ChrootTransportDecorator):
1123
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1124
        # clone all the way to the top
1125
        new_transport = t.clone('..')
1126
        while new_transport.base != t.base:
1127
            t = new_transport
1128
            new_transport = t.clone('..')
1129
        # we must be able to get a abspath of the root when we ask for
1130
        # t.abspath('..') - this due to our choice that clone('..')
1131
        # should return the root from the root, combined with the desire that
1132
        # the url from clone('..') and from abspath('..') should be the same.
1133
        self.assertEqual(t.base, t.abspath('..'))
1134
        # '' should give us the root
1135
        self.assertEqual(t.base, t.abspath(''))
1136
        # and a path should append to the url
1137
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
1138
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1139
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1140
        transport = self.get_transport()
1141
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1142
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1143
                              transport.iter_files_recursive)
1144
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1145
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1146
                         'isolated/dir/',
1147
                         'isolated/dir/foo',
1148
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1149
                         'isolated/dir/b%25z', # make sure quoting is correct
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1150
                         'isolated/bar'],
1151
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1152
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1153
        # nb the directories are not converted
1154
        self.assertEqual(paths,
1155
                    set(['isolated/dir/foo',
1156
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1157
                         'isolated/dir/b%2525z',
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1158
                         'isolated/bar']))
1159
        sub_transport = transport.clone('isolated')
1160
        paths = set(sub_transport.iter_files_recursive())
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1161
        self.assertEqual(paths,
1162
            set(['dir/foo', 'dir/bar', 'dir/b%2525z', 'bar']))
1163
1164
    def test_copy_tree(self):
1165
        # TODO: test file contents and permissions are preserved. This test was
1166
        # added just to ensure that quoting was handled correctly.
1167
        # -- David Allouche 2006-08-11
1168
        transport = self.get_transport()
1169
        if not transport.listable():
1170
            self.assertRaises(TransportNotPossible,
1171
                              transport.iter_files_recursive)
1172
            return
1173
        if transport.is_readonly():
1174
            return
1175
        self.build_tree(['from/',
1176
                         'from/dir/',
1177
                         'from/dir/foo',
1178
                         'from/dir/bar',
1179
                         'from/dir/b%25z', # make sure quoting is correct
1180
                         'from/bar'],
1181
                        transport=transport)
1182
        transport.copy_tree('from', 'to')
1183
        paths = set(transport.iter_files_recursive())
1184
        self.assertEqual(paths,
1185
                    set(['from/dir/foo',
1186
                         'from/dir/bar',
1187
                         'from/dir/b%2525z',
1188
                         'from/bar',
1189
                         'to/dir/foo',
1190
                         'to/dir/bar',
1191
                         'to/dir/b%2525z',
1192
                         'to/bar',]))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1193
1194
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
1195
        """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
1196
        t = self.get_transport()
1197
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
1198
        # With FAT32 and certain encodings on win32
1199
        # '\xe5' and '\xe4' actually map to the same file
1200
        # adding a suffix kicks in the 'preserving but insensitive'
1201
        # route, and maintains the right files
1202
        files = [u'\xe5.1', # a w/ circle iso-8859-1
1203
                 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
1204
                 u'\u017d', # Z with umlat iso-8859-2
1205
                 u'\u062c', # Arabic j
1206
                 u'\u0410', # Russian A
1207
                 u'\u65e5', # Kanji person
1208
                ]
1209
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1210
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
1211
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1212
        except UnicodeError:
1213
            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
1214
1215
        # A plain unicode string is not a valid url
1216
        for fname in files:
1217
            self.assertRaises(InvalidURL, t.get, fname)
1218
1219
        for fname in files:
1220
            fname_utf8 = fname.encode('utf-8')
1221
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
1222
            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
1223
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1224
    def test_connect_twice_is_same_content(self):
1225
        # check that our server (whatever it is) is accessable reliably
1226
        # via get_transport and multiple connections share content.
1227
        transport = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1228
        if isinstance(transport, chroot.ChrootTransportDecorator):
1229
            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.
1230
        if transport.is_readonly():
1231
            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
1232
        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.
1233
        transport2 = self.get_transport()
1234
        self.check_transport_contents('bar', transport2, 'foo')
1235
        # its base should be usable.
1236
        transport2 = bzrlib.transport.get_transport(transport.base)
1237
        self.check_transport_contents('bar', transport2, 'foo')
1238
1239
        # now opening at a relative url should give use a sane result:
1240
        transport.mkdir('newdir')
1241
        transport2 = bzrlib.transport.get_transport(transport.base + "newdir")
1242
        transport2 = transport2.clone('..')
1243
        self.check_transport_contents('bar', transport2, 'foo')
1244
1245
    def test_lock_write(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1246
        """Test transport-level write locks.
1247
1248
        These are deprecated and transports may decline to support them.
1249
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1250
        transport = self.get_transport()
1251
        if transport.is_readonly():
1252
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
1253
            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
1254
        transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1255
        try:
1256
            lock = transport.lock_write('lock')
1257
        except TransportNotPossible:
1258
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1259
        # TODO make this consistent on all platforms:
1260
        # self.assertRaises(LockError, transport.lock_write, 'lock')
1261
        lock.unlock()
1262
1263
    def test_lock_read(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1264
        """Test transport-level read 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
            file('lock', 'w').close()
1271
        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
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_read('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_read, 'lock')
1279
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
1280
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
1281
    def test_readv(self):
1282
        transport = self.get_transport()
1283
        if transport.is_readonly():
1284
            file('a', 'w').write('0123456789')
1285
        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
1286
            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
1287
2004.1.22 by v.ladeuil+lp at free
Implements Range header handling for GET requests. Fix a test.
1288
        d = list(transport.readv('a', ((0, 1),)))
1289
        self.assertEqual(d[0], (0, '0'))
1290
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1291
        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.
1292
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1293
        self.assertEqual(d[1], (1, '1'))
1294
        self.assertEqual(d[2], (3, '34'))
1295
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1296
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
1297
    def test_readv_out_of_order(self):
1298
        transport = self.get_transport()
1299
        if transport.is_readonly():
1300
            file('a', 'w').write('0123456789')
1301
        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
1302
            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
1303
1304
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
1305
        self.assertEqual(d[0], (1, '1'))
1306
        self.assertEqual(d[1], (9, '9'))
1307
        self.assertEqual(d[2], (0, '0'))
1308
        self.assertEqual(d[3], (3, '34'))
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1309
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1310
    def test_get_smart_medium(self):
1311
        """All transports must either give a smart medium, or know they can't.
1312
        """
1313
        transport = self.get_transport()
1314
        try:
1315
            medium = transport.get_smart_medium()
1316
            self.assertIsInstance(medium, smart.SmartClientMedium)
1317
        except errors.NoSmartMedium:
1318
            # as long as we got it we're fine
1319
            pass
1320
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1321
    def test_readv_short_read(self):
1322
        transport = self.get_transport()
1323
        if transport.is_readonly():
1324
            file('a', 'w').write('0123456789')
1325
        else:
1326
            transport.put_bytes('a', '01234567890')
1327
1328
        # This is intentionally reading off the end of the file
1329
        # 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 :)
1330
        self.assertListRaises((errors.ShortReadvError, errors.InvalidRange,
1331
                               # Can be raised by paramiko
1332
                               AssertionError),
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1333
                              transport.readv, 'a', [(1,1), (8,10)])
1334
1335
        # This is trying to seek past the end of the file, it should
1336
        # 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 :)
1337
        self.assertListRaises((errors.ShortReadvError, errors.InvalidRange),
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1338
                              transport.readv, 'a', [(12,2)])