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