/brz/remove-bazaar

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