/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1
# Copyright (C) 2005-2011, 2015, 2016 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
23
import os
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
24
import stat
25
import sys
1530.1.3 by Robert Collins
transport implementations now tested consistently.
26
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
27
from .. import (
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
28
    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
29
    osutils,
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
30
    pyutils,
3302.9.21 by Vincent Ladeuil
bzrlib.tests.test_transport_implementations use load_tests.
31
    tests,
5609.9.1 by Martin
Blindly change all users of get_transport to address the function via the transport module
32
    transport as _mod_transport,
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
33
    urlutils,
34
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
35
from ..errors import (ConnectionError,
36
                      FileExists,
37
                      InvalidURL,
38
                      NoSuchFile,
39
                      PathError,
40
                      TransportNotPossible,
41
                      )
42
from ..osutils import getcwd
43
from ..sixish import (
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
44
    BytesIO,
6631.2.3 by Martin
Fix per_versionedfile test failures and rethink future_builtins
45
    zip,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
46
    )
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
47
from ..bzr.smart import medium
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
48
from . import (
3010.2.2 by Martin Pool
Add missing import
49
    TestSkipped,
50
    TestNotApplicable,
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
51
    multiply_tests,
3010.2.2 by Martin Pool
Add missing import
52
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
53
from . import test_server
54
from .test_transport import TestTransportImplementation
55
from ..transport import (
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
56
    ConnectedTransport,
5436.3.8 by Martin Packman
Add per_transport tests for post_connection hook showing issue with smart clients
57
    Transport,
2485.8.50 by Vincent Ladeuil
merge bzr.dev @ 2584 resolving conflicts
58
    _get_transport_modules,
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
59
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
60
from ..transport.memory import MemoryTransport
61
from ..transport.remote import RemoteTransport
1530.1.3 by Robert Collins
transport implementations now tested consistently.
62
63
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
64
def get_transport_test_permutations(module):
65
    """Get the permutations module wants to have tested."""
66
    if getattr(module, 'get_test_permutations', None) is None:
67
        raise AssertionError(
68
            "transport module %s doesn't provide get_test_permutations()"
69
            % module.__name__)
70
        return []
71
    return module.get_test_permutations()
72
73
74
def transport_test_permutations():
75
    """Return a list of the klass, server_factory pairs to test."""
76
    result = []
77
    for module in _get_transport_modules():
78
        try:
79
            permutations = get_transport_test_permutations(
5436.2.1 by Andrew Bennetts
Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.
80
                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.
81
            for (klass, server_factory) in permutations:
4725.1.1 by Vincent Ladeuil
Mention transport class name in test id.
82
                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.
83
                    {"transport_class":klass,
84
                     "transport_server":server_factory})
85
                result.append(scenario)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
86
        except errors.DependencyNotPresent as e:
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
87
            # Continue even if a dependency prevents us
88
            # from adding this test
89
            pass
90
    return result
2553.2.5 by Robert Collins
And overhaul TransportTestProviderAdapter too.
91
92
6625.1.5 by Martin
Drop custom load_tests implementation and use unittest signature
93
def load_tests(loader, standard_tests, pattern):
3302.9.21 by Vincent Ladeuil
bzrlib.tests.test_transport_implementations use load_tests.
94
    """Multiply tests for tranport implementations."""
95
    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.
96
    scenarios = transport_test_permutations()
97
    return multiply_tests(standard_tests, scenarios, result)
3302.9.21 by Vincent Ladeuil
bzrlib.tests.test_transport_implementations use load_tests.
98
2553.2.5 by Robert Collins
And overhaul TransportTestProviderAdapter too.
99
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
100
class TransportTests(TestTransportImplementation):
101
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
    def setUp(self):
103
        super(TransportTests, self).setUp()
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
104
        self.overrideEnv('BRZ_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)
105
1530.1.3 by Robert Collins
transport implementations now tested consistently.
106
    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().
107
        """Check that transport.get_bytes(relpath) == content."""
108
        self.assertEqualDiff(content, transport.get_bytes(relpath))
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
109
2475.3.2 by John Arbash Meinel
Add Transport.ensure_base()
110
    def test_ensure_base_missing(self):
111
        """.ensure_base() should create the directory if it doesn't exist"""
112
        t = self.get_transport()
113
        t_a = t.clone('a')
114
        if t_a.is_readonly():
115
            self.assertRaises(TransportNotPossible,
116
                              t_a.ensure_base)
117
            return
118
        self.assertTrue(t_a.ensure_base())
119
        self.assertTrue(t.has('a'))
120
121
    def test_ensure_base_exists(self):
122
        """.ensure_base() should just be happy if it already exists"""
123
        t = self.get_transport()
124
        if t.is_readonly():
125
            return
126
127
        t.mkdir('a')
128
        t_a = t.clone('a')
129
        # ensure_base returns False if it didn't create the base
130
        self.assertFalse(t_a.ensure_base())
131
132
    def test_ensure_base_missing_parent(self):
133
        """.ensure_base() will fail if the parent dir doesn't exist"""
134
        t = self.get_transport()
135
        if t.is_readonly():
136
            return
137
138
        t_a = t.clone('a')
139
        t_b = t_a.clone('b')
140
        self.assertRaises(NoSuchFile, t_b.ensure_base)
141
2634.1.1 by Robert Collins
(robertc) Reinstate the accidentally backed out external_url patch.
142
    def test_external_url(self):
143
        """.external_url either works or raises InProcessTransport."""
144
        t = self.get_transport()
145
        try:
146
            t.external_url()
147
        except errors.InProcessTransport:
148
            pass
149
1530.1.3 by Robert Collins
transport implementations now tested consistently.
150
    def test_has(self):
151
        t = self.get_transport()
152
153
        files = ['a', 'b', 'e', 'g', '%']
154
        self.build_tree(files, transport=t)
155
        self.assertEqual(True, t.has('a'))
156
        self.assertEqual(False, t.has('c'))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
157
        self.assertEqual(True, t.has(urlutils.escape('%')))
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
158
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd',
159
                                           'e', 'f', 'g', 'h'])),
160
                         [True, True, False, False,
161
                          True, False, True, False])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
162
        self.assertEqual(True, t.has_any(['a', 'b', 'c']))
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
163
        self.assertEqual(False, t.has_any(['c', 'd', 'f',
164
                                           urlutils.escape('%%')]))
165
        self.assertEqual(list(t.has_multi(iter(['a', 'b', 'c', 'd',
166
                                                'e', 'f', 'g', 'h']))),
167
                         [True, True, False, False,
168
                          True, False, True, False])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
169
        self.assertEqual(False, t.has_any(['c', 'c', 'c']))
170
        self.assertEqual(True, t.has_any(['b', 'b', 'b']))
171
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
172
    def test_has_root_works(self):
5017.3.21 by Vincent Ladeuil
selftest -s bt.per_transport passing
173
        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.
174
            raise TestNotApplicable(
175
                "SmartTCPServer_for_testing intentionally does not allow "
176
                "access to /.")
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
177
        current_transport = self.get_transport()
178
        self.assertTrue(current_transport.has('/'))
179
        root = current_transport.clone('/')
180
        self.assertTrue(root.has(''))
181
1530.1.3 by Robert Collins
transport implementations now tested consistently.
182
    def test_get(self):
183
        t = self.get_transport()
184
185
        files = ['a', 'b', 'e', 'g']
186
        contents = ['contents of a\n',
187
                    'contents of b\n',
188
                    'contents of e\n',
189
                    'contents of g\n',
190
                    ]
