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