~bzr-pqm/bzr/bzr.dev

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,
32
    errors,
33
    )
34
from bzrlib.osutils import (
35
    pathjoin,
36
    lexists,
37
    set_or_unset_env,
38
    )
39
from bzrlib.tests import (
40
    TestCaseWithTransport,
41
    TestCase,
42
    TestSkipped,
43
    )
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
44
from bzrlib.tests.HttpServer import HttpServer
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
45
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
46
import bzrlib.transport.http
2822.1.1 by v.ladeuil+lp at free
Fix #59150 (again) by handling paramiko availability for transport_util.py.
47
48
if paramiko_loaded:
49
    from bzrlib.transport.sftp import (
50
        SFTPAbsoluteServer,
51
        SFTPHomeDirServer,
52
        SFTPTransport,
53
        )
54
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
55
from bzrlib.workingtree import WorkingTree
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
56
1874.1.12 by Carl Friedrich Bolz
More fixes according to John's comments.
57
1874.1.14 by Carl Friedrich Bolz
Rename setup method to make its intent clearer. Some PEP 8 issues.
58
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.
59
    """A helper to set transports on test case instances."""
1874.1.6 by holger krekel
(cfbolz, hpk) Factor out common set_transport code.
60
    if getattr(testcase, '_get_remote_is_absolute', None) is None:
61
        testcase._get_remote_is_absolute = True
62
    if testcase._get_remote_is_absolute:
2018.5.114 by Robert Collins
Commit current test pass improvements.
63
        testcase.transport_server = SFTPAbsoluteServer
1874.1.6 by holger krekel
(cfbolz, hpk) Factor out common set_transport code.
64
    else:
2018.5.114 by Robert Collins
Commit current test pass improvements.
65
        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 :)
66
    testcase.transport_readonly_server = HttpServer
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
67
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
68
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.
69
class TestCaseWithSFTPServer(TestCaseWithTransport):
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
70
    """A test case base class that provides a sftp server on localhost."""
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
71
72
    def setUp(self):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
73
        super(TestCaseWithSFTPServer, self).setUp()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
74
        if not paramiko_loaded:
75
            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.
76
        set_test_transport_to_sftp(self)
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
77
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
78
79
class SFTPLockTests (TestCaseWithSFTPServer):
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
80
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
81
    def test_sftp_locks(self):
82
        from bzrlib.errors import LockError
83
        t = self.get_transport()
84
85
        l = t.lock_write('bogus')
86
        self.failUnlessExists('bogus.write-lock')
87
88
        # Don't wait for the lock, locking an already locked
89
        # file should raise an assert
90
        self.assertRaises(LockError, t.lock_write, 'bogus')
91
92
        l.unlock()
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
93
        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
94
95
        open('something.write-lock', 'wb').write('fake lock\n')
96
        self.assertRaises(LockError, t.lock_write, 'something')
97
        os.remove('something.write-lock')
98
99
        l = t.lock_write('something')
100
101
        l2 = t.lock_write('bogus')
102
103
        l.unlock()
104
        l2.unlock()
105
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
106
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
107
class SFTPTransportTestRelative(TestCaseWithSFTPServer):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
108
    """Test the SFTP transport with homedir based relative paths."""
109
110
    def test__remote_path(self):
