/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4634.108.13 by John Arbash Meinel
Add a test case.
1
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
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
#
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
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
#
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
907.1.48 by John Arbash Meinel
Updated LocalTransport by passing it through the transport_test suite, and got it to pass.
16
17
1185.11.22 by John Arbash Meinel
Major refactoring of testtransport.
18
from cStringIO import StringIO
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
19
import os
20
import subprocess
21
import sys
22
import threading
1442.1.44 by Robert Collins
Many transport related tweaks:
23
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
24
from bzrlib import (
25
    errors,
2804.4.1 by Alexander Belchenko
some win32-specific fixes for selftest
26
    osutils,
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
27
    tests,
4634.108.13 by John Arbash Meinel
Add a test case.
28
    transport as _mod_transport,
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
29
    urlutils,
30
    )
4634.108.13 by John Arbash Meinel
Add a test case.
31
from bzrlib.transport import (
4946.1.2 by John Arbash Meinel
Clean up a few more imports.
32
    fakenfs,
4634.108.13 by John Arbash Meinel
Add a test case.
33
    memory,
4946.1.2 by John Arbash Meinel
Clean up a few more imports.
34
    readonly,
4634.108.13 by John Arbash Meinel
Add a test case.
35
    )
2892.1.1 by Andrew Bennetts
Fix bug 146715: bzr+ssh:// and sftp:// should not assume port-not-specified means port 22
36
from bzrlib.errors import (DependencyNotPresent,
2379.2.1 by Robert Collins
Rewritten chroot transport that prevents accidental chroot escapes when
37
                           FileExists,
38
                           InvalidURLJoin,
39
                           NoSuchFile,
40
                           PathNotChild,
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
41
                           ReadError,
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
42
                           UnsupportedProtocol,
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
43
                           )
4913.2.16 by John Arbash Meinel
Move bzrlib.tests.ParamikoFeature to bzrlib.tests.features.paramiko
44
from bzrlib.tests import features, TestCase, TestCaseInTempDir
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
45
from bzrlib.transport import (_clear_protocol_handlers,
46
                              _CoalescedOffset,
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
47
                              ConnectedTransport,
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
48
                              _get_protocol_handlers,
2241.2.2 by ghigo
Create the TransportList class
49
                              _set_protocol_handlers,
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
50
                              _get_transport_modules,
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
51
                              get_transport,
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
52
                              LateReadError,
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
53
                              register_lazy_transport,
2241.2.2 by ghigo
Create the TransportList class
54
                              register_transport_proto,
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
55
                              Transport,
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
56
                              )
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
57
from bzrlib.transport.chroot import ChrootServer
2245.6.1 by Alexander Belchenko
win32 UNC path: recursive cloning UNC path to root stops on //HOST, not on //
58
from bzrlib.transport.local import (LocalTransport,
2245.6.2 by Alexander Belchenko
Fix name of emulated Win32LocalTransport as Robert suggested.
59
                                    EmulatedWin32LocalTransport)
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
60
from bzrlib.transport.pathfilter import PathFilteringServer
1951.2.1 by Martin Pool
Change to using LocalURLServer for testing.
61
62
63
# TODO: Should possibly split transport-specific tests into their own files.
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
64
65
1185.58.3 by John Arbash Meinel
code cleanup
66
class TestTransport(TestCase):
67
    """Test the non transport-concrete class functionality."""
68
2241.3.1 by ghigo
uncomment test test__get_set_protocol_handlers
69
    def test__get_set_protocol_handlers(self):
70
        handlers = _get_protocol_handlers()
71
        self.assertNotEqual([], handlers.keys( ))
72
        try:
73
            _clear_protocol_handlers()
74
            self.assertEqual([], _get_protocol_handlers().keys())
75
        finally:
76
            _set_protocol_handlers(handlers)
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
77
78
    def test_get_transport_modules(self):
79
        handlers = _get_protocol_handlers()
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
80
        # don't pollute the current handlers
81
        _clear_protocol_handlers()
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
82
        class SampleHandler(object):
83
            """I exist, isnt that enough?"""
84
        try:
2241.2.2 by ghigo
Create the TransportList class
85
            _clear_protocol_handlers()
86
            register_transport_proto('foo')
3004.2.1 by Vincent Ladeuil
Fix 150860 by leaving port as user specified it.
87
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
88
                                    'TestTransport.SampleHandler')
2241.2.2 by ghigo
Create the TransportList class
89
            register_transport_proto('bar')
3004.2.1 by Vincent Ladeuil
Fix 150860 by leaving port as user specified it.
90
            register_lazy_transport('bar', 'bzrlib.tests.test_transport',
91
                                    'TestTransport.SampleHandler')
92
            self.assertEqual([SampleHandler.__module__,
4634.43.21 by Andrew Bennetts
Update test_get_transport_modules for pathfilter.
93
                              'bzrlib.transport.chroot',
94
                              'bzrlib.transport.pathfilter'],
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
95
                             _get_transport_modules())
96
        finally:
97
            _set_protocol_handlers(handlers)
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
98
99
    def test_transport_dependency(self):
100
        """Transport with missing dependency causes no error"""
101
        saved_handlers = _get_protocol_handlers()
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
102
        # don't pollute the current handlers
103
        _clear_protocol_handlers()
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
104
        try:
2241.2.2 by ghigo
Create the TransportList class
105
            register_transport_proto('foo')
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
106
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
107
                    'BadTransportHandler')
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
108
            try:
109
                get_transport('foo://fooserver/foo')
110
            except UnsupportedProtocol, e:
111
                e_str = str(e)
112
                self.assertEquals('Unsupported protocol'
113
                                  ' for url "foo://fooserver/foo":'
114
                                  ' Unable to import library "some_lib":'
115
                                  ' testing missing dependency', str(e))
116
            else:
117
                self.fail('Did not raise UnsupportedProtocol')
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
118
        finally:
1540.3.10 by Martin Pool
[broken] keep hooking pycurl into test framework
119
            # restore original values
120
            _set_protocol_handlers(saved_handlers)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
121
1540.3.10 by Martin Pool
[broken] keep hooking pycurl into test framework
122
    def test_transport_fallback(self):
123
        """Transport with missing dependency causes no error"""
124
        saved_handlers = _get_protocol_handlers()
125
        try:
2241.2.2 by ghigo
Create the TransportList class
126
            _clear_protocol_handlers()
127
            register_transport_proto('foo')
1540.3.10 by Martin Pool
[broken] keep hooking pycurl into test framework
128
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
129
                    'BackupTransportHandler')
130
            register_lazy_transport('foo', 'bzrlib.tests.test_transport',
131
                    'BadTransportHandler')
132
            t = get_transport('foo://fooserver/foo')
133
            self.assertTrue(isinstance(t, BackupTransportHandler))
