/brz/remove-bazaar

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