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