134
        finally:
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
135
            _set_protocol_handlers(saved_handlers)
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
136
4011.4.1 by Jelmer Vernooij
Point out bzr+ssh:// to the user when they use ssh://.
137
    def test_ssh_hints(self):
138
        """Transport ssh:// should raise an error pointing out bzr+ssh://"""
139
        try:
140
            get_transport('ssh://fooserver/foo')
141
        except UnsupportedProtocol, e:
142
            e_str = str(e)
143
            self.assertEquals('Unsupported protocol'
144
                              ' for url "ssh://fooserver/foo":'
4032.1.4 by John Arbash Meinel
Found 2 more files with trailing whitespace.
145
                              ' bzr supports bzr+ssh to operate over ssh, use "bzr+ssh://fooserver/foo".',
4011.4.1 by Jelmer Vernooij
Point out bzr+ssh:// to the user when they use ssh://.
146
                              str(e))
147
        else:
148
            self.fail('Did not raise UnsupportedProtocol')
149
2052.6.1 by Robert Collins
``Transport.get`` has had its interface made more clear for ease of use.
150
    def test_LateReadError(self):
151
        """The LateReadError helper should raise on read()."""
152
        a_file = LateReadError('a path')
153
        try:
154
            a_file.read()
155
        except ReadError, error:
156
            self.assertEqual('a path', error.path)
157
        self.assertRaises(ReadError, a_file.read, 40)
158
        a_file.close()
159
1996.3.20 by John Arbash Meinel
[merge] bzr.dev 2063
160
    def test__combine_paths(self):
161
        t = Transport('/')
162
        self.assertEqual('/home/sarah/project/foo',
163
                         t._combine_paths('/home/sarah', 'project/foo'))
164
        self.assertEqual('/etc',
165
                         t._combine_paths('/home/sarah', '../../etc'))
2070.3.2 by Andrew Bennetts
Merge from bzr.dev
166
        self.assertEqual('/etc',
167
                         t._combine_paths('/home/sarah', '../../../etc'))
168
        self.assertEqual('/etc',
169
                         t._combine_paths('/home/sarah', '/etc'))
1996.3.20 by John Arbash Meinel
[merge] bzr.dev 2063
170
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
171
    def test_local_abspath_non_local_transport(self):
172
        # the base implementation should throw
4634.108.13 by John Arbash Meinel
Add a test case.
173
        t = memory.MemoryTransport()
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
174
        e = self.assertRaises(errors.NotLocalUrl, t.local_abspath, 't')
175
        self.assertEqual('memory:///t is not a local path.', str(e))
176
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
177
178
class TestCoalesceOffsets(TestCase):
3059.2.17 by Vincent Ladeuil
Limit GET requests by body size instead of number of ranges.
179
180
    def check(self, expected, offsets, limit=0, max_size=0, fudge=0):
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
181
        coalesce = Transport._coalesce_offsets
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
182
        exp = [_CoalescedOffset(*x) for x in expected]
3059.2.17 by Vincent Ladeuil
Limit GET requests by body size instead of number of ranges.
183
        out = list(coalesce(offsets, limit=limit, fudge_factor=fudge,
184
                            max_size=max_size))
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
185
        self.assertEqual(exp, out)
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
186
187
    def test_coalesce_empty(self):
188
        self.check([], [])
189
190
    def test_coalesce_simple(self):
191
        self.check([(0, 10, [(0, 10)])], [(0, 10)])
192
193
    def test_coalesce_unrelated(self):
194
        self.check([(0, 10, [(0, 10)]),
195
                    (20, 10, [(0, 10)]),
196
                   ], [(0, 10), (20, 10)])
3059.2.17 by Vincent Ladeuil
Limit GET requests by body size instead of number of ranges.
197
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
198
    def test_coalesce_unsorted(self):
199
        self.check([(20, 10, [(0, 10)]),
200
                    (0, 10, [(0, 10)]),
201
                   ], [(20, 10), (0, 10)])
202
203
    def test_coalesce_nearby(self):
204
        self.check([(0, 20, [(0, 10), (10, 10)])],
205
                   [(0, 10), (10, 10)])
206
207
    def test_coalesce_overlapped(self):
3686.1.9 by John Arbash Meinel
Overlapping ranges are not allowed anymore.
208
        self.assertRaises(ValueError,
209
            self.check, [(0, 15, [(0, 10), (5, 10)])],
210
                        [(0, 10), (5, 10)])
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
211
212
    def test_coalesce_limit(self):
213
        self.check([(10, 50, [(0, 10), (10, 10), (20, 10),
214
                              (30, 10), (40, 10)]),
215
                    (60, 50, [(0, 10), (10, 10), (20, 10),
216
                              (30, 10), (40, 10)]),
217
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
218
                       (50, 10), (60, 10), (70, 10), (80, 10),
219
                       (90, 10), (100, 10)],
220
                    limit=5)
221
222
    def test_coalesce_no_limit(self):
223
        self.check([(10, 100, [(0, 10), (10, 10), (20, 10),
224
                               (30, 10), (40, 10), (50, 10),
225
                               (60, 10), (70, 10), (80, 10),
226
                               (90, 10)]),
227
                   ], [(10, 10), (20, 10), (30, 10), (40, 10),
228
                       (50, 10), (60, 10), (70, 10), (80, 10),
229
                       (90, 10), (100, 10)])
230
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
231
    def test_coalesce_fudge(self):
232
        self.check([(10, 30, [(0, 10), (20, 10)]),
233
                    (100, 10, [(0, 10),]),
234
                   ], [(10, 10), (30, 10), (100, 10)],
235
                   fudge=10
236
                  )
3059.2.17 by Vincent Ladeuil
Limit GET requests by body size instead of number of ranges.
237
    def test_coalesce_max_size(self):
238
        self.check([(10, 20, [(0, 10), (10, 10)]),
239
                    (30, 50, [(0, 50)]),
240
                    # If one range is above max_size, it gets its own coalesced
241
                    # offset
242
                    (100, 80, [(0, 80),]),],
243
                   [(10, 10), (20, 10), (30, 50), (100, 80)],
244
                   max_size=50
245
                  )
246
247
    def test_coalesce_no_max_size(self):
248
        self.check([(10, 170, [(0, 10), (10, 10), (20, 50), (70, 100)]),],
249
                   [(10, 10), (20, 10), (30, 50), (80, 100)],
250
                  )
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
251
3876.1.2 by John Arbash Meinel
Add a test case that checks the 100MB limit.
252
    def test_coalesce_default_limit(self):
253
        # By default we use a 100MB max size.
254
        ten_mb = 10*1024*1024
255
        self.check([(0, 10*ten_mb, [(i*ten_mb, ten_mb) for i in range(10)]),
256
                    (10*ten_mb, ten_mb, [(0, ten_mb)])],
257
                   [(i*ten_mb, ten_mb) for i in range(11)])