1551.2.39 by abentley
Fix line endings in tests
191
        self.build_tree(files, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
192
        self.check_transport_contents('contents of a\n', t, 'a')
193
        content_f = t.get_multi(files)
6631.2.3 by Martin
Fix per_versionedfile test failures and rethink future_builtins
194
        # Must use iter zip() from future not old version which will fully
195
        # evaluate its inputs, the transport requests should be issued and
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
196
        # handled sequentially (we don't want to force transport to buffer).
6631.2.2 by Martin
Run 2to3 itertools fixer and refactor
197
        for content, f in zip(contents, content_f):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
198
            self.assertEqual(content, f.read())
199
200
        content_f = t.get_multi(iter(files))
6631.2.3 by Martin
Fix per_versionedfile test failures and rethink future_builtins
201
        # Again this zip() must come from the future
6631.2.2 by Martin
Run 2to3 itertools fixer and refactor
202
        for content, f in zip(contents, content_f):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
203
            self.assertEqual(content, f.read())
204
4512.1.1 by Vincent Ladeuil
Fix bug #383920 by inserting the missing Content-Length header.
205
    def test_get_unknown_file(self):
206
        t = self.get_transport()
207
        files = ['a', 'b']
208
        contents = ['contents of a\n',
209
                    'contents of b\n',
210
                    ]
211
        self.build_tree(files, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
212
        self.assertRaises(NoSuchFile, t.get, 'c')
5807.5.1 by John Arbash Meinel
Fix bug #767177. Be more agressive with file.close() calls.
213
        def iterate_and_close(func, *args):
214
            for f in func(*args):
215
                # We call f.read() here because things like paramiko actually
216
                # spawn a thread to prefetch the content, which we want to
217
                # consume before we close the handle.
218
                content = f.read()
219
                f.close()
220
        self.assertRaises(NoSuchFile, iterate_and_close,
221
                          t.get_multi, ['a', 'b', 'c'])
222
        self.assertRaises(NoSuchFile, iterate_and_close,
223
                          t.get_multi, iter(['a', 'b', 'c']))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
224
2052.6.2 by Robert Collins
Merge bzr.dev.
225
    def test_get_directory_read_gives_ReadError(self):
226
        """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.
227
        t = self.get_transport()
228
        if t.is_readonly():
229
            self.build_tree(['a directory/'])
230
        else:
231
            t.mkdir('a%20directory')
232
        # getting the file must either work or fail with a PathError
233
        try:
234
            a_file = t.get('a%20directory')
2052.6.2 by Robert Collins
Merge bzr.dev.
235
        except (errors.PathError, errors.RedirectRequested):
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
236
            # early failure return immediately.
237
            return
3111.1.23 by Vincent Ladeuil
Make HTTP/1.1 the default implementation reveals one more bug.
238
        # having got a file, read() must either work (i.e. http reading a dir
239
        # listing) or fail with ReadError
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
240
        try:
241
            a_file.read()
242
        except errors.ReadError:
243
            pass
244
1955.3.3 by John Arbash Meinel
Implement and test 'get_bytes'
245
    def test_get_bytes(self):
246
        t = self.get_transport()
247
248
        files = ['a', 'b', 'e', 'g']
249
        contents = ['contents of a\n',
250
                    'contents of b\n',
251
                    'contents of e\n',
252
                    'contents of g\n',
253
                    ]
254
        self.build_tree(files, transport=t, line_endings='binary')
255
        self.check_transport_contents('contents of a\n', t, 'a')
256
257
        for content, fname in zip(contents, files):
258
            self.assertEqual(content, t.get_bytes(fname))
259
4512.1.1 by Vincent Ladeuil
Fix bug #383920 by inserting the missing Content-Length header.
260
    def test_get_bytes_unknown_file(self):
261
        t = self.get_transport()
1955.3.3 by John Arbash Meinel
Implement and test 'get_bytes'
262
        self.assertRaises(NoSuchFile, t.get_bytes, 'c')
263
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
264
    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.
265
        t = self.get_transport()
266
        if t.is_readonly():
267
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
268
        handle = t.open_write_stream('foo')
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
269
        try:
2671.3.6 by Robert Collins
Review feedback.
270
            handle.write('b')
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
271
            self.assertEqual('b', t.get_bytes('foo'))
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
272
        finally:
2671.3.6 by Robert Collins
Review feedback.
273
            handle.close()
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
274
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
275
    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.
276
        t = self.get_transport()
277
        if t.is_readonly():
278
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
279
        handle = t.open_write_stream('foo')
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
280
        try:
2671.3.6 by Robert Collins
Review feedback.
281
            handle.write('b')
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
282
            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().
283
            f = t.get('foo')
284
            try:
285
                self.assertEqual('b', f.read())
286
            finally:
287
                f.close()
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
288
        finally:
2671.3.6 by Robert Collins
Review feedback.
289
            handle.close()
2671.3.4 by Robert Collins
Sync up with open file streams on get/get_bytes.
290
1955.3.1 by John Arbash Meinel
Add put_bytes() and a base-level implementation for it
291
    def test_put_bytes(self):
292
        t = self.get_transport()
293
294
        if t.is_readonly():
295
            self.assertRaises(TransportNotPossible,
296
                    t.put_bytes, 'a', 'some text for a\n')
297
            return
298
299
        t.put_bytes('a', 'some text for a\n')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
300
        self.assertTrue(t.has('a'))
1955.3.1 by John Arbash Meinel
Add put_bytes() and a base-level implementation for it
301
        self.check_transport_contents('some text for a\n', t, 'a')
302
303
        # The contents should be overwritten
304
        t.put_bytes('a', 'new text for a\n')
305
        self.check_transport_contents('new text for a\n', t, 'a')
306
307
        self.assertRaises(NoSuchFile,
308
                          t.put_bytes, 'path/doesnt/exist/c', 'contents')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
309
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
310
    def test_put_bytes_non_atomic(self):
311
        t = self.get_transport()
312
313
        if t.is_readonly():
314
            self.assertRaises(TransportNotPossible,
315
                    t.put_bytes_non_atomic, 'a', 'some text for a\n')
316
            return
317
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
318
        self.assertFalse(t.has('a'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
319
        t.put_bytes_non_atomic('a', 'some text for a\n')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
320
        self.assertTrue(t.has('a'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
321
        self.check_transport_contents('some text for a\n', t, 'a')
322
        # Put also replaces contents
323
        t.put_bytes_non_atomic('a', 'new\ncontents for\na\n')
324
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
325
326
        # Make sure we can create another file
327
        t.put_bytes_non_atomic('d', 'contents for\nd\n')
328
        # And overwrite 'a' with empty contents
329
        t.put_bytes_non_atomic('a', '')
330
        self.check_transport_contents('contents for\nd\n', t, 'd')
331
        self.check_transport_contents('', t, 'a')
332
333
        self.assertRaises(NoSuchFile, t.put_bytes_non_atomic, 'no/such/path',
334
                                       'contents\n')
335
        # Now test the create_parent flag
336
        self.assertRaises(NoSuchFile, t.put_bytes_non_atomic, 'dir/a',
337
                                       'contents\n')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
338
        self.assertFalse(t.has('dir/a'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
339
        t.put_bytes_non_atomic('dir/a', 'contents for dir/a\n',
340
                               create_parent_dir=True)
341
        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
342
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
343
        # But we still get NoSuchFile if we can't make the parent dir
344
        self.assertRaises(NoSuchFile, t.put_bytes_non_atomic, 'not/there/a',
345
                                       'contents\n',
346
                                       create_parent_dir=True)
347
348
    def test_put_bytes_permissions(self):
349
        t = self.get_transport()
350
351
        if t.is_readonly():
352
            return
353
        if not t._can_roundtrip_unix_modebits():
354
            # Can't roundtrip, so no need to run this test
355
            return
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
356
        t.put_bytes('mode644', 'test text\n', mode=0o644)
357
        self.assertTransportMode(t, 'mode644', 0o644)
358
        t.put_bytes('mode666', 'test text\n', mode=0o666)
359
        self.assertTransportMode(t, 'mode666', 0o666)
360
        t.put_bytes('mode600', 'test text\n', mode=0o600)
361
        self.assertTransportMode(t, 'mode600', 0o600)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
362
        # Yes, you can put_bytes a file such that it becomes readonly
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
363
        t.put_bytes('mode400', 'test text\n', mode=0o400)
364
        self.assertTransportMode(t, 'mode400', 0o400)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
365
366
        # The default permissions should be based on the current umask
367
        umask = osutils.get_umask()
368
        t.put_bytes('nomode', 'test text\n', mode=None)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
369
        self.assertTransportMode(t, 'nomode', 0o666 & ~umask)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
370
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
371
    def test_put_bytes_non_atomic_permissions(self):
372
        t = self.get_transport()
373
374
        if t.is_readonly():
375
            return
376
        if not t._can_roundtrip_unix_modebits():
377
            # Can't roundtrip, so no need to run this test
378
            return
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
379
        t.put_bytes_non_atomic('mode644', 'test text\n', mode=0o644)
380
        self.assertTransportMode(t, 'mode644', 0o644)
381
        t.put_bytes_non_atomic('mode666', 'test text\n', mode=0o666)
382
        self.assertTransportMode(t, 'mode666', 0o666)
383
        t.put_bytes_non_atomic('mode600', 'test text\n', mode=0o600)
384
        self.assertTransportMode(t, 'mode600', 0o600)
385
        t.put_bytes_non_atomic('mode400', 'test text\n', mode=0o400)
386
        self.assertTransportMode(t, 'mode400', 0o400)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
387
388
        # The default permissions should be based on the current umask
389
        umask = osutils.get_umask()
390
        t.put_bytes_non_atomic('nomode', 'test text\n', mode=None)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
391
        self.assertTransportMode(t, 'nomode', 0o666 & ~umask)
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
392
393
        # We should also be able to set the mode for a parent directory
394
        # when it is created
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
395
        t.put_bytes_non_atomic('dir700/mode664', 'test text\n', mode=0o664,
396
                               dir_mode=0o700, create_parent_dir=True)
397
        self.assertTransportMode(t, 'dir700', 0o700)
398
        t.put_bytes_non_atomic('dir770/mode664', 'test text\n', mode=0o664,
399
                               dir_mode=0o770, create_parent_dir=True)
400
        self.assertTransportMode(t, 'dir770', 0o770)
401
        t.put_bytes_non_atomic('dir777/mode664', 'test text\n', mode=0o664,
402
                               dir_mode=0o777, create_parent_dir=True)
403
        self.assertTransportMode(t, 'dir777', 0o777)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
404
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
405
    def test_put_file(self):
406
        t = self.get_transport()
407
408
        if t.is_readonly():
409
            self.assertRaises(TransportNotPossible,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
410
                    t.put_file, 'a', BytesIO(b'some text for a\n'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
411
            return
412
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
413
        result = t.put_file('a', BytesIO(b'some text for a\n'))
2745.5.2 by Robert Collins
* ``bzrlib.transport.Transport.put_file`` now returns the number of bytes
414
        # put_file returns the length of the data written
415
        self.assertEqual(16, result)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
416
        self.assertTrue(t.has('a'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
417
        self.check_transport_contents('some text for a\n', t, 'a')
418
        # Put also replaces contents
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
419
        result = t.put_file('a', BytesIO(b'new\ncontents for\na\n'))
2745.5.2 by Robert Collins
* ``bzrlib.transport.Transport.put_file`` now returns the number of bytes
420
        self.assertEqual(19, result)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
421
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
422
        self.assertRaises(NoSuchFile,
423
                          t.put_file, 'path/doesnt/exist/c',
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
424
                              BytesIO(b'contents'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
425
426
    def test_put_file_non_atomic(self):
427
        t = self.get_transport()
428
429
        if t.is_readonly():
430
            self.assertRaises(TransportNotPossible,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
431
                    t.put_file_non_atomic, 'a', BytesIO(b'some text for a\n'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
432
            return
433
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
434
        self.assertFalse(t.has('a'))
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
435
        t.put_file_non_atomic('a', BytesIO(b'some text for a\n'))
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
436
        self.assertTrue(t.has('a'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
437
        self.check_transport_contents('some text for a\n', t, 'a')
438
        # Put also replaces contents
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
439
        t.put_file_non_atomic('a', BytesIO(b'new\ncontents for\na\n'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
440
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
441
442
        # Make sure we can create another file
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
443
        t.put_file_non_atomic('d', BytesIO(b'contents for\nd\n'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
444
        # And overwrite 'a' with empty contents
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
445
        t.put_file_non_atomic('a', BytesIO(b''))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
446
        self.check_transport_contents('contents for\nd\n', t, 'd')
447
        self.check_transport_contents('', t, 'a')
448
449
        self.assertRaises(NoSuchFile, t.put_file_non_atomic, 'no/such/path',
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
450
                                       BytesIO(b'contents\n'))
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
451
        # Now test the create_parent flag
452
        self.assertRaises(NoSuchFile, t.put_file_non_atomic, 'dir/a',
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
453
                                       BytesIO(b'contents\n'))
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
454
        self.assertFalse(t.has('dir/a'))
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
455
        t.put_file_non_atomic('dir/a', BytesIO(b'contents for dir/a\n'),
1955.3.20 by John Arbash Meinel
Add non_atomic_put_bytes() and tests for it
456
                              create_parent_dir=True)
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
457
        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
458
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
459
        # 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
460
        self.assertRaises(NoSuchFile, t.put_file_non_atomic, 'not/there/a',
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
461
                                       BytesIO(b'contents\n'),
1955.3.20 by John Arbash Meinel
Add non_atomic_put_bytes() and tests for it
462
                                       create_parent_dir=True)
463
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
464
    def test_put_file_permissions(self):
1955.3.18 by John Arbash Meinel
[merge] Transport.non_atomic_put()
465
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
466
        t = self.get_transport()
467
468
        if t.is_readonly():
469
            return
1711.4.32 by John Arbash Meinel
Skip permission tests on win32 no modebits
470
        if not t._can_roundtrip_unix_modebits():
471
            # Can't roundtrip, so no need to run this test
472
            return
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
473
        t.put_file('mode644', BytesIO(b'test text\n'), mode=0o644)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
474
        self.assertTransportMode(t, 'mode644', 0o644)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
475
        t.put_file('mode666', BytesIO(b'test text\n'), mode=0o666)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
476
        self.assertTransportMode(t, 'mode666', 0o666)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
477
        t.put_file('mode600', BytesIO(b'test text\n'), mode=0o600)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
478
        self.assertTransportMode(t, 'mode600', 0o600)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
479
        # Yes, you can put a file such that it becomes readonly
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
480
        t.put_file('mode400', BytesIO(b'test text\n'), mode=0o400)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
481
        self.assertTransportMode(t, 'mode400', 0o400)
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
482
        # The default permissions should be based on the current umask
483
        umask = osutils.get_umask()
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
484
        t.put_file('nomode', BytesIO(b'test text\n'), mode=None)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
485
        self.assertTransportMode(t, 'nomode', 0o666 & ~umask)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
486
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
487
    def test_put_file_non_atomic_permissions(self):
488
        t = self.get_transport()
489
490
        if t.is_readonly():
491
            return
492
        if not t._can_roundtrip_unix_modebits():
493
            # Can't roundtrip, so no need to run this test
494
            return
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
495
        t.put_file_non_atomic('mode644', BytesIO(b'test text\n'), mode=0o644)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
496
        self.assertTransportMode(t, 'mode644', 0o644)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
497
        t.put_file_non_atomic('mode666', BytesIO(b'test text\n'), mode=0o666)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
498
        self.assertTransportMode(t, 'mode666', 0o666)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
499
        t.put_file_non_atomic('mode600', BytesIO(b'test text\n'), mode=0o600)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
500
        self.assertTransportMode(t, 'mode600', 0o600)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
501
        # Yes, you can put_file_non_atomic a file such that it becomes readonly
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
502
        t.put_file_non_atomic('mode400', BytesIO(b'test text\n'), mode=0o400)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
503
        self.assertTransportMode(t, 'mode400', 0o400)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
504
505
        # The default permissions should be based on the current umask
506
        umask = osutils.get_umask()
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
507
        t.put_file_non_atomic('nomode', BytesIO(b'test text\n'), mode=None)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
508
        self.assertTransportMode(t, 'nomode', 0o666 & ~umask)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
509
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
510
        # We should also be able to set the mode for a parent directory
511
        # when it is created
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
512
        sio = BytesIO()
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
513
        t.put_file_non_atomic('dir700/mode664', sio, mode=0o664,
514
                              dir_mode=0o700, create_parent_dir=True)
515
        self.assertTransportMode(t, 'dir700', 0o700)
516
        t.put_file_non_atomic('dir770/mode664', sio, mode=0o664,
517
                              dir_mode=0o770, create_parent_dir=True)
518
        self.assertTransportMode(t, 'dir770', 0o770)
519
        t.put_file_non_atomic('dir777/mode664', sio, mode=0o664,
520
                              dir_mode=0o777, create_parent_dir=True)
521
        self.assertTransportMode(t, 'dir777', 0o777)
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
522
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.
523
    def test_put_bytes_unicode(self):
524
        t = self.get_transport()
525
        if t.is_readonly():
526
            return
527
        unicode_string = u'\u1234'
6609.2.1 by Vincent Ladeuil
Make all transport put_bytes() raises TypeError when given unicode strings rather than bytes.
528
        self.assertRaises(TypeError, t.put_bytes, 'foo', unicode_string)
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.
529
1530.1.3 by Robert Collins
transport implementations now tested consistently.
530
    def test_mkdir(self):
531
        t = self.get_transport()
532
533
        if t.is_readonly():
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
534
            # cannot mkdir on readonly transports. We're not testing for
1530.1.3 by Robert Collins
transport implementations now tested consistently.
535
            # cache coherency because cache behaviour is not currently
536
            # defined for the transport interface.
537
            self.assertRaises(TransportNotPossible, t.mkdir, '.')
538
            self.assertRaises(TransportNotPossible, t.mkdir, 'new_dir')
539
            self.assertRaises(TransportNotPossible, t.mkdir_multi, ['new_dir'])
540
            self.assertRaises(TransportNotPossible, t.mkdir, 'path/doesnt/exist')
541
            return
542
        # Test mkdir
543
        t.mkdir('dir_a')
544
        self.assertEqual(t.has('dir_a'), True)
545
        self.assertEqual(t.has('dir_b'), False)
546
547
        t.mkdir('dir_b')
548
        self.assertEqual(t.has('dir_b'), True)
549
550
        t.mkdir_multi(['dir_c', 'dir_d'])
551
552
        t.mkdir_multi(iter(['dir_e', 'dir_f']))
553
        self.assertEqual(list(t.has_multi(
554
            ['dir_a', 'dir_b', 'dir_c', 'dir_q',
555
             'dir_d', 'dir_e', 'dir_f', 'dir_b'])),
556
            [True, True, True, False,
557
             True, True, True, True])
558
559
        # we were testing that a local mkdir followed by a transport
560
        # 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
561
        # concurrently fiddle with disk dirs and then use transport to do
1530.1.3 by Robert Collins
transport implementations now tested consistently.
562
        # things, the win here seems marginal compared to the constraint on
563
        # the interface. RBC 20051227
564
        t.mkdir('dir_g')
565
        self.assertRaises(FileExists, t.mkdir, 'dir_g')
566
567
        # 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
568
        t.put_bytes('dir_a/a', 'contents of dir_a/a')
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
569
        t.put_file('dir_b/b', BytesIO(b'contents of dir_b/b'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
570
        self.check_transport_contents('contents of dir_a/a', t, 'dir_a/a')
571
        self.check_transport_contents('contents of dir_b/b', t, 'dir_b/b')
572
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
573
        # mkdir of a dir with an absent parent
574
        self.assertRaises(NoSuchFile, t.mkdir, 'missing/dir')
575
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
576
    def test_mkdir_permissions(self):
577
        t = self.get_transport()
578
        if t.is_readonly():
579
            return
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
580
        if not t._can_roundtrip_unix_modebits():
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
581
            # no sense testing on this transport
582
            return
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
583
        # Test mkdir with a mode
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
584
        t.mkdir('dmode755', mode=0o755)
585
        self.assertTransportMode(t, 'dmode755', 0o755)
586
        t.mkdir('dmode555', mode=0o555)
587
        self.assertTransportMode(t, 'dmode555', 0o555)
588
        t.mkdir('dmode777', mode=0o777)
589
        self.assertTransportMode(t, 'dmode777', 0o777)
590
        t.mkdir('dmode700', mode=0o700)
591
        self.assertTransportMode(t, 'dmode700', 0o700)
592
        t.mkdir_multi(['mdmode755'], mode=0o755)
593
        self.assertTransportMode(t, 'mdmode755', 0o755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
594
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
595
        # Default mode should be based on umask
596
        umask = osutils.get_umask()
597
        t.mkdir('dnomode', mode=None)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
598
        self.assertTransportMode(t, 'dnomode', 0o777 & ~umask)
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
599
2671.3.2 by Robert Collins
Start open_file_stream logic.
600
    def test_opening_a_file_stream_creates_file(self):
601
        t = self.get_transport()
602
        if t.is_readonly():
603
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
604
        handle = t.open_write_stream('foo')
2671.3.2 by Robert Collins
Start open_file_stream logic.
605
        try:
606
            self.assertEqual('', t.get_bytes('foo'))
607
        finally:
2671.3.6 by Robert Collins
Review feedback.
608
            handle.close()
2671.3.2 by Robert Collins
Start open_file_stream logic.
609
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
610
    def test_opening_a_file_stream_can_set_mode(self):
611
        t = self.get_transport()
612
        if t.is_readonly():
6606.3.1 by Vincent Ladeuil
Add rename() and open_write_stream() as explicitly not supported via the ReadonlyTransportDecorator to give better feedback when a decorated transport is misused
613
            self.assertRaises((TransportNotPossible, NotImplementedError),
614
                              t.open_write_stream, 'foo')
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
615
            return
616
        if not t._can_roundtrip_unix_modebits():
617
            # Can't roundtrip, so no need to run this test
618
            return
6606.3.1 by Vincent Ladeuil
Add rename() and open_write_stream() as explicitly not supported via the ReadonlyTransportDecorator to give better feedback when a decorated transport is misused
619
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
620
        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.
621
            handle = t.open_write_stream(name, mode=mode)
2671.3.6 by Robert Collins
Review feedback.
622
            handle.close()
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
623
            self.assertTransportMode(t, name, expected)
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
624
        check_mode('mode644', 0o644, 0o644)
625
        check_mode('mode666', 0o666, 0o666)
626
        check_mode('mode600', 0o600, 0o600)
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
627
        # The default permissions should be based on the current umask
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
628
        check_mode('nomode', None, 0o666 & ~osutils.get_umask())
2671.3.3 by Robert Collins
Add mode parameter to Transport.open_file_stream.
629
1530.1.3 by Robert Collins
transport implementations now tested consistently.
630
    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.
631
        # FIXME: test:   same server to same server (partly done)
632
        # same protocol two servers
633
        # and    different protocols (done for now except for MemoryTransport.
634
        # - RBC 20060122
635
636
        def simple_copy_files(transport_from, transport_to):
637
            files = ['a', 'b', 'c', 'd']
638
            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.
639
            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.
640
            for f in files:
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
641
                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.
642
                                              transport_from, f)
643
1530.1.3 by Robert Collins
transport implementations now tested consistently.
644
        t = self.get_transport()
6658.3.1 by Martin
Skip test_copy_to on SFTPTransport due to unreliablity
645
        if t.__class__.__name__ == "SFTPTransport":
646
            self.skipTest("SFTP copy_to currently too flakey to use")
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
647
        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.
648
        simple_copy_files(t, temp_transport)
649
        if not t.is_readonly():
650
            t.mkdir('copy_to_simple')
651
            t2 = t.clone('copy_to_simple')
652
            simple_copy_files(t, t2)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
653
654
655
        # Test that copying into a missing directory raises
656
        # NoSuchFile
657
        if t.is_readonly():
1530.1.21 by Robert Collins
Review feedback fixes.
658
            self.build_tree(['e/', 'e/f'])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
659
        else:
660
            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
661
            t.put_bytes('e/f', 'contents of e')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
662
        self.assertRaises(NoSuchFile, t.copy_to, ['e/f'], temp_transport)
663
        temp_transport.mkdir('e')
664
        t.copy_to(['e/f'], temp_transport)
665
666
        del temp_transport
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
667
        temp_transport = MemoryTransport('memory:///')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
668
669
        files = ['a', 'b', 'c', 'd']
670
        t.copy_to(iter(files), temp_transport)
671
        for f in files:
5602.1.1 by John Arbash Meinel
Change the per_transport tests to use .get_bytes() instead of .get().read().
672
            self.check_transport_contents(temp_transport.get_bytes(f),
1530.1.3 by Robert Collins
transport implementations now tested consistently.
673
                                          t, f)
674
        del temp_transport
675
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
676
        for mode in (0o666, 0o644, 0o600, 0o400):
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
677
            temp_transport = MemoryTransport("memory:///")
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
678
            t.copy_to(files, temp_transport, mode=mode)
679
            for f in files:
1530.1.21 by Robert Collins
Review feedback fixes.
680
                self.assertTransportMode(temp_transport, f, mode)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
681
4294.2.1 by Robert Collins
Move directory checking for bzr push options into Branch.create_clone_on_transport.
682
    def test_create_prefix(self):
683
        t = self.get_transport()
684
        sub = t.clone('foo').clone('bar')
685
        try:
686
            sub.create_prefix()
687
        except TransportNotPossible:
688
            self.assertTrue(t.is_readonly())
689
        else:
690
            self.assertTrue(t.has('foo/bar'))
691
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
692
    def test_append_file(self):
693
        t = self.get_transport()
694
695
        if t.is_readonly():
1530.1.3 by Robert Collins
transport implementations now tested consistently.
696
            self.assertRaises(TransportNotPossible,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
697
                    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
698
            return
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
699
        t.put_bytes('a', 'diff\ncontents for\na\n')
700
        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
701
702
        self.assertEqual(20,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
703
            t.append_file('a', BytesIO(b'add\nsome\nmore\ncontents\n')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
704
705
        self.check_transport_contents(
706
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
707
            t, 'a')
708
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
709
        # a file with no parent should fail..
710
        self.assertRaises(NoSuchFile,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
711
                          t.append_file, 'missing/path', BytesIO(b'content'))
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
712
713
        # And we can create new files, too
714
        self.assertEqual(0,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
715
            t.append_file('c', BytesIO(b'some text\nfor a missing file\n')))
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
716
        self.check_transport_contents('some text\nfor a missing file\n',
717
                                      t, 'c')
718
719
    def test_append_bytes(self):
720
        t = self.get_transport()
721
722
        if t.is_readonly():
723
            self.assertRaises(TransportNotPossible,
724
                    t.append_bytes, 'a', 'add\nsome\nmore\ncontents\n')
725
            return
726
727
        self.assertEqual(0, t.append_bytes('a', 'diff\ncontents for\na\n'))
728
        self.assertEqual(0, t.append_bytes('b', 'contents\nfor b\n'))
729
730
        self.assertEqual(20,
731
            t.append_bytes('a', 'add\nsome\nmore\ncontents\n'))
732
733
        self.check_transport_contents(
734
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
735
            t, 'a')
736
737
        # a file with no parent should fail..
738
        self.assertRaises(NoSuchFile,
739
                          t.append_bytes, 'missing/path', 'content')
740
741
    def test_append_multi(self):
742
        t = self.get_transport()
743
744
        if t.is_readonly():
745
            return
746
        t.put_bytes('a', 'diff\ncontents for\na\n'
747
                         'add\nsome\nmore\ncontents\n')
748
        t.put_bytes('b', 'contents\nfor b\n')
749
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
750
        self.assertEqual((43, 15),
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
751
            t.append_multi([('a', BytesIO(b'and\nthen\nsome\nmore\n')),
752
                            ('b', BytesIO(b'some\nmore\nfor\nb\n'))]))
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
753
1530.1.3 by Robert Collins
transport implementations now tested consistently.
754
        self.check_transport_contents(
755
            'diff\ncontents for\na\n'
756
            'add\nsome\nmore\ncontents\n'
757
            'and\nthen\nsome\nmore\n',
758
            t, 'a')
759
        self.check_transport_contents(
760
                'contents\nfor b\n'
761
                'some\nmore\nfor\nb\n',
762
                t, 'b')
763
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
764
        self.assertEqual((62, 31),
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
765
            t.append_multi(iter([('a', BytesIO(b'a little bit more\n')),
766
                                 ('b', BytesIO(b'from an iterator\n'))])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
767
        self.check_transport_contents(
768
            'diff\ncontents for\na\n'
769
            'add\nsome\nmore\ncontents\n'
770
            'and\nthen\nsome\nmore\n'
771
            'a little bit more\n',
772
            t, 'a')
773
        self.check_transport_contents(
774
                'contents\nfor b\n'
775
                'some\nmore\nfor\nb\n'
776
                'from an iterator\n',
777
                t, 'b')
778
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
779
        self.assertEqual((80, 0),
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
780
            t.append_multi([('a', BytesIO(b'some text in a\n')),
781
                            ('d', BytesIO(b'missing file r\n'))]))
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
782
1530.1.3 by Robert Collins
transport implementations now tested consistently.
783
        self.check_transport_contents(
784
            'diff\ncontents for\na\n'
785
            'add\nsome\nmore\ncontents\n'
786
            'and\nthen\nsome\nmore\n'
787
            'a little bit more\n'
788
            'some text in a\n',
789
            t, 'a')
790
        self.check_transport_contents('missing file r\n', t, 'd')
791
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
792
    def test_append_file_mode(self):
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
793
        """Check that append accepts a mode parameter"""
1666.1.6 by Robert Collins
Make knit the default format.
794
        # check append accepts a mode
795
        t = self.get_transport()
796
        if t.is_readonly():
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
797
            self.assertRaises(TransportNotPossible,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
798
                t.append_file, 'f', BytesIO(b'f'), mode=None)
1666.1.6 by Robert Collins
Make knit the default format.
799
            return
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
800
        t.append_file('f', BytesIO(b'f'), mode=None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
801
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
802
    def test_append_bytes_mode(self):
803
        # check append_bytes accepts a mode
804
        t = self.get_transport()
805
        if t.is_readonly():
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
806
            self.assertRaises(TransportNotPossible,
807
                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
808
            return
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
809
        t.append_bytes('f', 'f', mode=None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
810
1530.1.3 by Robert Collins
transport implementations now tested consistently.
811
    def test_delete(self):
812
        # TODO: Test Transport.delete
813
        t = self.get_transport()
814
815
        # Not much to do with a readonly transport
816
        if t.is_readonly():
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
817
            self.assertRaises(TransportNotPossible, t.delete, 'missing')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
818
            return
819
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
820
        t.put_bytes('a', 'a little bit of text\n')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
821
        self.assertTrue(t.has('a'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
822
        t.delete('a')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
823
        self.assertFalse(t.has('a'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
824
825
        self.assertRaises(NoSuchFile, t.delete, 'a')
826
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
827
        t.put_bytes('a', 'a text\n')
828
        t.put_bytes('b', 'b text\n')
829
        t.put_bytes('c', 'c text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
830
        self.assertEqual([True, True, True],
831
                list(t.has_multi(['a', 'b', 'c'])))
832
        t.delete_multi(['a', 'c'])
833
        self.assertEqual([False, True, False],
834
                list(t.has_multi(['a', 'b', 'c'])))
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
835
        self.assertFalse(t.has('a'))
836
        self.assertTrue(t.has('b'))
837
        self.assertFalse(t.has('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
838
839
        self.assertRaises(NoSuchFile,
840
                t.delete_multi, ['a', 'b', 'c'])
841
842
        self.assertRaises(NoSuchFile,
843
                t.delete_multi, iter(['a', 'b', 'c']))
844
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
845
        t.put_bytes('a', 'another a text\n')
846
        t.put_bytes('c', 'another c text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
847
        t.delete_multi(iter(['a', 'b', 'c']))
848
849
        # We should have deleted everything
850
        # SftpServer creates control files in the
851
        # working directory, so we can just do a
852
        # plain "listdir".
853
        # self.assertEqual([], os.listdir('.'))
854
2671.3.1 by Robert Collins
* New method ``bzrlib.transport.Transport.get_recommended_page_size``.
855
    def test_recommended_page_size(self):
856
        """Transports recommend a page size for partial access to files."""
857
        t = self.get_transport()
858
        self.assertIsInstance(t.recommended_page_size(), int)
859
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
860
    def test_rmdir(self):
861
        t = self.get_transport()
862
        # Not much to do with a readonly transport
863
        if t.is_readonly():
864
            self.assertRaises(TransportNotPossible, t.rmdir, 'missing')
865
            return
866
        t.mkdir('adir')
867
        t.mkdir('adir/bdir')
868
        t.rmdir('adir/bdir')
1948.3.12 by Vincent LADEUIL
Fix Aaron's third review remarks.
869
        # ftp may not be able to raise NoSuchFile for lack of
870
        # details when failing
871
        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.
872
        t.rmdir('adir')
1948.3.12 by Vincent LADEUIL
Fix Aaron's third review remarks.
873
        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.
874
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
875
    def test_rmdir_not_empty(self):
876
        """Deleting a non-empty directory raises an exception
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
877
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
878
        sftp (and possibly others) don't give us a specific "directory not
879
        empty" exception -- we can just see that the operation failed.
880
        """
881
        t = self.get_transport()
882
        if t.is_readonly():
883
            return
884
        t.mkdir('adir')
885
        t.mkdir('adir/bdir')
886
        self.assertRaises(PathError, t.rmdir, 'adir')
887
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
888
    def test_rmdir_empty_but_similar_prefix(self):
889
        """rmdir does not get confused by sibling paths.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
890
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
891
        A naive implementation of MemoryTransport would refuse to rmdir
892
        ".bzr/branch" if there is a ".bzr/branch-format" directory, because it
893
        uses "path.startswith(dir)" on all file paths to determine if directory
894
        is empty.
895
        """
896
        t = self.get_transport()
897
        if t.is_readonly():
898
            return
899
        t.mkdir('foo')
900
        t.put_bytes('foo-bar', '')
901
        t.mkdir('foo-baz')
902
        t.rmdir('foo')
903
        self.assertRaises((NoSuchFile, PathError), t.rmdir, 'foo')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
904
        self.assertTrue(t.has('foo-bar'))
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
905
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
906
    def test_rename_dir_succeeds(self):
907
        t = self.get_transport()
908
        if t.is_readonly():
6606.3.1 by Vincent Ladeuil
Add rename() and open_write_stream() as explicitly not supported via the ReadonlyTransportDecorator to give better feedback when a decorated transport is misused
909
            self.assertRaises((TransportNotPossible, NotImplementedError),
910
                              t.rename, 'foo', 'bar')
911
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
912
        t.mkdir('adir')
913
        t.mkdir('adir/asubdir')
914
        t.rename('adir', 'bdir')
915
        self.assertTrue(t.has('bdir/asubdir'))
916
        self.assertFalse(t.has('adir'))
917
918
    def test_rename_dir_nonempty(self):
919
        """Attempting to replace a nonemtpy directory should fail"""
920
        t = self.get_transport()
921
        if t.is_readonly():
6606.3.1 by Vincent Ladeuil
Add rename() and open_write_stream() as explicitly not supported via the ReadonlyTransportDecorator to give better feedback when a decorated transport is misused
922
            self.assertRaises((TransportNotPossible, NotImplementedError),
923
                              t.rename, 'foo', 'bar')
924
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
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')
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
994
        self.assertEqual([True, False], list(t.has_multi(['a', 'b'])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
995
996
        t.move('a', 'b')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
997
        self.assertTrue(t.has('b'))
998
        self.assertFalse(t.has('a'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
999
1000
        self.check_transport_contents('a first file\n', t, 'b')
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1001
        self.assertEqual([False, True], list(t.has_multi(['a', 'b'])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1006
        self.assertFalse(t.has('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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__)
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1044
        t = _mod_transport.get_transport_from_url(url)
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
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('.')
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
1055
        except TransportNotPossible as e:
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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('/'):
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1066
                self.assertTrue(S_ISDIR(st.st_mode))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1067
                # directory sizes are meaningless
1068
            else:
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1069
                self.assertTrue(S_ISREG(st.st_mode))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
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')
5807.5.1 by John Arbash Meinel
Fix bug #767177. Be more agressive with file.close() calls.
1082
        st = subdir.stat('./file')
1083
        st = 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
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1098
            self.assertTrue(t.has(source_name))
1099
            self.assertTrue(t.has(link_name))
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1100
1101
            st = t.stat(link_name)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1102
            self.assertEqual(st[ST_NLINK], 2)
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
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
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1120
            self.assertTrue(t.has(source_name))
1121
            self.assertTrue(t.has(link_name))
5056.1.1 by Neil Santos
Added default link() and symlink() methods to Transport.
1122
1123
            st = t.stat(link_name)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1124
            self.assertTrue(S_ISLNK(st.st_mode),
5349.2.1 by Martin Pool
Better test_symlink failure message
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:
6050.1.2 by Martin
Make tests raising KnownFailure use the knownFailure method instead
1130
            self.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):
6619.3.18 by Jelmer Vernooij
Run 2to3 idioms fixer.
1141
            l = sorted(transport.list_dir(d))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1142
            return l
1143
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1144
        self.assertEqual([], sorted_list('.', t))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
1145
        # c2 is precisely one letter longer than c here to test that
1146
        # suffixing is not confused.
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1147
        # a%25b checks that quoting is done consistently across transports
1148
        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
1149
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1150
        if not t.is_readonly():
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1151
            self.build_tree(tree_names, transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1152
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
1153
            self.build_tree(tree_names)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1154
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1155
        self.assertEqual(
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1156
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('', t))
1157
        self.assertEqual(
1158
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('.', t))
1159
        self.assertEqual(['d', 'e'], sorted_list('c', t))
1160
1161
        # Cloning the transport produces an equivalent listing
1162
        self.assertEqual(['d', 'e'], sorted_list('', t.clone('c')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1163
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1164
        if not t.is_readonly():
1165
            t.delete('c/d')
1166
            t.delete('b')
1167
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
1168
            os.unlink('c/d')
1169
            os.unlink('b')
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1170
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1171
        self.assertEqual(['a', 'a%2525b', 'c', 'c2'], sorted_list('.', t))
1172
        self.assertEqual(['e'], sorted_list('c', t))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1173
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
1174
        self.assertListRaises(PathError, t.list_dir, 'q')
1175
        self.assertListRaises(PathError, t.list_dir, 'c/f')
3508.1.4 by Vincent Ladeuil
Ensure that ftp transport are always in binary mode.
1176
        # 'a' is a file, list_dir should raise an error
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
1177
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1178
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1179
    def test_list_dir_result_is_url_escaped(self):
1180
        t = self.get_transport()
1181
        if not t.listable():
1182
            raise TestSkipped("transport not listable")
1183
1184
        if not t.is_readonly():
1185
            self.build_tree(['a/', 'a/%'], transport=t)
1186
        else:
1187
            self.build_tree(['a/', 'a/%'])
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1188
1910.7.2 by Andrew Bennetts
Also assert that list_dir returns plain str objects.
1189
        names = list(t.list_dir('a'))
1190
        self.assertEqual(['%25'], names)
1191
        self.assertIsInstance(names[0], str)
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1192
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
1193
    def test_clone_preserve_info(self):
1194
        t1 = self.get_transport()
1195
        if not isinstance(t1, ConnectedTransport):
1196
            raise TestSkipped("not a connected transport")
1197
1198
        t2 = t1.clone('subdir')
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1199
        self.assertEqual(t1._parsed_url.scheme, t2._parsed_url.scheme)
1200
        self.assertEqual(t1._parsed_url.user, t2._parsed_url.user)
1201
        self.assertEqual(t1._parsed_url.password, t2._parsed_url.password)
1202
        self.assertEqual(t1._parsed_url.host, t2._parsed_url.host)
1203
        self.assertEqual(t1._parsed_url.port, t2._parsed_url.port)
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
1204
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1205
    def test__reuse_for(self):
1206
        t = self.get_transport()
1207
        if not isinstance(t, ConnectedTransport):
1208
            raise TestSkipped("not a connected transport")
1209
1210
        def new_url(scheme=None, user=None, password=None,
1211
                    host=None, port=None, path=None):
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1212
            """Build a new url from t.base changing only parts of it.
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1213
1214
            Only the parameters different from None will be changed.
1215
            """
6055.2.1 by Jelmer Vernooij
Add UnparsedUrl.
1216
            if scheme   is None: scheme   = t._parsed_url.scheme
1217
            if user     is None: user     = t._parsed_url.user
1218
            if password is None: password = t._parsed_url.password
1219
            if user     is None: user     = t._parsed_url.user
1220
            if host     is None: host     = t._parsed_url.host
1221
            if port     is None: port     = t._parsed_url.port
1222
            if path     is None: path     = t._parsed_url.path
5268.7.13 by Jelmer Vernooij
Use URL.
1223
            return str(urlutils.URL(scheme, user, password, host, port, path))
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1224
6055.2.1 by Jelmer Vernooij
Add UnparsedUrl.
1225
        if t._parsed_url.scheme == 'ftp':
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1226
            scheme = 'sftp'
1227
        else:
1228
            scheme = 'ftp'
1229
        self.assertIsNot(t, t._reuse_for(new_url(scheme=scheme)))
6055.2.1 by Jelmer Vernooij
Add UnparsedUrl.
1230
        if t._parsed_url.user == 'me':
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1231
            user = 'you'
1232
        else:
1233
            user = 'me'
1234
        self.assertIsNot(t, t._reuse_for(new_url(user=user)))
1235
        # passwords are not taken into account because:
1236
        # - it makes no sense to have two different valid passwords for the
1237
        #   same user
1238
        # - _password in ConnectedTransport is intended to collect what the
1239
        #   user specified from the command-line and there are cases where the
1240
        #   new url can contain no password (if the url was built from an
1241
        #   existing transport.base for example)
1242
        # - password are considered part of the credentials provided at
1243
        #   connection creation time and as such may not be present in the url
1244
        #   (they may be typed by the user when prompted for example)
1245
        self.assertIs(t, t._reuse_for(new_url(password='from space')))
1246
        # We will not connect, we can use a invalid host
6055.2.1 by Jelmer Vernooij
Add UnparsedUrl.
1247
        self.assertIsNot(t, t._reuse_for(new_url(host=t._parsed_url.host + 'bar')))
1248
        if t._parsed_url.port == 1234:
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1249
            port = 4321
1250
        else:
1251
            port = 1234
1252
        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.
1253
        # 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.
1254
        self.assertIs(None, t._reuse_for('/valid_but_not_existing'))
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1255
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1256
    def test_connection_sharing(self):
1257
        t = self.get_transport()
1258
        if not isinstance(t, ConnectedTransport):
1259
            raise TestSkipped("not a connected transport")
1260
1261
        c = t.clone('subdir')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1262
        # 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
1263
        t.has('surely_not') # Force connection
1264
        self.assertIs(t._get_connection(), c._get_connection())
1265
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1266
        # Temporary failure, we need to create a new dummy connection
5247.2.12 by Vincent Ladeuil
Ensure that all transports close their underlying connection.
1267
        new_connection = None
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1268
        t._set_connection(new_connection)
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1269
        # Check that both transports use the same connection
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1270
        self.assertIs(new_connection, t._get_connection())
1271
        self.assertIs(new_connection, c._get_connection())
1272
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1273
    def test_reuse_connection_for_various_paths(self):
1274
        t = self.get_transport()
1275
        if not isinstance(t, ConnectedTransport):
1276
            raise TestSkipped("not a connected transport")
1277
1278
        t.has('surely_not') # Force connection
1279
        self.assertIsNot(None, t._get_connection())
1280
1281
        subdir = t._reuse_for(t.base + 'whatever/but/deep/down/the/path')
1282
        self.assertIsNot(t, subdir)
1283
        self.assertIs(t._get_connection(), subdir._get_connection())
1284
1285
        home = subdir._reuse_for(t.base + 'home')
1286
        self.assertIs(t._get_connection(), home._get_connection())
1287
        self.assertIs(subdir._get_connection(), home._get_connection())
1288
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1289
    def test_clone(self):
1290
        # TODO: Test that clone moves up and down the filesystem
1291
        t1 = self.get_transport()
1292
1293
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
1294
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1295
        self.assertTrue(t1.has('a'))
1296
        self.assertTrue(t1.has('b/c'))
1297
        self.assertFalse(t1.has('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1298
1299
        t2 = t1.clone('b')
1300
        self.assertEqual(t1.base + 'b/', t2.base)
1301
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1302
        self.assertTrue(t2.has('c'))
1303
        self.assertFalse(t2.has('a'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1304
1305
        t3 = t2.clone('..')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1306
        self.assertTrue(t3.has('a'))
1307
        self.assertFalse(t3.has('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1308
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1309
        self.assertFalse(t1.has('b/d'))
1310
        self.assertFalse(t2.has('d'))
1311
        self.assertFalse(t3.has('b/d'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1312
1313
        if t1.is_readonly():
3693.1.2 by John Arbash Meinel
Use build_tree_contents instead of direct open().write()
1314
            self.build_tree_contents([('b/d', 'newfile\n')])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1315
        else:
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
1316
            t2.put_bytes('d', 'newfile\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1317
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1318
        self.assertTrue(t1.has('b/d'))
1319
        self.assertTrue(t2.has('d'))
1320
        self.assertTrue(t3.has('b/d'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1321
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1322
    def test_clone_to_root(self):
1323
        orig_transport = self.get_transport()
1324
        # Repeatedly go up to a parent directory until we're at the root
1325
        # directory of this transport
1326
        root_transport = orig_transport
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1327
        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 //
1328
        # 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.
1329
        # growing less, except at the top
1330
        self.assertTrue(len(new_transport.base) < len(root_transport.base)
1331
            or new_transport.base == root_transport.base)
1332
        while new_transport.base != root_transport.base:
1333
            root_transport = new_transport
1334
            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 //
1335
            # 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.
1336
            # growing less, except at the top
1337
            self.assertTrue(len(new_transport.base) < len(root_transport.base)
1338
                or new_transport.base == root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1339
1340
        # Cloning to "/" should take us to exactly the same location.
1341
        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.
1342
        # the abspath of "/" from the original transport should be the same
1343
        # as the base at the root:
1344
        self.assertEqual(orig_transport.abspath("/"), root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1345
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
1346
        # At the root, the URL must still end with / as its a directory
1347
        self.assertEqual(root_transport.base[-1], '/')
1348
1349
    def test_clone_from_root(self):
1350
        """At the root, cloning to a simple dir should just do string append."""
1351
        orig_transport = self.get_transport()
1352
        root_transport = orig_transport.clone('/')
1353
        self.assertEqual(root_transport.base + '.bzr/',
1354
            root_transport.clone('.bzr').base)
1355
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1356
    def test_base_url(self):
1357
        t = self.get_transport()
1358
        self.assertEqual('/', t.base[-1])
1359
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1360
    def test_relpath(self):
1361
        t = self.get_transport()
1362
        self.assertEqual('', t.relpath(t.base))
1363
        # base ends with /
1364
        self.assertEqual('', t.relpath(t.base[:-1]))
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1365
        # subdirs which don't exist should still give relpaths.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1366
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
1367
        # trailing slash should be the same.
1368
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
1369
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1370
    def test_relpath_at_root(self):
1371
        t = self.get_transport()
1372
        # clone all the way to the top
1373
        new_transport = t.clone('..')
1374
        while new_transport.base != t.base:
1375
            t = new_transport
1376
            new_transport = t.clone('..')
1377
        # we must be able to get a relpath below the root
1378
        self.assertEqual('', t.relpath(t.base))
1379
        # and a deeper one should work too
1380
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
1381
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1382
    def test_abspath(self):
1383
        # smoke test for abspath. Corner cases for backends like unix fs's
1384
        # that have aliasing problems like symlinks should go in backend
1385
        # specific test cases.
1386
        transport = self.get_transport()
2485.8.21 by Vincent Ladeuil
Simplify debug.
1387
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1388
        self.assertEqual(transport.base + 'relpath',
1389
                         transport.abspath('relpath'))
1390
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1391
        # This should work without raising an error.
1392
        transport.abspath("/")
1393
1394
        # the abspath of "/" and "/foo/.." should result in the same location
1395
        self.assertEqual(transport.abspath("/"), transport.abspath("/foo/.."))
1396
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
1397
        self.assertEqual(transport.clone("/").abspath('foo'),
1398
                         transport.abspath("/foo"))
1399
5609.9.1 by Martin
Blindly change all users of get_transport to address the function via the transport module
1400
    # GZ 2011-01-26: Test in per_transport but not using self.get_transport?
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.
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1411
        transport = _mod_transport.get_transport_from_url("file:///")
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1412
        self.assertEqual(transport.abspath("/"), "file:///")
3693.2.2 by Mark Hammond
add a test for win32 abspath sematics, which as requested by lifeless,
1413
1414
        # but a transport that starts with a drive spec must keep it.
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1415
        transport = _mod_transport.get_transport_from_url("file:///C:/")
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1416
        self.assertEqual(transport.abspath("/"), "file:///C:/")
3693.2.2 by Mark Hammond
add a test for win32 abspath sematics, which as requested by lifeless,
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('.')
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
1422
        except (errors.NotLocalUrl, TransportNotPossible) as 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,
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1461
                    {'isolated/dir/foo',
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1462
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1463
                         'isolated/dir/b%2525z',
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1464
                         'isolated/bar'})
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
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,
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1468
            {'dir/foo', 'dir/bar', 'dir/b%2525z', 'bar'})
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
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,
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1491
                    {'from/dir/foo',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
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',
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
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,
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1521
                    {'from/dir/foo',
1551.21.5 by Aaron Bentley
Implement copy_tree on copy_tree_to_transport
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',
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1528
                         'to/bar',})
1551.21.5 by Aaron Bentley
Implement copy_tree on copy_tree_to_transport
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:
6050.1.2 by Martin
Make tests raising KnownFailure use the knownFailure method instead
1548
            self.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():
5861.2.6 by Wouter van Heyst
Fix the pypy refcount bugs in per_transport tests.
1619
            with file('a', 'w') as f: f.write('0123456789')
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
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():
5861.2.6 by Wouter van Heyst
Fix the pypy refcount bugs in per_transport tests.
1635
            with file('a', 'w') as f: f.write('0123456789')
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
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():
5861.2.6 by Wouter van Heyst
Fix the pypy refcount bugs in per_transport tests.
1713
            with file('a', 'w') as f: f.write('a'*1024*1024)
2890.1.2 by Robert Collins
More readv adjust for latency tests and bugfixes.
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():
5861.2.6 by Wouter van Heyst
Fix the pypy refcount bugs in per_transport tests.
1753
            with file('a', 'w') as f: f.write('0123456789')
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
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)])
5268.7.1 by Jelmer Vernooij
Fix segment_parameters for most transports.
1768
5268.7.2 by Jelmer Vernooij
merge bzr.dev.
1769
    def test_no_segment_parameters(self):
1770
        """Segment parameters should be stripped and stored in
1771
        transport.segment_parameters."""
1772
        transport = self.get_transport("foo")
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1773
        self.assertEqual({}, transport.get_segment_parameters())
5268.7.2 by Jelmer Vernooij
merge bzr.dev.
1774
5268.7.1 by Jelmer Vernooij
Fix segment_parameters for most transports.
1775
    def test_segment_parameters(self):
1776
        """Segment parameters should be stripped and stored in
5268.7.5 by Jelmer Vernooij
Use accessor for segment parameters.
1777
        transport.get_segment_parameters()."""
5268.7.1 by Jelmer Vernooij
Fix segment_parameters for most transports.
1778
        base_url = self._server.get_url()
5268.7.2 by Jelmer Vernooij
merge bzr.dev.
1779
        parameters = {"key1": "val1", "key2": "val2"}
1780
        url = urlutils.join_segment_parameters(base_url, parameters)
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1781
        transport = _mod_transport.get_transport_from_url(url)
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1782
        self.assertEqual(parameters, transport.get_segment_parameters())
5268.7.2 by Jelmer Vernooij
merge bzr.dev.
1783
6240.2.5 by Jelmer Vernooij
Add Transport.set_segment_parameter.
1784
    def test_set_segment_parameters(self):
1785
        """Segment parameters can be set and show up in base."""
1786
        transport = self.get_transport("foo")
1787
        orig_base = transport.base
1788
        transport.set_segment_parameter("arm", "board")
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1789
        self.assertEqual("%s,arm=board" % orig_base, transport.base)
1790
        self.assertEqual({"arm": "board"}, transport.get_segment_parameters())
6240.2.5 by Jelmer Vernooij
Add Transport.set_segment_parameter.
1791
        transport.set_segment_parameter("arm", None)
1792
        transport.set_segment_parameter("nonexistant", None)
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1793
        self.assertEqual({}, transport.get_segment_parameters())
1794
        self.assertEqual(orig_base, transport.base)
6240.2.5 by Jelmer Vernooij
Add Transport.set_segment_parameter.
1795
5349.2.3 by Martin Pool
Stat on a transport directly pointing to a symlink tells you about the symlink
1796
    def test_stat_symlink(self):
1797
        # if a transport points directly to a symlink (and supports symlinks
1798
        # at all) you can tell this.  helps with bug 32669.
1799
        t = self.get_transport()
1800
        try:
1801
            t.symlink('target', 'link')
1802
        except TransportNotPossible:
1803
            raise TestSkipped("symlinks not supported")
1804
        t2 = t.clone('link')
1805
        st = t2.stat('')
1806
        self.assertTrue(stat.S_ISLNK(st.st_mode))
6061.1.1 by Martin Packman
Add per_transport tests for url unquoting, which pathfilter fails on
1807
1808
    def test_abspath_url_unquote_unreserved(self):
6061.1.7 by Martin Packman
Add more reasoning and bug number to test docstrings, as suggested by poolie in review
1809
        """URLs from abspath should have unreserved characters unquoted
1810
        
1811
        Need consistent quoting notably for tildes, see lp:842223 for more.
1812
        """
6061.1.1 by Martin Packman
Add per_transport tests for url unquoting, which pathfilter fails on
1813
        t = self.get_transport()
1814
        needlessly_escaped_dir = "%2D%2E%30%39%41%5A%5F%61%7A%7E/"
1815
        self.assertEqual(t.base + "-.09AZ_az~",
1816
            t.abspath(needlessly_escaped_dir))
1817
1818
    def test_clone_url_unquote_unreserved(self):
6061.1.7 by Martin Packman
Add more reasoning and bug number to test docstrings, as suggested by poolie in review
1819
        """Base URL of a cloned branch needs unreserved characters unquoted
1820
        
1821
        Cloned transports should be prefix comparable for things like the
1822
        isolation checking of tests, see lp:842223 for more.
1823
        """
6061.1.1 by Martin Packman
Add per_transport tests for url unquoting, which pathfilter fails on
1824
        t1 = self.get_transport()
1825
        needlessly_escaped_dir = "%2D%2E%30%39%41%5A%5F%61%7A%7E/"
1826
        self.build_tree([needlessly_escaped_dir], transport=t1)
1827
        t2 = t1.clone(needlessly_escaped_dir)
1828
        self.assertEqual(t1.base + "-.09AZ_az~/", t2.base)
5436.3.8 by Martin Packman
Add per_transport tests for post_connection hook showing issue with smart clients
1829
1830
    def test_hook_post_connection_one(self):
1831
        """Fire post_connect hook after a ConnectedTransport is first used"""
1832
        log = []
1833
        Transport.hooks.install_named_hook("post_connect", log.append, None)
1834
        t = self.get_transport()
1835
        self.assertEqual([], log)
1836
        t.has("non-existant")
5436.3.10 by Martin Packman
Accept and document passing the medium rather than transport for smart connections
1837
        if isinstance(t, RemoteTransport):
1838
            self.assertEqual([t.get_smart_medium()], log)
1839
        elif isinstance(t, ConnectedTransport):
5436.3.8 by Martin Packman
Add per_transport tests for post_connection hook showing issue with smart clients
1840
            self.assertEqual([t], log)
1841
        else:
1842
            self.assertEqual([], log)
1843
1844
    def test_hook_post_connection_multi(self):
1845
        """Fire post_connect hook once per unshared underlying connection"""
1846
        log = []
1847
        Transport.hooks.install_named_hook("post_connect", log.append, None)
1848
        t1 = self.get_transport()
1849
        t2 = t1.clone(".")
1850
        t3 = self.get_transport()
1851
        self.assertEqual([], log)
1852
        t1.has("x")
1853
        t2.has("x")
1854
        t3.has("x")
5436.3.10 by Martin Packman
Accept and document passing the medium rather than transport for smart connections
1855
        if isinstance(t1, RemoteTransport):
1856
            self.assertEqual([t.get_smart_medium() for t in [t1, t3]], log)
1857
        elif isinstance(t1, ConnectedTransport):
5436.3.8 by Martin Packman
Add per_transport tests for post_connection hook showing issue with smart clients
1858
            self.assertEqual([t1, t3], log)
1859
        else:
1860
            self.assertEqual([], log)