~bzr-pqm/bzr/bzr.dev

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
748
        self.assertEqual([], sorted_list(u'.'))
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.
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
751
        if not t.is_readonly():
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
752
            self.build_tree(['a', 'b', 'c/', 'c/d', 'c/e', 'c2/'], transport=t)
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
753
        else:
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
754
            self.build_tree(['wd/a', 'wd/b', 'wd/c/', 'wd/c/d', 'wd/c/e', 'wd/c2/'])
1530.1.3 by Robert Collins
transport implementations now tested consistently.
755
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
756
        self.assertEqual([u'a', u'b', u'c', u'c2'], sorted_list(u'.'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
757
        self.assertEqual([u'd', u'e'], sorted_list(u'c'))
758
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
759
        if not t.is_readonly():
760
            t.delete('c/d')
761
            t.delete('b')
762
        else:
763
            os.unlink('wd/c/d')
764
            os.unlink('wd/b')
765
            
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
766
        self.assertEqual([u'a', u'c', u'c2'], sorted_list('.'))
1530.1.3 by Robert Collins
transport implementations now tested consistently.
767
        self.assertEqual([u'e'], sorted_list(u'c'))
768
1662.1.12 by Martin Pool
Translate unknown sftp errors to PathError, no NoSuchFile
769
        self.assertListRaises(PathError, t.list_dir, 'q')
770
        self.assertListRaises(PathError, t.list_dir, 'c/f')
771
        self.assertListRaises(PathError, t.list_dir, 'a')
1530.1.3 by Robert Collins
transport implementations now tested consistently.
772
773
    def test_clone(self):
774
        # TODO: Test that clone moves up and down the filesystem
775
        t1 = self.get_transport()
776
777
        self.build_tree(['a', 'b/', 'b/c'], transport=t1)
778
779
        self.failUnless(t1.has('a'))
780
        self.failUnless(t1.has('b/c'))
781
        self.failIf(t1.has('c'))
782
783
        t2 = t1.clone('b')
784
        self.assertEqual(t1.base + 'b/', t2.base)
785
786
        self.failUnless(t2.has('c'))
787
        self.failIf(t2.has('a'))
788
789
        t3 = t2.clone('..')
790
        self.failUnless(t3.has('a'))
791
        self.failIf(t3.has('c'))
792
793
        self.failIf(t1.has('b/d'))
794
        self.failIf(t2.has('d'))
795
        self.failIf(t3.has('b/d'))
796
797
        if t1.is_readonly():
798
            open('b/d', 'wb').write('newfile\n')
799
        else:
800
            t2.put('d', StringIO('newfile\n'))
801
802
        self.failUnless(t1.has('b/d'))
803
        self.failUnless(t2.has('d'))
804
        self.failUnless(t3.has('b/d'))
805
806
    def test_relpath(self):
807
        t = self.get_transport()
808
        self.assertEqual('', t.relpath(t.base))
809
        # base ends with /
810
        self.assertEqual('', t.relpath(t.base[:-1]))
811
        # subdirs which dont exist should still give relpaths.
812
        self.assertEqual('foo', t.relpath(t.base + 'foo'))
813
        # trailing slash should be the same.
814
        self.assertEqual('foo', t.relpath(t.base + 'foo/'))
815
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
816
    def test_relpath_at_root(self):
817
        t = self.get_transport()
818
        # clone all the way to the top
819
        new_transport = t.clone('..')
820
        while new_transport.base != t.base:
821
            t = new_transport
822
            new_transport = t.clone('..')
823
        # we must be able to get a relpath below the root
824
        self.assertEqual('', t.relpath(t.base))
825
        # and a deeper one should work too
826
        self.assertEqual('foo/bar', t.relpath(t.base + 'foo/bar'))
827
1530.1.3 by Robert Collins
transport implementations now tested consistently.
828
    def test_abspath(self):
829
        # smoke test for abspath. Corner cases for backends like unix fs's
830
        # that have aliasing problems like symlinks should go in backend
831
        # specific test cases.
832
        transport = self.get_transport()
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
833
        
834
        # disabled because some transports might normalize urls in generating
835
        # the abspath - eg http+pycurl-> just http -- mbp 20060308 
1530.1.3 by Robert Collins
transport implementations now tested consistently.
836
        self.assertEqual(transport.base + 'relpath',
837
                         transport.abspath('relpath'))
838
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
839
    def test_local_abspath(self):
840
        transport = self.get_transport()
841
        try:
842
            p = transport.local_abspath('.')
843
        except TransportNotPossible:
844
            pass # This is not a local transport
845
        else:
846
            self.assertEqual(getcwd(), p)
847
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
848
    def test_abspath_at_root(self):
849
        t = self.get_transport()
850
        # clone all the way to the top
851
        new_transport = t.clone('..')
852
        while new_transport.base != t.base:
853
            t = new_transport
854
            new_transport = t.clone('..')
855
        # we must be able to get a abspath of the root when we ask for
856
        # t.abspath('..') - this due to our choice that clone('..')
857
        # should return the root from the root, combined with the desire that
858
        # the url from clone('..') and from abspath('..') should be the same.
859
        self.assertEqual(t.base, t.abspath('..'))
860
        # '' should give us the root
861
        self.assertEqual(t.base, t.abspath(''))
862
        # and a path should append to the url
863
        self.assertEqual(t.base + 'foo', t.abspath('foo'))
864
1530.1.3 by Robert Collins
transport implementations now tested consistently.
865
    def test_iter_files_recursive(self):
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
866
        transport = self.get_transport()
867
        if not transport.listable():
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
868
            self.assertRaises(TransportNotPossible,
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
869
                              transport.iter_files_recursive)
870
            return
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
871
        self.build_tree(['isolated/',
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
872
                         'isolated/dir/',
873
                         'isolated/dir/foo',
874
                         'isolated/dir/bar',
875
                         'isolated/bar'],
876
                        transport=transport)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
877
        paths = set(transport.iter_files_recursive())
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
878
        # nb the directories are not converted
879
        self.assertEqual(paths,
880
                    set(['isolated/dir/foo',
881
                         'isolated/dir/bar',
882
                         'isolated/bar']))
883
        sub_transport = transport.clone('isolated')
884
        paths = set(sub_transport.iter_files_recursive())
1530.1.3 by Robert Collins
transport implementations now tested consistently.
885
        self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
1185.85.76 by John Arbash Meinel
Adding an InvalidURL so transports can report they expect utf-8 quoted paths. Updated tests
886
887
    def test_unicode_paths(self):
1685.1.57 by Martin Pool
[broken] Skip unicode blackbox tests if not supported by filesystem
888
        """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
889
        t = self.get_transport()
890
1711.7.36 by John Arbash Meinel
Use different filenames to avoid path collisions on win32 w/ FAT32
891
        # With FAT32 and certain encodings on win32
892
        # '\xe5' and '\xe4' actually map to the same file
893
        # adding a suffix kicks in the 'preserving but insensitive'
894
        # route, and maintains the right files
895
        files = [u'\xe5.1', # a w/ circle iso-8859-1
896
                 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
897
                 u'\u017d', # Z with umlat iso-8859-2
898
                 u'\u062c', # Arabic j
899
                 u'\u0410', # Russian A
900
                 u'\u65e5', # Kanji person
901
                ]
902
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
903
        try:
1711.4.13 by John Arbash Meinel
Use line_endings='binary' for win32
904
            self.build_tree(files, transport=t, line_endings='binary')
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
905
        except UnicodeError:
906
            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
907
908
        # A plain unicode string is not a valid url
909
        for fname in files:
910
            self.assertRaises(InvalidURL, t.get, fname)
911
912
        for fname in files:
913
            fname_utf8 = fname.encode('utf-8')
914
            contents = 'contents of %s\n' % (fname_utf8,)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
915
            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
916
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
917
    def test_connect_twice_is_same_content(self):
918
        # check that our server (whatever it is) is accessable reliably
919
        # via get_transport and multiple connections share content.
920
        transport = self.get_transport()
921
        if transport.is_readonly():
922
            return
923
        transport.put('foo', StringIO('bar'))
924
        transport2 = self.get_transport()
925
        self.check_transport_contents('bar', transport2, 'foo')
926
        # its base should be usable.
927
        transport2 = bzrlib.transport.get_transport(transport.base)
928
        self.check_transport_contents('bar', transport2, 'foo')
929
930
        # now opening at a relative url should give use a sane result:
931
        transport.mkdir('newdir')
932
        transport2 = bzrlib.transport.get_transport(transport.base + "newdir")
933
        transport2 = transport2.clone('..')
934
        self.check_transport_contents('bar', transport2, 'foo')
935
936
    def test_lock_write(self):
937
        transport = self.get_transport()
938
        if transport.is_readonly():
939
            self.assertRaises(TransportNotPossible, transport.lock_write, 'foo')
940
            return
941
        transport.put('lock', StringIO())
942
        lock = transport.lock_write('lock')
943
        # TODO make this consistent on all platforms:
944
        # self.assertRaises(LockError, transport.lock_write, 'lock')
945
        lock.unlock()
946
947
    def test_lock_read(self):
948
        transport = self.get_transport()
949
        if transport.is_readonly():
950
            file('lock', 'w').close()
951
        else:
952
            transport.put('lock', StringIO())
953
        lock = transport.lock_read('lock')
954
        # TODO make this consistent on all platforms:
955
        # self.assertRaises(LockError, transport.lock_read, 'lock')
956
        lock.unlock()
1185.85.80 by John Arbash Meinel
[merge] jam-integration 1527, including branch-formats, help text, misc bug fixes.
957
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
958
    def test_readv(self):
959
        transport = self.get_transport()
960
        if transport.is_readonly():
961
            file('a', 'w').write('0123456789')
962
        else:
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
963
            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
964
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
965
        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.
966
        self.assertEqual(d[0], (0, '0'))
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
967
        self.assertEqual(d[1], (1, '1'))
968
        self.assertEqual(d[2], (3, '34'))
969
        self.assertEqual(d[3], (9, '9'))
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
970
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
971
    def test_readv_out_of_order(self):
972
        transport = self.get_transport()
973
        if transport.is_readonly():
974
            file('a', 'w').write('0123456789')
975
        else:
976
            transport.put('a', StringIO('01234567890'))
977
978
        d = list(transport.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
979
        self.assertEqual(d[0], (1, '1'))
980
        self.assertEqual(d[1], (9, '9'))
981
        self.assertEqual(d[2], (0, '0'))
982
        self.assertEqual(d[3], (3, '34'))