/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2221.5.1 by Dmitry Vasiliev
Added support for Putty's SSH implementation
1
# Copyright (C) 2005 Robey Pointer <robey@lag.net>
2
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
3
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
8
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
13
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
import os
19
import socket
2321.3.7 by Alexander Belchenko
fixes for passing test_sftp_transport on win32 (thankyou John)
20
import sys
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
21
import threading
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
22
import time
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
23
2822.1.1 by v.ladeuil+lp at free
Fix #59150 (again) by handling paramiko availability for transport_util.py.
24
try:
25
    import paramiko
26
    paramiko_loaded = True
27
except ImportError:
28
    paramiko_loaded = False
29
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
30
from bzrlib import (
31
    bzrdir,
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
32
    config,
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
33
    errors,
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
34
    tests,
35
    transport as _mod_transport,
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
36
    )
37
from bzrlib.osutils import (
38
    pathjoin,
39
    lexists,
40
    set_or_unset_env,
41
    )
42
from bzrlib.tests import (
43
    TestCaseWithTransport,
44
    TestCase,
45
    TestSkipped,
46
    )
3102.1.1 by Vincent Ladeuil
Rename bzrlib/test/HTTPTestUtils.py to bzrlib/tests/http_utils.py and fix
47
from bzrlib.tests.http_server import HttpServer
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
48
from bzrlib.transport import get_transport
1711.2.132 by John Arbash Meinel
Clean up PEP8 and unused imports in bench_sftp.py, and missing import in bzrlib/tests/test_sftp_transport.py
49
import bzrlib.transport.http
2822.1.1 by v.ladeuil+lp at free
Fix #59150 (again) by handling paramiko availability for transport_util.py.
50
51
if paramiko_loaded:
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
52
    from bzrlib.transport import sftp as _mod_sftp
2822.1.1 by v.ladeuil+lp at free
Fix #59150 (again) by handling paramiko availability for transport_util.py.
53
    from bzrlib.transport.sftp import (
54
        SFTPAbsoluteServer,
55
        SFTPHomeDirServer,
56
        SFTPTransport,
57
        )
58
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
59
from bzrlib.workingtree import WorkingTree
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
60
1874.1.12 by Carl Friedrich Bolz
More fixes according to John's comments.
61
1874.1.14 by Carl Friedrich Bolz
Rename setup method to make its intent clearer. Some PEP 8 issues.
62
def set_test_transport_to_sftp(testcase):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
63
    """A helper to set transports on test case instances."""
1874.1.6 by holger krekel
(cfbolz, hpk) Factor out common set_transport code.
64
    if getattr(testcase, '_get_remote_is_absolute', None) is None:
65
        testcase._get_remote_is_absolute = True
66
    if testcase._get_remote_is_absolute:
2018.5.114 by Robert Collins
Commit current test pass improvements.
67
        testcase.transport_server = SFTPAbsoluteServer
1874.1.6 by holger krekel
(cfbolz, hpk) Factor out common set_transport code.
68
    else:
2018.5.114 by Robert Collins
Commit current test pass improvements.
69
        testcase.transport_server = SFTPHomeDirServer
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
70
    testcase.transport_readonly_server = HttpServer
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
71
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
72
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
73
class TestCaseWithSFTPServer(TestCaseWithTransport):
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
74
    """A test case base class that provides a sftp server on localhost."""
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
75
76
    def setUp(self):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
77
        super(TestCaseWithSFTPServer, self).setUp()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
78
        if not paramiko_loaded:
79
            raise TestSkipped('you must have paramiko to run this test')
2381.1.1 by Robert Collins
Split out hpss test fixes which dont depend on new or altered API's.
80
        set_test_transport_to_sftp(self)
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
81
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
82
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
83
class SFTPLockTests(TestCaseWithSFTPServer):
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
84
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
85
    def test_sftp_locks(self):
86
        from bzrlib.errors import LockError
87
        t = self.get_transport()
88
89
        l = t.lock_write('bogus')
90
        self.failUnlessExists('bogus.write-lock')
91
92
        # Don't wait for the lock, locking an already locked
93
        # file should raise an assert
94
        self.assertRaises(LockError, t.lock_write, 'bogus')