258
        self.check([(0, 11*ten_mb, [(i*ten_mb, ten_mb) for i in range(11)]),],
259
                   [(i*ten_mb, ten_mb) for i in range(11)],
260
                   max_size=1*1024*1024*1024)
261
1540.3.3 by Martin Pool
Review updates of pycurl transport
262
4634.108.13 by John Arbash Meinel
Add a test case.
263
class TestMemoryServer(TestCase):
264
265
    def test_create_server(self):
266
        server = memory.MemoryServer()
4946.1.2 by John Arbash Meinel
Clean up a few more imports.
267
        server.start_server()
4634.108.13 by John Arbash Meinel
Add a test case.
268
        url = server.get_url()
269
        self.assertTrue(url in _mod_transport.transport_list_registry)
270
        t = _mod_transport.get_transport(url)
271
        del t
4946.1.2 by John Arbash Meinel
Clean up a few more imports.
272
        server.stop_server()
4634.108.13 by John Arbash Meinel
Add a test case.
273
        self.assertFalse(url in _mod_transport.transport_list_registry)
274
        self.assertRaises(errors.UnsupportedProtocol,
275
                          _mod_transport.get_transport, url)
276
277
1442.1.44 by Robert Collins
Many transport related tweaks:
278
class TestMemoryTransport(TestCase):
279
280
    def test_get_transport(self):
4634.108.13 by John Arbash Meinel
Add a test case.
281
        memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
282
283
    def test_clone(self):
4634.108.13 by John Arbash Meinel
Add a test case.
284
        transport = memory.MemoryTransport()
285
        self.assertTrue(isinstance(transport, memory.MemoryTransport))
1910.15.3 by Andrew Bennetts
Make memory transport pass tests.
286
        self.assertEqual("memory:///", transport.clone("/").base)
1442.1.44 by Robert Collins
Many transport related tweaks:
287
288
    def test_abspath(self):
4634.108.13 by John Arbash Meinel
Add a test case.
289
        transport = memory.MemoryTransport()
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
290
        self.assertEqual("memory:///relpath", transport.abspath('relpath'))
1442.1.44 by Robert Collins
Many transport related tweaks:
291
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
292
    def test_abspath_of_root(self):
4634.108.13 by John Arbash Meinel
Add a test case.
293
        transport = memory.MemoryTransport()
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
294
        self.assertEqual("memory:///", transport.base)
295
        self.assertEqual("memory:///", transport.abspath('/'))
296
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
297
    def test_abspath_of_relpath_starting_at_root(self):
4634.108.13 by John Arbash Meinel
Add a test case.
298
        transport = memory.MemoryTransport()
2070.3.1 by Andrew Bennetts
Fix memory_transport.abspath('/foo')
299
        self.assertEqual("memory:///foo", transport.abspath('/foo'))
1442.1.44 by Robert Collins
Many transport related tweaks:
300
301
    def test_append_and_get(self):
4634.108.13 by John Arbash Meinel
Add a test case.
302
        transport = memory.MemoryTransport()
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
303
        transport.append_bytes('path', 'content')
1442.1.44 by Robert Collins
Many transport related tweaks:
304
        self.assertEqual(transport.get('path').read(), 'content')
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
305
        transport.append_file('path', StringIO('content'))
1442.1.44 by Robert Collins
Many transport related tweaks:
306
        self.assertEqual(transport.get('path').read(), 'contentcontent')
307
308
    def test_put_and_get(self):
4634.108.13 by John Arbash Meinel
Add a test case.
309
        transport = memory.MemoryTransport()
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
310
        transport.put_file('path', StringIO('content'))
1442.1.44 by Robert Collins
Many transport related tweaks:
311
        self.assertEqual(transport.get('path').read(), 'content')
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
312
        transport.put_bytes('path', 'content')
1442.1.44 by Robert Collins
Many transport related tweaks:
313
        self.assertEqual(transport.get('path').read(), 'content')
314
315
    def test_append_without_dir_fails(self):
4634.108.13 by John Arbash Meinel
Add a test case.
316
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
317
        self.assertRaises(NoSuchFile,
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
318
                          transport.append_bytes, 'dir/path', 'content')
1442.1.44 by Robert Collins
Many transport related tweaks:
319
320
    def test_put_without_dir_fails(self):
4634.108.13 by John Arbash Meinel
Add a test case.
321
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
322
        self.assertRaises(NoSuchFile,
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
323
                          transport.put_file, 'dir/path', StringIO('content'))
1442.1.44 by Robert Collins
Many transport related tweaks:
324
325
    def test_get_missing(self):
4634.108.13 by John Arbash Meinel
Add a test case.
326
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
327
        self.assertRaises(NoSuchFile, transport.get, 'foo')
328
329
    def test_has_missing(self):
4634.108.13 by John Arbash Meinel
Add a test case.
330
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
331
        self.assertEquals(False, transport.has('foo'))
332
333
    def test_has_present(self):
4634.108.13 by John Arbash Meinel
Add a test case.
334
        transport = memory.MemoryTransport()
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
335
        transport.append_bytes('foo', 'content')
1442.1.44 by Robert Collins
Many transport related tweaks:
336
        self.assertEquals(True, transport.has('foo'))
337
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
338
    def test_list_dir(self):
4634.108.13 by John Arbash Meinel
Add a test case.
339
        transport = memory.MemoryTransport()
2120.3.1 by John Arbash Meinel
Fix MemoryTransport.list_dir() implementation, and update tests
340
        transport.put_bytes('foo', 'content')
341
        transport.mkdir('dir')
342
        transport.put_bytes('dir/subfoo', 'content')
343
        transport.put_bytes('dirlike', 'content')
344
345
        self.assertEquals(['dir', 'dirlike', 'foo'], sorted(transport.list_dir('.')))
346
        self.assertEquals(['subfoo'], sorted(transport.list_dir('dir')))
347
1442.1.44 by Robert Collins
Many transport related tweaks:
348
    def test_mkdir(self):
4634.108.13 by John Arbash Meinel
Add a test case.
349
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
350
        transport.mkdir('dir')
1955.3.16 by John Arbash Meinel
Switch over to Transport.append_bytes or append_files
351
        transport.append_bytes('dir/path', 'content')
1442.1.44 by Robert Collins
Many transport related tweaks:
352
        self.assertEqual(transport.get('dir/path').read(), 'content')
353
354
    def test_mkdir_missing_parent(self):
4634.108.13 by John Arbash Meinel
Add a test case.
355
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
356
        self.assertRaises(NoSuchFile,
357
                          transport.mkdir, 'dir/dir')
358
359
    def test_mkdir_twice(self):
4634.108.13 by John Arbash Meinel
Add a test case.
360
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
361
        transport.mkdir('dir')
362
        self.assertRaises(FileExists, transport.mkdir, 'dir')
1530.1.5 by Robert Collins
Reinstate Memory parameter tests.
363
364
    def test_parameters(self):
