/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2005-2011 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1530.1.3 by Robert Collins
transport implementations now tested consistently.
16
17
"""Tests for Transport implementations.
18
19
Transport implementations tested here are supplied by
20
TransportTestProviderAdapter.
21
"""
22
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
23
import itertools
1530.1.3 by Robert Collins
transport implementations now tested consistently.
24
import os
25
from cStringIO import StringIO
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
26
from StringIO import StringIO as pyStringIO
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
27
import stat
28
import sys
1530.1.3 by Robert Collins
transport implementations now tested consistently.
29
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
from bzrlib import (
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
31
    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
32
    osutils,
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
33
    pyutils,
3302.9.21 by Vincent Ladeuil
bzrlib.tests.test_transport_implementations use load_tests.
34
    tests,
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
35
    urlutils,
36
    )
2400.2.1 by Robert Collins
Split out the improvement to Transport.local_abspath to raise NotLocalURL from the hpss-faster-copy branch. (Martin Pool, Ian Clatworthy)
37
from bzrlib.errors import (ConnectionError,
38
                           FileExists,
39
                           InvalidURL,
40
                           NoSuchFile,
41
                           PathError,
42
                           TransportNotPossible,
43
                           )
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
44
from bzrlib.osutils import getcwd
2018.5.139 by Andrew Bennetts
Merge from bzr.dev, resolving conflicts.
45
from bzrlib.smart import medium
3010.2.2 by Martin Pool
Add missing import
46
from bzrlib.tests import (
47
    TestSkipped,
48
    TestNotApplicable,
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
49
    multiply_tests,
3010.2.2 by Martin Pool
Add missing import
50
    )
5017.3.21 by Vincent Ladeuil
selftest -s bt.per_transport passing
51
from bzrlib.tests import test_server
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
52
from bzrlib.tests.test_transport import TestTransportImplementation
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
53
from bzrlib.transport import (
54
    ConnectedTransport,
55
    get_transport,
2485.8.50 by Vincent Ladeuil
merge bzr.dev @ 2584 resolving conflicts
56
    _get_transport_modules,
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
57
    )
58
from bzrlib.transport.memory import MemoryTransport
1530.1.3 by Robert Collins
transport implementations now tested consistently.
59
60
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
61
def get_transport_test_permutations(module):
62
    """Get the permutations module wants to have tested."""
63
    if getattr(module, 'get_test_permutations', None) is None:
64
        raise AssertionError(
65
            "transport module %s doesn't provide get_test_permutations()"
66
            % module.__name__)
67
        return []
68
    return module.get_test_permutations()
69
70
71
def transport_test_permutations():
72
    """Return a list of the klass, server_factory pairs to test."""
73
    result = []
74
    for module in _get_transport_modules():
75
        try:
76
            permutations = get_transport_test_permutations(
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
77
                pyutils.get_named_object(module))
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
78
            for (klass, server_factory) in permutations:
4725.1.1 by Vincent Ladeuil
Mention transport class name in test id.
79
                scenario = ('%s,%s' % (klass.__name__, server_factory.__name__),
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
80
                    {"transport_class":klass,
81
                     "transport_server":server_factory})
82
                result.append(scenario)
83
        except errors.DependencyNotPresent, e:
84
            # Continue even if a dependency prevents us
85
            # from adding this test
86
            pass
87
    return result
2553.2.5 by Robert Collins
And overhaul TransportTestProviderAdapter too.
88
89
3302.9.21 by Vincent Ladeuil
bzrlib.tests.test_transport_implementations use load_tests.
90
def load_tests(standard_tests, module, loader):
91
    """Multiply tests for tranport implementations."""
92
    result = loader.suiteClass()
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
93
    scenarios = transport_test_permutations()
94
    return multiply_tests(standard_tests, scenarios, result)
3302.9.21 by Vincent Ladeuil
bzrlib.tests.test_transport_implementations use load_tests.
95
2553.2.5 by Robert Collins
And overhaul TransportTestProviderAdapter too.
96
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
97
class TransportTests(TestTransportImplementation):
98
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
99
    def setUp(self):
100
        super(TransportTests, self).setUp()
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
101
        self.overrideEnv('BZR_NO_SMART_VFS', None)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
102
1530.1.3 by Robert Collins
transport implementations now tested consistently.
103
    def check_transport_contents(self, content, transport, relpath):
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
104
        """Check that transport.get_bytes(relpath) == content."""
105
        self.assertEqualDiff(content, transport.get_bytes(relpath))
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
106
2475.3.2 by John Arbash Meinel
Add Transport.ensure_base()
107
    def test_ensure_base_missing(self):
108
        """.ensure_base() should create the directory if it doesn't exist"""
109
        t = self.get_transport()
110
        t_a = t.clone('a')
111
        if t_a.is_readonly():
112
            self.assertRaises(TransportNotPossible,
113
                              t_a.ensure_base)
114
            return
115
        self.assertTrue(t_a.ensure_base())
116
        self.assertTrue(t.has('a'))
117
118
    def test_ensure_base_exists(self):
119
        """.ensure_base() should just be happy if it already exists"""
120
        t = self.get_transport()
121
        if t.is_readonly():
122
            return
123
124
        t.mkdir('a')
125
        t_a = t.clone('a')
126
        # ensure_base returns False if it didn't create the base
127
        self.assertFalse(t_a.ensure_base())
128
129
    def test_ensure_base_missing_parent(self):
130
        """.ensure_base() will fail if the parent dir doesn't exist"""
131
        t = self.get_transport()
132
        if t.is_readonly():
133
            return
134
135
        t_a = t.clone('a')
136
        t_b = t_a.clone('b')
137
        self.assertRaises(NoSuchFile, t_b.ensure_base)
138
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
139
    def test_external_url(self):
140
        """.external_url either works or raises InProcessTransport."""
141
        t = self.get_transport()
142
        try:
143
            t.external_url()
144
        except errors.InProcessTransport:
145
            pass
146
1530.1.3 by Robert Collins
transport implementations now tested consistently.
147
    def test_has(self):
148
        t = self.get_transport()
149
150
        files = ['a', 'b', 'e', 'g', '%']
151
        self.build_tree(files, transport=t)
152
        self.assertEqual(True, t.has('a'))
153
        self.assertEqual(False, t.has('c'))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
154
        self.assertEqual(True, t.has(urlutils.escape('%')))
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
155
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd',
156
                                           'e', 'f', 'g', 'h'])),
157
                         [True, True, False, False,
158
                          True, False, True, False])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
159
        self.assertEqual(True, t.has_any(['a', 'b', 'c']))
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
160
        self.assertEqual(False, t.has_any(['c', 'd', 'f',
161
                                           urlutils.escape('%%')]))
162
        self.assertEqual(list(t.has_multi(iter(['a', 'b', 'c', 'd',
163
                                                'e', 'f', 'g', 'h']))),
164
                         [True, True, False, False,
165
                          True, False, True, False])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
166
        self.assertEqual(False, t.has_any(['c', 'c', 'c']))
167
        self.assertEqual(True, t.has_any(['b', 'b', 'b']))
168
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
169
    def test_has_root_works(self):
5017.3.21 by Vincent Ladeuil
selftest -s bt.per_transport passing
170
        if self.transport_server is test_server.SmartTCPServer_for_testing:
2692.1.11 by Andrew Bennetts
Improve test coverage by making SmartTCPServer_for_testing by default create a server that does not serve the backing transport's root at its own root. This mirrors the way most HTTP smart servers are configured.
171
            raise TestNotApplicable(
172
                "SmartTCPServer_for_testing intentionally does not allow "
173
                "access to /.")
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
174
        current_transport = self.get_transport()
175
        self.assertTrue(current_transport.has('/'))
176
        root = current_transport.clone('/')
177
        self.assertTrue(root.has(''))
178
1530.1.3 by Robert Collins
transport implementations now tested consistently.
179
    def test_get(self):
180
        t = self.get_transport()
181
182
        files = ['a', 'b', 'e', 'g']
183
        contents = ['contents of a\n',
184
                    'contents of b\n',
185
                    'contents of e\n',
186
                    'contents of g\n',
187
                    ]
