/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
4294.2.1 by Robert Collins
Move directory checking for bzr push options into Branch.create_clone_on_transport.
677
    def test_create_prefix(self):
678
        t = self.get_transport()
679
        sub = t.clone('foo').clone('bar')
680
        try:
681
            sub.create_prefix()
682
        except TransportNotPossible:
683
            self.assertTrue(t.is_readonly())
684
        else:
685
            self.assertTrue(t.has('foo/bar'))
686
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
687
    def test_append_file(self):
688
        t = self.get_transport()
689
690
        if t.is_readonly():
1530.1.3 by Robert Collins
transport implementations now tested consistently.
691
            self.assertRaises(TransportNotPossible,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
692
                    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
693
            return
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
694
        t.put_bytes('a', 'diff\ncontents for\na\n')
695
        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
696
697
        self.assertEqual(20,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
698
            t.append_file('a', StringIO('add\nsome\nmore\ncontents\n')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
699
700
        self.check_transport_contents(
701
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
702
            t, 'a')
703
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
704
        # a file with no parent should fail..
705
        self.assertRaises(NoSuchFile,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
706
                          t.append_file, 'missing/path', StringIO('content'))
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
707
708
        # And we can create new files, too
709
        self.assertEqual(0,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
710
            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
711
        self.check_transport_contents('some text\nfor a missing file\n',
712
                                      t, 'c')
713
714
    def test_append_bytes(self):
715
        t = self.get_transport()
716
717
        if t.is_readonly():
718
            self.assertRaises(TransportNotPossible,
719
                    t.append_bytes, 'a', 'add\nsome\nmore\ncontents\n')
720
            return
721
722
        self.assertEqual(0, t.append_bytes('a', 'diff\ncontents for\na\n'))
723
        self.assertEqual(0, t.append_bytes('b', 'contents\nfor b\n'))
724
725
        self.assertEqual(20,
726
            t.append_bytes('a', 'add\nsome\nmore\ncontents\n'))
727
728
        self.check_transport_contents(
729
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
730
            t, 'a')
731
732
        # a file with no parent should fail..
733
        self.assertRaises(NoSuchFile,
734
                          t.append_bytes, 'missing/path', 'content')
735
736
    def test_append_multi(self):
737
        t = self.get_transport()
738
739
        if t.is_readonly():
740
            return
741
        t.put_bytes('a', 'diff\ncontents for\na\n'
742
                         'add\nsome\nmore\ncontents\n')
743
        t.put_bytes('b', 'contents\nfor b\n')
744
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
745
        self.assertEqual((43, 15),
746
            t.append_multi([('a', StringIO('and\nthen\nsome\nmore\n')),
747
                            ('b', StringIO('some\nmore\nfor\nb\n'))]))
748
1530.1.3 by Robert Collins
transport implementations now tested consistently.
749
        self.check_transport_contents(
750
            'diff\ncontents for\na\n'
751
            'add\nsome\nmore\ncontents\n'
752
            'and\nthen\nsome\nmore\n',
753
            t, 'a')
754
        self.check_transport_contents(
755
                'contents\nfor b\n'
756
                'some\nmore\nfor\nb\n',
757
                t, 'b')
758
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
759
        self.assertEqual((62, 31),
760
            t.append_multi(iter([('a', StringIO('a little bit more\n')),
761
                                 ('b', StringIO('from an iterator\n'))])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
762
        self.check_transport_contents(
763
            'diff\ncontents for\na\n'
764
            'add\nsome\nmore\ncontents\n'
765
            'and\nthen\nsome\nmore\n'
766
            'a little bit more\n',
767
            t, 'a')
768
        self.check_transport_contents(
769
                'contents\nfor b\n'
770
                'some\nmore\nfor\nb\n'
771
                'from an iterator\n',
772
                t, 'b')
773
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
774
        self.assertEqual((80, 0),
775
            t.append_multi([('a', StringIO('some text in a\n')),
776
                            ('d', StringIO('missing file r\n'))]))
777
1530.1.3 by Robert Collins
transport implementations now tested consistently.
778
        self.check_transport_contents(
779
            'diff\ncontents for\na\n'
780
            'add\nsome\nmore\ncontents\n'
781
            'and\nthen\nsome\nmore\n'
782
            'a little bit more\n'
783
            'some text in a\n',
784
            t, 'a')
785
        self.check_transport_contents('missing file r\n', t, 'd')
786
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
787
    def test_append_file_mode(self):
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
788
        """Check that append accepts a mode parameter"""
1666.1.6 by Robert Collins
Make knit the default format.
789
        # check append accepts a mode
790
        t = self.get_transport()
791
        if t.is_readonly():
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
792
            self.assertRaises(TransportNotPossible,
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
793
                t.append_file, 'f', StringIO('f'), mode=None)
1666.1.6 by Robert Collins
Make knit the default format.
794
            return
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
795
        t.append_file('f', StringIO('f'), mode=None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
796
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
797
    def test_append_bytes_mode(self):
798
        # check append_bytes accepts a mode
799
        t = self.get_transport()
800
        if t.is_readonly():
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
801
            self.assertRaises(TransportNotPossible,
802
                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
803
            return
1955.3.10 by John Arbash Meinel
clean up append, append_bytes, and append_multi tests
804
        t.append_bytes('f', 'f', mode=None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
805
1530.1.3 by Robert Collins
transport implementations now tested consistently.
806
    def test_delete(self):
807
        # TODO: Test Transport.delete
808
        t = self.get_transport()
809
810
        # Not much to do with a readonly transport
811
        if t.is_readonly():
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
812
            self.assertRaises(TransportNotPossible, t.delete, 'missing')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
813
            return
814
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
815
        t.put_bytes('a', 'a little bit of text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
816
        self.failUnless(t.has('a'))
817
        t.delete('a')
818
        self.failIf(t.has('a'))
819
820
        self.assertRaises(NoSuchFile, t.delete, 'a')
821
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
822
        t.put_bytes('a', 'a text\n')
823
        t.put_bytes('b', 'b text\n')
824
        t.put_bytes('c', 'c text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
825
        self.assertEqual([True, True, True],
826
                list(t.has_multi(['a', 'b', 'c'])))
827
        t.delete_multi(['a', 'c'])
828
        self.assertEqual([False, True, False],
829
                list(t.has_multi(['a', 'b', 'c'])))
830
        self.failIf(t.has('a'))
831
        self.failUnless(t.has('b'))
832
        self.failIf(t.has('c'))
833
834
        self.assertRaises(NoSuchFile,
835
                t.delete_multi, ['a', 'b', 'c'])
836
837
        self.assertRaises(NoSuchFile,
838
                t.delete_multi, iter(['a', 'b', 'c']))
839
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
840
        t.put_bytes('a', 'another a text\n')
841
        t.put_bytes('c', 'another c text\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
842
        t.delete_multi(iter(['a', 'b', 'c']))
843
844
        # We should have deleted everything
845
        # SftpServer creates control files in the
846
        # working directory, so we can just do a
847
        # plain "listdir".
848
        # self.assertEqual([], os.listdir('.'))
849
2671.3.1 by Robert Collins
* New method ``bzrlib.transport.Transport.get_recommended_page_size``.
850
    def test_recommended_page_size(self):
851
        """Transports recommend a page size for partial access to files."""
852
        t = self.get_transport()
853
        self.assertIsInstance(t.recommended_page_size(), int)
854
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
855
    def test_rmdir(self):
856
        t = self.get_transport()
857
        # Not much to do with a readonly transport
858
        if t.is_readonly():
859
            self.assertRaises(TransportNotPossible, t.rmdir, 'missing')
860
            return
861
        t.mkdir('adir')
862
        t.mkdir('adir/bdir')
863
        t.rmdir('adir/bdir')
1948.3.12 by Vincent LADEUIL
Fix Aaron's third review remarks.
864
        # ftp may not be able to raise NoSuchFile for lack of
865
        # details when failing
866
        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.
867
        t.rmdir('adir')
1948.3.12 by Vincent LADEUIL
Fix Aaron's third review remarks.
868
        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.
869
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
870
    def test_rmdir_not_empty(self):
871
        """Deleting a non-empty directory raises an exception
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
872
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
873
        sftp (and possibly others) don't give us a specific "directory not
874
        empty" exception -- we can just see that the operation failed.
875
        """
876
        t = self.get_transport()
877
        if t.is_readonly():
878
            return
879
        t.mkdir('adir')
880
        t.mkdir('adir/bdir')
881
        self.assertRaises(PathError, t.rmdir, 'adir')
882
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
883
    def test_rmdir_empty_but_similar_prefix(self):
884
        """rmdir does not get confused by sibling paths.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
885
2338.5.1 by Andrew Bennetts
Fix bug in MemoryTransport.rmdir.
886
        A naive implementation of MemoryTransport would refuse to rmdir
887
        ".bzr/branch" if there is a ".bzr/branch-format" directory, because it
888
        uses "path.startswith(dir)" on all file paths to determine if directory
889
        is empty.
890
        """
891
        t = self.get_transport()
892
        if t.is_readonly():
893
            return
894
        t.mkdir('foo')
895
        t.put_bytes('foo-bar', '')
896
        t.mkdir('foo-baz')
897
        t.rmdir('foo')
898
        self.assertRaises((NoSuchFile, PathError), t.rmdir, 'foo')
899
        self.failUnless(t.has('foo-bar'))
900
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
901
    def test_rename_dir_succeeds(self):
902
        t = self.get_transport()
903
        if t.is_readonly():
904
            raise TestSkipped("transport is readonly")
905
        t.mkdir('adir')
906
        t.mkdir('adir/asubdir')
907
        t.rename('adir', 'bdir')
908
        self.assertTrue(t.has('bdir/asubdir'))
909
        self.assertFalse(t.has('adir'))
910
911
    def test_rename_dir_nonempty(self):
912
        """Attempting to replace a nonemtpy directory should fail"""
913
        t = self.get_transport()
914
        if t.is_readonly():
915
            raise TestSkipped("transport is readonly")
916
        t.mkdir('adir')
917
        t.mkdir('adir/asubdir')
918
        t.mkdir('bdir')
919
        t.mkdir('bdir/bsubdir')
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
920
        # any kind of PathError would be OK, though we normally expect
921
        # DirectoryNotEmpty
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
922
        self.assertRaises(PathError, t.rename, 'bdir', 'adir')
923
        # nothing was changed so it should still be as before
924
        self.assertTrue(t.has('bdir/bsubdir'))
925
        self.assertFalse(t.has('adir/bdir'))
926
        self.assertFalse(t.has('adir/bsubdir'))
927
3010.2.1 by Martin Pool
Followon from MemoryTransport._abspath fix: add test_rename_across_subdirs, and fix error construction
928
    def test_rename_across_subdirs(self):
929
        t = self.get_transport()
930
        if t.is_readonly():
931
            raise TestNotApplicable("transport is readonly")
932
        t.mkdir('a')
933
        t.mkdir('b')
934
        ta = t.clone('a')
935
        tb = t.clone('b')
936
        ta.put_bytes('f', 'aoeu')
937
        ta.rename('f', '../b/f')
938
        self.assertTrue(tb.has('f'))
939
        self.assertFalse(ta.has('f'))
940
        self.assertTrue(t.has('b/f'))
941
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
942
    def test_delete_tree(self):
943
        t = self.get_transport()
944
945
        # Not much to do with a readonly transport
946
        if t.is_readonly():
947
            self.assertRaises(TransportNotPossible, t.delete_tree, 'missing')
948
            return
949
950
        # and does it like listing ?
951
        t.mkdir('adir')
952
        try:
953
            t.delete_tree('adir')
954
        except TransportNotPossible:
955
            # ok, this transport does not support delete_tree
956
            return
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
957
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
958
        # did it delete that trivial case?
959
        self.assertRaises(NoSuchFile, t.stat, 'adir')
960
961
        self.build_tree(['adir/',
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
962
                         'adir/file',
963
                         'adir/subdir/',
964
                         'adir/subdir/file',
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
965
                         'adir/subdir2/',
966
                         'adir/subdir2/file',
967
                         ], transport=t)
968
969
        t.delete_tree('adir')
970
        # adir should be gone now.
971
        self.assertRaises(NoSuchFile, t.stat, 'adir')
972
1530.1.3 by Robert Collins
transport implementations now tested consistently.
973
    def test_move(self):
974
        t = self.get_transport()
975
976
        if t.is_readonly():
977
            return
978
979
        # TODO: I would like to use os.listdir() to
980
        # make sure there are no extra files, but SftpServer
981
        # creates control files in the working directory
982
        # perhaps all of this could be done in a subdirectory
983
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
984
        t.put_bytes('a', 'a first file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
985
        self.assertEquals([True, False], list(t.has_multi(['a', 'b'])))
986
987
        t.move('a', 'b')
988
        self.failUnless(t.has('b'))
989
        self.failIf(t.has('a'))
990
991
        self.check_transport_contents('a first file\n', t, 'b')
992
        self.assertEquals([False, True], list(t.has_multi(['a', 'b'])))
993
994
        # 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
995
        t.put_bytes('c', 'c this file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
996
        t.move('c', 'b')
997
        self.failIf(t.has('c'))
998
        self.check_transport_contents('c this file\n', t, 'b')
999
1000
        # TODO: Try to write a test for atomicity
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1001
        # TODO: Test moving into a non-existent subdirectory
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1002
        # TODO: Test Transport.move_multi
1003
1004
    def test_copy(self):
1005
        t = self.get_transport()
1006
1007
        if t.is_readonly():
1008
            return
1009
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
1010
        t.put_bytes('a', 'a file\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1011
        t.copy('a', 'b')
1012
        self.check_transport_contents('a file\n', t, 'b')
1013
1014
        self.assertRaises(NoSuchFile, t.copy, 'c', 'd')
1015
        os.mkdir('c')
1016
        # What should the assert be if you try to copy a
1017
        # file over a directory?
1018
        #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
1019
        t.put_bytes('d', 'text in d\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1020
        t.copy('d', 'b')
1021
        self.check_transport_contents('text in d\n', t, 'b')
1022
1023
        # TODO: test copy_multi
1024
1025
    def test_connection_error(self):
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
1026
        """ConnectionError is raised when connection is impossible.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1027
3021.1.2 by Vincent Ladeuil
Fix bug #164567 by catching connection errors.
1028
        The error should be raised from the first operation on the transport.
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
1029
        """
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
1030
        try:
1031
            url = self._server.get_bogus_url()
1032
        except NotImplementedError:
1033
            raise TestSkipped("Transport %s has no bogus URL support." %
1034
                              self._server.__class__)
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
1035
        t = get_transport(url)
1036
        self.assertRaises((ConnectionError, NoSuchFile), t.get, '.bzr/branch')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1037
1038
    def test_stat(self):
1039
        # TODO: Test stat, just try once, and if it throws, stop testing
1040
        from stat import S_ISDIR, S_ISREG
1041
1042
        t = self.get_transport()
1043
1044
        try:
1045
            st = t.stat('.')
1046
        except TransportNotPossible, e:
1047
            # This transport cannot stat
1048
            return
1049
1050
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e']
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1051
        sizes = [14, 0, 16, 0, 18]
1551.2.39 by abentley
Fix line endings in tests
1052
        self.build_tree(paths, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1053
1054
        for path, size in zip(paths, sizes):
1055
            st = t.stat(path)
1056
            if path.endswith('/'):
1057
                self.failUnless(S_ISDIR(st.st_mode))
1058
                # directory sizes are meaningless
1059
            else:
1060
                self.failUnless(S_ISREG(st.st_mode))
1061
                self.assertEqual(size, st.st_size)
1062
1063
        remote_stats = list(t.stat_multi(paths))
1064
        remote_iter_stats = list(t.stat_multi(iter(paths)))
1065
1066
        self.assertRaises(NoSuchFile, t.stat, 'q')
1067
        self.assertRaises(NoSuchFile, t.stat, 'b/a')
1068
1069
        self.assertListRaises(NoSuchFile, t.stat_multi, ['a', 'c', 'd'])
1070
        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.
1071
        self.build_tree(['subdir/', 'subdir/file'], transport=t)
1072
        subdir = t.clone('subdir')
1073
        subdir.stat('./file')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1074
        subdir.stat('.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1075
1076
    def test_list_dir(self):
1077
        # TODO: Test list_dir, just try once, and if it throws, stop testing
1078
        t = self.get_transport()
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1079
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1080
        if not t.listable():
1081
            self.assertRaises(TransportNotPossible, t.list_dir, '.')
1082
            return
1083
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1084
        def sorted_list(d, transport):
1085
            l = list(transport.list_dir(d))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1086
            l.sort()
1087
            return l
1088
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1089
        self.assertEqual([], sorted_list('.', t))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
1090
        # c2 is precisely one letter longer than c here to test that
1091
        # suffixing is not confused.
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1092
        # a%25b checks that quoting is done consistently across transports
1093
        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
1094
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1095
        if not t.is_readonly():
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1096
            self.build_tree(tree_names, transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1097
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
1098
            self.build_tree(tree_names)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1099
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1100
        self.assertEqual(
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1101
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('', t))
1102
        self.assertEqual(
1103
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('.', t))
1104
        self.assertEqual(['d', 'e'], sorted_list('c', t))
1105
1106
        # Cloning the transport produces an equivalent listing
1107
        self.assertEqual(['d', 'e'], sorted_list('', t.clone('c')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1108
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1109
        if not t.is_readonly():
1110
            t.delete('c/d')
1111
            t.delete('b')
1112
        else:
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
1113
            os.unlink('c/d')
1114
            os.unlink('b')
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1115
3211.6.1 by James Henstridge
* Remove relpath='' special case in MemoryTransport._abspath(), which
1116
        self.assertEqual(['a', 'a%2525b', 'c', 'c2'], sorted_list('.', t))
1117
        self.assertEqual(['e'], sorted_list('c', t))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1118
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
1119
        self.assertListRaises(PathError, t.list_dir, 'q')
1120
        self.assertListRaises(PathError, t.list_dir, 'c/f')
3508.1.4 by Vincent Ladeuil
Ensure that ftp transport are always in binary mode.
1121
        # 'a' is a file, list_dir should raise an error
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
1122
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1123
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1124
    def test_list_dir_result_is_url_escaped(self):
1125
        t = self.get_transport()
1126
        if not t.listable():
1127
            raise TestSkipped("transport not listable")
1128
1129
        if not t.is_readonly():
1130
            self.build_tree(['a/', 'a/%'], transport=t)
1131
        else:
1132
            self.build_tree(['a/', 'a/%'])
3484.1.1 by Vincent Ladeuil
Trivial drive-by cleanups.
1133
1910.7.2 by Andrew Bennetts
Also assert that list_dir returns plain str objects.
1134
        names = list(t.list_dir('a'))
1135
        self.assertEqual(['%25'], names)
1136
        self.assertIsInstance(names[0], str)
1910.7.1 by Andrew Bennetts
Make sure list_dir always returns url-escaped names.
1137
2485.8.25 by Vincent Ladeuil
Separate abspath from _remote_path, the intents are different.
1138
    def test_clone_preserve_info(self):
1139
        t1 = self.get_transport()
1140
        if not isinstance(t1, ConnectedTransport):
1141
            raise TestSkipped("not a connected transport")
1142
1143
        t2 = t1.clone('subdir')
1144
        self.assertEquals(t1._scheme, t2._scheme)
1145
        self.assertEquals(t1._user, t2._user)
1146
        self.assertEquals(t1._password, t2._password)
1147
        self.assertEquals(t1._host, t2._host)
1148
        self.assertEquals(t1._port, t2._port)
1149
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1150
    def test__reuse_for(self):
1151
        t = self.get_transport()
1152
        if not isinstance(t, ConnectedTransport):
1153
            raise TestSkipped("not a connected transport")
1154
1155
        def new_url(scheme=None, user=None, password=None,
1156
                    host=None, port=None, path=None):
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1157
            """Build a new url from t.base changing only parts of it.
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1158
1159
            Only the parameters different from None will be changed.
1160
            """
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1161
            if scheme   is None: scheme   = t._scheme
1162
            if user     is None: user     = t._user
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1163
            if password is None: password = t._password
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1164
            if user     is None: user     = t._user
1165
            if host     is None: host     = t._host
1166
            if port     is None: port     = t._port
1167
            if path     is None: path     = t._path
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1168
            return t._unsplit_url(scheme, user, password, host, port, path)
1169
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1170
        if t._scheme == 'ftp':
1171
            scheme = 'sftp'
1172
        else:
1173
            scheme = 'ftp'
1174
        self.assertIsNot(t, t._reuse_for(new_url(scheme=scheme)))
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1175
        if t._user == 'me':
1176
            user = 'you'
1177
        else:
1178
            user = 'me'
1179
        self.assertIsNot(t, t._reuse_for(new_url(user=user)))
1180
        # passwords are not taken into account because:
1181
        # - it makes no sense to have two different valid passwords for the
1182
        #   same user
1183
        # - _password in ConnectedTransport is intended to collect what the
1184
        #   user specified from the command-line and there are cases where the
1185
        #   new url can contain no password (if the url was built from an
1186
        #   existing transport.base for example)
1187
        # - password are considered part of the credentials provided at
1188
        #   connection creation time and as such may not be present in the url
1189
        #   (they may be typed by the user when prompted for example)
1190
        self.assertIs(t, t._reuse_for(new_url(password='from space')))
1191
        # We will not connect, we can use a invalid host
1192
        self.assertIsNot(t, t._reuse_for(new_url(host=t._host + 'bar')))
1193
        if t._port == 1234:
1194
            port = 4321
1195
        else:
1196
            port = 1234
1197
        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.
1198
        # 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.
1199
        self.assertIs(None, t._reuse_for('/valid_but_not_existing'))
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1200
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1201
    def test_connection_sharing(self):
1202
        t = self.get_transport()
1203
        if not isinstance(t, ConnectedTransport):
1204
            raise TestSkipped("not a connected transport")
1205
1206
        c = t.clone('subdir')
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1207
        # 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
1208
        t.has('surely_not') # Force connection
1209
        self.assertIs(t._get_connection(), c._get_connection())
1210
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1211
        # 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
1212
        new_connection = object()
1213
        t._set_connection(new_connection)
2485.8.54 by Vincent Ladeuil
Refactor medium uses by making a distinction betweem shared and real medium.
1214
        # Check that both transports use the same connection
2485.8.53 by Vincent Ladeuil
Apply test_connection_sharing to all transports to make smart
1215
        self.assertIs(new_connection, t._get_connection())
1216
        self.assertIs(new_connection, c._get_connection())
1217
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
1218
    def test_reuse_connection_for_various_paths(self):
1219
        t = self.get_transport()
1220
        if not isinstance(t, ConnectedTransport):
1221
            raise TestSkipped("not a connected transport")
1222
1223
        t.has('surely_not') # Force connection
1224
        self.assertIsNot(None, t._get_connection())
1225
1226
        subdir = t._reuse_for(t.base + 'whatever/but/deep/down/the/path')
1227
        self.assertIsNot(t, subdir)
1228
        self.assertIs(t._get_connection(), subdir._get_connection())
1229
1230
        home = subdir._reuse_for(t.base + 'home')
1231
        self.assertIs(t._get_connection(), home._get_connection())
1232
        self.assertIs(subdir._get_connection(), home._get_connection())
1233
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1234
    def test_clone(self):
1235
        # TODO: Test that clone moves up and down the filesystem
1236
        t1 = self.get_transport()
1237
1238
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
1239
1240
        self.failUnless(t1.has('a'))
1241
        self.failUnless(t1.has('b/c'))
1242
        self.failIf(t1.has('c'))
1243
1244
        t2 = t1.clone('b')
1245
        self.assertEqual(t1.base + 'b/', t2.base)
1246
1247
        self.failUnless(t2.has('c'))
1248
        self.failIf(t2.has('a'))
1249
1250
        t3 = t2.clone('..')
1251
        self.failUnless(t3.has('a'))
1252
        self.failIf(t3.has('c'))
1253
1254
        self.failIf(t1.has('b/d'))
1255
        self.failIf(t2.has('d'))
1256
        self.failIf(t3.has('b/d'))
1257
1258
        if t1.is_readonly():
3693.1.2 by John Arbash Meinel
Use build_tree_contents instead of direct open().write()
1259
            self.build_tree_contents([('b/d', 'newfile\n')])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1260
        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
1261
            t2.put_bytes('d', 'newfile\n')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1262
1263
        self.failUnless(t1.has('b/d'))
1264
        self.failUnless(t2.has('d'))
1265
        self.failUnless(t3.has('b/d'))
1266
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1267
    def test_clone_to_root(self):
1268
        orig_transport = self.get_transport()
1269
        # Repeatedly go up to a parent directory until we're at the root
1270
        # directory of this transport
1271
        root_transport = orig_transport
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
1272
        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 //
1273
        # 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.
1274
        # growing less, except at the top
1275
        self.assertTrue(len(new_transport.base) < len(root_transport.base)
1276
            or new_transport.base == root_transport.base)
1277
        while new_transport.base != root_transport.base:
1278
            root_transport = new_transport
1279
            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 //
1280
            # 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.
1281
            # growing less, except at the top
1282
            self.assertTrue(len(new_transport.base) < len(root_transport.base)
1283
                or new_transport.base == root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1284
1285
        # Cloning to "/" should take us to exactly the same location.
1286
        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.
1287
        # the abspath of "/" from the original transport should be the same
1288
        # as the base at the root:
1289
        self.assertEqual(orig_transport.abspath("/"), root_transport.base)
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1290
1910.15.5 by Andrew Bennetts
Transport behaviour at the root of the URL is now defined and tested.
1291
        # At the root, the URL must still end with / as its a directory
1292
        self.assertEqual(root_transport.base[-1], '/')
1293
1294
    def test_clone_from_root(self):
1295
        """At the root, cloning to a simple dir should just do string append."""
1296
        orig_transport = self.get_transport()
1297
        root_transport = orig_transport.clone('/')
1298
        self.assertEqual(root_transport.base + '.bzr/',
1299
            root_transport.clone('.bzr').base)
1300
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1301
    def test_base_url(self):
1302
        t = self.get_transport()
1303
        self.assertEqual('/', t.base[-1])
1304
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1305
    def test_relpath(self):
1306
        t = self.get_transport()
1307
        self.assertEqual('', t.relpath(t.base))
1308
        # base ends with /
1309
        self.assertEqual('', t.relpath(t.base[:-1]))
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1310
        # subdirs which don't exist should still give relpaths.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1311
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
1312
        # trailing slash should be the same.
1313
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
1314
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1315
    def test_relpath_at_root(self):
1316
        t = self.get_transport()
1317
        # clone all the way to the top
1318
        new_transport = t.clone('..')
1319
        while new_transport.base != t.base:
1320
            t = new_transport
1321
            new_transport = t.clone('..')
1322
        # we must be able to get a relpath below the root
1323
        self.assertEqual('', t.relpath(t.base))
1324
        # and a deeper one should work too
1325
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
1326
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1327
    def test_abspath(self):
1328
        # smoke test for abspath. Corner cases for backends like unix fs's
1329
        # that have aliasing problems like symlinks should go in backend
1330
        # specific test cases.
1331
        transport = self.get_transport()
2485.8.21 by Vincent Ladeuil
Simplify debug.
1332
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1333
        self.assertEqual(transport.base + 'relpath',
1334
                         transport.abspath('relpath'))
1335
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
1336
        # This should work without raising an error.
1337
        transport.abspath("/")
1338
1339
        # the abspath of "/" and "/foo/.." should result in the same location
1340
        self.assertEqual(transport.abspath("/"), transport.abspath("/foo/.."))
1341
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
1342
        self.assertEqual(transport.clone("/").abspath('foo'),
1343
                         transport.abspath("/foo"))
1344
3693.2.2 by Mark Hammond
add a test for win32 abspath sematics, which as requested by lifeless,
1345
    def test_win32_abspath(self):
3712.1.1 by Ian Clatworthy
LocalTransport.abspath returns drive letter if transport has one (Mark Hammond)
1346
        # Note: we tried to set sys.platform='win32' so we could test on
1347
        # other platforms too, but then osutils does platform specific
1348
        # things at import time which defeated us...
3693.2.3 by Mark Hammond
Back to skipping the tests on non-windows platforms.
1349
        if sys.platform != 'win32':
1350
            raise TestSkipped(
1351
                '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,
1352
1353
        # smoke test for abspath on win32.
1354
        # a transport based on 'file:///' never fully qualifies the drive.
1355
        transport = get_transport("file:///")
1356
        self.failUnlessEqual(transport.abspath("/"), "file:///")
1357
1358
        # but a transport that starts with a drive spec must keep it.
1359
        transport = get_transport("file:///C:/")
1360
        self.failUnlessEqual(transport.abspath("/"), "file:///C:/")
1361
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
1362
    def test_local_abspath(self):
1363
        transport = self.get_transport()
1364
        try:
1365
            p = transport.local_abspath('.')
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
1366
        except (errors.NotLocalUrl, TransportNotPossible), e:
2018.18.22 by Martin Pool
merge bzr.dev
1367
            # should be formattable
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
1368
            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
1369
        else:
1370
            self.assertEqual(getcwd(), p)
1371
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
1372
    def test_abspath_at_root(self):
1373
        t = self.get_transport()
1374
        # clone all the way to the top
1375
        new_transport = t.clone('..')
1376
        while new_transport.base != t.base:
1377
            t = new_transport
1378
            new_transport = t.clone('..')
1379
        # we must be able to get a abspath of the root when we ask for
1380
        # t.abspath('..') - this due to our choice that clone('..')
1381
        # should return the root from the root, combined with the desire that
1382
        # the url from clone('..') and from abspath('..') should be the same.
1383
        self.assertEqual(t.base, t.abspath('..'))
1384
        # '' should give us the root
1385
        self.assertEqual(t.base, t.abspath(''))
1386
        # and a path should append to the url
1387
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
1388
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1389
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1390
        transport = self.get_transport()
1391
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1392
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1393
                              transport.iter_files_recursive)
1394
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1395
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1396
                         'isolated/dir/',
1397
                         'isolated/dir/foo',
1398
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1399
                         'isolated/dir/b%25z', # make sure quoting is correct
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
1400
                         'isolated/bar'],
1401
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1402
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1403
        # nb the directories are not converted
1404
        self.assertEqual(paths,
1405
                    set(['isolated/dir/foo',
1406
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1407
                         'isolated/dir/b%2525z',
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
1408
                         'isolated/bar']))
1409
        sub_transport = transport.clone('isolated')
1410
        paths = set(sub_transport.iter_files_recursive())
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
1411
        self.assertEqual(paths,
1412
            set(['dir/foo', 'dir/bar', 'dir/b%2525z', 'bar']))
1413
1414
    def test_copy_tree(self):
1415
        # TODO: test file contents and permissions are preserved. This test was
1416
        # added just to ensure that quoting was handled correctly.
1417
        # -- David Allouche 2006-08-11
1418
        transport = self.get_transport()
1419
        if not transport.listable():
1420
            self.assertRaises(TransportNotPossible,
1421
                              transport.iter_files_recursive)
1422
            return
1423
        if transport.is_readonly():
1424
            return
1425
        self.build_tree(['from/',
1426
                         'from/dir/',
1427
                         'from/dir/foo',
1428
                         'from/dir/bar',
1429
                         'from/dir/b%25z', # make sure quoting is correct
1430
                         'from/bar'],
1431
                        transport=transport)
1432
        transport.copy_tree('from', 'to')
1433
        paths = set(transport.iter_files_recursive())
1434
        self.assertEqual(paths,
1435
                    set(['from/dir/foo',
1436
                         'from/dir/bar',
1437
                         'from/dir/b%2525z',
1438
                         'from/bar',
1439
                         'to/dir/foo',
1440
                         'to/dir/bar',
1441
                         'to/dir/b%2525z',
1442
                         'to/bar',]))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1443
1551.21.5 by Aaron Bentley
Implement copy_tree on copy_tree_to_transport
1444
    def test_copy_tree_to_transport(self):
1445
        transport = self.get_transport()
1446
        if not transport.listable():
1447
            self.assertRaises(TransportNotPossible,
1448
                              transport.iter_files_recursive)
1449
            return
1450
        if transport.is_readonly():
1451
            return
1452
        self.build_tree(['from/',
1453
                         'from/dir/',
1454
                         'from/dir/foo',
1455
                         'from/dir/bar',
1456
                         'from/dir/b%25z', # make sure quoting is correct
1457
                         'from/bar'],
1458
                        transport=transport)
1459
        from_transport = transport.clone('from')
1460
        to_transport = transport.clone('to')
1461
        to_transport.ensure_base()
1462
        from_transport.copy_tree_to_transport(to_transport)
1463
        paths = set(transport.iter_files_recursive())
1464
        self.assertEqual(paths,
1465
                    set(['from/dir/foo',
1466
                         'from/dir/bar',
1467
                         'from/dir/b%2525z',
1468
                         'from/bar',
1469
                         'to/dir/foo',
1470
                         'to/dir/bar',
1471
                         'to/dir/b%2525z',
1472
                         'to/bar',]))
1473
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1474
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
1475
        """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
1476
        t = self.get_transport()
1477
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
1478
        # With FAT32 and certain encodings on win32
1479
        # '\xe5' and '\xe4' actually map to the same file
1480
        # adding a suffix kicks in the 'preserving but insensitive'
1481
        # route, and maintains the right files
1482
        files = [u'\xe5.1', # a w/ circle iso-8859-1
1483
                 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
1484
                 u'\u017d', # Z with umlat iso-8859-2
1485
                 u'\u062c', # Arabic j
1486
                 u'\u0410', # Russian A
1487
                 u'\u65e5', # Kanji person
1488
                ]
1489
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1490
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
1491
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
1492
        except UnicodeError:
1493
            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
1494
1495
        # A plain unicode string is not a valid url
1496
        for fname in files:
1497
            self.assertRaises(InvalidURL, t.get, fname)
1498
1499
        for fname in files:
1500
            fname_utf8 = fname.encode('utf-8')
1501
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
1502
            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
1503
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1504
    def test_connect_twice_is_same_content(self):
2485.8.21 by Vincent Ladeuil
Simplify debug.
1505
        # 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.
1506
        # via get_transport and multiple connections share content.
1507
        transport = self.get_transport()
1508
        if transport.is_readonly():
1509
            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
1510
        transport.put_bytes('foo', 'bar')
2485.8.21 by Vincent Ladeuil
Simplify debug.
1511
        transport3 = self.get_transport()
1512
        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.
1513
1514
        # now opening at a relative url should give use a sane result:
1515
        transport.mkdir('newdir')
3508.1.13 by Vincent Ladeuil
Fix last failing tests under python2.6.
1516
        transport5 = self.get_transport('newdir')
2485.8.21 by Vincent Ladeuil
Simplify debug.
1517
        transport6 = transport5.clone('..')
1518
        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.
1519
1520
    def test_lock_write(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1521
        """Test transport-level write locks.
1522
1523
        These are deprecated and transports may decline to support them.
1524
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1525
        transport = self.get_transport()
1526
        if transport.is_readonly():
1527
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
1528
            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
1529
        transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1530
        try:
1531
            lock = transport.lock_write('lock')
1752.3.6 by Andrew Bennetts
Merge from test-tweaks
1532
        except TransportNotPossible:
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1533
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1534
        # TODO make this consistent on all platforms:
1535
        # self.assertRaises(LockError, transport.lock_write, 'lock')
1536
        lock.unlock()
1537
1538
    def test_lock_read(self):
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1539
        """Test transport-level read locks.
1540
1541
        These are deprecated and transports may decline to support them.
1542
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1543
        transport = self.get_transport()
1544
        if transport.is_readonly():
1545
            file('lock', 'w').close()
1546
        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
1547
            transport.put_bytes('lock', '')
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1548
        try:
1549
            lock = transport.lock_read('lock')
1752.3.6 by Andrew Bennetts
Merge from test-tweaks
1550
        except TransportNotPossible:
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
1551
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
1552
        # TODO make this consistent on all platforms:
1553
        # self.assertRaises(LockError, transport.lock_read, 'lock')
1554
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
1555
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
1556
    def test_readv(self):
1557
        transport = self.get_transport()
1558
        if transport.is_readonly():
1559
            file('a', 'w').write('0123456789')
1560
        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
1561
            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
1562
2004.1.22 by v.ladeuil+lp at free
Implements Range header handling for GET requests. Fix a test.
1563
        d = list(transport.readv('a', ((0, 1),)))
1564
        self.assertEqual(d[0], (0, '0'))
1565
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1566
        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.
1567
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1568
        self.assertEqual(d[1], (1, '1'))
1569
        self.assertEqual(d[2], (3, '34'))
1570
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1571
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
1572
    def test_readv_out_of_order(self):
1573
        transport = self.get_transport()
1574
        if transport.is_readonly():
1575
            file('a', 'w').write('0123456789')
1576
        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
1577
            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
1578
1579
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
1580
        self.assertEqual(d[0], (1, '1'))
1581
        self.assertEqual(d[1], (9, '9'))
1582
        self.assertEqual(d[2], (0, '0'))
1583
        self.assertEqual(d[3], (3, '34'))
1752.2.40 by Andrew Bennetts
Merge from bzr.dev.
1584
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1585
    def test_readv_with_adjust_for_latency(self):
1586
        transport = self.get_transport()
1587
        # the adjust for latency flag expands the data region returned
1588
        # according to a per-transport heuristic, so testing is a little
1589
        # tricky as we need more data than the largest combining that our
1590
        # transports do. To accomodate this we generate random data and cross
1591
        # reference the returned data with the random data. To avoid doing
1592
        # multiple large random byte look ups we do several tests on the same
1593
        # backing data.
1594
        content = osutils.rand_bytes(200*1024)
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1595
        content_size = len(content)
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1596
        if transport.is_readonly():
3693.1.2 by John Arbash Meinel
Use build_tree_contents instead of direct open().write()
1597
            self.build_tree_contents([('a', content)])
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1598
        else:
1599
            transport.put_bytes('a', content)
1600
        def check_result_data(result_vector):
1601
            for item in result_vector:
1602
                data_len = len(item[1])
1603
                self.assertEqual(content[item[0]:item[0] + data_len], item[1])
1604
1605
        # start corner case
1606
        result = list(transport.readv('a', ((0, 30),),
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1607
            adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1608
        # we expect 1 result, from 0, to something > 30
1609
        self.assertEqual(1, len(result))
1610
        self.assertEqual(0, result[0][0])
1611
        self.assertTrue(len(result[0][1]) >= 30)
1612
        check_result_data(result)
1613
        # end of file corner case
1614
        result = list(transport.readv('a', ((204700, 100),),
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1615
            adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1616
        # we expect 1 result, from 204800- its length, to the end
1617
        self.assertEqual(1, len(result))
1618
        data_len = len(result[0][1])
1619
        self.assertEqual(204800-data_len, result[0][0])
1620
        self.assertTrue(data_len >= 100)
1621
        check_result_data(result)
1622
        # out of order ranges are made in order
1623
        result = list(transport.readv('a', ((204700, 100), (0, 50)),
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1624
            adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1625
        # we expect 2 results, in order, start and end.
1626
        self.assertEqual(2, len(result))
1627
        # start
1628
        data_len = len(result[0][1])
1629
        self.assertEqual(0, result[0][0])
1630
        self.assertTrue(data_len >= 30)
1631
        # end
1632
        data_len = len(result[1][1])
1633
        self.assertEqual(204800-data_len, result[1][0])
1634
        self.assertTrue(data_len >= 100)
1635
        check_result_data(result)
1636
        # close ranges get combined (even if out of order)
1637
        for request_vector in [((400,50), (800, 234)), ((800, 234), (400,50))]:
1638
            result = list(transport.readv('a', request_vector,
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
1639
                adjust_for_latency=True, upper_limit=content_size))
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1640
            self.assertEqual(1, len(result))
1641
            data_len = len(result[0][1])
3059.2.18 by Vincent Ladeuil
Take spiv review comments into account.
1642
            # minimum length is from 400 to 1034 - 634
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1643
            self.assertTrue(data_len >= 634)
1644
            # must contain the region 400 to 1034
1645
            self.assertTrue(result[0][0] <= 400)
1646
            self.assertTrue(result[0][0] + data_len >= 1034)
1647
            check_result_data(result)
3469.1.1 by Vincent Ladeuil
Split test to achieve better defect localization :)
1648
1649
    def test_readv_with_adjust_for_latency_with_big_file(self):
1650
        transport = self.get_transport()
2890.1.2 by Robert Collins
More readv adjust for latency tests and bugfixes.
1651
        # test from observed failure case.
1652
        if transport.is_readonly():
1653
            file('a', 'w').write('a'*1024*1024)
1654
        else:
1655
            transport.put_bytes('a', 'a'*1024*1024)
1656
        broken_vector = [(465219, 800), (225221, 800), (445548, 800),
1657
            (225037, 800), (221357, 800), (437077, 800), (947670, 800),
1658
            (465373, 800), (947422, 800)]
1659
        results = list(transport.readv('a', broken_vector, True, 1024*1024))
1660
        found_items = [False]*9
1661
        for pos, (start, length) in enumerate(broken_vector):
1662
            # check the range is covered by the result
1663
            for offset, data in results:
1664
                if offset <= start and start + length <= offset + len(data):
1665
                    found_items[pos] = True
1666
        self.assertEqual([True]*9, found_items)
2745.5.1 by Robert Collins
* New parameter on ``bzrlib.transport.Transport.readv``
1667
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
1668
    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
1669
        t = self.get_transport()
1670
        if t.is_readonly():
1671
            return
2671.3.9 by Robert Collins
Review feedback and fix VFat emulated transports to not claim to have unix permissions.
1672
        handle = t.open_write_stream('foo')
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1673
        try:
2671.3.6 by Robert Collins
Review feedback.
1674
            handle.write('bcd')
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1675
            self.assertEqual([(0, 'b'), (2, 'd')], list(t.readv('foo', ((0,1), (2,1)))))
1676
        finally:
2671.3.6 by Robert Collins
Review feedback.
1677
            handle.close()
2671.3.5 by Robert Collins
* New methods on ``bzrlib.transport.Transport`` ``open_file_stream`` and
1678
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1679
    def test_get_smart_medium(self):
1680
        """All transports must either give a smart medium, or know they can't.
1681
        """
1682
        transport = self.get_transport()
1683
        try:
2018.5.2 by Andrew Bennetts
Start splitting bzrlib/transport/smart.py into a package.
1684
            client_medium = transport.get_smart_medium()
1685
            self.assertIsInstance(client_medium, medium.SmartClientMedium)
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
1686
        except errors.NoSmartMedium:
1687
            # as long as we got it we're fine
1688
            pass
1689
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1690
    def test_readv_short_read(self):
1691
        transport = self.get_transport()
1692
        if transport.is_readonly():
1693
            file('a', 'w').write('0123456789')
1694
        else:
1695
            transport.put_bytes('a', '01234567890')
1696
1697
        # This is intentionally reading off the end of the file
1698
        # 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 :)
1699
        self.assertListRaises((errors.ShortReadvError, errors.InvalidRange,
1700
                               # Can be raised by paramiko
1701
                               AssertionError),
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1702
                              transport.readv, 'a', [(1,1), (8,10)])
1703
1704
        # This is trying to seek past the end of the file, it should
1705
        # 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 :)
1706
        self.assertListRaises((errors.ShortReadvError, errors.InvalidRange),
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
1707
                              transport.readv, 'a', [(12,2)])