4634.108.13 by John Arbash Meinel
Add a test case.
365
        transport = memory.MemoryTransport()
1530.1.5 by Robert Collins
Reinstate Memory parameter tests.
366
        self.assertEqual(True, transport.listable())
367
        self.assertEqual(False, transport.is_readonly())
1442.1.44 by Robert Collins
Many transport related tweaks:
368
369
    def test_iter_files_recursive(self):
4634.108.13 by John Arbash Meinel
Add a test case.
370
        transport = memory.MemoryTransport()
1442.1.44 by Robert Collins
Many transport related tweaks:
371
        transport.mkdir('dir')
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
372
        transport.put_bytes('dir/foo', 'content')
373
        transport.put_bytes('dir/bar', 'content')
374
        transport.put_bytes('bar', 'content')
1442.1.44 by Robert Collins
Many transport related tweaks:
375
        paths = set(transport.iter_files_recursive())
376
        self.assertEqual(set(['dir/foo', 'dir/bar', 'bar']), paths)
377
378
    def test_stat(self):
4634.108.13 by John Arbash Meinel
Add a test case.
379
        transport = memory.MemoryTransport()
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
380
        transport.put_bytes('foo', 'content')
381
        transport.put_bytes('bar', 'phowar')
1442.1.44 by Robert Collins
Many transport related tweaks:
382
        self.assertEqual(7, transport.stat('foo').st_size)
383
        self.assertEqual(6, transport.stat('bar').st_size)
1185.35.31 by Aaron Bentley
Throw ConnectionError instead of NoSuchFile except when we get a 404
384
2070.5.1 by Andrew Bennetts
Add ChrootTransportDecorator.
385
386
class ChrootDecoratorTransportTest(TestCase):
387
    """Chroot decoration specific tests."""
388
2018.5.54 by Andrew Bennetts
Fix ChrootTransportDecorator's abspath method to be consistent with its clone
389
    def test_abspath(self):
390
        # The abspath is always relative to the chroot_url.
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
391
        server = ChrootServer(get_transport('memory:///foo/bar/'))
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
392
        self.start_server(server)
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
393
        transport = get_transport(server.get_url())
394
        self.assertEqual(server.get_url(), transport.abspath('/'))
2018.5.54 by Andrew Bennetts
Fix ChrootTransportDecorator's abspath method to be consistent with its clone
395
396
        subdir_transport = transport.clone('subdir')
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
397
        self.assertEqual(server.get_url(), subdir_transport.abspath('/'))
2379.2.1 by Robert Collins
Rewritten chroot transport that prevents accidental chroot escapes when
398
399
    def test_clone(self):
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
400
        server = ChrootServer(get_transport('memory:///foo/bar/'))
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
401
        self.start_server(server)
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
402
        transport = get_transport(server.get_url())
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
403
        # relpath from root and root path are the same
404
        relpath_cloned = transport.clone('foo')
405
        abspath_cloned = transport.clone('/foo')
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
406
        self.assertEqual(server, relpath_cloned.server)
407
        self.assertEqual(server, abspath_cloned.server)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
408
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
409
    def test_chroot_url_preserves_chroot(self):
410
        """Calling get_transport on a chroot transport's base should produce a
411
        transport with exactly the same behaviour as the original chroot
412
        transport.
413
414
        This is so that it is not possible to escape a chroot by doing::
415
            url = chroot_transport.base
416
            parent_url = urlutils.join(url, '..')
417
            new_transport = get_transport(parent_url)
418
        """
419
        server = ChrootServer(get_transport('memory:///path/subpath'))
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
420
        self.start_server(server)
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
421
        transport = get_transport(server.get_url())
422
        new_transport = get_transport(transport.base)
423
        self.assertEqual(transport.server, new_transport.server)
424
        self.assertEqual(transport.base, new_transport.base)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
425
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
426
    def test_urljoin_preserves_chroot(self):
427
        """Using urlutils.join(url, '..') on a chroot URL should not produce a
428
        URL that escapes the intended chroot.
429
430
        This is so that it is not possible to escape a chroot by doing::
431
            url = chroot_transport.base
432
            parent_url = urlutils.join(url, '..')
433
            new_transport = get_transport(parent_url)
434
        """
435
        server = ChrootServer(get_transport('memory:///path/'))
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
436
        self.start_server(server)
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
437
        transport = get_transport(server.get_url())
438
        self.assertRaises(
439
            InvalidURLJoin, urlutils.join, transport.base, '..')
440
441
442
class ChrootServerTest(TestCase):
443
444
    def test_construct(self):
4634.108.13 by John Arbash Meinel
Add a test case.
445
        backing_transport = memory.MemoryTransport()
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
446
        server = ChrootServer(backing_transport)
447
        self.assertEqual(backing_transport, server.backing_transport)
448
449
    def test_setUp(self):
4634.108.13 by John Arbash Meinel
Add a test case.
450
        backing_transport = memory.MemoryTransport()
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
451
        server = ChrootServer(backing_transport)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
452
        server.start_server()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
453
        try:
454
            self.assertTrue(server.scheme in _get_protocol_handlers().keys())
455
        finally:
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
456
            server.stop_server()
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
457
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
458
    def test_stop_server(self):
4634.108.13 by John Arbash Meinel
Add a test case.
459
        backing_transport = memory.MemoryTransport()
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
460
        server = ChrootServer(backing_transport)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
461
        server.start_server()
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
462
        server.stop_server()
2241.3.5 by ghigo
update to the latest bzr.dev
463
        self.assertFalse(server.scheme in _get_protocol_handlers().keys())
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
464
465
    def test_get_url(self):
4634.108.13 by John Arbash Meinel
Add a test case.
466
        backing_transport = memory.MemoryTransport()
2018.5.104 by Andrew Bennetts
Completely rework chrooted transports.
467
        server = ChrootServer(backing_transport)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
468
        server.start_server()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
469
        try:
470
            self.assertEqual('chroot-%d:///' % id(server), server.get_url())
471
        finally:
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
472
            server.stop_server()
2018.5.53 by Andrew Bennetts
Small fix to urlutils.joinpath that was causing a misbehaviour in
473
2156.2.1 by v.ladeuil+lp at free
Make the tests windows compatible.
474
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
475
class PathFilteringDecoratorTransportTest(TestCase):
476
    """Pathfilter decoration specific tests."""
477
478
    def test_abspath(self):
479
        # The abspath is always relative to the base of the backing transport.
480
        server = PathFilteringServer(get_transport('memory:///foo/bar/'),
481
            lambda x: x)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
482
        server.start_server()
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
483
        transport = get_transport(server.get_url())
484
        self.assertEqual(server.get_url(), transport.abspath('/'))
485
486
        subdir_transport = transport.clone('subdir')
487
        self.assertEqual(server.get_url(), subdir_transport.abspath('/'))
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
488
        server.stop_server()
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
489
490
    def make_pf_transport(self, filter_func=None):