1551.2.39 by abentley
Fix line endings in tests
188
        self.build_tree(files, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
189
        self.check_transport_contents('contents of a\n', t, 'a')
190
        content_f = t.get_multi(files)
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
191
        # Use itertools.izip() instead of use zip() or map(), since they fully
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
192
        # evaluate their inputs, the transport requests should be issued and
193
        # handled sequentially (we don't want to force transport to buffer).
3059.2.10 by Vincent Ladeuil
Jam's review feedback.
194
        for content, f in itertools.izip(contents, content_f):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
195
            self.assertEqual(content, f.read())
196
197
        content_f = t.get_multi(iter(files))
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
198
        # Use itertools.izip() for the same reason
3059.2.10 by Vincent Ladeuil
Jam's review feedback.
199
        for content, f in itertools.izip(contents, content_f):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
200
            self.assertEqual(content, f.read())
201
4512.1.1 by Vincent Ladeuil
Fix bug #383920 by inserting the missing Content-Length header.
202
    def test_get_unknown_file(self):
203
        t = self.get_transport()
204
        files = ['a', 'b']
205
        contents = ['contents of a\n',
206
                    'contents of b\n',
207
                    ]
208
        self.build_tree(files, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
209
        self.assertRaises(NoSuchFile, t.get, 'c')
210
        self.assertListRaises(NoSuchFile, t.get_multi, ['a', 'b', 'c'])
211
        self.assertListRaises(NoSuchFile, t.get_multi, iter(['a', 'b', 'c']))
212
2052.6.2 by Robert Collins
Merge bzr.dev.
213
    def test_get_directory_read_gives_ReadError(self):
214
        """consistent errors for read() on a file returned by get()."""
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
215
        t = self.get_transport()
216
        if t.is_readonly():
217
            self.build_tree(['a directory/'])
218
        else:
219
            t.mkdir('a%20directory')
220
        # getting the file must either work or fail with a PathError
221
        try:
222
            a_file = t.get('a%20directory')
2052.6.2 by Robert Collins
Merge bzr.dev.
223
        except (errors.PathError, errors.RedirectRequested):
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
224
            # early failure return immediately.
225
            return
3111.1.23 by Vincent Ladeuil
Make HTTP/1.1 the default implementation reveals one more bug.
226
        # having got a file, read() must either work (i.e. http reading a dir
227
        # listing) or fail with ReadError
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
228
        try:
229
            a_file.read()
230
        except errors.ReadError:
231
            pass
232
1955.3.3 by John Arbash Meinel
Implement and test 'get_bytes'
233
    def test_get_bytes(self):
234
        t = self.get_transport()
235
236
        files = ['a', 'b', 'e', 'g']
237
        contents = ['contents of a\n',
238
                    'contents of b\n',
239
                    'contents of e\n',
240
                    'contents of g\n',
241
                    ]
242
        self.build_tree(files, transport=t, line_endings='binary')
243
        self.check_transport_contents('contents of a\n', t, 'a')
244
245
        for content, fname in zip(contents, files):
246
            self.assertEqual(content, t.get_bytes(fname))
247
4512.1.1 by Vincent Ladeuil
Fix bug #383920 by inserting the missing Content-Length header.
248
    def test_get_bytes_unknown_file(self):
249
        t = self.get_transport()
1955.3.3 by John Arbash Meinel
Implement and test 'get_bytes'
250
        self.assertRaises(NoSuchFile, t.get_bytes, 'c')
251
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
252
    def test_get_with_open_write_stream_sees_all_content(self):
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
253
        t = self.get_transport()
254
        if t.is_readonly():
255
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
256
        handle = t.open_write_stream('foo')
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
257
        try:
2671.3.6 by Robert Collins
Review feedback.
258
            handle.write('b')
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
259
            self.assertEqual('b', t.get_bytes('foo'))
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
260
        finally:
2671.3.6 by Robert Collins
Review feedback.
261
            handle.close()
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
262
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
263
    def test_get_bytes_with_open_write_stream_sees_all_content(self):
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
264
        t = self.get_transport()
265
        if t.is_readonly():
266
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
267
        handle = t.open_write_stream('foo')
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
268
        try:
2671.3.6 by Robert Collins
Review feedback.
269
            handle.write('b')
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
270
            self.assertEqual('b', t.get_bytes('foo'))
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
271
            f = t.get('foo')
272
            try:
273
                self.assertEqual('b', f.read())
274
            finally:
275
                f.close()
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
276
        finally:
2671.3.6 by Robert Collins
Review feedback.
277
            handle.close()
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
278
1955.3.1 by John Arbash Meinel
Add put_bytes() and a base-level implementation for it
279
    def test_put_bytes(self):
280
        t = self.get_transport()
281
282
        if t.is_readonly():
283
            self.assertRaises(TransportNotPossible,
284
                    t.put_bytes, 'a', 'some text for a\n')
285
            return
286
287
        t.put_bytes('a', 'some text for a\n')
288
        self.failUnless(t.has('a'))
289
        self.check_transport_contents('some text for a\n', t, 'a')
290
291
        # The contents should be overwritten
292
        t.put_bytes('a', 'new text for a\n')
293
        self.check_transport_contents('new text for a\n', t, 'a')
294
295
        self.assertRaises(NoSuchFile,
296
                          t.put_bytes, 'path/doesnt/exist/c', 'contents')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
297
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
298
    def test_put_bytes_non_atomic(self):
299
        t = self.get_transport()
300
301
        if t.is_readonly():
302
            self.assertRaises(TransportNotPossible,
303
                    t.put_bytes_non_atomic, 'a', 'some text for a\n')
304
            return
305
306
        self.failIf(t.has('a'))
307
        t.put_bytes_non_atomic('a', 'some text for a\n')
308
        self.failUnless(t.has('a'))
309
        self.check_transport_contents('some text for a\n', t, 'a')
310
        # Put also replaces contents
311
        t.put_bytes_non_atomic('a', 'new\ncontents for\na\n')
312
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
313
314
        # Make sure we can create another file
315
        t.put_bytes_non_atomic('d', 'contents for\nd\n')
316
        # And overwrite 'a' with empty contents
317
        t.put_bytes_non_atomic('a', '')
318
        self.check_transport_contents('contents for\nd\n', t, 'd')
319
        self.check_transport_contents('', t, 'a')
320
321
        self.assertRaises(NoSuchFile, t.put_bytes_non_atomic, 'no/such/path',
322
                                       'contents\n')
323
        # Now test the create_parent flag
324
        self.assertRaises(NoSuchFile, t.put_bytes_non_atomic, 'dir/a',
325
                                       'contents\n')
326
        self.failIf(t.has('dir/a'))
327
        t.put_bytes_non_atomic('dir/a', 'contents for dir/a\n',
328
                               create_parent_dir=True)
329
        self.check_transport_contents('contents for dir/a\n', t, 'dir/a')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
330
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
331
        # But we still get NoSuchFile if we can't make the parent dir
332
        self.assertRaises(NoSuchFile, t.put_bytes_non_atomic, 'not/there/a',
333
                                       'contents\n',
334
                                       create_parent_dir=True)
335
336
    def test_put_bytes_permissions(self):
337
        t = self.get_transport()
338
339
        if t.is_readonly():
340
            return
341
        if not t._can_roundtrip_unix_modebits():
342
            # Can't roundtrip, so no need to run this test
343
            return
344
        t.put_bytes('mode644', 'test text\n', mode=0644)
345
        self.assertTransportMode(t, 'mode644', 0644)
346
        t.put_bytes('mode666', 'test text\n', mode=0666)
347
        self.assertTransportMode(t, 'mode666', 0666)
348
        t.put_bytes('mode600', 'test text\n', mode=0600)
349
        self.assertTransportMode(t, 'mode600', 0600)
350
        # Yes, you can put_bytes a file such that it becomes readonly
351
        t.put_bytes('mode400', 'test text\n', mode=0400)
352
        self.assertTransportMode(t, 'mode400', 0400)
353
354
        # The default permissions should be based on the current umask
355
        umask = osutils.get_umask()
356
        t.put_bytes('nomode', 'test text\n', mode=None)
357
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
358
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
359
    def test_put_bytes_non_atomic_permissions(self):
360
        t = self.get_transport()
361
362
        if t.is_readonly():
363
            return
364
        if not t._can_roundtrip_unix_modebits():
365
            # Can't roundtrip, so no need to run this test
366
            return
367
        t.put_bytes_non_atomic('mode644', 'test text\n', mode=0644)
368
        self.assertTransportMode(t, 'mode644', 0644)
369
        t.put_bytes_non_atomic('mode666', 'test text\n', mode=0666)
370
        self.assertTransportMode(t, 'mode666', 0666)
371
        t.put_bytes_non_atomic('mode600', 'test text\n', mode=0600)
372
        self.assertTransportMode(t, 'mode600', 0600)
373
        t.put_bytes_non_atomic('mode400', 'test text\n', mode=0400)
374
        self.assertTransportMode(t, 'mode400', 0400)
375
376
        # The default permissions should be based on the current umask
377
        umask = osutils.get_umask()
378
        t.put_bytes_non_atomic('nomode', 'test text\n', mode=None)
379
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
380
381
        # We should also be able to set the mode for a parent directory
382
        # when it is created
383
        t.put_bytes_non_atomic('dir700/mode664', 'test text\n', mode=0664,
384
                               dir_mode=0700, create_parent_dir=True)
385
        self.assertTransportMode(t, 'dir700', 0700)
386
        t.put_bytes_non_atomic('dir770/mode664', 'test text\n', mode=0664,
387
                               dir_mode=0770, create_parent_dir=True)
388
        self.assertTransportMode(t, 'dir770', 0770)
389
        t.put_bytes_non_atomic('dir777/mode664', 'test text\n', mode=0664,
390
                               dir_mode=0777, create_parent_dir=True)
391
        self.assertTransportMode(t, 'dir777', 0777)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
392
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
393
    def test_put_file(self):
394
        t = self.get_transport()
395
396
        if t.is_readonly():
397
            self.assertRaises(TransportNotPossible,
398
                    t.put_file, 'a', StringIO('some text for a\n'))
399
            return
400
2745.5.2 by Robert Collins
* ``bzrlib.transport.Transport.put_file`` now returns the number of bytes
401
        result = t.put_file('a', StringIO('some text for a\n'))
402
        # put_file returns the length of the data written
403
        self.assertEqual(16, result)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
404
        self.failUnless(t.has('a'))
405
        self.check_transport_contents('some text for a\n', t, 'a')
406
        # Put also replaces contents
2745.5.2 by Robert Collins
* ``bzrlib.transport.Transport.put_file`` now returns the number of bytes
407
        result = t.put_file('a', StringIO('new\ncontents for\na\n'))
408
        self.assertEqual(19, result)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
409
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
410
        self.assertRaises(NoSuchFile,
411
                          t.put_file, 'path/doesnt/exist/c',
412
                              StringIO('contents'))
413
414
    def test_put_file_non_atomic(self):
415
        t = self.get_transport()
416
417
        if t.is_readonly():
418
            self.assertRaises(TransportNotPossible,
419
                    t.put_file_non_atomic, 'a', StringIO('some text for a\n'))
420
            return
421
422
        self.failIf(t.has('a'))
423
        t.put_file_non_atomic('a', StringIO('some text for a\n'))
424
        self.failUnless(t.has('a'))
425
        self.check_transport_contents('some text for a\n', t, 'a')
426
        # Put also replaces contents
427
        t.put_file_non_atomic('a', StringIO('new\ncontents for\na\n'))
428
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
429
430
        # Make sure we can create another file
431
        t.put_file_non_atomic('d', StringIO('contents for\nd\n'))
432
        # And overwrite 'a' with empty contents
433
        t.put_file_non_atomic('a', StringIO(''))
434
        self.check_transport_contents('contents for\nd\n', t, 'd')
435
        self.check_transport_contents('', t, 'a')
436
437
        self.assertRaises(NoSuchFile, t.put_file_non_atomic, 'no/such/path',
438
                                       StringIO('contents\n'))
439
        # Now test the create_parent flag
440
        self.assertRaises(NoSuchFile, t.put_file_non_atomic, 'dir/a',
441
                                       StringIO('contents\n'))
442
        self.failIf(t.has('dir/a'))
443
        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
444
                              create_parent_dir=True)
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
445
        self.check_transport_contents('contents for dir/a\n', t, 'dir/a')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
446
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
447
        # 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
448
        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
449
                                       StringIO('contents\n'),
450
                                       create_parent_dir=True)
