/brz/remove-bazaar

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