/brz/remove-bazaar

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