95
96
        l.unlock()
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
97
        self.failIf(lexists('bogus.write-lock'))
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
98
99
        open('something.write-lock', 'wb').write('fake lock\n')
100
        self.assertRaises(LockError, t.lock_write, 'something')
101
        os.remove('something.write-lock')
102
103
        l = t.lock_write('something')
104
105
        l2 = t.lock_write('bogus')
106
107
        l.unlock()
108
        l2.unlock()
109
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
110
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
111
class SFTPTransportTestRelative(TestCaseWithSFTPServer):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
112
    """Test the SFTP transport with homedir based relative paths."""
113
114
    def test__remote_path(self):
2823.1.4 by Vincent Ladeuil
Use assertIsSameRealPath to avoid OSX aliasing (specifically /tmp
115
        if sys.platform == 'darwin':
2823.1.11 by Vincent Ladeuil
Review feedback.
116
            # This test is about sftp absolute path handling. There is already
117
            # (in this test) a TODO about windows needing an absolute path
118
            # without drive letter. To me, using self.test_dir is a trick to
119
            # get an absolute path for comparison purposes.  That fails for OSX
120
            # because the sftp server doesn't resolve the links (and it doesn't
121
            # have to). --vila 20070924
2823.1.8 by Vincent Ladeuil
Rewrite expected failure message
122
            self.knownFailure('Mac OSX symlinks /tmp to /private/tmp,'
123
                              ' testing against self.test_dir'
124
                              ' is not appropriate')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
125
        t = self.get_transport()
2321.3.7 by Alexander Belchenko
fixes for passing test_sftp_transport on win32 (thankyou John)
126
        # This test require unix-like absolute path
127
        test_dir = self.test_dir
128
        if sys.platform == 'win32':
129
            # using hack suggested by John Meinel.
130
            # TODO: write another mock server for this test
131
            #       and use absolute path without drive letter
132
            test_dir = '/' + test_dir
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
133
        # try what is currently used:
134
        # remote path = self._abspath(relpath)
2823.1.14 by Vincent Ladeuil
Fix 141382 by comparing real paths.
135
        self.assertIsSameRealPath(test_dir + '/relative',
136
                                  t._remote_path('relative'))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
137
        # we dont os.path.join because windows gives us the wrong path
2321.3.7 by Alexander Belchenko
fixes for passing test_sftp_transport on win32 (thankyou John)
138
        root_segments = test_dir.split('/')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
139
        root_parent = '/'.join(root_segments[:-1])
140
        # .. should be honoured
2823.1.14 by Vincent Ladeuil
Fix 141382 by comparing real paths.
141
        self.assertIsSameRealPath(root_parent + '/sibling',
142
                                  t._remote_path('../sibling'))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
143
        # /  should be illegal ?
144
        ### FIXME decide and then test for all transports. RBC20051208
145
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
146
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
147
class SFTPTransportTestRelativeRoot(TestCaseWithSFTPServer):
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
148
    """Test the SFTP transport with homedir based relative paths."""
149
150
    def setUp(self):
2485.8.43 by Vincent Ladeuil
Cleaning.
151
        # Only SFTPHomeDirServer is tested here
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
152
        self._get_remote_is_absolute = False
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
153
        super(SFTPTransportTestRelativeRoot, self).setUp()
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
154
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
155
    def test__remote_path_relative_root(self):
156
        # relative paths are preserved
157
        t = self.get_transport('')
2485.8.27 by Vincent Ladeuil
Hearing jam saying "vila, you're trying too hard", I simplified again.
158
        self.assertEqual('/~/', t._path)
159
        # the remote path should be relative to home dir
160
        # (i.e. not begining with a '/')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
161
        self.assertEqual('a', t._remote_path('a'))
162
163
1185.49.14 by John Arbash Meinel
[merge] bzr.dev
164
class SFTPNonServerTest(TestCase):
1185.58.12 by John Arbash Meinel
Changing so that sftp tests are skipped rather than hidden when paramiko isn't present
165
    def setUp(self):
166
        TestCase.setUp(self)
167
        if not paramiko_loaded:
168
            raise TestSkipped('you must have paramiko to run this test')
169
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
170
    def test_parse_url_with_home_dir(self):
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
171
        s = SFTPTransport('sftp://ro%62ey:h%40t@example.com:2222/~/relative')
1185.40.4 by Robey Pointer
fix sftp urls to support the ietf draft url spec wrt relative vs absolute sftp urls (this will break existing branch urls); fix username/password parsing in sftp urls; add unit tests to make sure sftp url parsing is working
172
        self.assertEquals(s._host, 'example.com')
173
        self.assertEquals(s._port, 2222)
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
174
        self.assertEquals(s._user, 'robey')
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
175
        self.assertEquals(s._password, 'h@t')
2485.8.27 by Vincent Ladeuil
Hearing jam saying "vila, you're trying too hard", I simplified again.
176
        self.assertEquals(s._path, '/~/relative/')
1185.49.23 by John Arbash Meinel
bugreport from Matthieu Moy: relpath was failing, but throwing an unhelpful exception.
177
178
    def test_relpath(self):
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
179
        s = SFTPTransport('sftp://user@host.com/abs/path')
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
180
        self.assertRaises(errors.PathNotChild, s.relpath,
181
                          'sftp://user@host.com/~/rel/path/sub')
1185.33.58 by Martin Pool
[patch] Better error when sftp urls are given with invalid port numbers (Matthieu Moy)
182
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
183
    def test_get_paramiko_vendor(self):
184
        """Test that if no 'ssh' is available we get builtin paramiko"""
185
        from bzrlib.transport import ssh
186
        # set '.' as the only location in the path, forcing no 'ssh' to exist
2221.5.18 by Dmitry Vasiliev
Fixed variable name
187
        orig_vendor = ssh._ssh_vendor_manager._cached_ssh_vendor
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
188
        orig_path = set_or_unset_env('PATH', '.')
189
        try:
190
            # No vendor defined yet, query for one
2221.5.18 by Dmitry Vasiliev
Fixed variable name
191
            ssh._ssh_vendor_manager.clear_cache()
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
192
            vendor = ssh._get_ssh_vendor()
193
            self.assertIsInstance(vendor, ssh.ParamikoVendor)
194
        finally:
195
            set_or_unset_env('PATH', orig_path)
2221.5.18 by Dmitry Vasiliev
Fixed variable name
196
            ssh._ssh_vendor_manager._cached_ssh_vendor = orig_vendor
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
197
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
198
    def test_abspath_root_sibling_server(self):
199
        from bzrlib.transport.sftp import SFTPSiblingAbsoluteServer
200
        server = SFTPSiblingAbsoluteServer()
201
        server.setUp()
202
        try:
203
            transport = get_transport(server.get_url())
204
            self.assertFalse(transport.abspath('/').endswith('/~/'))
205
            self.assertTrue(transport.abspath('/').endswith('/'))
206
            del transport
207
        finally:
208
            server.tearDown()
209
1185.40.4 by Robey Pointer
fix sftp urls to support the ietf draft url spec wrt relative vs absolute sftp urls (this will break existing branch urls); fix username/password parsing in sftp urls; add unit tests to make sure sftp url parsing is working
210
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
211
class SFTPBranchTest(TestCaseWithSFTPServer):
212
    """Test some stuff when accessing a bzr Branch over sftp"""
213
214
    def test_lock_file(self):
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
215
        # old format branches use a special lock file on sftp.
216
        b = self.make_branch('', format=bzrdir.BzrDirFormat6())
217
        b = bzrlib.branch.Branch.open(self.get_url())
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
218
        self.failUnlessExists('.bzr/')
219
        self.failUnlessExists('.bzr/branch-format')
220
        self.failUnlessExists('.bzr/branch-lock')
221
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
222
        self.failIf(lexists('.bzr/branch-lock.write-lock'))
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
223
        b.lock_write()
224
        self.failUnlessExists('.bzr/branch-lock.write-lock')
225
        b.unlock()
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
226
        self.failIf(lexists('.bzr/branch-lock.write-lock'))
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
227
1185.49.26 by John Arbash Meinel
Adding tests for remote sftp branches without working trees, plus a bugfix to allow push to still work with a warning.
228
    def test_push_support(self):
229
        self.build_tree(['a/', 'a/foo'])
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
230
        t = bzrdir.BzrDir.create_standalone_workingtree('a')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
231
        b = t.branch
1185.49.26 by John Arbash Meinel
Adding tests for remote sftp branches without working trees, plus a bugfix to allow push to still work with a warning.
232
        t.add('foo')
233
        t.commit('foo', rev_id='a1')
234
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
235
        b2 = bzrdir.BzrDir.create_branch_and_repo(self.get_url('/b'))
1185.49.26 by John Arbash Meinel
Adding tests for remote sftp branches without working trees, plus a bugfix to allow push to still work with a warning.
236
        b2.pull(b)
237
238
        self.assertEquals(b2.revision_history(), ['a1'])
239
1185.31.48 by John Arbash Meinel
Added a small test to sftp to make sure some replacing was going on in the remote side.
240
        open('a/foo', 'wt').write('something new in foo\n')
241
        t.commit('new', rev_id='a2')
242
        b2.pull(b)
243
244
        self.assertEquals(b2.revision_history(), ['a1', 'a2'])
245
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
246
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
247
class SSHVendorConnection(TestCaseWithSFTPServer):
248
    """Test that the ssh vendors can all connect.
249
250
    Verify that a full-handshake (SSH over loopback TCP) sftp connection works.
251
252
    We have 3 sftp implementations in the test suite:
253
      'loopback': Doesn't use ssh, just uses a local socket. Most tests are
254
                  done this way to save the handshaking time, so it is not
255
                  tested again here
256
      'none':     This uses paramiko's built-in ssh client and server, and layers
257
                  sftp on top of it.
258
      None:       If 'ssh' exists on the machine, then it will be spawned as a
259
                  child process.
260
    """
1547.1.4 by Robey Pointer
add a single full-handshake test to verify that sftp-over-ssh works
261
    
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
262
    def setUp(self):
263
        super(SSHVendorConnection, self).setUp()
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
264
        from bzrlib.transport.sftp import SFTPFullAbsoluteServer
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
265
266
        def create_server():
267
            """Just a wrapper so that when created, it will set _vendor"""
268
            # SFTPFullAbsoluteServer can handle any vendor,
269
            # it just needs to be set between the time it is instantiated
270
            # and the time .setUp() is called
271
            server = SFTPFullAbsoluteServer()
272
            server._vendor = self._test_vendor
273
            return server
274
        self._test_vendor = 'loopback'
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
275
        self.vfs_transport_server = create_server
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
276
        f = open('a_file', 'wb')
277
        try:
278
            f.write('foobar\n')
279
        finally:
280
            f.close()
281
282
    def set_vendor(self, vendor):
283
        self._test_vendor = vendor
284
285
    def test_connection_paramiko(self):
1951.1.8 by Andrew Bennetts
Make _get_ssh_vendor return the vendor object, rather than just a string.
286
        from bzrlib.transport import ssh
287
        self.set_vendor(ssh.ParamikoVendor())
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
288
        t = self.get_transport()
289
        self.assertEqual('foobar\n', t.get('a_file').read())
290
291
    def test_connection_vendor(self):
292
        raise TestSkipped("We don't test spawning real ssh,"
293
                          " because it prompts for a password."
294
                          " Enable this test if we figure out"
295
                          " how to prevent this.")
296
        self.set_vendor(None)
297
        t = self.get_transport()
298
        self.assertEqual('foobar\n', t.get('a_file').read())
299
300
301
class SSHVendorBadConnection(TestCaseWithTransport):
302
    """Test that the ssh vendors handle bad connection properly
303
304
    We don't subclass TestCaseWithSFTPServer, because we don't actually
305
    need an SFTP connection.
306
    """
307
308
    def setUp(self):
309
        if not paramiko_loaded:
310
            raise TestSkipped('you must have paramiko to run this test')
311
        super(SSHVendorBadConnection, self).setUp()
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
312
        import bzrlib.transport.ssh
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
313
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
314
        # open a random port, so we know nobody else is using it
315
        # but don't actually listen on the port.
316
        s = socket.socket()
317
        s.bind(('localhost', 0))
318
        self.bogus_url = 'sftp://%s:%s/' % s.getsockname()
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
319
2221.5.18 by Dmitry Vasiliev
Fixed variable name
320
        orig_vendor = bzrlib.transport.ssh._ssh_vendor_manager._cached_ssh_vendor
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
321
        def reset():
2221.5.18 by Dmitry Vasiliev
Fixed variable name
322
            bzrlib.transport.ssh._ssh_vendor_manager._cached_ssh_vendor = orig_vendor
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
323
            s.close()
324
        self.addCleanup(reset)
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
325
326
    def set_vendor(self, vendor):
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
327
        import bzrlib.transport.ssh
2221.5.18 by Dmitry Vasiliev
Fixed variable name
328
        bzrlib.transport.ssh._ssh_vendor_manager._cached_ssh_vendor = vendor
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
329
330
    def test_bad_connection_paramiko(self):
331
        """Test that a real connection attempt raises the right error"""
1951.1.8 by Andrew Bennetts
Make _get_ssh_vendor return the vendor object, rather than just a string.
332
        from bzrlib.transport import ssh
333
        self.set_vendor(ssh.ParamikoVendor())
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
334
        t = bzrlib.transport.get_transport(self.bogus_url)
335
        self.assertRaises(errors.ConnectionError, t.get, 'foobar')
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
336
337
    def test_bad_connection_ssh(self):
338
        """None => auto-detect vendor"""
339
        self.set_vendor(None)
1185.49.33 by John Arbash Meinel
Spawn another bzr instance using run_bzr_subprocess, so we don't get stipple
340
        # This is how I would normally test the connection code
341
        # it makes it very clear what we are testing.
342
        # However, 'ssh' will create stipple on the output, so instead
343
        # I'm using run_bzr_subprocess, and parsing the output
344
        # try:
345
        #     t = bzrlib.transport.get_transport(self.bogus_url)
346
        # except errors.ConnectionError:
347
        #     # Correct error
348
        #     pass
349
        # except errors.NameError, e:
350
        #     if 'SSHException' in str(e):
351
        #         raise TestSkipped('Known NameError bug in paramiko 1.6.1')
352
        #     raise
353
        # else:
354
        #     self.fail('Excepted ConnectionError to be raised')
355
2665.4.1 by Aaron Bentley
teach run_bzr_subprocess to accept either a list of strings or a string
356
        out, err = self.run_bzr_subprocess(['log', self.bogus_url], retcode=3)
1185.49.33 by John Arbash Meinel
Spawn another bzr instance using run_bzr_subprocess, so we don't get stipple
357
        self.assertEqual('', out)
358
        if "NameError: global name 'SSHException'" in err:
359
            # We aren't fixing this bug, because it is a bug in
360
            # paramiko, but we know about it, so we don't have to
361
            # fail the test
362
            raise TestSkipped('Known NameError bug with paramiko-1.6.1')
2052.4.4 by John Arbash Meinel
Create a SocketConnectionError to make creating nice errors easier
363
        self.assertContainsRe(err, r'bzr: ERROR: Unable to connect to SSH host'
364
                                   r' 127\.0\.0\.1:\d+; ')
1185.49.32 by John Arbash Meinel
Update tests to show that all ssh vendor failed connections work correctly, has some stipple from real ssh
365
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
366
367
class SFTPLatencyKnob(TestCaseWithSFTPServer):
368
    """Test that the testing SFTPServer's latency knob works."""
369
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
370
    def test_latency_knob_slows_transport(self):
371
        # change the latency knob to 500ms. We take about 40ms for a 
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
372
        # loopback connection ordinarily.
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
373
        start_time = time.time()
374
        self.get_server().add_latency = 0.5
375
        transport = self.get_transport()
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
376
        transport.has('not me') # Force connection by issuing a request
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
377
        with_latency_knob_time = time.time() - start_time
378
        self.assertTrue(with_latency_knob_time > 0.4)
379
380
    def test_default(self):
381
        # This test is potentially brittle: under extremely high machine load
382
        # it could fail, but that is quite unlikely
2631.1.1 by Aaron Bentley
Disable timing-sensitive test
383
        raise TestSkipped('Timing-sensitive test')
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
384
        start_time = time.time()
385
        transport = self.get_transport()
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
386
        transport.has('not me') # Force connection by issuing a request
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
387
        regular_time = time.time() - start_time
388
        self.assertTrue(regular_time < 0.5)
389
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
390
391
class FakeSocket(object):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
392
    """Fake socket object used to test the SocketDelay wrapper without
393
    using a real socket.
394
    """
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
395
396
    def __init__(self):
397
        self._data = ""
398
399
    def send(self, data, flags=0):
400
        self._data += data
401
        return len(data)
402
403
    def sendall(self, data, flags=0):
404
        self._data += data
405
        return len(data)
406
407
    def recv(self, size, flags=0):
408
        if size < len(self._data):
409
            result = self._data[:size]
410
            self._data = self._data[size:]
411
            return result
412
        else:
413
            result = self._data
414
            self._data = ""
415
            return result
416
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
417
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
418
class TestSocketDelay(TestCase):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
419
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
420
    def setUp(self):
421
        TestCase.setUp(self)
1993.2.2 by John Arbash Meinel
Skip tests that require paramiko (or think they do)
422
        if not paramiko_loaded:
423
            raise TestSkipped('you must have paramiko to run this test')
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
424
425
    def test_delay(self):
426
        from bzrlib.transport.sftp import SocketDelay
427
        sending = FakeSocket()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
428
        receiving = SocketDelay(sending, 0.1, bandwidth=1000000,
429
                                really_sleep=False)
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
430
        # check that simulated time is charged only per round-trip:
431
        t1 = SocketDelay.simulated_time
432
        receiving.send("connect1")
433
        self.assertEqual(sending.recv(1024), "connect1")
434
        t2 = SocketDelay.simulated_time
435
        self.assertAlmostEqual(t2 - t1, 0.1)
436
        receiving.send("connect2")
437
        self.assertEqual(sending.recv(1024), "connect2")
438
        sending.send("hello")
439
        self.assertEqual(receiving.recv(1024), "hello")
440
        t3 = SocketDelay.simulated_time
441
        self.assertAlmostEqual(t3 - t2, 0.1)
442
        sending.send("hello")
443
        self.assertEqual(receiving.recv(1024), "hello")
444
        sending.send("hello")
445
        self.assertEqual(receiving.recv(1024), "hello")
446
        sending.send("hello")
447
        self.assertEqual(receiving.recv(1024), "hello")
448
        t4 = SocketDelay.simulated_time
449
        self.assertAlmostEqual(t4, t3)
450
451
    def test_bandwidth(self):
452
        from bzrlib.transport.sftp import SocketDelay
453
        sending = FakeSocket()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
454
        receiving = SocketDelay(sending, 0, bandwidth=8.0/(1024*1024),
455
                                really_sleep=False)
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
456
        # check that simulated time is charged only per round-trip:
457
        t1 = SocketDelay.simulated_time
458
        receiving.send("connect")
459
        self.assertEqual(sending.recv(1024), "connect")
460
        sending.send("a" * 100)
461
        self.assertEqual(receiving.recv(1024), "a" * 100)
462
        t2 = SocketDelay.simulated_time
463
        self.assertAlmostEqual(t2 - t1, 100 + 7)
464
1874.1.3 by Carl Friedrich Bolz
Merge bzr.dev.
465
3815.2.4 by Martin Pool
merge fix for out-of-order SFTP readv
466
class ReadvFile(object):
467
    """An object that acts like Paramiko's SFTPFile.readv()"""
468
469
    def __init__(self, data):
470
        self._data = data
471
472
    def readv(self, requests):
473
        for start, length in requests:
474
            yield self._data[start:start+length]
475
476
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
477
class Test_SFTPReadvHelper(tests.TestCase):
478
3686.1.6 by John Arbash Meinel
Respond to Martin's review comments.
479
    def checkGetRequests(self, expected_requests, offsets):
3741.1.1 by Vincent Ladeuil
Fix test requirement (paramiko).
480
        if not paramiko_loaded:
481
            raise TestSkipped('you must have paramiko to run this test')
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
482
        helper = _mod_sftp._SFTPReadvHelper(offsets, 'artificial_test')
483
        self.assertEqual(expected_requests, helper._get_requests())
484
485
    def test__get_requests(self):
486
        # Small single requests become a single readv request
3686.1.6 by John Arbash Meinel
Respond to Martin's review comments.
487
        self.checkGetRequests([(0, 100)],
488
                              [(0, 20), (30, 50), (20, 10), (80, 20)])
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
489
        # Non-contiguous ranges are given as multiple requests
3686.1.6 by John Arbash Meinel
Respond to Martin's review comments.
490
        self.checkGetRequests([(0, 20), (30, 50)],
491
                              [(10, 10), (30, 20), (0, 10), (50, 30)])
3686.1.2 by John Arbash Meinel
Start moving the readv code into a helper.
492
        # Ranges larger than _max_request_size (32kB) are broken up into
493
        # multiple requests, even if it actually spans multiple logical
494
        # requests
3686.1.6 by John Arbash Meinel
Respond to Martin's review comments.
495
        self.checkGetRequests([(0, 32768), (32768, 32768), (65536, 464)],
496
                              [(0, 40000), (40000, 100), (40100, 1900),
497
                               (42000, 24000)])
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
498
3815.2.4 by Martin Pool
merge fix for out-of-order SFTP readv
499
    def checkRequestAndYield(self, expected, data, offsets):
3734.2.18 by Vincent Ladeuil
Fix missing dependency check for paramiko.
500
        if not paramiko_loaded:
501
            raise TestSkipped('you must have paramiko to run this test')
3815.2.4 by Martin Pool
merge fix for out-of-order SFTP readv
502
        helper = _mod_sftp._SFTPReadvHelper(offsets, 'artificial_test')
503
        data_f = ReadvFile(data)
504
        result = list(helper.request_and_yield_offsets(data_f))
505
        self.assertEqual(expected, result)
506
507
    def test_request_and_yield_offsets(self):
508
        data = 'abcdefghijklmnopqrstuvwxyz'
509
        self.checkRequestAndYield([(0, 'a'), (5, 'f'), (10, 'klm')], data,
510
                                  [(0, 1), (5, 1), (10, 3)])
511
        # Should combine requests, and split them again
512
        self.checkRequestAndYield([(0, 'a'), (1, 'b'), (10, 'klm')], data,
513
                                  [(0, 1), (1, 1), (10, 3)])
514
        # Out of order requests. The requests should get combined, but then be
515
        # yielded out-of-order. We also need one that is at the end of a
516
        # previous range. See bug #293746
517
        self.checkRequestAndYield([(0, 'a'), (10, 'k'), (4, 'efg'), (1, 'bcd')],
518
                                  data, [(0, 1), (10, 1), (4, 3), (1, 3)])
519
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
520
521
class TestUsesAuthConfig(TestCaseWithSFTPServer):
3777.1.4 by Aaron Bentley
bzr+ssh and sftp both use ssh scheme.
522
    """Test that AuthenticationConfig can supply default usernames."""
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
523
3777.1.2 by Aaron Bentley
Make testing more thorough
524
    def get_transport_for_connection(self, set_config):
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
525
        port = self.get_server()._listener.port
3777.1.2 by Aaron Bentley
Make testing more thorough
526
        if set_config:
527
            conf = config.AuthenticationConfig()
528
            conf._get_config().update(
3777.1.4 by Aaron Bentley
bzr+ssh and sftp both use ssh scheme.
529
                {'sftptest': {'scheme': 'ssh', 'port': port, 'user': 'bar'}})
3777.1.2 by Aaron Bentley
Make testing more thorough
530
            conf._save()
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
531
        t = get_transport('sftp://localhost:%d' % port)
3777.1.2 by Aaron Bentley
Make testing more thorough
532
        # force a connection to be performed.
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
533
        t.has('foo')
3777.1.2 by Aaron Bentley
Make testing more thorough
534
        return t
535
536
    def test_sftp_uses_config(self):
537
        t = self.get_transport_for_connection(set_config=True)
3777.1.1 by Aaron Bentley
Use auth.conf for sftp
538
        self.assertEqual('bar', t._get_credentials()[0])
3777.1.2 by Aaron Bentley
Make testing more thorough
539
540
    def test_sftp_is_none_if_no_config(self):
541
        t = self.get_transport_for_connection(set_config=False)
542
        self.assertIs(None, t._get_credentials()[0])