~bzr-pqm/bzr/bzr.dev

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