/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
1
# Copyright (C) 2004, 2005, 2006 by 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
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
25
import stat
26
import sys
1530.1.3 by Robert Collins
transport implementations now tested consistently.
27
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
28
from bzrlib import (
29
    osutils,
30
    urlutils,
31
    )
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
32
from bzrlib.errors import (DirectoryNotEmpty, NoSuchFile, FileExists,
1185.85.84 by John Arbash Meinel
[merge] bzr.dev 1573, lots of updates
33
                           LockError, PathError,
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
34
                           TransportNotPossible, ConnectionError,
35
                           InvalidURL)
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
36
from bzrlib.osutils import getcwd
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
37
from bzrlib.tests import TestCaseInTempDir, TestSkipped
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
38
from bzrlib.tests.test_transport import TestTransportImplementation
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
39
from bzrlib.transport import memory
1530.1.3 by Robert Collins
transport implementations now tested consistently.
40
import bzrlib.transport
41
42
43
def _append(fn, txt):
44
    """Append the given text (file-like object) to the supplied filename."""
45
    f = open(fn, 'ab')
1530.1.21 by Robert Collins
Review feedback fixes.
46
    try:
47
        f.write(txt.read())
48
    finally:
49
        f.close()
1530.1.3 by Robert Collins
transport implementations now tested consistently.
50
51
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
52
class TransportTests(TestTransportImplementation):
53
1530.1.3 by Robert Collins
transport implementations now tested consistently.
54
    def check_transport_contents(self, content, transport, relpath):
55
        """Check that transport.get(relpath).read() == content."""
1530.1.21 by Robert Collins
Review feedback fixes.
56
        self.assertEqualDiff(content, transport.get(relpath).read())
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
57
1530.1.3 by Robert Collins
transport implementations now tested consistently.
58
    def assertListRaises(self, excClass, func, *args, **kwargs):
1530.1.21 by Robert Collins
Review feedback fixes.
59
        """Fail unless excClass is raised when the iterator from func is used.
60
        
61
        Many transport functions can return generators this makes sure
1530.1.3 by Robert Collins
transport implementations now tested consistently.
62
        to wrap them in a list() call to make sure the whole generator
63
        is run, and that the proper exception is raised.
64
        """
65
        try:
66
            list(func(*args, **kwargs))
67
        except excClass:
68
            return
69
        else:
70
            if hasattr(excClass,'__name__'): excName = excClass.__name__
71
            else: excName = str(excClass)
72
            raise self.failureException, "%s not raised" % excName
73
74
    def test_has(self):
75
        t = self.get_transport()
76
77
        files = ['a', 'b', 'e', 'g', '%']
78
        self.build_tree(files, transport=t)
79
        self.assertEqual(True, t.has('a'))
80
        self.assertEqual(False, t.has('c'))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
81
        self.assertEqual(True, t.has(urlutils.escape('%')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
82
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])),
83
                [True, True, False, False, True, False, True, False])
