/brz/remove-bazaar

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