491
        """Make a PathFilteringTransport backed by a MemoryTransport.
492
        
493
        :param filter_func: by default this will be a no-op function.  Use this
494
            parameter to override it."""
495
        if filter_func is None:
496
            filter_func = lambda x: x
497
        server = PathFilteringServer(
498
            get_transport('memory:///foo/bar/'), filter_func)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
499
        server.start_server()
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
500
        self.addCleanup(server.stop_server)
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
501
        return get_transport(server.get_url())
502
503
    def test__filter(self):
504
        # _filter (with an identity func as filter_func) always returns
505
        # paths relative to the base of the backing transport.
506
        transport = self.make_pf_transport()
507
        self.assertEqual('foo', transport._filter('foo'))
508
        self.assertEqual('foo/bar', transport._filter('foo/bar'))
509
        self.assertEqual('', transport._filter('..'))
510
        self.assertEqual('', transport._filter('/'))
511
        # The base of the pathfiltering transport is taken into account too.
512
        transport = transport.clone('subdir1/subdir2')
513
        self.assertEqual('subdir1/subdir2/foo', transport._filter('foo'))
514
        self.assertEqual(
515
            'subdir1/subdir2/foo/bar', transport._filter('foo/bar'))
516
        self.assertEqual('subdir1', transport._filter('..'))
517
        self.assertEqual('', transport._filter('/'))
518
4634.44.2 by Andrew Bennetts
Add another test.
519
    def test_filter_invocation(self):
520
        filter_log = []
521
        def filter(path):
522
            filter_log.append(path)
523
            return path
524
        transport = self.make_pf_transport(filter)
525
        transport.has('abc')
526
        self.assertEqual(['abc'], filter_log)
527
        del filter_log[:]
528
        transport.clone('abc').has('xyz')
529
        self.assertEqual(['abc/xyz'], filter_log)
530
        del filter_log[:]
531
        transport.has('/abc')
532
        self.assertEqual(['abc'], filter_log)
533
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
534
    def test_clone(self):
4634.44.2 by Andrew Bennetts
Add another test.
535
        transport = self.make_pf_transport()
536
        # relpath from root and root path are the same
537
        relpath_cloned = transport.clone('foo')
538
        abspath_cloned = transport.clone('/foo')
539
        self.assertEqual(transport.server, relpath_cloned.server)
540
        self.assertEqual(transport.server, abspath_cloned.server)
4634.44.1 by Andrew Bennetts
First draft of a generic path-filtering transport decorator.
541
542
    def test_url_preserves_pathfiltering(self):
543
        """Calling get_transport on a pathfiltered transport's base should
544
        produce a transport with exactly the same behaviour as the original
545
        pathfiltered transport.
546
547
        This is so that it is not possible to escape (accidentally or
548
        otherwise) the filtering by doing::
549
            url = filtered_transport.base
550
            parent_url = urlutils.join(url, '..')
551
            new_transport = get_transport(parent_url)
552
        """
553
        transport = self.make_pf_transport()
554
        new_transport = get_transport(transport.base)
555
        self.assertEqual(transport.server, new_transport.server)
556
        self.assertEqual(transport.base, new_transport.base)
557
558
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
559
class ReadonlyDecoratorTransportTest(TestCase):
560
    """Readonly decoration specific tests."""
561
562
    def test_local_parameters(self):
563
        # connect to . in readonly mode
564
        transport = readonly.ReadonlyTransportDecorator('readonly+.')
565
        self.assertEqual(True, transport.listable())
566
        self.assertEqual(True, transport.is_readonly())
567
568
    def test_http_parameters(self):
2929.3.7 by Vincent Ladeuil
Rename bzrlib/test/HttpServer.py to bzrlib/tests/http_server.py and fix uses.
569
        from bzrlib.tests.http_server import HttpServer
570
        # connect to '.' via http which is not listable
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
571
        server = HttpServer()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
572
        self.start_server(server)
573
        transport = get_transport('readonly+' + server.get_url())
574
        self.failUnless(isinstance(transport,
575
                                   readonly.ReadonlyTransportDecorator))
576
        self.assertEqual(False, transport.listable())
577
        self.assertEqual(True, transport.is_readonly())
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
578
579
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
580
class FakeNFSDecoratorTests(TestCaseInTempDir):
581
    """NFS decorator specific tests."""
582
583
    def get_nfs_transport(self, url):
584
        # connect to url with nfs decoration
585
        return fakenfs.FakeNFSTransportDecorator('fakenfs+' + url)
586
587
    def test_local_parameters(self):
2701.1.1 by Martin Pool
Remove Transport.should_cache.
588
        # the listable and is_readonly parameters
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
589
        # are not changed by the fakenfs decorator
590
        transport = self.get_nfs_transport('.')
591
        self.assertEqual(True, transport.listable())
592
        self.assertEqual(False, transport.is_readonly())
593
594
    def test_http_parameters(self):
2701.1.1 by Martin Pool
Remove Transport.should_cache.
595
        # the listable and is_readonly parameters
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
596
        # are not changed by the fakenfs decorator
2929.3.7 by Vincent Ladeuil
Rename bzrlib/test/HttpServer.py to bzrlib/tests/http_server.py and fix uses.
597
        from bzrlib.tests.http_server import HttpServer
598
        # connect to '.' via http which is not listable
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
599
        server = HttpServer()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
600
        self.start_server(server)
601
        transport = self.get_nfs_transport(server.get_url())
602
        self.assertIsInstance(
4946.1.2 by John Arbash Meinel
Clean up a few more imports.
603
            transport, fakenfs.FakeNFSTransportDecorator)
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
604
        self.assertEqual(False, transport.listable())
605
        self.assertEqual(True, transport.is_readonly())
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
606
607
    def test_fakenfs_server_default(self):
608
        # a FakeNFSServer() should bring up a local relpath server for itself
609
        server = fakenfs.FakeNFSServer()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
610
        self.start_server(server)
611
        # the url should be decorated appropriately
612
        self.assertStartsWith(server.get_url(), 'fakenfs+')
613
        # and we should be able to get a transport for it
614
        transport = get_transport(server.get_url())
615
        # which must be a FakeNFSTransportDecorator instance.
616
        self.assertIsInstance(transport, fakenfs.FakeNFSTransportDecorator)
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
617
618
    def test_fakenfs_rename_semantics(self):
619
        # a FakeNFS transport must mangle the way rename errors occur to
620
        # look like NFS problems.
621
        transport = self.get_nfs_transport('.')
622
        self.build_tree(['from/', 'from/foo', 'to/', 'to/bar'],
623
                        transport=transport)
2018.18.12 by Martin Pool
small test cleanups
624
        self.assertRaises(errors.ResourceBusy,
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
625
                          transport.rename, 'from', 'to')
