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