/brz/remove-bazaar

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