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