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