626
627
1608.2.4 by Martin Pool
[broken] Add FakeFVATTransport
628
class FakeVFATDecoratorTests(TestCaseInTempDir):
629
    """Tests for simulation of VFAT restrictions"""
630
631
    def get_vfat_transport(self, url):
632
        """Return vfat-backed transport for test directory"""
633
        from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
634
        return FakeVFATTransportDecorator('vfat+' + url)
635
636
    def test_transport_creation(self):
637
        from bzrlib.transport.fakevfat import FakeVFATTransportDecorator
638
        transport = self.get_vfat_transport('.')
639
        self.assertIsInstance(transport, FakeVFATTransportDecorator)
640
641
    def test_transport_mkdir(self):
642
        transport = self.get_vfat_transport('.')
643
        transport.mkdir('HELLO')
644
        self.assertTrue(transport.has('hello'))
645
        self.assertTrue(transport.has('Hello'))
646
1608.2.11 by Martin Pool
(FakeVFAT) add test for detection of invalid characters
647
    def test_forbidden_chars(self):
648
        transport = self.get_vfat_transport('.')
649
        self.assertRaises(ValueError, transport.has, "<NU>")
650
651
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
652
class BadTransportHandler(Transport):
653
    def __init__(self, base_url):
654
        raise DependencyNotPresent('some_lib', 'testing missing dependency')
655
656
657
class BackupTransportHandler(Transport):
658
    """Test transport that works as a backup for the BadTransportHandler"""
1540.3.10 by Martin Pool
[broken] keep hooking pycurl into test framework
659
    pass
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
660
661
662
class TestTransportImplementation(TestCaseInTempDir):
663
    """Implementation verification for transports.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
664
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
665
    To verify a transport we need a server factory, which is a callable
666
    that accepts no parameters and returns an implementation of
667
    bzrlib.transport.Server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
668
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
669
    That Server is then used to construct transport instances and test
670
    the transport via loopback activity.
671
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
672
    Currently this assumes that the Transport object is connected to the
673
    current working directory.  So that whatever is done
674
    through the transport, should show up in the working
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
675
    directory, and vice-versa. This is a bug, because its possible to have
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
676
    URL schemes which provide access to something that may not be
677
    result in storage on the local disk, i.e. due to file system limits, or
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
678
    due to it being a database or some other non-filesystem tool.
679
680
    This also tests to make sure that the functions work with both
681
    generators and lists (assuming iter(list) is effectively a generator)
682
    """
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
683
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
684
    def setUp(self):
685
        super(TestTransportImplementation, self).setUp()
686
        self._server = self.transport_server()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
687
        self.start_server(self._server)
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
688
2520.3.1 by Vincent Ladeuil
Fix 110448 by adding a relpath parameter to get_transport.
689
    def get_transport(self, relpath=None):
690
        """Return a connected transport to the local directory.
691
692
        :param relpath: a path relative to the base url.
693
        """
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
694
        base_url = self._server.get_url()
2520.3.1 by Vincent Ladeuil
Fix 110448 by adding a relpath parameter to get_transport.
695
        url = self._adjust_url(base_url, relpath)
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
696
        # try getting the transport via the regular interface:
2520.3.1 by Vincent Ladeuil
Fix 110448 by adding a relpath parameter to get_transport.
697
        t = get_transport(url)
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
698
        # vila--20070607 if the following are commented out the test suite
699
        # still pass. Is this really still needed or was it a forgotten
700
        # temporary fix ?
1986.2.5 by Robert Collins
Unbreak transport tests.
701
        if not isinstance(t, self.transport_class):
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
702
            # we did not get the correct transport class type. Override the
703
            # regular connection behaviour by direct construction.
2520.3.1 by Vincent Ladeuil
Fix 110448 by adding a relpath parameter to get_transport.
704
            t = self.transport_class(url)
1871.1.2 by Robert Collins
Reduce code duplication in transport-parameterised tests.
705
        return t
1951.2.1 by Martin Pool
Change to using LocalURLServer for testing.
706
707
708
class TestLocalTransports(TestCase):
709
710
    def test_get_transport_from_abspath(self):
2804.4.1 by Alexander Belchenko
some win32-specific fixes for selftest
711
        here = osutils.abspath('.')
1951.2.1 by Martin Pool
Change to using LocalURLServer for testing.
712
        t = get_transport(here)
713
        self.assertIsInstance(t, LocalTransport)
714
        self.assertEquals(t.base, urlutils.local_path_to_url(here) + '/')
715
716
    def test_get_transport_from_relpath(self):
2804.4.1 by Alexander Belchenko
some win32-specific fixes for selftest
717
        here = osutils.abspath('.')
1951.2.1 by Martin Pool
Change to using LocalURLServer for testing.
718
        t = get_transport('.')
719
        self.assertIsInstance(t, LocalTransport)
1951.2.3 by Martin Pool
Localtransport cleanup review (john)
720
        self.assertEquals(t.base, urlutils.local_path_to_url('.') + '/')
1951.2.1 by Martin Pool
Change to using LocalURLServer for testing.
721
722
    def test_get_transport_from_local_url(self):
2804.4.1 by Alexander Belchenko
some win32-specific fixes for selftest
723
        here = osutils.abspath('.')
1951.2.1 by Martin Pool
Change to using LocalURLServer for testing.
724
        here_url = urlutils.local_path_to_url(here) + '/'
725
        t = get_transport(here_url)
726
        self.assertIsInstance(t, LocalTransport)
727
        self.assertEquals(t.base, here_url)
2245.6.1 by Alexander Belchenko
win32 UNC path: recursive cloning UNC path to root stops on //HOST, not on //
728
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
729
    def test_local_abspath(self):
2804.4.1 by Alexander Belchenko
some win32-specific fixes for selftest
730
        here = osutils.abspath('.')
2018.18.4 by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test.
731
        t = get_transport(here)
732
        self.assertEquals(t.local_abspath(''), here)
733
2245.6.1 by Alexander Belchenko
win32 UNC path: recursive cloning UNC path to root stops on //HOST, not on //
734
735
class TestWin32LocalTransport(TestCase):
736
737
    def test_unc_clone_to_root(self):
738
        # Win32 UNC path like \\HOST\path
739
        # clone to root should stop at least at \\HOST part
740
        # not on \\
2245.6.2 by Alexander Belchenko
Fix name of emulated Win32LocalTransport as Robert suggested.
741
        t = EmulatedWin32LocalTransport('file://HOST/path/to/some/dir/')
2245.6.1 by Alexander Belchenko
win32 UNC path: recursive cloning UNC path to root stops on //HOST, not on //
742
        for i in xrange(4):
743
            t = t.clone('..')
744
        self.assertEquals(t.base, 'file://HOST/')
745
        # make sure we reach the root
746
        t = t.clone('..')
747
        self.assertEquals(t.base, 'file://HOST/')