84
        self.assertEqual(True, t.has_any(['a', 'b', 'c']))
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
85
        self.assertEqual(False, t.has_any(['c', 'd', 'f', urlutils.escape('%%')]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
86
        self.assertEqual(list(t.has_multi(iter(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']))),
87
                [True, True, False, False, True, False, True, False])
88
        self.assertEqual(False, t.has_any(['c', 'c', 'c']))
89
        self.assertEqual(True, t.has_any(['b', 'b', 'b']))
90
91
    def test_get(self):
92
        t = self.get_transport()
93
94
        files = ['a', 'b', 'e', 'g']
95
        contents = ['contents of a\n',
96
                    'contents of b\n',
97
                    'contents of e\n',
98
                    'contents of g\n',
99
                    ]
1551.2.39 by abentley
Fix line endings in tests
100
        self.build_tree(files, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
101
        self.check_transport_contents('contents of a\n', t, 'a')
102
        content_f = t.get_multi(files)
103
        for content, f in zip(contents, content_f):
104
            self.assertEqual(content, f.read())
105
106
        content_f = t.get_multi(iter(files))
107
        for content, f in zip(contents, content_f):
108
            self.assertEqual(content, f.read())
109
110
        self.assertRaises(NoSuchFile, t.get, 'c')
111
        self.assertListRaises(NoSuchFile, t.get_multi, ['a', 'b', 'c'])
112
        self.assertListRaises(NoSuchFile, t.get_multi, iter(['a', 'b', 'c']))
113
114
    def test_put(self):
115
        t = self.get_transport()
116
117
        if t.is_readonly():
118
            self.assertRaises(TransportNotPossible,
119
                    t.put, 'a', 'some text for a\n')
120
            return
121
122
        t.put('a', StringIO('some text for a\n'))
123
        self.failUnless(t.has('a'))
124
        self.check_transport_contents('some text for a\n', t, 'a')
125
        # Make sure 'has' is updated
126
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e'])),
127
                [True, False, False, False, False])
128
        # Put also replaces contents
129
        self.assertEqual(t.put_multi([('a', StringIO('new\ncontents for\na\n')),
130
                                      ('d', StringIO('contents\nfor d\n'))]),
131
                         2)
132
        self.assertEqual(list(t.has_multi(['a', 'b', 'c', 'd', 'e'])),
133
                [True, False, False, True, False])
134
        self.check_transport_contents('new\ncontents for\na\n', t, 'a')
135
        self.check_transport_contents('contents\nfor d\n', t, 'd')
136
137
        self.assertEqual(
138
            t.put_multi(iter([('a', StringIO('diff\ncontents for\na\n')),
139
                              ('d', StringIO('another contents\nfor d\n'))])),
140
                        2)
141
        self.check_transport_contents('diff\ncontents for\na\n', t, 'a')
142
        self.check_transport_contents('another contents\nfor d\n', t, 'd')
143
144
        self.assertRaises(NoSuchFile,
145
                          t.put, 'path/doesnt/exist/c', 'contents')
146
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
147
    def test_put_permissions(self):
148
        t = self.get_transport()
149
150
        if t.is_readonly():
151
            return
1711.4.32 by John Arbash Meinel
Skip permission tests on win32 no modebits
152
        if not t._can_roundtrip_unix_modebits():
153
            # Can't roundtrip, so no need to run this test
154
            return
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
155
        t.put('mode644', StringIO('test text\n'), mode=0644)
1530.1.21 by Robert Collins
Review feedback fixes.
156
        self.assertTransportMode(t, 'mode644', 0644)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
157
        t.put('mode666', StringIO('test text\n'), mode=0666)
1530.1.21 by Robert Collins
Review feedback fixes.
158
        self.assertTransportMode(t, 'mode666', 0666)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
159
        t.put('mode600', StringIO('test text\n'), mode=0600)
1530.1.21 by Robert Collins
Review feedback fixes.
160
        self.assertTransportMode(t, 'mode600', 0600)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
161
        # Yes, you can put a file such that it becomes readonly
162
        t.put('mode400', StringIO('test text\n'), mode=0400)
1530.1.21 by Robert Collins
Review feedback fixes.
163
        self.assertTransportMode(t, 'mode400', 0400)
1530.1.15 by Robert Collins
Move put mode tests into test_transport_implementation.
164
        t.put_multi([('mmode644', StringIO('text\n'))], mode=0644)
1530.1.21 by Robert Collins
Review feedback fixes.
165
        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
166
167
        # The default permissions should be based on the current umask
168
        umask = osutils.get_umask()
169
        t.put('nomode', StringIO('test text\n'), mode=None)
170
        self.assertTransportMode(t, 'nomode', 0666 & ~umask)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
171
        
1530.1.3 by Robert Collins
transport implementations now tested consistently.
172
    def test_mkdir(self):
173
        t = self.get_transport()
174
175
        if t.is_readonly():
176
            # cannot mkdir on readonly transports. We're not testing for 
177
            # cache coherency because cache behaviour is not currently
178
            # defined for the transport interface.
179
            self.assertRaises(TransportNotPossible, t.mkdir, '.')
180
            self.assertRaises(TransportNotPossible, t.mkdir, 'new_dir')
181
            self.assertRaises(TransportNotPossible, t.mkdir_multi, ['new_dir'])
182
            self.assertRaises(TransportNotPossible, t.mkdir, 'path/doesnt/exist')
183
            return
184
        # Test mkdir
185
        t.mkdir('dir_a')
186
        self.assertEqual(t.has('dir_a'), True)
187
        self.assertEqual(t.has('dir_b'), False)
188
189
        t.mkdir('dir_b')
190
        self.assertEqual(t.has('dir_b'), True)
191
192
        t.mkdir_multi(['dir_c', 'dir_d'])
193
194
        t.mkdir_multi(iter(['dir_e', 'dir_f']))
195
        self.assertEqual(list(t.has_multi(
196
            ['dir_a', 'dir_b', 'dir_c', 'dir_q',
197
             'dir_d', 'dir_e', 'dir_f', 'dir_b'])),
198
            [True, True, True, False,
199
             True, True, True, True])
200
201
        # we were testing that a local mkdir followed by a transport
202
        # mkdir failed thusly, but given that we * in one process * do not
203
        # concurrently fiddle with disk dirs and then use transport to do 
204
        # things, the win here seems marginal compared to the constraint on
205
        # the interface. RBC 20051227
206
        t.mkdir('dir_g')
207
        self.assertRaises(FileExists, t.mkdir, 'dir_g')
208
209
        # Test get/put in sub-directories
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.
210
        self.assertEqual(2, 
1530.1.3 by Robert Collins
transport implementations now tested consistently.
211
            t.put_multi([('dir_a/a', StringIO('contents of dir_a/a')),
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.
212
                         ('dir_b/b', StringIO('contents of dir_b/b'))]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
213
        self.check_transport_contents('contents of dir_a/a', t, 'dir_a/a')
214
        self.check_transport_contents('contents of dir_b/b', t, 'dir_b/b')
215
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
216
        # mkdir of a dir with an absent parent
217
        self.assertRaises(NoSuchFile, t.mkdir, 'missing/dir')
218
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
219
    def test_mkdir_permissions(self):
220
        t = self.get_transport()
221
        if t.is_readonly():
222
            return
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
223
        if not t._can_roundtrip_unix_modebits():
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
224
            # no sense testing on this transport
225
            return
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
226
        # Test mkdir with a mode
227
        t.mkdir('dmode755', mode=0755)
1530.1.21 by Robert Collins
Review feedback fixes.
228
        self.assertTransportMode(t, 'dmode755', 0755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
229
        t.mkdir('dmode555', mode=0555)
1530.1.21 by Robert Collins
Review feedback fixes.
230
        self.assertTransportMode(t, 'dmode555', 0555)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
231
        t.mkdir('dmode777', mode=0777)
1530.1.21 by Robert Collins
Review feedback fixes.
232
        self.assertTransportMode(t, 'dmode777', 0777)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
233
        t.mkdir('dmode700', mode=0700)
1530.1.21 by Robert Collins
Review feedback fixes.
234
        self.assertTransportMode(t, 'dmode700', 0700)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
235
        t.mkdir_multi(['mdmode755'], mode=0755)
1530.1.21 by Robert Collins
Review feedback fixes.
236
        self.assertTransportMode(t, 'mdmode755', 0755)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
237
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
238
        # Default mode should be based on umask
239
        umask = osutils.get_umask()
240
        t.mkdir('dnomode', mode=None)
241
        self.assertTransportMode(t, 'dnomode', 0777 & ~umask)
242
1530.1.3 by Robert Collins
transport implementations now tested consistently.
243
    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.
244
        # FIXME: test:   same server to same server (partly done)
245
        # same protocol two servers
246
        # and    different protocols (done for now except for MemoryTransport.
247
        # - RBC 20060122
1530.1.3 by Robert Collins
transport implementations now tested consistently.
248
        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.
249
250
        def simple_copy_files(transport_from, transport_to):
251
            files = ['a', 'b', 'c', 'd']
252
            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.
253
            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.
254
            for f in files:
255
                self.check_transport_contents(transport_to.get(f).read(),
256
                                              transport_from, f)
257
1530.1.3 by Robert Collins
transport implementations now tested consistently.
258
        t = self.get_transport()
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
259
        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.
260
        simple_copy_files(t, temp_transport)
261
        if not t.is_readonly():
262
            t.mkdir('copy_to_simple')
263
            t2 = t.clone('copy_to_simple')
264
            simple_copy_files(t, t2)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
265
266
267
        # Test that copying into a missing directory raises
268
        # NoSuchFile
269
        if t.is_readonly():
1530.1.21 by Robert Collins
Review feedback fixes.
270
            self.build_tree(['e/', 'e/f'])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
271
        else:
272
            t.mkdir('e')
273
            t.put('e/f', StringIO('contents of e'))
274
        self.assertRaises(NoSuchFile, t.copy_to, ['e/f'], temp_transport)
275
        temp_transport.mkdir('e')
276
        t.copy_to(['e/f'], temp_transport)
277
278
        del temp_transport
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
279
        temp_transport = MemoryTransport('memory:///')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
280
281
        files = ['a', 'b', 'c', 'd']
282
        t.copy_to(iter(files), temp_transport)
283
        for f in files:
284
            self.check_transport_contents(temp_transport.get(f).read(),
285
                                          t, f)
286
        del temp_transport
287
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
288
        for mode in (0666, 0644, 0600, 0400):
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
289
            temp_transport = MemoryTransport("memory:///")
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
290
            t.copy_to(files, temp_transport, mode=mode)
291
            for f in files:
1530.1.21 by Robert Collins
Review feedback fixes.
292
                self.assertTransportMode(temp_transport, f, mode)
1530.1.16 by Robert Collins
Move mkdir and copy_to permissions tests to test_transport_impleentation.
293
1530.1.3 by Robert Collins
transport implementations now tested consistently.
294
    def test_append(self):
295
        t = self.get_transport()
296
297
        if t.is_readonly():
298
            open('a', 'wb').write('diff\ncontents for\na\n')
299
            open('b', 'wb').write('contents\nfor b\n')
300
        else:
301
            t.put_multi([
302
                    ('a', StringIO('diff\ncontents for\na\n')),
303
                    ('b', StringIO('contents\nfor b\n'))
304
                    ])
305
306
        if t.is_readonly():
307
            self.assertRaises(TransportNotPossible,
308
                    t.append, 'a', 'add\nsome\nmore\ncontents\n')
309
            _append('a', StringIO('add\nsome\nmore\ncontents\n'))
310
        else:
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.
311
            self.assertEqual(20,
312
                t.append('a', StringIO('add\nsome\nmore\ncontents\n')))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
313
314
        self.check_transport_contents(
315
            'diff\ncontents for\na\nadd\nsome\nmore\ncontents\n',
316
            t, 'a')
317
318
        if t.is_readonly():
319
            self.assertRaises(TransportNotPossible,
320
                    t.append_multi,
321
                        [('a', 'and\nthen\nsome\nmore\n'),
322
                         ('b', 'some\nmore\nfor\nb\n')])
323
            _append('a', StringIO('and\nthen\nsome\nmore\n'))
324
            _append('b', StringIO('some\nmore\nfor\nb\n'))
325
        else:
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.
326
            self.assertEqual((43, 15), 
327
                t.append_multi([('a', StringIO('and\nthen\nsome\nmore\n')),
328
                                ('b', StringIO('some\nmore\nfor\nb\n'))]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
329
        self.check_transport_contents(
330
            'diff\ncontents for\na\n'
331
            'add\nsome\nmore\ncontents\n'
332
            'and\nthen\nsome\nmore\n',
333
            t, 'a')
334
        self.check_transport_contents(
335
                'contents\nfor b\n'
336
                'some\nmore\nfor\nb\n',
337
                t, 'b')
338
339
        if t.is_readonly():
340
            _append('a', StringIO('a little bit more\n'))
341
            _append('b', StringIO('from an iterator\n'))
342
        else:
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.
343
            self.assertEqual((62, 31),
344
                t.append_multi(iter([('a', StringIO('a little bit more\n')),
345
                                     ('b', StringIO('from an iterator\n'))])))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
346
        self.check_transport_contents(
347
            'diff\ncontents for\na\n'
348
            'add\nsome\nmore\ncontents\n'
349
            'and\nthen\nsome\nmore\n'
350
            'a little bit more\n',
351
            t, 'a')
352
        self.check_transport_contents(
353
                'contents\nfor b\n'
354
                'some\nmore\nfor\nb\n'
355
                'from an iterator\n',
356
                t, 'b')
357
358
        if t.is_readonly():
359
            _append('c', StringIO('some text\nfor a missing file\n'))
360
            _append('a', StringIO('some text in a\n'))
361
            _append('d', StringIO('missing file r\n'))
362
        else:
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.
363
            self.assertEqual(0,
364
                t.append('c', StringIO('some text\nfor a missing file\n')))
365
            self.assertEqual((80, 0),
366
                t.append_multi([('a', StringIO('some text in a\n')),
367
                                ('d', StringIO('missing file r\n'))]))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
368
        self.check_transport_contents(
369
            'diff\ncontents for\na\n'
370
            'add\nsome\nmore\ncontents\n'
371
            'and\nthen\nsome\nmore\n'
372
            'a little bit more\n'
373
            'some text in a\n',
374
            t, 'a')
375
        self.check_transport_contents('some text\nfor a missing file\n',
376
                                      t, 'c')
377
        self.check_transport_contents('missing file r\n', t, 'd')
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
378
        
379
        # a file with no parent should fail..
380
        if not t.is_readonly():
381
            self.assertRaises(NoSuchFile,
382
                              t.append, 'missing/path', 
383
                              StringIO('content'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
384
385
    def test_append_file(self):
386
        t = self.get_transport()
387
388
        contents = [
389
            ('f1', StringIO('this is a string\nand some more stuff\n')),
390
            ('f2', StringIO('here is some text\nand a bit more\n')),
391
            ('f3', StringIO('some text for the\nthird file created\n')),
392
            ('f4', StringIO('this is a string\nand some more stuff\n')),
393
            ('f5', StringIO('here is some text\nand a bit more\n')),
394
            ('f6', StringIO('some text for the\nthird file created\n'))
395
        ]
396
        
397
        if t.is_readonly():
398
            for f, val in contents:
399
                open(f, 'wb').write(val.read())
400
        else:
401
            t.put_multi(contents)
402
403
        a1 = StringIO('appending to\none\n')
404
        if t.is_readonly():
405
            _append('f1', a1)
406
        else:
407
            t.append('f1', a1)
408
409
        del a1
410
411
        self.check_transport_contents(
412
                'this is a string\nand some more stuff\n'
413
                'appending to\none\n',
414
                t, 'f1')
415
416
        a2 = StringIO('adding more\ntext to two\n')
417
        a3 = StringIO('some garbage\nto put in three\n')
418
419
        if t.is_readonly():
420
            _append('f2', a2)
421
            _append('f3', a3)
422
        else:
423
            t.append_multi([('f2', a2), ('f3', a3)])
424
425
        del a2, a3
426
427
        self.check_transport_contents(
428
                'here is some text\nand a bit more\n'
429
                'adding more\ntext to two\n',
430
                t, 'f2')
431
        self.check_transport_contents( 
432
                'some text for the\nthird file created\n'
433
                'some garbage\nto put in three\n',
434
                t, 'f3')
435
436
        # Test that an actual file object can be used with put
437
        a4 = t.get('f1')
438
        if t.is_readonly():
439
            _append('f4', a4)
440
        else:
441
            t.append('f4', a4)
442
443
        del a4
444
445
        self.check_transport_contents(
446
                'this is a string\nand some more stuff\n'
447
                'this is a string\nand some more stuff\n'
448
                'appending to\none\n',
449
                t, 'f4')
450
451
        a5 = t.get('f2')
452
        a6 = t.get('f3')
453
        if t.is_readonly():
454
            _append('f5', a5)
455
            _append('f6', a6)
456
        else:
457
            t.append_multi([('f5', a5), ('f6', a6)])
458
459
        del a5, a6
460
461
        self.check_transport_contents(
462
                'here is some text\nand a bit more\n'
463
                'here is some text\nand a bit more\n'
464
                'adding more\ntext to two\n',
465
                t, 'f5')
466
        self.check_transport_contents(
467
                'some text for the\nthird file created\n'
468
                'some text for the\nthird file created\n'
469
                'some garbage\nto put in three\n',
470
                t, 'f6')
471
472
        a5 = t.get('f2')
473
        a6 = t.get('f2')
474
        a7 = t.get('f3')
475
        if t.is_readonly():
476
            _append('c', a5)
477
            _append('a', a6)
478
            _append('d', a7)
479
        else:
480
            t.append('c', a5)
481
            t.append_multi([('a', a6), ('d', a7)])
482
        del a5, a6, a7
483
        self.check_transport_contents(t.get('f2').read(), t, 'c')
484
        self.check_transport_contents(t.get('f3').read(), t, 'd')
485
1666.1.6 by Robert Collins
Make knit the default format.
486
    def test_append_mode(self):
487
        # check append accepts a mode
488
        t = self.get_transport()
489
        if t.is_readonly():
490
            return
491
        t.append('f', StringIO('f'), mode=None)
492
        
1530.1.3 by Robert Collins
transport implementations now tested consistently.
493
    def test_delete(self):
494
        # TODO: Test Transport.delete
495
        t = self.get_transport()
496
497
        # Not much to do with a readonly transport
498
        if t.is_readonly():
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
499
            self.assertRaises(TransportNotPossible, t.delete, 'missing')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
500
            return
501
502
        t.put('a', StringIO('a little bit of text\n'))
503
        self.failUnless(t.has('a'))
504
        t.delete('a')
505
        self.failIf(t.has('a'))
506
507
        self.assertRaises(NoSuchFile, t.delete, 'a')
508
509
        t.put('a', StringIO('a text\n'))
510
        t.put('b', StringIO('b text\n'))
511
        t.put('c', StringIO('c text\n'))
512
        self.assertEqual([True, True, True],
513
                list(t.has_multi(['a', 'b', 'c'])))
514
        t.delete_multi(['a', 'c'])
515
        self.assertEqual([False, True, False],
516
                list(t.has_multi(['a', 'b', 'c'])))
517
        self.failIf(t.has('a'))
518
        self.failUnless(t.has('b'))
519
        self.failIf(t.has('c'))
520
521
        self.assertRaises(NoSuchFile,
522
                t.delete_multi, ['a', 'b', 'c'])
523
524
        self.assertRaises(NoSuchFile,
525
                t.delete_multi, iter(['a', 'b', 'c']))
526
527
        t.put('a', StringIO('another a text\n'))
528
        t.put('c', StringIO('another c text\n'))
529
        t.delete_multi(iter(['a', 'b', 'c']))
530
531
        # We should have deleted everything
532
        # SftpServer creates control files in the
533
        # working directory, so we can just do a
534
        # plain "listdir".
535
        # self.assertEqual([], os.listdir('.'))
536
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
537
    def test_rmdir(self):
538
        t = self.get_transport()
539
        # Not much to do with a readonly transport
540
        if t.is_readonly():
541
            self.assertRaises(TransportNotPossible, t.rmdir, 'missing')
542
            return
543
        t.mkdir('adir')
544
        t.mkdir('adir/bdir')
545
        t.rmdir('adir/bdir')
546
        self.assertRaises(NoSuchFile, t.stat, 'adir/bdir')
547
        t.rmdir('adir')
548
        self.assertRaises(NoSuchFile, t.stat, 'adir')
549
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
550
    def test_rmdir_not_empty(self):
551
        """Deleting a non-empty directory raises an exception
552
        
553
        sftp (and possibly others) don't give us a specific "directory not
554
        empty" exception -- we can just see that the operation failed.
555
        """
556
        t = self.get_transport()
557
        if t.is_readonly():
558
            return
559
        t.mkdir('adir')
560
        t.mkdir('adir/bdir')
561
        self.assertRaises(PathError, t.rmdir, 'adir')
562
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
563
    def test_rename_dir_succeeds(self):
564
        t = self.get_transport()
565
        if t.is_readonly():
566
            raise TestSkipped("transport is readonly")
567
        t.mkdir('adir')
568
        t.mkdir('adir/asubdir')
569
        t.rename('adir', 'bdir')
570
        self.assertTrue(t.has('bdir/asubdir'))
571
        self.assertFalse(t.has('adir'))
572
573
    def test_rename_dir_nonempty(self):
574
        """Attempting to replace a nonemtpy directory should fail"""
575
        t = self.get_transport()
576
        if t.is_readonly():
577
            raise TestSkipped("transport is readonly")
578
        t.mkdir('adir')
579
        t.mkdir('adir/asubdir')
580
        t.mkdir('bdir')
581
        t.mkdir('bdir/bsubdir')
582
        self.assertRaises(PathError, t.rename, 'bdir', 'adir')
583
        # nothing was changed so it should still be as before
584
        self.assertTrue(t.has('bdir/bsubdir'))
585
        self.assertFalse(t.has('adir/bdir'))
586
        self.assertFalse(t.has('adir/bsubdir'))
587
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
588
    def test_delete_tree(self):
589
        t = self.get_transport()
590
591
        # Not much to do with a readonly transport
592
        if t.is_readonly():
593
            self.assertRaises(TransportNotPossible, t.delete_tree, 'missing')
594
            return
595
596
        # and does it like listing ?
597
        t.mkdir('adir')
598
        try:
599
            t.delete_tree('adir')
600
        except TransportNotPossible:
601
            # ok, this transport does not support delete_tree
602
            return
603
        
604
        # did it delete that trivial case?
605
        self.assertRaises(NoSuchFile, t.stat, 'adir')
606
607
        self.build_tree(['adir/',
608
                         'adir/file', 
609
                         'adir/subdir/', 
610
                         'adir/subdir/file', 
611
                         'adir/subdir2/',
612
                         'adir/subdir2/file',
613
                         ], transport=t)
614
615
        t.delete_tree('adir')
616
        # adir should be gone now.
617
        self.assertRaises(NoSuchFile, t.stat, 'adir')
618
1530.1.3 by Robert Collins
transport implementations now tested consistently.
619
    def test_move(self):
620
        t = self.get_transport()
621
622
        if t.is_readonly():
623
            return
624
625
        # TODO: I would like to use os.listdir() to
626
        # make sure there are no extra files, but SftpServer
627
        # creates control files in the working directory
628
        # perhaps all of this could be done in a subdirectory
629
630
        t.put('a', StringIO('a first file\n'))
631
        self.assertEquals([True, False], list(t.has_multi(['a', 'b'])))
632
633
        t.move('a', 'b')
634
        self.failUnless(t.has('b'))
635
        self.failIf(t.has('a'))
636
637
        self.check_transport_contents('a first file\n', t, 'b')
638
        self.assertEquals([False, True], list(t.has_multi(['a', 'b'])))
639
640
        # Overwrite a file
641
        t.put('c', StringIO('c this file\n'))
642
        t.move('c', 'b')
643
        self.failIf(t.has('c'))
644
        self.check_transport_contents('c this file\n', t, 'b')
645
646
        # TODO: Try to write a test for atomicity
647
        # TODO: Test moving into a non-existant subdirectory
648
        # TODO: Test Transport.move_multi
649
650
    def test_copy(self):
651
        t = self.get_transport()
652
653
        if t.is_readonly():
654
            return
655
656
        t.put('a', StringIO('a file\n'))
657
        t.copy('a', 'b')
658
        self.check_transport_contents('a file\n', t, 'b')
659
660
        self.assertRaises(NoSuchFile, t.copy, 'c', 'd')
661
        os.mkdir('c')
662
        # What should the assert be if you try to copy a
663
        # file over a directory?
664
        #self.assertRaises(Something, t.copy, 'a', 'c')
665
        t.put('d', StringIO('text in d\n'))
666
        t.copy('d', 'b')
667
        self.check_transport_contents('text in d\n', t, 'b')
668
669
        # TODO: test copy_multi
670
671
    def test_connection_error(self):
672
        """ConnectionError is raised when connection is impossible"""
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
673
        try:
674
            url = self._server.get_bogus_url()
675
        except NotImplementedError:
676
            raise TestSkipped("Transport %s has no bogus URL support." %
677
                              self._server.__class__)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
678
        try:
1711.2.42 by John Arbash Meinel
enable bogus_url support for SFTP tests
679
            t = bzrlib.transport.get_transport(url)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
680
            t.get('.bzr/branch')
681
        except (ConnectionError, NoSuchFile), e:
682
            pass
683
        except (Exception), e:
1786.1.27 by John Arbash Meinel
Fix up the http transports so that tests pass with the new configuration.
684
            self.fail('Wrong exception thrown (%s.%s): %s' 
685
                        % (e.__class__.__module__, e.__class__.__name__, e))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
686
        else:
1707.3.11 by John Arbash Meinel
fixing more tests.
687
            self.fail('Did not get the expected ConnectionError or NoSuchFile.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
688
689
    def test_stat(self):
690
        # TODO: Test stat, just try once, and if it throws, stop testing
691
        from stat import S_ISDIR, S_ISREG
692
693
        t = self.get_transport()
694
695
        try:
696
            st = t.stat('.')
697
        except TransportNotPossible, e:
698
            # This transport cannot stat
699
            return
700
701
        paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e']
702
        sizes = [14, 0, 16, 0, 18] 
1551.2.39 by abentley
Fix line endings in tests
703
        self.build_tree(paths, transport=t, line_endings='binary')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
704
705
        for path, size in zip(paths, sizes):
706
            st = t.stat(path)
707
            if path.endswith('/'):
708
                self.failUnless(S_ISDIR(st.st_mode))
709
                # directory sizes are meaningless
710
            else:
711
                self.failUnless(S_ISREG(st.st_mode))
712
                self.assertEqual(size, st.st_size)
713
714
        remote_stats = list(t.stat_multi(paths))
715
        remote_iter_stats = list(t.stat_multi(iter(paths)))
716
717
        self.assertRaises(NoSuchFile, t.stat, 'q')
718
        self.assertRaises(NoSuchFile, t.stat, 'b/a')
719
720
        self.assertListRaises(NoSuchFile, t.stat_multi, ['a', 'c', 'd'])
721
        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.
722
        self.build_tree(['subdir/', 'subdir/file'], transport=t)
723
        subdir = t.clone('subdir')
724
        subdir.stat('./file')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
725
        subdir.stat('.')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
726
727
    def test_list_dir(self):
728
        # TODO: Test list_dir, just try once, and if it throws, stop testing
729
        t = self.get_transport()
730
        
731
        if not t.listable():
732
            self.assertRaises(TransportNotPossible, t.list_dir, '.')
733
            return
734
735
        def sorted_list(d):
736
            l = list(t.list_dir(d))
737
            l.sort()
738
            return l
739
740
        # SftpServer creates control files in the working directory
741
        # so lets move down a directory to avoid those.
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
742
        if not t.is_readonly():
743
            t.mkdir('wd')
744
        else:
745
            os.mkdir('wd')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
746
        t = t.clone('wd')
747
1959.2.2 by John Arbash Meinel
Apply Andrew Bennetts list_dir fixes
748
        self.assertEqual([], sorted_list('.'))
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
749
        # c2 is precisely one letter longer than c here to test that
750
        # suffixing is not confused.
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
751
        # a%25b checks that quoting is done consistently across transports
752
        tree_names = ['a', 'a%25b', 'b', 'c/', 'c/d', 'c/e', 'c2/']
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
753
        if not t.is_readonly():
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
754
            self.build_tree(tree_names, transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
755
        else:
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
756
            self.build_tree(['wd/' + name for name in tree_names])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
757
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
758
        self.assertEqual(
1959.2.3 by John Arbash Meinel
Remove some unicode string notations
759
            ['a', 'a%2525b', 'b', 'c', 'c2'], sorted_list('.'))
760
        self.assertEqual(['d', 'e'], sorted_list('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
761
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
762
        if not t.is_readonly():
763
            t.delete('c/d')
764
            t.delete('b')
765
        else:
766
            os.unlink('wd/c/d')
767
            os.unlink('wd/b')
768
            
1959.2.3 by John Arbash Meinel
Remove some unicode string notations
769
        self.assertEqual(['a', 'a%2525b', 'c', 'c2'], sorted_list('.'))
770
        self.assertEqual(['e'], sorted_list('c'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
771
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
772
        self.assertListRaises(PathError, t.list_dir, 'q')
773
        self.assertListRaises(PathError, t.list_dir, 'c/f')
774
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
775
776
    def test_clone(self):
777
        # TODO: Test that clone moves up and down the filesystem
778
        t1 = self.get_transport()
779
780
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
781
782
        self.failUnless(t1.has('a'))
783
        self.failUnless(t1.has('b/c'))
784
        self.failIf(t1.has('c'))
785
786
        t2 = t1.clone('b')
787
        self.assertEqual(t1.base + 'b/', t2.base)
788
789
        self.failUnless(t2.has('c'))
790
        self.failIf(t2.has('a'))
791
792
        t3 = t2.clone('..')
793
        self.failUnless(t3.has('a'))
794
        self.failIf(t3.has('c'))
795
796
        self.failIf(t1.has('b/d'))
797
        self.failIf(t2.has('d'))
798
        self.failIf(t3.has('b/d'))
799
800
        if t1.is_readonly():
801
            open('b/d', 'wb').write('newfile\n')
802
        else:
803
            t2.put('d', StringIO('newfile\n'))
804
805
        self.failUnless(t1.has('b/d'))
806
        self.failUnless(t2.has('d'))
807
        self.failUnless(t3.has('b/d'))
808
809
    def test_relpath(self):
810
        t = self.get_transport()
811
        self.assertEqual('', t.relpath(t.base))
812
        # base ends with /
813
        self.assertEqual('', t.relpath(t.base[:-1]))
814
        # subdirs which dont exist should still give relpaths.
815
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
816
        # trailing slash should be the same.
817
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
818
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
819
    def test_relpath_at_root(self):
820
        t = self.get_transport()
821
        # clone all the way to the top
822
        new_transport = t.clone('..')
823
        while new_transport.base != t.base:
824
            t = new_transport
825
            new_transport = t.clone('..')
826
        # we must be able to get a relpath below the root
827
        self.assertEqual('', t.relpath(t.base))
828
        # and a deeper one should work too
829
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
830
1530.1.3 by Robert Collins
transport implementations now tested consistently.
831
    def test_abspath(self):
832
        # smoke test for abspath. Corner cases for backends like unix fs's
833
        # that have aliasing problems like symlinks should go in backend
834
        # specific test cases.
835
        transport = self.get_transport()
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
836
        
837
        # disabled because some transports might normalize urls in generating
838
        # the abspath - eg http+pycurl-> just http -- mbp 20060308 
1530.1.3 by Robert Collins
transport implementations now tested consistently.
839
        self.assertEqual(transport.base + 'relpath',
840
                         transport.abspath('relpath'))
841
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
842
    def test_local_abspath(self):
843
        transport = self.get_transport()
844
        try:
845
            p = transport.local_abspath('.')
846
        except TransportNotPossible:
847
            pass # This is not a local transport
848
        else:
849
            self.assertEqual(getcwd(), p)
850
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
851
    def test_abspath_at_root(self):
852
        t = self.get_transport()
853
        # clone all the way to the top
854
        new_transport = t.clone('..')
855
        while new_transport.base != t.base:
856
            t = new_transport
857
            new_transport = t.clone('..')
858
        # we must be able to get a abspath of the root when we ask for
859
        # t.abspath('..') - this due to our choice that clone('..')
860
        # should return the root from the root, combined with the desire that
861
        # the url from clone('..') and from abspath('..') should be the same.
862
        self.assertEqual(t.base, t.abspath('..'))
863
        # '' should give us the root
864
        self.assertEqual(t.base, t.abspath(''))
865
        # and a path should append to the url
866
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
867
1530.1.3 by Robert Collins
transport implementations now tested consistently.
868
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
869
        transport = self.get_transport()
870
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
871
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
872
                              transport.iter_files_recursive)
873
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
874
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
875
                         'isolated/dir/',
876
                         'isolated/dir/foo',
877
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
878
                         'isolated/dir/b%25z', # make sure quoting is correct
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
879
                         'isolated/bar'],
880
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
881
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
882
        # nb the directories are not converted
883
        self.assertEqual(paths,
884
                    set(['isolated/dir/foo',
885
                         'isolated/dir/bar',
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
886
                         'isolated/dir/b%2525z',
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
887
                         'isolated/bar']))
888
        sub_transport = transport.clone('isolated')
889
        paths = set(sub_transport.iter_files_recursive())
1959.2.1 by John Arbash Meinel
David Allouche: Make transports return escaped paths
890
        self.assertEqual(paths,
891
            set(['dir/foo', 'dir/bar', 'dir/b%2525z', 'bar']))
892
893
    def test_copy_tree(self):
894
        # TODO: test file contents and permissions are preserved. This test was
895
        # added just to ensure that quoting was handled correctly.
896
        # -- David Allouche 2006-08-11
897
        transport = self.get_transport()
898
        if not transport.listable():
899
            self.assertRaises(TransportNotPossible,
900
                              transport.iter_files_recursive)
901
            return
902
        if transport.is_readonly():
903
            self.assertRaises(TransportNotPossible,
904
                              transport.put, 'a', 'some text for a\n')
905
            return
906
        self.build_tree(['from/',
907
                         'from/dir/',
908
                         'from/dir/foo',
909
                         'from/dir/bar',
910
                         'from/dir/b%25z', # make sure quoting is correct
911
                         'from/bar'],
912
                        transport=transport)
913
        transport.copy_tree('from', 'to')
914
        paths = set(transport.iter_files_recursive())
915
        self.assertEqual(paths,
916
                    set(['from/dir/foo',
917
                         'from/dir/bar',
918
                         'from/dir/b%2525z',
919
                         'from/bar',
920
                         'to/dir/foo',
921
                         'to/dir/bar',
922
                         'to/dir/b%2525z',
923
                         'to/bar',]))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
924
925
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
926
        """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
927
        t = self.get_transport()
928
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
929
        # With FAT32 and certain encodings on win32
930
        # '\xe5' and '\xe4' actually map to the same file
931
        # adding a suffix kicks in the 'preserving but insensitive'
932
        # route, and maintains the right files
933
        files = [u'\xe5.1', # a w/ circle iso-8859-1
934
                 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
935
                 u'\u017d', # Z with umlat iso-8859-2
936
                 u'\u062c', # Arabic j
937
                 u'\u0410', # Russian A
938
                 u'\u65e5', # Kanji person
939
                ]
940
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
941
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
942
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
943
        except UnicodeError:
944
            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
945
946
        # A plain unicode string is not a valid url
947
        for fname in files:
948
            self.assertRaises(InvalidURL, t.get, fname)
949
950
        for fname in files:
951
            fname_utf8 = fname.encode('utf-8')
952
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
953
            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
954
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
955
    def test_connect_twice_is_same_content(self):
956
        # check that our server (whatever it is) is accessable reliably
957
        # via get_transport and multiple connections share content.
958
        transport = self.get_transport()
959
        if transport.is_readonly():
960
            return
961
        transport.put('foo', StringIO('bar'))
962
        transport2 = self.get_transport()
963
        self.check_transport_contents('bar', transport2, 'foo')
964
        # its base should be usable.
965
        transport2 = bzrlib.transport.get_transport(transport.base)
966
        self.check_transport_contents('bar', transport2, 'foo')
967
968
        # now opening at a relative url should give use a sane result:
969
        transport.mkdir('newdir')
970
        transport2 = bzrlib.transport.get_transport(transport.base + "newdir")
971
        transport2 = transport2.clone('..')
972
        self.check_transport_contents('bar', transport2, 'foo')
973
974
    def test_lock_write(self):
975
        transport = self.get_transport()
976
        if transport.is_readonly():
977
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
978
            return
979
        transport.put('lock', StringIO())
980
        lock = transport.lock_write('lock')
981
        # TODO make this consistent on all platforms:
982
        # self.assertRaises(LockError, transport.lock_write, 'lock')
983
        lock.unlock()
984
985
    def test_lock_read(self):
986
        transport = self.get_transport()
987
        if transport.is_readonly():
988
            file('lock', 'w').close()
989
        else:
990
            transport.put('lock', StringIO())
991
        lock = transport.lock_read('lock')
992
        # TODO make this consistent on all platforms:
993
        # self.assertRaises(LockError, transport.lock_read, 'lock')
994
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
995
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
996
    def test_readv(self):
997
        transport = self.get_transport()
998
        if transport.is_readonly():
999
            file('a', 'w').write('0123456789')
1000
        else:
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1001
            transport.put('a', StringIO('0123456789'))
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
1002
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1003
        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.
1004
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
1005
        self.assertEqual(d[1], (1, '1'))
1006
        self.assertEqual(d[2], (3, '34'))
1007
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
1008
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
1009
    def test_readv_out_of_order(self):
1010
        transport = self.get_transport()
1011
        if transport.is_readonly():
1012
            file('a', 'w').write('0123456789')
1013
        else:
1014
            transport.put('a', StringIO('01234567890'))
1015
1016
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
1017
        self.assertEqual(d[0], (1, '1'))
1018
        self.assertEqual(d[1], (9, '9'))
1019
        self.assertEqual(d[2], (0, '0'))
1020
        self.assertEqual(d[3], (3, '34'))