451
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
452
    def test_put_file_permissions(self):
1955.3.18 by John Arbash Meinel
[merge] Transport.non_atomic_put()
453
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
454
        t = self.get_transport()
455
456
        if t.is_readonly():
457
            return
1711.4.32 by John Arbash Meinel
Skip permission tests on win32 no modebits
458
        if not t._can_roundtrip_unix_modebits():
459
            # Can't roundtrip, so no need to run this test
460
            return
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
461
        t.put_file('mode644', StringIO('test text\n'), mode=0644)
1530.1.21 by Robert Collins
Review feedback fixes.
462
        self.assertTransportMode(t, 'mode644', 0644)
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
463
        t.put_file('mode666', StringIO('test text\n'), mode=0666)
1530.1.21 by Robert Collins
Review feedback fixes.
464
        self.assertTransportMode(t, 'mode666', 0666)
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
465
        t.put_file('mode600', StringIO('test text\n'), mode=0600)
1530.1.21 by Robert Collins
Review feedback fixes.
466
        self.assertTransportMode(t, 'mode600', 0600)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
467
        # 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
468
        t.put_file('mode400', StringIO('test text\n'), mode=0400)
1530.1.21 by Robert Collins
Review feedback fixes.
469
        self.assertTransportMode(t, 'mode400', 0400)
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
470
        # The default permissions should be based on the current umask
471
        umask = osutils.get_umask()
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
472
        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
473
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
474
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
475
    def test_put_file_non_atomic_permissions(self):
476
        t = self.get_transport()
477
478
        if t.is_readonly():
479
            return
480
        if not t._can_roundtrip_unix_modebits():
481
            # Can't roundtrip, so no need to run this test
482
            return
483
        t.put_file_non_atomic('mode644', StringIO('test text\n'), mode=0644)
484
        self.assertTransportMode(t, 'mode644', 0644)
485
        t.put_file_non_atomic('mode666', StringIO('test text\n'), mode=0666)
486
        self.assertTransportMode(t, 'mode666', 0666)
487
        t.put_file_non_atomic('mode600', StringIO('test text\n'), mode=0600)
488
        self.assertTransportMode(t, 'mode600', 0600)
489
        # Yes, you can put_file_non_atomic a file such that it becomes readonly
490
        t.put_file_non_atomic('mode400', StringIO('test text\n'), mode=0400)
491
        self.assertTransportMode(t, 'mode400', 0400)
492
493
        # The default permissions should be based on the current umask
494
        umask = osutils.get_umask()
495
        t.put_file_non_atomic('nomode', StringIO('test text\n'), mode=None)
496
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
497
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
498
        # We should also be able to set the mode for a parent directory
499
        # when it is created
500
        sio = StringIO()
501
        t.put_file_non_atomic('dir700/mode664', sio, mode=0664,
502
                              dir_mode=0700, create_parent_dir=True)
503
        self.assertTransportMode(t, 'dir700', 0700)
504
        t.put_file_non_atomic('dir770/mode664', sio, mode=0664,
505
                              dir_mode=0770, create_parent_dir=True)
506
        self.assertTransportMode(t, 'dir770', 0770)
507
        t.put_file_non_atomic('dir777/mode664', sio, mode=0664,
508
                              dir_mode=0777, create_parent_dir=True)
509
        self.assertTransportMode(t, 'dir777', 0777)
510
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
511
    def test_put_bytes_unicode(self):
512
        # Expect put_bytes to raise AssertionError or UnicodeEncodeError if
513
        # given unicode "bytes".  UnicodeEncodeError doesn't really make sense
514
        # (we don't want to encode unicode here at all, callers should be
515
        # strictly passing bytes to put_bytes), but we allow it for backwards
516
        # compatibility.  At some point we should use a specific exception.
2414.1.2 by Andrew Bennetts
Deal with review comments.
517
        # See https://bugs.launchpad.net/bzr/+bug/106898.
2018.5.131 by Andrew Bennetts
Be strict about unicode passed to transport.put_{bytes,file} and SmartClient.call_with_body_bytes, fixing part of TestLockableFiles_RemoteLockDir.test_read_write.
518
        t = self.get_transport()
519
        if t.is_readonly():
520
            return
521
        unicode_string = u'\u1234'
522
        self.assertRaises(
523
            (AssertionError, UnicodeEncodeError),
524
            t.put_bytes, 'foo', unicode_string)
525
526
    def test_put_file_unicode(self):
527
        # Like put_bytes, except with a StringIO.StringIO of a unicode string.
528
        # This situation can happen (and has) if code is careless about the type
529
        # of "string" they initialise/write to a StringIO with.  We cannot use
530
        # cStringIO, because it never returns unicode from read.
531
        # Like put_bytes, UnicodeEncodeError isn't quite the right exception to
532
        # raise, but we raise it for hysterical raisins.
533
        t = self.get_transport()
534
        if t.is_readonly():
535
            return
536
        unicode_file = pyStringIO(u'\u1234')
537
        self.assertRaises(UnicodeEncodeError, t.put_file, 'foo', unicode_file)
538
1530.1.3 by Robert Collins
transport implementations now tested consistently.
539
    def test_mkdir(self):
540
        t = self.get_transport()
541
542
        if t.is_readonly():
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
543
            # cannot mkdir on readonly transports. We're not testing for
1530.1.3 by Robert Collins
transport implementations now tested consistently.
544
            # cache coherency because cache behaviour is not currently
545
            # defined for the transport interface.
546
            self.assertRaises(TransportNotPossible, t.mkdir, '.')
547
            self.assertRaises(TransportNotPossible, t.mkdir, 'new_dir')
548
            self.assertRaises(TransportNotPossible, t.mkdir_multi, ['new_dir'])
549
            self.assertRaises(TransportNotPossible, t.mkdir, 'path/doesnt/exist')
550
            return
551
        # Test mkdir
552
        t.mkdir('dir_a')
553
        self.assertEqual(t.has('dir_a'), True)
554
        self.assertEqual(t.has('dir_b'), False)
555
556
        t.mkdir('dir_b')
557
        self.assertEqual(t.has('dir_b'), True)
558
559
        t.mkdir_multi(['dir_c', 'dir_d'])
560
561
        t.mkdir_multi(iter(['dir_e', 'dir_f']))
562
        self.assertEqual(list(t.has_multi(
563
            ['dir_a', 'dir_b', 'dir_c', 'dir_q',
564
             'dir_d', 'dir_e', 'dir_f', 'dir_b'])),
565
            [True, True, True, False,
566
             True, True, True, True])
567
568
        # we were testing that a local mkdir followed by a transport
569
        # mkdir failed thusly, but given that we * in one process * do not
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
570
        # concurrently fiddle with disk dirs and then use transport to do
1530.1.3 by Robert Collins
transport implementations now tested consistently.
571
        # things, the win here seems marginal compared to the constraint on
572
        # the interface. RBC 20051227
573
        t.mkdir('dir_g')
574
        self.assertRaises(FileExists, t.mkdir, 'dir_g')
575
576
        # 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
577
        t.put_bytes('dir_a/a', 'contents of dir_a/a')
