/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1530.1.3 by Robert Collins
transport implementations now tested consistently.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1530.1.3 by Robert Collins
transport implementations now tested consistently.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1530.1.3 by Robert Collins
transport implementations now tested consistently.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for Transport implementations.
18
19
Transport implementations tested here are supplied by
20
TransportTestProviderAdapter.
21
"""
22
23
import os
24
from cStringIO import StringIO
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
25
import stat
26
import sys
1530.1.3 by Robert Collins
transport implementations now tested consistently.
27
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
28
from bzrlib import (
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
29
    errors,
1755.3.7 by John Arbash Meinel
Clean up and write tests for permissions. Now we use fstat which should be cheap, and lets us check the permissions and the file size
30
    osutils,
31
    urlutils,
32
    )
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
33
from bzrlib.errors import (DirectoryNotEmpty, NoSuchFile, FileExists,
1910.19.2 by Andrew Bennetts
Add a new method ``Transport.get_smart_client()``. This is provided to allow
34
                           LockError, NoSmartServer, PathError,
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
35
                           TransportNotPossible, ConnectionError,
36
                           InvalidURL)
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
37
from bzrlib.osutils import getcwd
1955.3.29 by John Arbash Meinel
Use applyDeprecated instead of callDeprecated
38
from bzrlib.symbol_versioning import zero_eleven
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
39
from bzrlib.tests import TestCaseInTempDir, TestSkipped
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
40
from bzrlib.tests.test_transport import TestTransportImplementation
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
41
from bzrlib.transport import memory, smart, chroot
1530.1.3 by Robert Collins
transport implementations now tested consistently.
42
import bzrlib.transport
43
44
45
def _append(fn, txt):
46
    """Append the given text (file-like object) to the supplied filename."""
47
    f = open(fn, 'ab')
1530.1.21 by Robert Collins
Review feedback fixes.
48
    try:
49
        f.write(txt.read())
50
    finally:
51
        f.close()
1530.1.3 by Robert Collins
transport implementations now tested consistently.
52
53
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
54
class TransportTests(TestTransportImplementation):
55
1530.1.3 by Robert Collins
transport implementations now tested consistently.
56
    def check_transport_contents(self, content, transport, relpath):
57
        """Check that transport.get(relpath).read() == content."""
1530.1.21 by Robert Collins
Review feedback fixes.
58
        self.assertEqualDiff(content, transport.get(relpath).read())
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
59
1530.1.3 by Robert Collins
transport implementations now tested consistently.
60
    def 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
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
965
        self.assertEqual([], sorted_list('.'))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
966
        # c2 is precisely one letter longer than c here to test that
967
        # suffixing is not confused.
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
968
        # a%25b checks that quoting is done consistently across transports
969
        tree_names = ['a', 'a%25b', 'b', 'c/', 'c/d', 'c/e', 'c2/']
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
970
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
971
        if not t.is_readonly():
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
972
            self.build_tree(tree_names, transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
973
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
974
            self.build_tree(tree_names)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
975
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
976
        self.assertEqual(
1959.2.3 by John Arbash Meinel
Remove some unicode string notations
977
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('.'))
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
978
        self.assertEqual(['d', 'e'], sorted_list('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
979
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
980
        if not t.is_readonly():
981
            t.delete('c/d')
982
            t.delete('b')
983
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
984
            os.unlink('c/d')
985
            os.unlink('b')
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
986
            
1959.2.3 by John Arbash Meinel
Remove some unicode string notations
987
        self.assertEqual(['a', 'a%2525b', 'c', 'c2'], sorted_list('.'))
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
988
        self.assertEqual(['e'], sorted_list('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
989
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
990
        self.assertListRaises(PathError, t.list_dir, 'q')
991
        self.assertListRaises(PathError, t.list_dir, 'c/f')
992
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
993
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
994
    def test_list_dir_result_is_url_escaped(self):
995
        t = self.get_transport()
996
        if not t.listable():
997
            raise TestSkipped("transport not listable")
998
999
        if not t.is_readonly():
1000
            self.build_tree(['a/', 'a/%'], transport=t)
1001
        else:
1002
            self.build_tree(['a/', 'a/%'])
1003
        
1910.7.2 by Andrew Bennetts
Also assert that list_dir returns plain str objects.
1004
        names = list(t.list_dir('a'))
1005
        self.assertEqual(['%25'], names)
1006
        self.assertIsInstance(names[0], str)
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1007
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1008
    def test_clone(self):
1009
        # TODO: Test that clone moves up and down the filesystem
1010
        t1 = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1011
        if isinstance(t1, chroot.ChrootTransportDecorator):
1012
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1013
1014
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
1015
1016
        self.failUnless(t1.has('a'))
1017
        self.failUnless(t1.has('b/c'))
1018
        self.failIf(t1.has('c'))
1019
1020
        t2 = t1.clone('b')
1021
        self.assertEqual(t1.base + 'b/', t2.base)
1022
1023
        self.failUnless(t2.has('c'))
1024
        self.failIf(t2.has('a'))
1025
1026
        t3 = t2.clone('..')
1027
        self.failUnless(t3.has('a'))
1028
        self.failIf(t3.has('c'))
1029
1030
        self.failIf(t1.has('b/d'))
1031
        self.failIf(t2.has('d'))
1032
        self.failIf(t3.has('b/d'))
1033
1034
        if t1.is_readonly():
1035
            open('b/d', 'wb').write('newfile\n')
1036
        else:
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1037
            t2.put_bytes('d', 'newfile\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1038
1039
        self.failUnless(t1.has('b/d'))
1040
        self.failUnless(t2.has('d'))
1041
        self.failUnless(t3.has('b/d'))
1042
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1043
    def test_clone_to_root(self):
1044
        orig_transport = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1045
        if isinstance(orig_transport, chroot.ChrootTransportDecorator):
1046
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1047
        # Repeatedly go up to a parent directory until we're at the root
1048
        # directory of this transport
1049
        root_transport = orig_transport
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1050
        new_transport = root_transport.clone("..")
1051
        # as we are walking up directories, the path must be must be 
1052
        # growing less, except at the top
1053
        self.assertTrue(len(new_transport.base) < len(root_transport.base)
1054
            or new_transport.base == root_transport.base)
1055
        while new_transport.base != root_transport.base:
1056
            root_transport = new_transport
1057
            new_transport = root_transport.clone("..")
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)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1062
1063
        # Cloning to "/" should take us to exactly the same location.
1064
        self.assertEqual(root_transport.base, orig_transport.clone("/").base)
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1065
        # the abspath of "/" from the original transport should be the same
1066
        # as the base at the root:
1067
        self.assertEqual(orig_transport.abspath("/"), root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1068
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
1069
        # At the root, the URL must still end with / as its a directory
1070
        self.assertEqual(root_transport.base[-1], '/')
1071
1072
    def test_clone_from_root(self):
1073
        """At the root, cloning to a simple dir should just do string append."""
1074
        orig_transport = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1075
        if isinstance(orig_transport, chroot.ChrootTransportDecorator):
1076
            raise TestSkipped("ChrootTransportDecorator disallows clone('/')")
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
1077
        root_transport = orig_transport.clone('/')
1078
        self.assertEqual(root_transport.base + '.bzr/',
1079
            root_transport.clone('.bzr').base)
1080
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1081
    def test_base_url(self):
1082
        t = self.get_transport()
1083
        self.assertEqual('/', t.base[-1])
1084
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1085
    def test_relpath(self):
1086
        t = self.get_transport()
1087
        self.assertEqual('', t.relpath(t.base))
1088
        # base ends with /
1089
        self.assertEqual('', t.relpath(t.base[:-1]))
1090
        # subdirs which dont exist should still give relpaths.
1091
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
1092
        # trailing slash should be the same.
1093
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
1094
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1095
    def test_relpath_at_root(self):
1096
        t = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1097
        if isinstance(t, chroot.ChrootTransportDecorator):
1098
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1099
        # clone all the way to the top
1100
        new_transport = t.clone('..')
1101
        while new_transport.base != t.base:
1102
            t = new_transport
1103
            new_transport = t.clone('..')
1104
        # we must be able to get a relpath below the root
1105
        self.assertEqual('', t.relpath(t.base))
1106
        # and a deeper one should work too
1107
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
1108
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1109
    def test_abspath(self):
1110
        # smoke test for abspath. Corner cases for backends like unix fs's
1111
        # that have aliasing problems like symlinks should go in backend
1112
        # specific test cases.
1113
        transport = self.get_transport()
2070.5.2 by Andrew Bennetts
Merge from 'memory transport abspath'.
1114
        if isinstance(transport, chroot.ChrootTransportDecorator):
1115
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
1116
        
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1117
        self.assertEqual(transport.base + 'relpath',
1118
                         transport.abspath('relpath'))
1119
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1120
        # This should work without raising an error.
1121
        transport.abspath("/")
1122
1123
        # the abspath of "/" and "/foo/.." should result in the same location
1124
        self.assertEqual(transport.abspath("/"), transport.abspath("/foo/.."))
1125
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
1126
        self.assertEqual(transport.clone("/").abspath('foo'),
1127
                         transport.abspath("/foo"))
1128
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
1129
    def test_local_abspath(self):
1130
        transport = self.get_transport()
1131
        try:
1132
            p = transport.local_abspath('.')
1133
        except TransportNotPossible:
1134
            pass # This is not a local transport
1135
        else:
1136
            self.assertEqual(getcwd(), p)
1137
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1138
    def test_abspath_at_root(self):
1139
        t = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1140
        if isinstance(t, chroot.ChrootTransportDecorator):
1141
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1142
        # clone all the way to the top
1143
        new_transport = t.clone('..')
1144
        while new_transport.base != t.base:
1145
            t = new_transport
1146
            new_transport = t.clone('..')
1147
        # we must be able to get a abspath of the root when we ask for
1148
        # t.abspath('..') - this due to our choice that clone('..')
1149
        # should return the root from the root, combined with the desire that
1150
        # the url from clone('..') and from abspath('..') should be the same.
1151
        self.assertEqual(t.base, t.abspath('..'))
1152
        # '' should give us the root
1153
        self.assertEqual(t.base, t.abspath(''))
1154
        # and a path should append to the url
1155
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
1156
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1157
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1158
        transport = self.get_transport()
1159
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1160
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1161
                              transport.iter_files_recursive)
1162
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1163
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1164
                         'isolated/dir/',
1165
                         'isolated/dir/foo',
1166
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1167
                         'isolated/dir/b%25z', # make sure quoting is correct
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1168
                         'isolated/bar'],
1169
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1170
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1171
        # nb the directories are not converted
1172
        self.assertEqual(paths,
1173
                    set(['isolated/dir/foo',
1174
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1175
                         'isolated/dir/b%2525z',
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1176
                         'isolated/bar']))
1177
        sub_transport = transport.clone('isolated')
1178
        paths = set(sub_transport.iter_files_recursive())
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1179
        self.assertEqual(paths,
1180
            set(['dir/foo', 'dir/bar', 'dir/b%2525z', 'bar']))
1181
1182
    def test_copy_tree(self):
1183
        # TODO: test file contents and permissions are preserved. This test was
1184
        # added just to ensure that quoting was handled correctly.
1185
        # -- David Allouche 2006-08-11
1186
        transport = self.get_transport()
1187
        if not transport.listable():
1188
            self.assertRaises(TransportNotPossible,
1189
                              transport.iter_files_recursive)
1190
            return
1191
        if transport.is_readonly():
1192
            return
1193
        self.build_tree(['from/',
1194
                         'from/dir/',
1195
                         'from/dir/foo',
1196
                         'from/dir/bar',
1197
                         'from/dir/b%25z', # make sure quoting is correct
1198
                         'from/bar'],
1199
                        transport=transport)
1200
        transport.copy_tree('from', 'to')
1201
        paths = set(transport.iter_files_recursive())
1202
        self.assertEqual(paths,
1203
                    set(['from/dir/foo',
1204
                         'from/dir/bar',
1205
                         'from/dir/b%2525z',
1206
                         'from/bar',
1207
                         'to/dir/foo',
1208
                         'to/dir/bar',
1209
                         'to/dir/b%2525z',
1210
                         'to/bar',]))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1211
1212
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
1213
        """Test that we can read/write files with Unicode names."""
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1214
        t = self.get_transport()
1215
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
1216
        # With FAT32 and certain encodings on win32
1217
        # '\xe5' and '\xe4' actually map to the same file
1218
        # adding a suffix kicks in the 'preserving but insensitive'
1219
        # route, and maintains the right files
1220
        files = [u'\xe5.1', # a w/ circle iso-8859-1
1221
                 u'\xe4.2', # a w/ dots iso-8859-1
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1222
                 u'\u017d', # Z with umlat iso-8859-2
1223
                 u'\u062c', # Arabic j
1224
                 u'\u0410', # Russian A
1225
                 u'\u65e5', # Kanji person
1226
                ]
1227
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1228
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
1229
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1230
        except UnicodeError:
1231
            raise TestSkipped("cannot handle unicode paths in current encoding")
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1232
1233
        # A plain unicode string is not a valid url
1234
        for fname in files:
1235
            self.assertRaises(InvalidURL, t.get, fname)
1236
1237
        for fname in files:
1238
            fname_utf8 = fname.encode('utf-8')
1239
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
1240
            self.check_transport_contents(contents, t, urlutils.escape(fname))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1241
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1242
    def test_connect_twice_is_same_content(self):
1243
        # check that our server (whatever it is) is accessable reliably
1244
        # via get_transport and multiple connections share content.
1245
        transport = self.get_transport()
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
1246
        if isinstance(transport, chroot.ChrootTransportDecorator):
1247
            raise TestSkipped("ChrootTransportDecorator disallows clone('..')")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1248
        if transport.is_readonly():
1249
            return
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1250
        transport.put_bytes('foo', 'bar')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1251
        transport2 = self.get_transport()
1252
        self.check_transport_contents('bar', transport2, 'foo')
1253
        # its base should be usable.
1254
        transport2 = bzrlib.transport.get_transport(transport.base)
1255
        self.check_transport_contents('bar', transport2, 'foo')
1256
1257
        # now opening at a relative url should give use a sane result:
1258
        transport.mkdir('newdir')
1259
        transport2 = bzrlib.transport.get_transport(transport.base + "newdir")
1260
        transport2 = transport2.clone('..')
1261
        self.check_transport_contents('bar', transport2, 'foo')
1262
1263
    def test_lock_write(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1264
        """Test transport-level write locks.
