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