/brz/remove-bazaar

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