2477.1.7 by Martin Pool
test_transport must provide get_test_permutations
748
2485.8.61 by Vincent Ladeuil
From review comments, use a private scheme for testing.
749
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
750
class TestConnectedTransport(TestCase):
751
    """Tests for connected to remote server transports"""
752
753
    def test_parse_url(self):
2892.1.1 by Andrew Bennetts
Fix bug 146715: bzr+ssh:// and sftp:// should not assume port-not-specified means port 22
754
        t = ConnectedTransport('http://simple.example.com/home/source')
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
755
        self.assertEquals(t._host, 'simple.example.com')
3004.2.1 by Vincent Ladeuil
Fix 150860 by leaving port as user specified it.
756
        self.assertEquals(t._port, None)
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
757
        self.assertEquals(t._path, '/home/source/')
758
        self.failUnless(t._user is None)
759
        self.failUnless(t._password is None)
760
2892.1.1 by Andrew Bennetts
Fix bug 146715: bzr+ssh:// and sftp:// should not assume port-not-specified means port 22
761
        self.assertEquals(t.base, 'http://simple.example.com/home/source/')
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
762
3498.2.1 by Neil Martinsen-Burrell
Fix bug 228058: user names with @ signs should work
763
    def test_parse_url_with_at_in_user(self):
764
        # Bug 228058
765
        t = ConnectedTransport('ftp://user@host.com@www.host.com/')
766
        self.assertEquals(t._user, 'user@host.com')
767
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
768
    def test_parse_quoted_url(self):
769
        t = ConnectedTransport('http://ro%62ey:h%40t@ex%41mple.com:2222/path')
770
        self.assertEquals(t._host, 'exAmple.com')
771
        self.assertEquals(t._port, 2222)
772
        self.assertEquals(t._user, 'robey')
773
        self.assertEquals(t._password, 'h@t')
774
        self.assertEquals(t._path, '/path/')
775
776
        # Base should not keep track of the password
777
        self.assertEquals(t.base, 'http://robey@exAmple.com:2222/path/')
778
779
    def test_parse_invalid_url(self):
780
        self.assertRaises(errors.InvalidURL,
781
                          ConnectedTransport,
782
                          'sftp://lily.org:~janneke/public/bzr/gub')
783
784
    def test_relpath(self):
785
        t = ConnectedTransport('sftp://user@host.com/abs/path')
786
787
        self.assertEquals(t.relpath('sftp://user@host.com/abs/path/sub'), 'sub')
788
        self.assertRaises(errors.PathNotChild, t.relpath,
789
                          'http://user@host.com/abs/path/sub')
790
        self.assertRaises(errors.PathNotChild, t.relpath,
791
                          'sftp://user2@host.com/abs/path/sub')
792
        self.assertRaises(errors.PathNotChild, t.relpath,
793
                          'sftp://user@otherhost.com/abs/path/sub')
794
        self.assertRaises(errors.PathNotChild, t.relpath,
795
                          'sftp://user@host.com:33/abs/path/sub')
796
        # Make sure it works when we don't supply a username
797
        t = ConnectedTransport('sftp://host.com/abs/path')
798
        self.assertEquals(t.relpath('sftp://host.com/abs/path/sub'), 'sub')
799
800
        # Make sure it works when parts of the path will be url encoded
801
        t = ConnectedTransport('sftp://host.com/dev/%path')
802
        self.assertEquals(t.relpath('sftp://host.com/dev/%path/sub'), 'sub')
803
2485.8.32 by Vincent Ladeuil
Keep credentials used at connection creation for reconnection purposes.
804
    def test_connection_sharing_propagate_credentials(self):
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
805
        t = ConnectedTransport('ftp://user@host.com/abs/path')
806
        self.assertEquals('user', t._user)
807
        self.assertEquals('host.com', t._host)
2485.8.32 by Vincent Ladeuil
Keep credentials used at connection creation for reconnection purposes.
808
        self.assertIs(None, t._get_connection())
809
        self.assertIs(None, t._password)
810
        c = t.clone('subdir')
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
811
        self.assertIs(None, c._get_connection())
2485.8.32 by Vincent Ladeuil
Keep credentials used at connection creation for reconnection purposes.
812
        self.assertIs(None, t._password)
813
814
        # Simulate the user entering a password
815
        password = 'secret'
816
        connection = object()
817
        t._set_connection(connection, password)
818
        self.assertIs(connection, t._get_connection())
819
        self.assertIs(password, t._get_credentials())
820
        self.assertIs(connection, c._get_connection())
821
        self.assertIs(password, c._get_credentials())
2485.8.30 by Vincent Ladeuil
Implement reliable connection sharing.
822
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
823
        # credentials can be updated
824
        new_password = 'even more secret'
825
        c._update_credentials(new_password)
826
        self.assertIs(connection, t._get_connection())
827
        self.assertIs(new_password, t._get_credentials())
828
        self.assertIs(connection, c._get_connection())
829
        self.assertIs(new_password, c._get_credentials())
830
2477.1.7 by Martin Pool
test_transport must provide get_test_permutations
831
2476.3.5 by Vincent Ladeuil
Naive implementation of transport reuse by Transport.get_transport().
832
class TestReusedTransports(TestCase):
2485.8.19 by Vincent Ladeuil
Add a new ConnectedTransport class refactored from [s]ftp and http.
833
    """Tests for transport reuse"""
2476.3.5 by Vincent Ladeuil
Naive implementation of transport reuse by Transport.get_transport().
834
835
    def test_reuse_same_transport(self):
1551.18.10 by Aaron Bentley
get_transport appends to possible_transports if it's an empty list
836
        possible_transports = []
837
        t1 = get_transport('http://foo/',
838
                           possible_transports=possible_transports)
839
        self.assertEqual([t1], possible_transports)