1265
1266
        These are deprecated and transports may decline to support them.
1267
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1268
        transport = self.get_transport()
1269
        if transport.is_readonly():
1270
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
1271
            return
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1272
        transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1273
        try:
1274
            lock = transport.lock_write('lock')
1275
        except TransportNotPossible:
1276
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1277
        # TODO make this consistent on all platforms:
1278
        # self.assertRaises(LockError, transport.lock_write, 'lock')
1279
        lock.unlock()
1280
1281
    def test_lock_read(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1282
        """Test transport-level read locks.
1283
1284
        These are deprecated and transports may decline to support them.
1285
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1286
        transport = self.get_transport()
1287
        if transport.is_readonly():
1288
            file('lock', 'w').close()
1289
        else:
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1290
            transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1291
        try:
1292
            lock = transport.lock_read('lock')
1293
        except TransportNotPossible:
1294
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1295
        # TODO make this consistent on all platforms:
1296
        # self.assertRaises(LockError, transport.lock_read, 'lock')
1297
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
1298
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
1299
    def test_readv(self):
1300
        transport = self.get_transport()
1301
        if transport.is_readonly():
1302
            file('a', 'w').write('0123456789')
1303
        else:
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1304
            transport.put_bytes('a', '0123456789')
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1305
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1306
        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.
1307
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1308
        self.assertEqual(d[1], (1, '1'))
1309
        self.assertEqual(d[2], (3, '34'))
1310
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1311
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
1312
    def test_readv_out_of_order(self):
1313
        transport = self.get_transport()
1314
        if transport.is_readonly():
1315
            file('a', 'w').write('0123456789')
1316
        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
1317
            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
1318
1319
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
1320
        self.assertEqual(d[0], (1, '1'))
1321
        self.assertEqual(d[1], (9, '9'))
1322
        self.assertEqual(d[2], (0, '0'))
1323
        self.assertEqual(d[3], (3, '34'))
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1324
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1325
    def test_get_smart_medium(self):
1326
        """All transports must either give a smart medium, or know they can't.
1327
        """
1328
        transport = self.get_transport()
1329
        try:
1330
            medium = transport.get_smart_medium()
1331
            self.assertIsInstance(medium, smart.SmartClientMedium)
1332
        except errors.NoSmartMedium:
1333
            # as long as we got it we're fine
1334
            pass
1335
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1336
    def test_readv_short_read(self):
1337
        transport = self.get_transport()
1338
        if transport.is_readonly():
1339
            file('a', 'w').write('0123456789')
1340
        else:
1341
            transport.put_bytes('a', '01234567890')
1342
1343
        # This is intentionally reading off the end of the file
1344
        # since we are sure that it cannot get there
1345
        self.assertListRaises((errors.ShortReadvError, AssertionError),
1346
                              transport.readv, 'a', [(1,1), (8,10)])
1347
1348
        # This is trying to seek past the end of the file, it should
1349
        # also raise a special error
1350
        self.assertListRaises(errors.ShortReadvError,
1351
                              transport.readv, 'a', [(12,2)])