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