2485.8.37 by Vincent Ladeuil
Fix merge multiple connections. Test suite *not* passing (sftp
840
        t2 = get_transport('http://foo/', possible_transports=[t1])
841
        self.assertIs(t1, t2)
842
843
        # Also check that final '/' are handled correctly
844
        t3 = get_transport('http://foo/path/')
845
        t4 = get_transport('http://foo/path', possible_transports=[t3])
846
        self.assertIs(t3, t4)
847
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
848
        t5 = get_transport('http://foo/path')
849
        t6 = get_transport('http://foo/path/', possible_transports=[t5])
850
        self.assertIs(t5, t6)
2476.3.5 by Vincent Ladeuil
Naive implementation of transport reuse by Transport.get_transport().
851
852
    def test_don_t_reuse_different_transport(self):
2485.8.39 by Vincent Ladeuil
Add tests around connection reuse.
853
        t1 = get_transport('http://foo/path')
854
        t2 = get_transport('http://bar/path', possible_transports=[t1])
2485.8.40 by Vincent Ladeuil
Fix typo.
855
        self.assertIsNot(t1, t2)
2476.3.13 by Vincent Ladeuil
merge bzr.dev@2495
856
857
2745.5.3 by Robert Collins
* Move transport logging into a new transport class
858
class TestTransportTrace(TestCase):
859
860
    def test_get(self):
861
        transport = get_transport('trace+memory://')
862
        self.assertIsInstance(
863
            transport, bzrlib.transport.trace.TransportTraceDecorator)
864
865
    def test_clone_preserves_activity(self):
866
        transport = get_transport('trace+memory://')
867
        transport2 = transport.clone('.')
868
        self.assertTrue(transport is not transport2)
869
        self.assertTrue(transport._activity is transport2._activity)
870
871
    # the following specific tests are for the operations that have made use of
872
    # logging in tests; we could test every single operation but doing that
873
    # still won't cause a test failure when the top level Transport API
874
    # changes; so there is little return doing that.
875
    def test_get(self):
876
        transport = get_transport('trace+memory:///')
877
        transport.put_bytes('foo', 'barish')
878
        transport.get('foo')
879
        expected_result = []
880
        # put_bytes records the bytes, not the content to avoid memory
881
        # pressure.
882
        expected_result.append(('put_bytes', 'foo', 6, None))
883
        # get records the file name only.
884
        expected_result.append(('get', 'foo'))
885
        self.assertEqual(expected_result, transport._activity)
886
887
    def test_readv(self):
888
        transport = get_transport('trace+memory:///')
889
        transport.put_bytes('foo', 'barish')
890
        list(transport.readv('foo', [(0, 1), (3, 2)], adjust_for_latency=True,
891
            upper_limit=6))
892
        expected_result = []
893
        # put_bytes records the bytes, not the content to avoid memory
894
        # pressure.
895
        expected_result.append(('put_bytes', 'foo', 6, None))
896
        # readv records the supplied offset request
897
        expected_result.append(('readv', 'foo', [(0, 1), (3, 2)], True, 6))
898
        self.assertEqual(expected_result, transport._activity)
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
899
900
901
class TestSSHConnections(tests.TestCaseWithTransport):
902
903
    def test_bzr_connect_to_bzr_ssh(self):
904
        """User acceptance that get_transport of a bzr+ssh:// behaves correctly.
905
906
        bzr+ssh:// should cause bzr to run a remote bzr smart server over SSH.
907
        """
908
        # This test actually causes a bzr instance to be invoked, which is very
909
        # expensive: it should be the only such test in the test suite.
910
        # A reasonable evolution for this would be to simply check inside
911
        # check_channel_exec_request that the command is appropriate, and then
912
        # satisfy requests in-process.
4913.2.16 by John Arbash Meinel
Move bzrlib.tests.ParamikoFeature to bzrlib.tests.features.paramiko
913
        self.requireFeature(features.paramiko)
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
914
        # SFTPFullAbsoluteServer has a get_url method, and doesn't
915
        # override the interface (doesn't change self._vendor).
916
        # Note that this does encryption, so can be slow.
917
        from bzrlib.transport.sftp import SFTPFullAbsoluteServer
918
        from bzrlib.tests.stub_sftp import StubServer
919
920
        # Start an SSH server
921
        self.command_executed = []
922
        # XXX: This is horrible -- we define a really dumb SSH server that
923
        # executes commands, and manage the hooking up of stdin/out/err to the
924
        # SSH channel ourselves.  Surely this has already been implemented
925
        # elsewhere?
4857.2.2 by John Arbash Meinel
Change the connect-to-bzr test so that it cleans itself up.
926
        started = []
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
927
        class StubSSHServer(StubServer):
928
929
            test = self
930
931
            def check_channel_exec_request(self, channel, command):
932
                self.test.command_executed.append(command)
933
                proc = subprocess.Popen(
934
                    command, shell=True, stdin=subprocess.PIPE,
935
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
936
937
                # XXX: horribly inefficient, not to mention ugly.
938
                # Start a thread for each of stdin/out/err, and relay bytes from
939
                # the subprocess to channel and vice versa.
940
                def ferry_bytes(read, write, close):
941
                    while True:
942
                        bytes = read(1)
943
                        if bytes == '':
944
                            close()
945
                            break
946
                        write(bytes)
947
948
                file_functions = [
949
                    (channel.recv, proc.stdin.write, proc.stdin.close),
950
                    (proc.stdout.read, channel.sendall, channel.close),
951
                    (proc.stderr.read, channel.sendall_stderr, channel.close)]
4857.2.2 by John Arbash Meinel
Change the connect-to-bzr test so that it cleans itself up.
952
                started.append(proc)
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
953
                for read, write, close in file_functions:
954
                    t = threading.Thread(
955
                        target=ferry_bytes, args=(read, write, close))
956
                    t.start()
4857.2.2 by John Arbash Meinel
Change the connect-to-bzr test so that it cleans itself up.
957
                    started.append(t)
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
958
959
                return True
960
961
        ssh_server = SFTPFullAbsoluteServer(StubSSHServer)
962
        # We *don't* want to override the default SSH vendor: the detected one
963
        # is the one to use.
964
        self.start_server(ssh_server)
965
        port = ssh_server._listener.port
966
967
        if sys.platform == 'win32':
968
            bzr_remote_path = sys.executable + ' ' + self.get_bzr_path()
969
        else:
970
            bzr_remote_path = self.get_bzr_path()
971
        os.environ['BZR_REMOTE_PATH'] = bzr_remote_path
972
973
        # Access the branch via a bzr+ssh URL.  The BZR_REMOTE_PATH environment
974
        # variable is used to tell bzr what command to run on the remote end.
975
        path_to_branch = osutils.abspath('.')
976
        if sys.platform == 'win32':
4700.1.2 by Robert Collins
Review feedback.
977
            # On Windows, we export all drives as '/C:/, etc. So we need to
978
            # prefix a '/' to get the right path.
979
            path_to_branch = '/' + path_to_branch
980
        url = 'bzr+ssh://fred:secret@localhost:%d%s' % (port, path_to_branch)
981
        t = get_transport(url)
982
        self.permit_url(t.base)
4700.1.1 by Robert Collins
Focus and move out of blackbox the acceptance test for bzr+ssh connection handshake/process spawning.
983
        t.mkdir('foo')
984
985
        self.assertEqual(
986
            ['%s serve --inet --directory=/ --allow-writes' % bzr_remote_path],
987
            self.command_executed)
4857.2.2 by John Arbash Meinel
Change the connect-to-bzr test so that it cleans itself up.
988
        # Make sure to disconnect, so that the remote process can stop, and we
989
        # can cleanup. Then pause the test until everything is shutdown
990
        t._client._medium.disconnect()
991
        if not started:
992
            return
993
        # First wait for the subprocess
994
        started[0].wait()
995
        # And the rest are threads
996
        for t in started[1:]:
997
            t.join()