578
        t.put_file('dir_b/b', StringIO('contents of dir_b/b'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
579
        self.check_transport_contents('contents of dir_a/a', t, 'dir_a/a')
580
        self.check_transport_contents('contents of dir_b/b', t, 'dir_b/b')
581
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
582
        # mkdir of a dir with an absent parent
583
        self.assertRaises(NoSuchFile, t.mkdir, 'missing/dir')
584
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
585
    def test_mkdir_permissions(self):
586
        t = self.get_transport()
587
        if t.is_readonly():
588
            return
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
589
        if not t._can_roundtrip_unix_modebits():
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
590
            # no sense testing on this transport
591
            return
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
592
        # Test mkdir with a mode
593
        t.mkdir('dmode755', mode=0755)
1530.1.21 by Robert Collins
Review feedback fixes.
594
        self.assertTransportMode(t, 'dmode755', 0755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
595
        t.mkdir('dmode555', mode=0555)
1530.1.21 by Robert Collins
Review feedback fixes.
596
        self.assertTransportMode(t, 'dmode555', 0555)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
597
        t.mkdir('dmode777', mode=0777)
1530.1.21 by Robert Collins
Review feedback fixes.
598
        self.assertTransportMode(t, 'dmode777', 0777)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
599
        t.mkdir('dmode700', mode=0700)
1530.1.21 by Robert Collins
Review feedback fixes.
600
        self.assertTransportMode(t, 'dmode700', 0700)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
601
        t.mkdir_multi(['mdmode755'], mode=0755)
1530.1.21 by Robert Collins
Review feedback fixes.
602
        self.assertTransportMode(t, 'mdmode755', 0755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
603
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
604
        # Default mode should be based on umask
605
        umask = osutils.get_umask()
606
        t.mkdir('dnomode', mode=None)
607
        self.assertTransportMode(t, 'dnomode', 0777 & ~umask)
608
2671.3.2 by Robert Collins
Start open_file_stream logic.
609
    def test_opening_a_file_stream_creates_file(self):
610
        t = self.get_transport()
611
        if t.is_readonly():
612
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
613
        handle = t.open_write_stream('foo')
2671.3.2 by Robert Collins
Start open_file_stream logic.
614
        try:
615
            self.assertEqual('', t.get_bytes('foo'))
616
        finally:
2671.3.6 by Robert Collins
Review feedback.
617
            handle.close()
2671.3.2 by Robert Collins
Start open_file_stream logic.
618
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
619
    def test_opening_a_file_stream_can_set_mode(self):
620
        t = self.get_transport()
621
        if t.is_readonly():
622
            return
623
        if not t._can_roundtrip_unix_modebits():
624
            # Can't roundtrip, so no need to run this test
625
            return
626
        def check_mode(name, mode, expected):
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
627
            handle = t.open_write_stream(name, mode=mode)
2671.3.6 by Robert Collins
Review feedback.
628
            handle.close()
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
629
            self.assertTransportMode(t, name, expected)
630
        check_mode('mode644', 0644, 0644)
631
        check_mode('mode666', 0666, 0666)
632
        check_mode('mode600', 0600, 0600)
633
        # The default permissions should be based on the current umask
634
        check_mode('nomode', None, 0666 & ~osutils.get_umask())
635
1530.1.3 by Robert Collins
transport implementations now tested consistently.
636
    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.
637
        # FIXME: test:   same server to same server (partly done)
638
        # same protocol two servers
639
        # and    different protocols (done for now except for MemoryTransport.
640
        # - RBC 20060122
641
642
        def simple_copy_files(transport_from, transport_to):
643
            files = ['a', 'b', 'c', 'd']
644
            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.
645
            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.
646
            for f in files:
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
647
                self.check_transport_contents(transport_to.get_bytes(f),
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.
648
                                              transport_from, f)
649
1530.1.3 by Robert Collins
transport implementations now tested consistently.
650
        t = self.get_transport()
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
651
        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.
652
        simple_copy_files(t, temp_transport)
653
        if not t.is_readonly():
654
            t.mkdir('copy_to_simple')
655
            t2 = t.clone('copy_to_simple')
656
            simple_copy_files(t, t2)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
657
658
659
        # Test that copying into a missing directory raises
660
        # NoSuchFile
661
        if t.is_readonly():
1530.1.21 by Robert Collins
Review feedback fixes.
662
            self.build_tree(['e/', 'e/f'])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
663
        else:
664
            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
665
            t.put_bytes('e/f', 'contents of e')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
666
        self.assertRaises(NoSuchFile, t.copy_to, ['e/f'], temp_transport)
667
        temp_transport.mkdir('e')
668
        t.copy_to(['e/f'], temp_transport)
669
670
        del temp_transport
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
671
        temp_transport = MemoryTransport('memory:///')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
672
673
        files = ['a', 'b', 'c', 'd']
674
        t.copy_to(iter(files), temp_transport)
675
        for f in files:
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
676
            self.check_transport_contents(temp_transport.get_bytes(f),
1530.1.3 by Robert Collins
transport implementations now tested consistently.
677
                                          t, f)
678
        del temp_transport
679
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
680
        for mode in (0666, 0644, 0600, 0400):
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
681
            temp_transport = MemoryTransport("memory:///")
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
682
            t.copy_to(files, temp_transport, mode=mode)
683
            for f in files:
1530.1.21 by Robert Collins
Review feedback fixes.
684
                self.assertTransportMode(temp_transport, f, mode)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
685
4294.2.1 by Robert Collins
Move directory checking for bzr push options into Branch.create_clone_on_transport.
686
    def test_create_prefix(self):
687
        t = self.get_transport()
688
        sub = t.clone('foo').clone('bar')
689
        try:
690
            sub.create_prefix()
691
        except TransportNotPossible:
692
            self.assertTrue(t.is_readonly())
693
        else:
694
            self.assertTrue(t.has('foo/bar'))
695
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
696
    def test_append_file(self):
697
        t = self.get_transport()
698
699
        if t.is_readonly():
1530.1.3 by Robert Collins
transport implementations now tested consistently.
700
            self.assertRaises(TransportNotPossible,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
701
                    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
702
            return
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
703
        t.put_bytes('a', 'diff\ncontents for\na\n')
704
        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
705
706
        self.assertEqual(20,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
707
            t.append_file('a', StringIO('add\nsome\nmore\ncontents\n')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
708
709
        self.check_transport_contents(
710
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
711
            t, 'a')
712
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
713
        # a file with no parent should fail..
714
        self.assertRaises(NoSuchFile,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
715
                          t.append_file, 'missing/path', StringIO('content'))
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
716
717
        # And we can create new files, too
718
        self.assertEqual(0,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
719
            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
720
        self.check_transport_contents('some text\nfor a missing file\n',
721
                                      t, 'c')
722
723
    def test_append_bytes(self):
724
        t = self.get_transport()
725
726
        if t.is_readonly():
727
            self.assertRaises(TransportNotPossible,
728
                    t.append_bytes, 'a', 'add\nsome\nmore\ncontents\n')
729
            return
730
731
        self.assertEqual(0, t.append_bytes('a', 'diff\ncontents for\na\n'))
732
        self.assertEqual(0, t.append_bytes('b', 'contents\nfor b\n'))
733
734
        self.assertEqual(20,
735
            t.append_bytes('a', 'add\nsome\nmore\ncontents\n'))
736
737
        self.check_transport_contents(
738
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
739
            t, 'a')
740
741
        # a file with no parent should fail..
742
        self.assertRaises(NoSuchFile,
743
                          t.append_bytes, 'missing/path', 'content')
744
745
    def test_append_multi(self):
746
        t = self.get_transport()
747
748
        if t.is_readonly():
749
            return
750
        t.put_bytes('a', 'diff\ncontents for\na\n'
751
                         'add\nsome\nmore\ncontents\n')
752
        t.put_bytes('b', 'contents\nfor b\n')
753
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
754
        self.assertEqual((43, 15),
755
            t.append_multi([('a', StringIO('and\nthen\nsome\nmore\n')),
756
                            ('b', StringIO('some\nmore\nfor\nb\n'))]))
757
1530.1.3 by Robert Collins
transport implementations now tested consistently.
758
        self.check_transport_contents(
759
            'diff\ncontents for\na\n'
760
            'add\nsome\nmore\ncontents\n'
761
            'and\nthen\nsome\nmore\n',
762
            t, 'a')
763
        self.check_transport_contents(
764
                'contents\nfor b\n'
765
                'some\nmore\nfor\nb\n',
766
                t, 'b')
767
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
768
        self.assertEqual((62, 31),
769
            t.append_multi(iter([('a', StringIO('a little bit more\n')),
770
                                 ('b', StringIO('from an iterator\n'))])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
771
        self.check_transport_contents(
772
            'diff\ncontents for\na\n'
773
            'add\nsome\nmore\ncontents\n'
774
            'and\nthen\nsome\nmore\n'
775
            'a little bit more\n',
776
            t, 'a')
777
        self.check_transport_contents(
778
                'contents\nfor b\n'
779
                'some\nmore\nfor\nb\n'
780
                'from an iterator\n',
781
                t, 'b')
782
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
783
        self.assertEqual((80, 0),
784
            t.append_multi([('a', StringIO('some text in a\n')),
785
                            ('d', StringIO('missing file r\n'))]))
786
1530.1.3 by Robert Collins
transport implementations now tested consistently.
787
        self.check_transport_contents(
788
            'diff\ncontents for\na\n'
789
            'add\nsome\nmore\ncontents\n'
790
            'and\nthen\nsome\nmore\n'
791
            'a little bit more\n'
792
            'some text in a\n',
793
            t, 'a')
794
        self.check_transport_contents('missing file r\n', t, 'd')
795
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
796
    def test_append_file_mode(self):
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
797
        """Check that append accepts a mode parameter"""
1666.1.6 by Robert Collins
Make knit the default format.
798
        # check append accepts a mode
799
        t = self.get_transport()
800
        if t.is_readonly():
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
801
            self.assertRaises(TransportNotPossible,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
802
                t.append_file, 'f', StringIO('f'), mode=None)
1666.1.6 by Robert Collins
Make knit the default format.
803
            return
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
804
        t.append_file('f', StringIO('f'), mode=None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
805
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
806
    def test_append_bytes_mode(self):
807
        # check append_bytes accepts a mode
808
        t = self.get_transport()
809
        if t.is_readonly():
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
810
            self.assertRaises(TransportNotPossible,
811
                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
812
            return
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
813
        t.append_bytes('f', 'f', mode=None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
814
1530.1.3 by Robert Collins
transport implementations now tested consistently.
815
    def test_delete(self):
816
        # TODO: Test Transport.delete
817
        t = self.get_transport()
818
819
        # Not much to do with a readonly transport
820
        if t.is_readonly():
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
821
            self.assertRaises(TransportNotPossible, t.delete, 'missing')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
822
            return
823
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
824
        t.put_bytes('a', 'a little bit of text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
825
        self.failUnless(t.has('a'))
826
        t.delete('a')
827
        self.failIf(t.has('a'))
828
829
        self.assertRaises(NoSuchFile, t.delete, 'a')
830
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
831
        t.put_bytes('a', 'a text\n')
832
        t.put_bytes('b', 'b text\n')
833
        t.put_bytes('c', 'c text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
834
        self.assertEqual([True, True, True],
835
                list(t.has_multi(['a', 'b', 'c'])))
836
        t.delete_multi(['a', 'c'])
837
        self.assertEqual([False, True, False],
838
                list(t.has_multi(['a', 'b', 'c'])))
839
        self.failIf(t.has('a'))
840
        self.failUnless(t.has('b'))
841
        self.failIf(t.has('c'))
842
843
        self.assertRaises(NoSuchFile,
844
                t.delete_multi, ['a', 'b', 'c'])
845
846
        self.assertRaises(NoSuchFile,
847
                t.delete_multi, iter(['a', 'b', 'c']))
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', 'another a text\n')
850
        t.put_bytes('c', 'another c text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
851
        t.delete_multi(iter(['a', 'b', 'c']))
852
853
        # We should have deleted everything
854
        # SftpServer creates control files in the
855
        # working directory, so we can just do a
856
        # plain "listdir".
857
        # self.assertEqual([], os.listdir('.'))
858
2671.3.1 by Robert Collins
* New method ``bzrlib.transport.Transport.get_recommended_page_size``.
859
    def test_recommended_page_size(self):
860
        """Transports recommend a page size for partial access to files."""
861
        t = self.get_transport()
862
        self.assertIsInstance(t.recommended_page_size(), int)
863
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
864
    def test_rmdir(self):
865
        t = self.get_transport()
866
        # Not much to do with a readonly transport
867
        if t.is_readonly():
868
            self.assertRaises(TransportNotPossible, t.rmdir, 'missing')
869
            return
870
        t.mkdir('adir')
871
        t.mkdir('adir/bdir')
872
        t.rmdir('adir/bdir')
1948.3.12 by Vincent LADEUIL
Fix Aaron's third review remarks.
873
        # ftp may not be able to raise NoSuchFile for lack of
874
        # details when failing
875
        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.
876
        t.rmdir('adir')
1948.3.12 by Vincent LADEUIL
Fix Aaron's third review remarks.
877
        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.
878
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
879
    def test_rmdir_not_empty(self):
880
        """Deleting a non-empty directory raises an exception
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
881
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
882
        sftp (and possibly others) don't give us a specific "directory not
883
        empty" exception -- we can just see that the operation failed.
884
        """
885
        t = self.get_transport()
886
        if t.is_readonly():
887
            return
888
        t.mkdir('adir')
889
        t.mkdir('adir/bdir')
890
        self.assertRaises(PathError, t.rmdir, 'adir')
891
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
892
    def test_rmdir_empty_but_similar_prefix(self):
893
        """rmdir does not get confused by sibling paths.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
894
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
895
        A naive implementation of MemoryTransport would refuse to rmdir
896
        ".bzr/branch" if there is a ".bzr/branch-format" directory, because it
897
        uses "path.startswith(dir)" on all file paths to determine if directory
898
        is empty.
899
        """
900
        t = self.get_transport()
901
        if t.is_readonly():
902
            return
903
        t.mkdir('foo')
904
        t.put_bytes('foo-bar', '')
905
        t.mkdir('foo-baz')
906
        t.rmdir('foo')
907
        self.assertRaises((NoSuchFile, PathError), t.rmdir, 'foo')
908
        self.failUnless(t.has('foo-bar'))
909
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
910
    def test_rename_dir_succeeds(self):
911
        t = self.get_transport()
912
        if t.is_readonly():
913
            raise TestSkipped("transport is readonly")
914
        t.mkdir('adir')
915
        t.mkdir('adir/asubdir')
916
        t.rename('adir', 'bdir')
917
        self.assertTrue(t.has('bdir/asubdir'))
918
        self.assertFalse(t.has('adir'))
919
920
    def test_rename_dir_nonempty(self):
921
        """Attempting to replace a nonemtpy directory should fail"""
922
        t = self.get_transport()
923
        if t.is_readonly():
924
            raise TestSkipped("transport is readonly")
925
        t.mkdir('adir')
926
        t.mkdir('adir/asubdir')
927
        t.mkdir('bdir')
928
        t.mkdir('bdir/bsubdir')
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
929
        # any kind of PathError would be OK, though we normally expect
930
        # DirectoryNotEmpty
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
931
        self.assertRaises(PathError, t.rename, 'bdir', 'adir')
932
        # nothing was changed so it should still be as before
933
        self.assertTrue(t.has('bdir/bsubdir'))
934
        self.assertFalse(t.has('adir/bdir'))
935
        self.assertFalse(t.has('adir/bsubdir'))
936
3010.2.1 by Martin Pool
Followon from MemoryTransport._abspath fix: add test_rename_across_subdirs, and fix error construction
937
    def test_rename_across_subdirs(self):
938
        t = self.get_transport()
939
        if t.is_readonly():
940
            raise TestNotApplicable("transport is readonly")
941
        t.mkdir('a')
942
        t.mkdir('b')
943
        ta = t.clone('a')
944
        tb = t.clone('b')
945
        ta.put_bytes('f', 'aoeu')
946
        ta.rename('f', '../b/f')
947
        self.assertTrue(tb.has('f'))
948
        self.assertFalse(ta.has('f'))
949
        self.assertTrue(t.has('b/f'))
950
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
951
    def test_delete_tree(self):
952
        t = self.get_transport()
953
954
        # Not much to do with a readonly transport
955
        if t.is_readonly():
956
            self.assertRaises(TransportNotPossible, t.delete_tree, 'missing')
957
            return
958
959
        # and does it like listing ?
960
        t.mkdir('adir')
961
        try:
962
            t.delete_tree('adir')
963
        except TransportNotPossible:
964
            # ok, this transport does not support delete_tree
965
            return
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
966
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
967
        # did it delete that trivial case?
968
        self.assertRaises(NoSuchFile, t.stat, 'adir')
969
970
        self.build_tree(['adir/',
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
971
                         'adir/file',
972
                         'adir/subdir/',
973
                         'adir/subdir/file',
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
974
                         'adir/subdir2/',
975
                         'adir/subdir2/file',
976
                         ], transport=t)
977
978
        t.delete_tree('adir')
979
        # adir should be gone now.
980
        self.assertRaises(NoSuchFile, t.stat, 'adir')
981
1530.1.3 by Robert Collins
transport implementations now tested consistently.
982
    def test_move(self):
983
        t = self.get_transport()
984
985
        if t.is_readonly():
986
            return
987
988
        # TODO: I would like to use os.listdir() to
989
        # make sure there are no extra files, but SftpServer
990
        # creates control files in the working directory
991
        # perhaps all of this could be done in a subdirectory
992
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
993
        t.put_bytes('a', 'a first file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
994
        self.assertEquals([True, False], list(t.has_multi(['a', 'b'])))
995
996
        t.move('a', 'b')
997
        self.failUnless(t.has('b'))
998
        self.failIf(t.has('a'))
999
1000
        self.check_transport_contents('a first file\n', t, 'b')
1001
        self.assertEquals([False, True], list(t.has_multi(['a', 'b'])))
1002
1003
        # 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
1004
        t.put_bytes('c', 'c this file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1005
        t.move('c', 'b')
1006
        self.failIf(t.has('c'))
1007
        self.check_transport_contents('c this file\n', t, 'b')
1008
1009
        # TODO: Try to write a test for atomicity
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1010
        # TODO: Test moving into a non-existent subdirectory
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1011
        # TODO: Test Transport.move_multi
1012
1013
    def test_copy(self):
1014
        t = self.get_transport()
1015
1016
        if t.is_readonly():
1017
            return
1018
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1019
        t.put_bytes('a', 'a file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1020
        t.copy('a', 'b')
1021
        self.check_transport_contents('a file\n', t, 'b')
1022
1023
        self.assertRaises(NoSuchFile, t.copy, 'c', 'd')
1024
        os.mkdir('c')
1025
        # What should the assert be if you try to copy a
1026
        # file over a directory?
1027
        #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
1028
        t.put_bytes('d', 'text in d\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1029
        t.copy('d', 'b')
1030
        self.check_transport_contents('text in d\n', t, 'b')
1031
1032
        # TODO: test copy_multi
1033
1034
    def test_connection_error(self):
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
1035
        """ConnectionError is raised when connection is impossible.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1036
3021.1.2 by Vincent Ladeuil
Fix bug #164567 by catching connection errors.
1037
        The error should be raised from the first operation on the transport.
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
1038
        """
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
1039
        try:
1040
            url = self._server.get_bogus_url()
1041
        except NotImplementedError:
1042
            raise TestSkipped("Transport %s has no bogus URL support." %
1043
                              self._server.__class__)
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
1044
        t = get_transport(url)
1045
        self.assertRaises((ConnectionError, NoSuchFile), t.get, '.bzr/branch')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1046
1047
    def test_stat(self):
1048
        # TODO: Test stat, just try once, and if it throws, stop testing
1049
        from stat import S_ISDIR, S_ISREG
1050
1051
        t = self.get_transport()
1052
1053
        try:
1054
            st = t.stat('.')
1055
        except TransportNotPossible, e:
1056
            # This transport cannot stat
1057
            return
1058
1059
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e']
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1060
        sizes = [14, 0, 16, 0, 18]
1551.2.39 by abentley
Fix line endings in tests
1061
        self.build_tree(paths, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1062
1063
        for path, size in zip(paths, sizes):
1064
            st = t.stat(path)
1065
            if path.endswith('/'):
1066
                self.failUnless(S_ISDIR(st.st_mode))
1067
                # directory sizes are meaningless
1068
            else:
1069
                self.failUnless(S_ISREG(st.st_mode))
1070
                self.assertEqual(size, st.st_size)
1071
1072
        remote_stats = list(t.stat_multi(paths))
1073
        remote_iter_stats = list(t.stat_multi(iter(paths)))
1074
1075
        self.assertRaises(NoSuchFile, t.stat, 'q')
1076
        self.assertRaises(NoSuchFile, t.stat, 'b/a')
1077
1078
        self.assertListRaises(NoSuchFile, t.stat_multi, ['a', 'c', 'd'])
1079
        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.
1080
        self.build_tree(['subdir/', 'subdir/file'], transport=t)
1081
        subdir = t.clone('subdir')
1082
        subdir.stat('./file')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1083
        subdir.stat('.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1084
5056.1.9 by Neil Santos
Renamed link() methods to hardlink(), as per mbp's suggestion
1085
    def test_hardlink(self):
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1086
        from stat import ST_NLINK
1087
1088
        t = self.get_transport()
1089
1090
        source_name = "original_target"
1091
        link_name = "target_link"
1092
1093
        self.build_tree([source_name], transport=t)
1094
1095
        try:
5056.1.9 by Neil Santos
Renamed link() methods to hardlink(), as per mbp's suggestion
1096
            t.hardlink(source_name, link_name)
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1097
1098
            self.failUnless(t.has(source_name))
1099
            self.failUnless(t.has(link_name))
1100
1101
            st = t.stat(link_name)
1102
            self.failUnlessEqual(st[ST_NLINK], 2)
1103
        except TransportNotPossible:
5056.1.8 by Neil Santos
Fixed link and symlink tests to raise TestSkipped when going through non-supporting transports, rather than just returning.
1104
            raise TestSkipped("Transport %s does not support hardlinks." %
1105
                              self._server.__class__)
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1106
1107
    def test_symlink(self):
1108
        from stat import S_ISLNK
1109
1110
        t = self.get_transport()
1111
1112
        source_name = "original_target"
1113
        link_name = "target_link"
1114
1115
        self.build_tree([source_name], transport=t)
1116
1117
        try:
5056.1.4 by Neil Santos
Changed stat() in SFTPTransport and LocalTransport back to calling plain stat(), instead of lstat().
1118
            t.symlink(source_name, link_name)
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1119
1120
            self.failUnless(t.has(source_name))
1121
            self.failUnless(t.has(link_name))
1122
1123
            st = t.stat(link_name)
5349.2.1 by Martin Pool
Better test_symlink failure message
1124
            self.failUnless(S_ISLNK(st.st_mode),
1125
                "expected symlink, got mode %o" % st.st_mode)
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1126
        except TransportNotPossible:
5056.1.8 by Neil Santos
Fixed link and symlink tests to raise TestSkipped when going through non-supporting transports, rather than just returning.
1127
            raise TestSkipped("Transport %s does not support symlinks." %
1128
                              self._server.__class__)
1129
        except IOError:
1130
            raise tests.KnownFailure("Paramiko fails to create symlinks during tests")
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1131
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1132
    def test_list_dir(self):
1133
        # TODO: Test list_dir, just try once, and if it throws, stop testing
1134
        t = self.get_transport()
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1135
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1136
        if not t.listable():
1137
            self.assertRaises(TransportNotPossible, t.list_dir, '.')
1138
            return
1139
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1140
        def sorted_list(d, transport):
1141
            l = list(transport.list_dir(d))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1142
            l.sort()
1143
            return l
1144
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1145
        self.assertEqual([], sorted_list('.', t))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
1146
        # c2 is precisely one letter longer than c here to test that
1147
        # suffixing is not confused.
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1148
        # a%25b checks that quoting is done consistently across transports
1149
        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
1150
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1151
        if not t.is_readonly():
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1152
            self.build_tree(tree_names, transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1153
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
1154
            self.build_tree(tree_names)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1155
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1156
        self.assertEqual(
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1157
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('', t))
1158
        self.assertEqual(
1159
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('.', t))
1160
        self.assertEqual(['d', 'e'], sorted_list('c', t))
1161
1162
        # Cloning the transport produces an equivalent listing
1163
        self.assertEqual(['d', 'e'], sorted_list('', t.clone('c')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1164
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1165
        if not t.is_readonly():
1166
            t.delete('c/d')
1167
            t.delete('b')
1168
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
1169
            os.unlink('c/d')
1170
            os.unlink('b')
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1171
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1172
        self.assertEqual(['a', 'a%2525b', 'c', 'c2'], sorted_list('.', t))
1173
        self.assertEqual(['e'], sorted_list('c', t))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1174
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
1175
        self.assertListRaises(PathError, t.list_dir, 'q')
1176
        self.assertListRaises(PathError, t.list_dir, 'c/f')
3508.1.4 by Vincent Ladeuil
Ensure that ftp transport are always in binary mode.
1177
        # 'a' is a file, list_dir should raise an error
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
1178
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1179
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1180
    def test_list_dir_result_is_url_escaped(self):
1181
        t = self.get_transport()
1182
        if not t.listable():
1183
            raise TestSkipped("transport not listable")
1184
1185
        if not t.is_readonly():
1186
            self.build_tree(['a/', 'a/%'], transport=t)
1187
        else:
1188
            self.build_tree(['a/', 'a/%'])
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1189
1910.7.2 by Andrew Bennetts
Also assert that list_dir returns plain str objects.
1190
        names = list(t.list_dir('a'))
1191
        self.assertEqual(['%25'], names)
1192
        self.assertIsInstance(names[0], str)
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1193
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
1194
    def test_clone_preserve_info(self):
1195
        t1 = self.get_transport()
1196
        if not isinstance(t1, ConnectedTransport):
1197
            raise TestSkipped("not a connected transport")
1198
1199
        t2 = t1.clone('subdir')
1200
        self.assertEquals(t1._scheme, t2._scheme)
1201
        self.assertEquals(t1._user, t2._user)
1202
        self.assertEquals(t1._password, t2._password)
1203
        self.assertEquals(t1._host, t2._host)
1204
        self.assertEquals(t1._port, t2._port)
1205
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1206
    def test__reuse_for(self):
1207
        t = self.get_transport()
1208
        if not isinstance(t, ConnectedTransport):
1209
            raise TestSkipped("not a connected transport")
1210
1211
        def new_url(scheme=None, user=None, password=None,
1212
                    host=None, port=None, path=None):
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1213
            """Build a new url from t.base changing only parts of it.
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1214
1215
            Only the parameters different from None will be changed.
1216
            """
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1217
            if scheme   is None: scheme   = t._scheme
1218
            if user     is None: user     = t._user
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1219
            if password is None: password = t._password
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1220
            if user     is None: user     = t._user
1221
            if host     is None: host     = t._host
1222
            if port     is None: port     = t._port
1223
            if path     is None: path     = t._path
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1224
            return t._unsplit_url(scheme, user, password, host, port, path)
1225
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1226
        if t._scheme == 'ftp':
1227
            scheme = 'sftp'
1228
        else:
1229
            scheme = 'ftp'
1230
        self.assertIsNot(t, t._reuse_for(new_url(scheme=scheme)))
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1231
        if t._user == 'me':
1232
            user = 'you'
1233
        else:
1234
            user = 'me'
1235
        self.assertIsNot(t, t._reuse_for(new_url(user=user)))
1236
        # passwords are not taken into account because:
1237
        # - it makes no sense to have two different valid passwords for the
1238
        #   same user
1239
        # - _password in ConnectedTransport is intended to collect what the
1240
        #   user specified from the command-line and there are cases where the
1241
        #   new url can contain no password (if the url was built from an
1242
        #   existing transport.base for example)
1243
        # - password are considered part of the credentials provided at
1244
        #   connection creation time and as such may not be present in the url
1245
        #   (they may be typed by the user when prompted for example)
1246
        self.assertIs(t, t._reuse_for(new_url(password='from space')))
1247
        # We will not connect, we can use a invalid host
1248
        self.assertIsNot(t, t._reuse_for(new_url(host=t._host + 'bar')))
1249
        if t._port == 1234:
1250
            port = 4321
1251
        else:
1252
            port = 1234
1253
        self.assertIsNot(t, t._reuse_for(new_url(port=port)))
2990.2.1 by Vincent Ladeuil
ConnectedTransport._reuse_for fails to deal with local URLs.
1254
        # No point in trying to reuse a transport for a local URL
2990.2.2 by Vincent Ladeuil
Detect invalid transport reuse attempts by catching invalid URLs.
1255
        self.assertIs(None, t._reuse_for('/valid_but_not_existing'))
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1256
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1257
    def test_connection_sharing(self):
1258
        t = self.get_transport()
1259
        if not isinstance(t, ConnectedTransport):
1260
            raise TestSkipped("not a connected transport")
1261
1262
        c = t.clone('subdir')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1263
        # Some transports will create the connection  only when needed
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1264
        t.has('surely_not') # Force connection
1265
        self.assertIs(t._get_connection(), c._get_connection())
1266
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1267
        # Temporary failure, we need to create a new dummy connection
5247.2.12 by Vincent Ladeuil
Ensure that all transports close their underlying connection.
1268
        new_connection = None
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1269
        t._set_connection(new_connection)
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1270
        # Check that both transports use the same connection
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1271
        self.assertIs(new_connection, t._get_connection())
1272
        self.assertIs(new_connection, c._get_connection())
1273
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1274
    def test_reuse_connection_for_various_paths(self):
1275
        t = self.get_transport()
1276
        if not isinstance(t, ConnectedTransport):
1277
            raise TestSkipped("not a connected transport")
1278
1279
        t.has('surely_not') # Force connection
1280
        self.assertIsNot(None, t._get_connection())
1281
1282
        subdir = t._reuse_for(t.base + 'whatever/but/deep/down/the/path')
1283
        self.assertIsNot(t, subdir)
1284
        self.assertIs(t._get_connection(), subdir._get_connection())
1285
1286
        home = subdir._reuse_for(t.base + 'home')
1287
        self.assertIs(t._get_connection(), home._get_connection())
1288
        self.assertIs(subdir._get_connection(), home._get_connection())
1289
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1290
    def test_clone(self):
1291
        # TODO: Test that clone moves up and down the filesystem
1292
        t1 = self.get_transport()
1293
1294
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
1295
1296
        self.failUnless(t1.has('a'))
1297
        self.failUnless(t1.has('b/c'))
1298
        self.failIf(t1.has('c'))
1299
1300
        t2 = t1.clone('b')
1301
        self.assertEqual(t1.base + 'b/', t2.base)
1302
1303
        self.failUnless(t2.has('c'))
1304
        self.failIf(t2.has('a'))
1305
1306
        t3 = t2.clone('..')
1307
        self.failUnless(t3.has('a'))
1308
        self.failIf(t3.has('c'))
1309
1310
        self.failIf(t1.has('b/d'))
1311
        self.failIf(t2.has('d'))
1312
        self.failIf(t3.has('b/d'))
1313
1314
        if t1.is_readonly():
3693.1.2 by John Arbash Meinel
Use build_tree_contents instead of direct open().write()
1315
            self.build_tree_contents([('b/d', 'newfile\n')])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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
            t2.put_bytes('d', 'newfile\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1318
1319
        self.failUnless(t1.has('b/d'))
1320
        self.failUnless(t2.has('d'))
1321
        self.failUnless(t3.has('b/d'))
1322
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1323
    def test_clone_to_root(self):
1324
        orig_transport = self.get_transport()
1325
        # Repeatedly go up to a parent directory until we're at the root
1326
        # directory of this transport
1327
        root_transport = orig_transport
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1328
        new_transport = root_transport.clone("..")
2245.6.1 by Alexander Belchenko
win32 UNC path: recursive cloning UNC path to root stops on //HOST, not on //
1329
        # as we are walking up directories, the path must be
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1330
        # growing less, except at the top
1331
        self.assertTrue(len(new_transport.base) < len(root_transport.base)
1332
            or new_transport.base == root_transport.base)
1333
        while new_transport.base != root_transport.base:
1334
            root_transport = new_transport
1335
            new_transport = root_transport.clone("..")
2245.6.1 by Alexander Belchenko
win32 UNC path: recursive cloning UNC path to root stops on //HOST, not on //
1336
            # as we are walking up directories, the path must be
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1337
            # growing less, except at the top
1338
            self.assertTrue(len(new_transport.base) < len(root_transport.base)
1339
                or new_transport.base == root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1340
1341
        # Cloning to "/" should take us to exactly the same location.
1342
        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.
1343
        # the abspath of "/" from the original transport should be the same
1344
        # as the base at the root:
1345
        self.assertEqual(orig_transport.abspath("/"), root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1346
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
1347
        # At the root, the URL must still end with / as its a directory
1348
        self.assertEqual(root_transport.base[-1], '/')
1349
1350
    def test_clone_from_root(self):
1351
        """At the root, cloning to a simple dir should just do string append."""
1352
        orig_transport = self.get_transport()
1353
        root_transport = orig_transport.clone('/')
1354
        self.assertEqual(root_transport.base + '.bzr/',
1355
            root_transport.clone('.bzr').base)
1356
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1357
    def test_base_url(self):
1358
        t = self.get_transport()
1359
        self.assertEqual('/', t.base[-1])
1360
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1361
    def test_relpath(self):
1362
        t = self.get_transport()
1363
        self.assertEqual('', t.relpath(t.base))
1364
        # base ends with /
1365
        self.assertEqual('', t.relpath(t.base[:-1]))
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1366
        # subdirs which don't exist should still give relpaths.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1367
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
1368
        # trailing slash should be the same.
1369
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
1370
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1371
    def test_relpath_at_root(self):
1372
        t = self.get_transport()
1373
        # clone all the way to the top
1374
        new_transport = t.clone('..')
1375
        while new_transport.base != t.base:
1376
            t = new_transport
1377
            new_transport = t.clone('..')
1378
        # we must be able to get a relpath below the root
1379
        self.assertEqual('', t.relpath(t.base))
1380
        # and a deeper one should work too
1381
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
1382
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1383
    def test_abspath(self):
1384
        # smoke test for abspath. Corner cases for backends like unix fs's
1385
        # that have aliasing problems like symlinks should go in backend
1386
        # specific test cases.
1387
        transport = self.get_transport()
2485.8.21 by Vincent Ladeuil
Simplify debug.
1388
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1389
        self.assertEqual(transport.base + 'relpath',
1390
                         transport.abspath('relpath'))
1391
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1392
        # This should work without raising an error.
1393
        transport.abspath("/")
1394
1395
        # the abspath of "/" and "/foo/.." should result in the same location
1396
        self.assertEqual(transport.abspath("/"), transport.abspath("/foo/.."))
1397
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
1398
        self.assertEqual(transport.clone("/").abspath('foo'),
1399
                         transport.abspath("/foo"))
1400
3693.2.2 by Mark Hammond
add a test for win32 abspath sematics, which as requested by lifeless,
1401
    def test_win32_abspath(self):
3712.1.1 by Ian Clatworthy
LocalTransport.abspath returns drive letter if transport has one (Mark Hammond)
1402
        # Note: we tried to set sys.platform='win32' so we could test on
1403
        # other platforms too, but then osutils does platform specific
1404
        # things at import time which defeated us...
3693.2.3 by Mark Hammond
Back to skipping the tests on non-windows platforms.
1405
        if sys.platform != 'win32':
1406
            raise TestSkipped(
1407
                'Testing drive letters in abspath implemented only for win32')
3693.2.2 by Mark Hammond
add a test for win32 abspath sematics, which as requested by lifeless,
1408
1409
        # smoke test for abspath on win32.
1410
        # a transport based on 'file:///' never fully qualifies the drive.
1411
        transport = get_transport("file:///")
1412
        self.failUnlessEqual(transport.abspath("/"), "file:///")
1413
1414
        # but a transport that starts with a drive spec must keep it.
1415
        transport = get_transport("file:///C:/")
1416
        self.failUnlessEqual(transport.abspath("/"), "file:///C:/")
1417
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
1418
    def test_local_abspath(self):
1419
        transport = self.get_transport()
1420
        try:
1421
            p = transport.local_abspath('.')
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
1422
        except (errors.NotLocalUrl, TransportNotPossible), e:
2018.18.22 by Martin Pool
merge bzr.dev
1423
            # should be formattable
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
1424
            s = str(e)
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
1425
        else:
1426
            self.assertEqual(getcwd(), p)
1427
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1428
    def test_abspath_at_root(self):
1429
        t = self.get_transport()
1430
        # clone all the way to the top
1431
        new_transport = t.clone('..')
1432
        while new_transport.base != t.base:
1433
            t = new_transport
1434
            new_transport = t.clone('..')
1435
        # we must be able to get a abspath of the root when we ask for
1436
        # t.abspath('..') - this due to our choice that clone('..')
1437
        # should return the root from the root, combined with the desire that
1438
        # the url from clone('..') and from abspath('..') should be the same.
1439
        self.assertEqual(t.base, t.abspath('..'))
1440
        # '' should give us the root
1441
        self.assertEqual(t.base, t.abspath(''))
1442
        # and a path should append to the url
1443
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
1444
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1445
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1446
        transport = self.get_transport()
1447
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1448
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1449
                              transport.iter_files_recursive)
1450
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1451
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1452
                         'isolated/dir/',
1453
                         'isolated/dir/foo',
1454
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1455
                         'isolated/dir/b%25z', # make sure quoting is correct
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1456
                         'isolated/bar'],
1457
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1458
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1459
        # nb the directories are not converted
1460
        self.assertEqual(paths,
1461
                    set(['isolated/dir/foo',
1462
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1463
                         'isolated/dir/b%2525z',
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1464
                         'isolated/bar']))
1465
        sub_transport = transport.clone('isolated')
1466
        paths = set(sub_transport.iter_files_recursive())
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1467
        self.assertEqual(paths,
1468
            set(['dir/foo', 'dir/bar', 'dir/b%2525z', 'bar']))
1469
1470
    def test_copy_tree(self):
1471
        # TODO: test file contents and permissions are preserved. This test was
1472
        # added just to ensure that quoting was handled correctly.
1473
        # -- David Allouche 2006-08-11
1474
        transport = self.get_transport()
1475
        if not transport.listable():
1476
            self.assertRaises(TransportNotPossible,
1477
                              transport.iter_files_recursive)
1478
            return
1479
        if transport.is_readonly():
1480
            return
1481
        self.build_tree(['from/',
1482
                         'from/dir/',
1483
                         'from/dir/foo',
1484
                         'from/dir/bar',
1485
                         'from/dir/b%25z', # make sure quoting is correct
1486
                         'from/bar'],
1487
                        transport=transport)
1488
        transport.copy_tree('from', 'to')
1489
        paths = set(transport.iter_files_recursive())
1490
        self.assertEqual(paths,
1491
                    set(['from/dir/foo',
1492
                         'from/dir/bar',
1493
                         'from/dir/b%2525z',
1494
                         'from/bar',
1495
                         'to/dir/foo',
1496
                         'to/dir/bar',
1497
                         'to/dir/b%2525z',
1498
                         'to/bar',]))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1499
1551.21.5 by Aaron Bentley
Implement copy_tree on copy_tree_to_transport
1500
    def test_copy_tree_to_transport(self):
1501
        transport = self.get_transport()
1502
        if not transport.listable():
1503
            self.assertRaises(TransportNotPossible,
1504
                              transport.iter_files_recursive)
1505
            return
1506
        if transport.is_readonly():
1507
            return
1508
        self.build_tree(['from/',
1509
                         'from/dir/',
1510
                         'from/dir/foo',
1511
                         'from/dir/bar',
1512
                         'from/dir/b%25z', # make sure quoting is correct
1513
                         'from/bar'],
1514
                        transport=transport)
1515
        from_transport = transport.clone('from')
1516
        to_transport = transport.clone('to')
1517
        to_transport.ensure_base()
1518
        from_transport.copy_tree_to_transport(to_transport)
1519
        paths = set(transport.iter_files_recursive())
1520
        self.assertEqual(paths,
1521
                    set(['from/dir/foo',
1522
                         'from/dir/bar',
1523
                         'from/dir/b%2525z',
1524
                         'from/bar',
1525
                         'to/dir/foo',
1526
                         'to/dir/bar',
1527
                         'to/dir/b%2525z',
1528
                         'to/bar',]))
1529
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1530
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
1531
        """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
1532
        t = self.get_transport()
1533
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
1534
        # With FAT32 and certain encodings on win32
1535
        # '\xe5' and '\xe4' actually map to the same file
1536
        # adding a suffix kicks in the 'preserving but insensitive'
1537
        # route, and maintains the right files
1538
        files = [u'\xe5.1', # a w/ circle iso-8859-1
1539
                 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
1540
                 u'\u017d', # Z with umlat iso-8859-2
1541
                 u'\u062c', # Arabic j
1542
                 u'\u0410', # Russian A
1543
                 u'\u65e5', # Kanji person
1544
                ]
1545
4935.1.2 by Vincent Ladeuil
Fixed as per jam's review.
1546
        no_unicode_support = getattr(self._server, 'no_unicode_support', False)
4935.1.1 by Vincent Ladeuil
Support Unicode paths for ftp transport (encoded as utf8).
1547
        if no_unicode_support:
4935.1.2 by Vincent Ladeuil
Fixed as per jam's review.
1548
            raise tests.KnownFailure("test server cannot handle unicode paths")
4935.1.1 by Vincent Ladeuil
Support Unicode paths for ftp transport (encoded as utf8).
1549
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1550
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
1551
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1552
        except UnicodeError:
1553
            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
1554
1555
        # A plain unicode string is not a valid url
1556
        for fname in files:
1557
            self.assertRaises(InvalidURL, t.get, fname)
1558
1559
        for fname in files:
1560
            fname_utf8 = fname.encode('utf-8')
1561
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
1562
            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
1563
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1564
    def test_connect_twice_is_same_content(self):
2485.8.21 by Vincent Ladeuil
Simplify debug.
1565
        # check that our server (whatever it is) is accessible reliably
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1566
        # via get_transport and multiple connections share content.
1567
        transport = self.get_transport()
1568
        if transport.is_readonly():
1569
            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
1570
        transport.put_bytes('foo', 'bar')
2485.8.21 by Vincent Ladeuil
Simplify debug.
1571
        transport3 = self.get_transport()
1572
        self.check_transport_contents('bar', transport3, 'foo')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1573
1574
        # now opening at a relative url should give use a sane result:
1575
        transport.mkdir('newdir')
3508.1.13 by Vincent Ladeuil
Fix last failing tests under python2.6.
1576
        transport5 = self.get_transport('newdir')
2485.8.21 by Vincent Ladeuil
Simplify debug.
1577
        transport6 = transport5.clone('..')
1578
        self.check_transport_contents('bar', transport6, 'foo')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1579
1580
    def test_lock_write(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1581
        """Test transport-level write locks.
1582
1583
        These are deprecated and transports may decline to support them.
1584
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1585
        transport = self.get_transport()
1586
        if transport.is_readonly():
1587
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
1588
            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
1589
        transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1590
        try:
1591
            lock = transport.lock_write('lock')
1752.3.6 by Andrew Bennetts
Merge from test-tweaks
1592
        except TransportNotPossible:
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1593
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1594
        # TODO make this consistent on all platforms:
1595
        # self.assertRaises(LockError, transport.lock_write, 'lock')
1596
        lock.unlock()
1597
1598
    def test_lock_read(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1599
        """Test transport-level read locks.
1600
1601
        These are deprecated and transports may decline to support them.
1602
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1603
        transport = self.get_transport()
1604
        if transport.is_readonly():
1605
            file('lock', 'w').close()
1606
        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
1607
            transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1608
        try:
1609
            lock = transport.lock_read('lock')
1752.3.6 by Andrew Bennetts
Merge from test-tweaks
1610
        except TransportNotPossible:
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1611
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1612
        # TODO make this consistent on all platforms:
1613
        # self.assertRaises(LockError, transport.lock_read, 'lock')
1614
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
1615
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
1616
    def test_readv(self):
1617
        transport = self.get_transport()
1618
        if transport.is_readonly():
1619
            file('a', 'w').write('0123456789')
1620
        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
1621
            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
1622
2004.1.22 by v.ladeuil+lp at free
Implements Range header handling for GET requests. Fix a test.
1623
        d = list(transport.readv('a', ((0, 1),)))
1624
        self.assertEqual(d[0], (0, '0'))
1625
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1626
        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.
1627
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1628
        self.assertEqual(d[1], (1, '1'))
1629
        self.assertEqual(d[2], (3, '34'))
1630
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1631
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
1632
    def test_readv_out_of_order(self):
1633
        transport = self.get_transport()
1634
        if transport.is_readonly():
1635
            file('a', 'w').write('0123456789')
1636
        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
1637
            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
1638
1639
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
1640
        self.assertEqual(d[0], (1, '1'))
1641
        self.assertEqual(d[1], (9, '9'))
1642
        self.assertEqual(d[2], (0, '0'))
1643
        self.assertEqual(d[3], (3, '34'))
1752.2.40 by Andrew Bennetts
Merge from bzr.dev.
1644
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1645
    def test_readv_with_adjust_for_latency(self):
1646
        transport = self.get_transport()
1647
        # the adjust for latency flag expands the data region returned
1648
        # according to a per-transport heuristic, so testing is a little
1649
        # tricky as we need more data than the largest combining that our
1650
        # transports do. To accomodate this we generate random data and cross
1651
        # reference the returned data with the random data. To avoid doing
1652
        # multiple large random byte look ups we do several tests on the same
1653
        # backing data.
1654
        content = osutils.rand_bytes(200*1024)
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1655
        content_size = len(content)
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1656
        if transport.is_readonly():
3693.1.2 by John Arbash Meinel
Use build_tree_contents instead of direct open().write()
1657
            self.build_tree_contents([('a', content)])
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1658
        else:
1659
            transport.put_bytes('a', content)
1660
        def check_result_data(result_vector):
1661
            for item in result_vector:
1662
                data_len = len(item[1])
1663
                self.assertEqual(content[item[0]:item[0] + data_len], item[1])
1664
1665
        # start corner case
1666
        result = list(transport.readv('a', ((0, 30),),
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1667
            adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1668
        # we expect 1 result, from 0, to something > 30
1669
        self.assertEqual(1, len(result))
1670
        self.assertEqual(0, result[0][0])
1671
        self.assertTrue(len(result[0][1]) >= 30)
1672
        check_result_data(result)
1673
        # end of file corner case
1674
        result = list(transport.readv('a', ((204700, 100),),
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1675
            adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1676
        # we expect 1 result, from 204800- its length, to the end
1677
        self.assertEqual(1, len(result))
1678
        data_len = len(result[0][1])
1679
        self.assertEqual(204800-data_len, result[0][0])
1680
        self.assertTrue(data_len >= 100)
1681
        check_result_data(result)
1682
        # out of order ranges are made in order
1683
        result = list(transport.readv('a', ((204700, 100), (0, 50)),
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1684
            adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1685
        # we expect 2 results, in order, start and end.
1686
        self.assertEqual(2, len(result))
1687
        # start
1688
        data_len = len(result[0][1])
1689
        self.assertEqual(0, result[0][0])
1690
        self.assertTrue(data_len >= 30)
1691
        # end
1692
        data_len = len(result[1][1])
1693
        self.assertEqual(204800-data_len, result[1][0])
1694
        self.assertTrue(data_len >= 100)
1695
        check_result_data(result)
1696
        # close ranges get combined (even if out of order)
1697
        for request_vector in [((400,50), (800, 234)), ((800, 234), (400,50))]:
1698
            result = list(transport.readv('a', request_vector,
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1699
                adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1700
            self.assertEqual(1, len(result))
1701
            data_len = len(result[0][1])
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1702
            # minimum length is from 400 to 1034 - 634
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1703
            self.assertTrue(data_len >= 634)
1704
            # must contain the region 400 to 1034
1705
            self.assertTrue(result[0][0] <= 400)
1706
            self.assertTrue(result[0][0] + data_len >= 1034)
1707
            check_result_data(result)
3469.1.1 by Vincent Ladeuil
Split test to achieve better defect localization :)
1708
1709
    def test_readv_with_adjust_for_latency_with_big_file(self):
1710
        transport = self.get_transport()
2890.1.2 by Robert Collins
More readv adjust for latency tests and bugfixes.
1711
        # test from observed failure case.
1712
        if transport.is_readonly():
1713
            file('a', 'w').write('a'*1024*1024)
1714
        else:
1715
            transport.put_bytes('a', 'a'*1024*1024)
1716
        broken_vector = [(465219, 800), (225221, 800), (445548, 800),
1717
            (225037, 800), (221357, 800), (437077, 800), (947670, 800),
1718
            (465373, 800), (947422, 800)]
1719
        results = list(transport.readv('a', broken_vector, True, 1024*1024))
1720
        found_items = [False]*9
1721
        for pos, (start, length) in enumerate(broken_vector):
1722
            # check the range is covered by the result
1723
            for offset, data in results:
1724
                if offset <= start and start + length <= offset + len(data):
1725
                    found_items[pos] = True
1726
        self.assertEqual([True]*9, found_items)
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1727
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
1728
    def test_get_with_open_write_stream_sees_all_content(self):
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1729
        t = self.get_transport()
1730
        if t.is_readonly():
1731
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
1732
        handle = t.open_write_stream('foo')
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1733
        try:
2671.3.6 by Robert Collins
Review feedback.
1734
            handle.write('bcd')
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1735
            self.assertEqual([(0, 'b'), (2, 'd')], list(t.readv('foo', ((0,1), (2,1)))))
1736
        finally:
2671.3.6 by Robert Collins
Review feedback.
1737
            handle.close()
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1738
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1739
    def test_get_smart_medium(self):
1740
        """All transports must either give a smart medium, or know they can't.
1741
        """
1742
        transport = self.get_transport()
1743
        try:
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1744
            client_medium = transport.get_smart_medium()
1745
            self.assertIsInstance(client_medium, medium.SmartClientMedium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1746
        except errors.NoSmartMedium:
1747
            # as long as we got it we're fine
1748
            pass
1749
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1750
    def test_readv_short_read(self):
1751
        transport = self.get_transport()
1752
        if transport.is_readonly():
1753
            file('a', 'w').write('0123456789')
1754
        else:
1755
            transport.put_bytes('a', '01234567890')
1756
1757
        # This is intentionally reading off the end of the file
1758
        # since we are sure that it cannot get there
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
1759
        self.assertListRaises((errors.ShortReadvError, errors.InvalidRange,
1760
                               # Can be raised by paramiko
1761
                               AssertionError),
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1762
                              transport.readv, 'a', [(1,1), (8,10)])
1763
1764
        # This is trying to seek past the end of the file, it should
1765
        # also raise a special error
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
1766
        self.assertListRaises((errors.ShortReadvError, errors.InvalidRange),
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1767
                              transport.readv, 'a', [(12,2)])
5349.2.3 by Martin Pool
Stat on a transport directly pointing to a symlink tells you about the symlink
1768
1769
    def test_stat_symlink(self):
1770
        # if a transport points directly to a symlink (and supports symlinks
1771
        # at all) you can tell this.  helps with bug 32669.
1772
        t = self.get_transport()
1773
        try:
1774
            t.symlink('target', 'link')
1775
        except TransportNotPossible:
1776
            raise TestSkipped("symlinks not supported")
1777
        t2 = t.clone('link')
1778
        st = t2.stat('')
1779
        self.assertTrue(stat.S_ISLNK(st.st_mode))