2823.1.4 by Vincent Ladeuil
Use assertIsSameRealPath to avoid OSX aliasing (specifically /tmp
111
        if sys.platform == 'darwin':
2823.1.11 by Vincent Ladeuil
Review feedback.
112
            # This test is about sftp absolute path handling. There is already
113
            # (in this test) a TODO about windows needing an absolute path
114
            # without drive letter. To me, using self.test_dir is a trick to
115
            # get an absolute path for comparison purposes.  That fails for OSX
116
            # because the sftp server doesn't resolve the links (and it doesn't
117
            # have to). --vila 20070924
2823.1.8 by Vincent Ladeuil
Rewrite expected failure message
118
            self.knownFailure('Mac OSX symlinks /tmp to /private/tmp,'
119
                              ' testing against self.test_dir'
120
                              ' is not appropriate')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
121
        t = self.get_transport()
2321.3.7 by Alexander Belchenko
fixes for passing test_sftp_transport on win32 (thankyou John)
122
        # This test require unix-like absolute path
123
        test_dir = self.test_dir
124
        if sys.platform == 'win32':
125
            # using hack suggested by John Meinel.
126
            # TODO: write another mock server for this test
127
            #       and use absolute path without drive letter
128
            test_dir = '/' + test_dir
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
129
        # try what is currently used:
130
        # remote path = self._abspath(relpath)
2823.1.14 by Vincent Ladeuil
Fix 141382 by comparing real paths.
131
        self.assertIsSameRealPath(test_dir + '/relative',
132
                                  t._remote_path('relative'))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
133
        # 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)
134
        root_segments = test_dir.split('/')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
135
        root_parent = '/'.join(root_segments[:-1])
136
        # .. should be honoured
2823.1.14 by Vincent Ladeuil
Fix 141382 by comparing real paths.
137
        self.assertIsSameRealPath(root_parent + '/sibling',
138
                                  t._remote_path('../sibling'))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
139
        # /  should be illegal ?
140
        ### FIXME decide and then test for all transports. RBC20051208
141
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
142
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
143
class SFTPTransportTestRelativeRoot(TestCaseWithSFTPServer):
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
144
    """Test the SFTP transport with homedir based relative paths."""
145
146
    def setUp(self):
2485.8.43 by Vincent Ladeuil
Cleaning.
147
        # Only SFTPHomeDirServer is tested here
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
148
        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.
149
        super(SFTPTransportTestRelativeRoot, self).setUp()
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
150
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
151
    def test__remote_path_relative_root(self):
152
        # relative paths are preserved
153
        t = self.get_transport('')
2485.8.27 by Vincent Ladeuil
Hearing jam saying "vila, you're trying too hard", I simplified again.
154
        self.assertEqual('/~/', t._path)
155
        # the remote path should be relative to home dir
156
        # (i.e. not begining with a '/')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
157
        self.assertEqual('a', t._remote_path('a'))
158
159
1185.49.14 by John Arbash Meinel
[merge] bzr.dev
160
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
161
    def setUp(self):
162
        TestCase.setUp(self)
163
        if not paramiko_loaded:
164
            raise TestSkipped('you must have paramiko to run this test')
165
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
166
    def test_parse_url_with_home_dir(self):
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
167
        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
168
        self.assertEquals(s._host, 'example.com')
169
        self.assertEquals(s._port, 2222)
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
170
        self.assertEquals(s._user, 'robey')
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
171
        self.assertEquals(s._password, 'h@t')
2485.8.27 by Vincent Ladeuil
Hearing jam saying "vila, you're trying too hard", I simplified again.
172
        self.assertEquals(s._path, '/~/relative/')
1185.49.23 by John Arbash Meinel
bugreport from Matthieu Moy: relpath was failing, but throwing an unhelpful exception.
173
174
    def test_relpath(self):
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
175
        s = SFTPTransport('sftp://user@host.com/abs/path')
2485.8.20 by Vincent Ladeuil
Refactor SFTPTransport. Test suite passes.
176
        self.assertRaises(errors.PathNotChild, s.relpath,
177
                          '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)
178
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
179
    def test_get_paramiko_vendor(self):
180
        """Test that if no 'ssh' is available we get builtin paramiko"""
181
        from bzrlib.transport import ssh
182
        # set '.' as the only location in the path, forcing no 'ssh' to exist
2221.5.18 by Dmitry Vasiliev
Fixed variable name
183
        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
184
        orig_path = set_or_unset_env('PATH', '.')
185
        try:
186
            # No vendor defined yet, query for one
2221.5.18 by Dmitry Vasiliev
Fixed variable name
187
            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
188
            vendor = ssh._get_ssh_vendor()
189
            self.assertIsInstance(vendor, ssh.ParamikoVendor)
190
        finally:
191
            set_or_unset_env('PATH', orig_path)
2221.5.18 by Dmitry Vasiliev
Fixed variable name
192
            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
193
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
194
    def test_abspath_root_sibling_server(self):
195
        from bzrlib.transport.sftp import SFTPSiblingAbsoluteServer
196
        server = SFTPSiblingAbsoluteServer()
197
        server.setUp()
198
        try:
199
            transport = get_transport(server.get_url())
200
            self.assertFalse(transport.abspath('/').endswith('/~/'))
201
            self.assertTrue(transport.abspath('/').endswith('/'))
202
            del transport
203
        finally:
204
            server.tearDown()
205
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
206
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
207
class SFTPBranchTest(TestCaseWithSFTPServer):
208
    """Test some stuff when accessing a bzr Branch over sftp"""
209
210
    def test_lock_file(self):
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
211
        # old format branches use a special lock file on sftp.
212
        b = self.make_branch('', format=bzrdir.BzrDirFormat6())
213
        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
214
        self.failUnlessExists('.bzr/')
215
        self.failUnlessExists('.bzr/branch-format')
216
        self.failUnlessExists('.bzr/branch-lock')
217
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
218
        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
219
        b.lock_write()
220
        self.failUnlessExists('.bzr/branch-lock.write-lock')
221
        b.unlock()
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
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.
224
    def test_push_support(self):
225
        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.
226
        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.
227
        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.
228
        t.add('foo')
229
        t.commit('foo', rev_id='a1')
230
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.
231
        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.
232
        b2.pull(b)
233
234
        self.assertEquals(b2.revision_history(), ['a1'])
235
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.
236
        open('a/foo', 'wt').write('something new in foo\n')
237
        t.commit('new', rev_id='a2')
238
        b2.pull(b)
239
240
        self.assertEquals(b2.revision_history(), ['a1', 'a2'])
241
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
242
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
243
class SSHVendorConnection(TestCaseWithSFTPServer):
244
    """Test that the ssh vendors can all connect.
245
246
    Verify that a full-handshake (SSH over loopback TCP) sftp connection works.
247
248
    We have 3 sftp implementations in the test suite:
249
      'loopback': Doesn't use ssh, just uses a local socket. Most tests are
250
                  done this way to save the handshaking time, so it is not
251
                  tested again here
252
      'none':     This uses paramiko's built-in ssh client and server, and layers
253
                  sftp on top of it.
254
      None:       If 'ssh' exists on the machine, then it will be spawned as a
255
                  child process.
256
    """
1547.1.4 by Robey Pointer
add a single full-handshake test to verify that sftp-over-ssh works
257
    
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
258
    def setUp(self):
259
        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.
260
        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
261
262
        def create_server():
263
            """Just a wrapper so that when created, it will set _vendor"""
264
            # SFTPFullAbsoluteServer can handle any vendor,
265
            # it just needs to be set between the time it is instantiated
266
            # and the time .setUp() is called
267
            server = SFTPFullAbsoluteServer()
268
            server._vendor = self._test_vendor
269
            return server
270
        self._test_vendor = 'loopback'
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
271
        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
272
        f = open('a_file', 'wb')
273
        try:
274
            f.write('foobar\n')
275
        finally:
276
            f.close()
277
278
    def set_vendor(self, vendor):
279
        self._test_vendor = vendor
280
281
    def test_connection_paramiko(self):
1951.1.8 by Andrew Bennetts
Make _get_ssh_vendor return the vendor object, rather than just a string.
282
        from bzrlib.transport import ssh
283
        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
284
        t = self.get_transport()
285
        self.assertEqual('foobar\n', t.get('a_file').read())
286
287
    def test_connection_vendor(self):
288
        raise TestSkipped("We don't test spawning real ssh,"
289
                          " because it prompts for a password."
290
                          " Enable this test if we figure out"
291
                          " how to prevent this.")
292
        self.set_vendor(None)
293
        t = self.get_transport()
294
        self.assertEqual('foobar\n', t.get('a_file').read())
295
296
297
class SSHVendorBadConnection(TestCaseWithTransport):
298
    """Test that the ssh vendors handle bad connection properly
299
300
    We don't subclass TestCaseWithSFTPServer, because we don't actually
301
    need an SFTP connection.
302
    """
303
304
    def setUp(self):
305
        if not paramiko_loaded:
306
            raise TestSkipped('you must have paramiko to run this test')
307
        super(SSHVendorBadConnection, self).setUp()
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
308
        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
309
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
310
        # open a random port, so we know nobody else is using it
311
        # but don't actually listen on the port.
312
        s = socket.socket()
313
        s.bind(('localhost', 0))
314
        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
315
2221.5.18 by Dmitry Vasiliev
Fixed variable name
316
        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
317
        def reset():
2221.5.18 by Dmitry Vasiliev
Fixed variable name
318
            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
319
            s.close()
320
        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
321
322
    def set_vendor(self, vendor):
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
323
        import bzrlib.transport.ssh
2221.5.18 by Dmitry Vasiliev
Fixed variable name
324
        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
325
326
    def test_bad_connection_paramiko(self):
327
        """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.
328
        from bzrlib.transport import ssh
329
        self.set_vendor(ssh.ParamikoVendor())
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
330
        t = bzrlib.transport.get_transport(self.bogus_url)
331
        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
332
333
    def test_bad_connection_ssh(self):
334
        """None => auto-detect vendor"""
335
        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
336
        # This is how I would normally test the connection code
337
        # it makes it very clear what we are testing.
338
        # However, 'ssh' will create stipple on the output, so instead
339
        # I'm using run_bzr_subprocess, and parsing the output
340
        # try:
341
        #     t = bzrlib.transport.get_transport(self.bogus_url)
342
        # except errors.ConnectionError:
343
        #     # Correct error
344
        #     pass
345
        # except errors.NameError, e:
346
        #     if 'SSHException' in str(e):
347
        #         raise TestSkipped('Known NameError bug in paramiko 1.6.1')
348
        #     raise
349
        # else:
350
        #     self.fail('Excepted ConnectionError to be raised')
351
2665.4.1 by Aaron Bentley
teach run_bzr_subprocess to accept either a list of strings or a string
352
        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
353
        self.assertEqual('', out)
354
        if "NameError: global name 'SSHException'" in err:
355
            # We aren't fixing this bug, because it is a bug in
356
            # paramiko, but we know about it, so we don't have to
357
            # fail the test
358
            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
359
        self.assertContainsRe(err, r'bzr: ERROR: Unable to connect to SSH host'
360
                                   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
361
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
362
363
class SFTPLatencyKnob(TestCaseWithSFTPServer):
364
    """Test that the testing SFTPServer's latency knob works."""
365
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
366
    def test_latency_knob_slows_transport(self):
367
        # change the latency knob to 500ms. We take about 40ms for a 
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
368
        # loopback connection ordinarily.
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
369
        start_time = time.time()
370
        self.get_server().add_latency = 0.5
371
        transport = self.get_transport()
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
372
        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.
373
        with_latency_knob_time = time.time() - start_time
374
        self.assertTrue(with_latency_knob_time > 0.4)
375
376
    def test_default(self):
377
        # This test is potentially brittle: under extremely high machine load
378
        # it could fail, but that is quite unlikely
2631.1.1 by Aaron Bentley
Disable timing-sensitive test
379
        raise TestSkipped('Timing-sensitive test')
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
380
        start_time = time.time()
381
        transport = self.get_transport()
2485.8.38 by Vincent Ladeuil
Finish sftp refactoring. Test suite passing.
382
        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.
383
        regular_time = time.time() - start_time
384
        self.assertTrue(regular_time < 0.5)
385
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
386
387
class FakeSocket(object):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
388
    """Fake socket object used to test the SocketDelay wrapper without
389
    using a real socket.
390
    """
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
391
392
    def __init__(self):
393
        self._data = ""
394
395
    def send(self, data, flags=0):
396
        self._data += data
397
        return len(data)
398
399
    def sendall(self, data, flags=0):
400
        self._data += data
401
        return len(data)
402
403
    def recv(self, size, flags=0):
404
        if size < len(self._data):
405
            result = self._data[:size]
406
            self._data = self._data[size:]
407
            return result
408
        else:
409
            result = self._data
410
            self._data = ""
411
            return result
412
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
413
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
414
class TestSocketDelay(TestCase):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
415
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
416
    def setUp(self):
417
        TestCase.setUp(self)
1993.2.2 by John Arbash Meinel
Skip tests that require paramiko (or think they do)
418
        if not paramiko_loaded:
419
            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
420
421
    def test_delay(self):
422
        from bzrlib.transport.sftp import SocketDelay
423
        sending = FakeSocket()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
424
        receiving = SocketDelay(sending, 0.1, bandwidth=1000000,
425
                                really_sleep=False)
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
426
        # check that simulated time is charged only per round-trip:
427
        t1 = SocketDelay.simulated_time
428
        receiving.send("connect1")
429
        self.assertEqual(sending.recv(1024), "connect1")
430
        t2 = SocketDelay.simulated_time
431
        self.assertAlmostEqual(t2 - t1, 0.1)
432
        receiving.send("connect2")
433
        self.assertEqual(sending.recv(1024), "connect2")
434
        sending.send("hello")
435
        self.assertEqual(receiving.recv(1024), "hello")
436
        t3 = SocketDelay.simulated_time
437
        self.assertAlmostEqual(t3 - t2, 0.1)
438
        sending.send("hello")
439
        self.assertEqual(receiving.recv(1024), "hello")
440
        sending.send("hello")
441
        self.assertEqual(receiving.recv(1024), "hello")
442
        sending.send("hello")
443
        self.assertEqual(receiving.recv(1024), "hello")
444
        t4 = SocketDelay.simulated_time
445
        self.assertAlmostEqual(t4, t3)
446
447
    def test_bandwidth(self):
448
        from bzrlib.transport.sftp import SocketDelay
449
        sending = FakeSocket()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
450
        receiving = SocketDelay(sending, 0, bandwidth=8.0/(1024*1024),
451
                                really_sleep=False)
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
452
        # check that simulated time is charged only per round-trip:
453
        t1 = SocketDelay.simulated_time
454
        receiving.send("connect")
455
        self.assertEqual(sending.recv(1024), "connect")
456
        sending.send("a" * 100)
457
        self.assertEqual(receiving.recv(1024), "a" * 100)
458
        t2 = SocketDelay.simulated_time
459
        self.assertAlmostEqual(t2 - t1, 100 + 7)
460
1874.1.3 by Carl Friedrich Bolz
Merge bzr.dev.
461