/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
1
# Copyright (C) 2005 Robey Pointer <robey@lag.net>, Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
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
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
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
#
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
import os
18
import socket
19
import threading
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
20
import time
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
21
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.
22
import bzrlib.bzrdir as bzrdir
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
23
import bzrlib.errors as errors
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
24
from bzrlib.osutils import pathjoin, lexists, set_or_unset_env
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.
25
from bzrlib.tests import TestCaseWithTransport, TestCase, TestSkipped
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
26
from bzrlib.tests.HttpServer import HttpServer
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
27
import bzrlib.transport
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
28
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
29
import bzrlib.transport.http
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
30
from bzrlib.workingtree import WorkingTree
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
31
32
try:
33
    import paramiko
34
    paramiko_loaded = True
35
except ImportError:
36
    paramiko_loaded = False
37
1874.1.12 by Carl Friedrich Bolz
More fixes according to John's comments.
38
1874.1.14 by Carl Friedrich Bolz
Rename setup method to make its intent clearer. Some PEP 8 issues.
39
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.
40
    """A helper to set transports on test case instances."""
1874.1.6 by holger krekel
(cfbolz, hpk) Factor out common set_transport code.
41
    from bzrlib.transport.sftp import SFTPAbsoluteServer, SFTPHomeDirServer
42
    if getattr(testcase, '_get_remote_is_absolute', None) is None:
43
        testcase._get_remote_is_absolute = True
44
    if testcase._get_remote_is_absolute:
45
        testcase.transport_server = SFTPAbsoluteServer
46
    else:
47
        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 :)
48
    testcase.transport_readonly_server = HttpServer
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
49
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
50
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.
51
class TestCaseWithSFTPServer(TestCaseWithTransport):
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
52
    """A test case base class that provides a sftp server on localhost."""
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
53
54
    def setUp(self):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
55
        super(TestCaseWithSFTPServer, self).setUp()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
56
        if not paramiko_loaded:
57
            raise TestSkipped('you must have paramiko to run this test')
1874.1.14 by Carl Friedrich Bolz
Rename setup method to make its intent clearer. Some PEP 8 issues.
58
        set_test_transport_to_sftp(self) 
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
59
60
    def get_transport(self, path=None):
61
        """Return a transport relative to self._test_root."""
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.
62
        return bzrlib.transport.get_transport(self.get_url(path))
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
63
64
65
class SFTPLockTests (TestCaseWithSFTPServer):
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
66
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
67
    def test_sftp_locks(self):
68
        from bzrlib.errors import LockError
69
        t = self.get_transport()
70
71
        l = t.lock_write('bogus')
72
        self.failUnlessExists('bogus.write-lock')
73
74
        # Don't wait for the lock, locking an already locked
75
        # file should raise an assert
76
        self.assertRaises(LockError, t.lock_write, 'bogus')
77
78
        l.unlock()
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
79
        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
80
81
        open('something.write-lock', 'wb').write('fake lock\n')
82
        self.assertRaises(LockError, t.lock_write, 'something')
83
        os.remove('something.write-lock')
84
85
        l = t.lock_write('something')
86
87
        l2 = t.lock_write('bogus')
88
89
        l.unlock()
90
        l2.unlock()
91
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
92
    def test_multiple_connections(self):
93
        t = self.get_transport()
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.
94
        self.assertTrue('sftpserver - new connection' in self.get_server().logs)
95
        self.get_server().logs = []
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
96
        # The second request should reuse the first connection
97
        # SingleListener only allows for a single connection,
98
        # So the next line fails unless the connection is reused
99
        t2 = self.get_transport()
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.
100
        self.assertEquals(self.get_server().logs, [])
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
101
102
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
103
class SFTPTransportTestRelative(TestCaseWithSFTPServer):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
104
    """Test the SFTP transport with homedir based relative paths."""
105
106
    def test__remote_path(self):
107
        t = self.get_transport()
108
        # try what is currently used:
109
        # remote path = self._abspath(relpath)
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.
110
        self.assertEqual(self.test_dir + '/relative', t._remote_path('relative'))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
111
        # we dont os.path.join because windows gives us the wrong path
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.
112
        root_segments = self.test_dir.split('/')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
113
        root_parent = '/'.join(root_segments[:-1])
114
        # .. should be honoured
115
        self.assertEqual(root_parent + '/sibling', t._remote_path('../sibling'))
116
        # /  should be illegal ?
117
        ### FIXME decide and then test for all transports. RBC20051208
118
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
119
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
120
class SFTPTransportTestRelativeRoot(TestCaseWithSFTPServer):
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
121
    """Test the SFTP transport with homedir based relative paths."""
122
123
    def setUp(self):
124
        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.
125
        super(SFTPTransportTestRelativeRoot, self).setUp()
1530.1.6 by Robert Collins
Trim duplicate sftp tests.
126
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
127
    def test__remote_path_relative_root(self):
128
        # relative paths are preserved
129
        t = self.get_transport('')
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
130
        # the remote path should be ''
131
        self.assertEqual('', t._path)
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
132
        self.assertEqual('a', t._remote_path('a'))
133
134
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
135
class FakeSFTPTransport (object):
136
    _sftp = object()
137
fake = FakeSFTPTransport()
138
139
1185.49.14 by John Arbash Meinel
[merge] bzr.dev
140
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
141
    def setUp(self):
142
        TestCase.setUp(self)
143
        if not paramiko_loaded:
144
            raise TestSkipped('you must have paramiko to run this test')
145
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
146
    def test_parse_url(self):
147
        from bzrlib.transport.sftp import SFTPTransport
1534.1.8 by Robert Collins
Update SFTP Urls as per mailing list thread.
148
        s = SFTPTransport('sftp://simple.example.com/home/source', clone_from=fake)
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
149
        self.assertEquals(s._host, 'simple.example.com')
1185.49.23 by John Arbash Meinel
bugreport from Matthieu Moy: relpath was failing, but throwing an unhelpful exception.
150
        self.assertEquals(s._port, None)
1185.48.5 by James Henstridge
Change SFTP url parsing back to treat the path in sftp://host/path as
151
        self.assertEquals(s._path, '/home/source')
1185.49.19 by John Arbash Meinel
Testing that sftp.base gets properly sanitized
152
        self.failUnless(s._password is None)
153
1534.1.8 by Robert Collins
Update SFTP Urls as per mailing list thread.
154
        self.assertEquals(s.base, 'sftp://simple.example.com/home/source/')
155
156
        s = SFTPTransport('sftp://ro%62ey:h%40t@example.com:2222/~/relative', clone_from=fake)
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
157
        self.assertEquals(s._host, 'example.com')
158
        self.assertEquals(s._port, 2222)
159
        self.assertEquals(s._username, 'robey')
160
        self.assertEquals(s._password, 'h@t')
1185.48.5 by James Henstridge
Change SFTP url parsing back to treat the path in sftp://host/path as
161
        self.assertEquals(s._path, 'relative')
1185.33.58 by Martin Pool
[patch] Better error when sftp urls are given with invalid port numbers (Matthieu Moy)
162
1185.49.19 by John Arbash Meinel
Testing that sftp.base gets properly sanitized
163
        # Base should not keep track of the password
1534.1.8 by Robert Collins
Update SFTP Urls as per mailing list thread.
164
        self.assertEquals(s.base, 'sftp://robey@example.com:2222/~/relative/')
1185.49.23 by John Arbash Meinel
bugreport from Matthieu Moy: relpath was failing, but throwing an unhelpful exception.
165
166
    def test_relpath(self):
167
        from bzrlib.transport.sftp import SFTPTransport
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
168
        from bzrlib.errors import PathNotChild
1185.49.23 by John Arbash Meinel
bugreport from Matthieu Moy: relpath was failing, but throwing an unhelpful exception.
169
1534.1.8 by Robert Collins
Update SFTP Urls as per mailing list thread.
170
        s = SFTPTransport('sftp://user@host.com/abs/path', clone_from=fake)
171
        self.assertEquals(s.relpath('sftp://user@host.com/abs/path/sub'), 'sub')
2216 by Canonical.com Patch Queue Manager
(Vincent Ladeuil) Fix proxy issues with earlier python versions.
172
        # Can't test this one, because we actually get an AssertionError
173
        # TODO: Consider raising an exception rather than an assert
174
        #self.assertRaises(PathNotChild, s.relpath, 'http://user@host.com/abs/path/sub')
1534.1.8 by Robert Collins
Update SFTP Urls as per mailing list thread.
175
        self.assertRaises(PathNotChild, s.relpath, 'sftp://user2@host.com/abs/path/sub')
176
        self.assertRaises(PathNotChild, s.relpath, 'sftp://user@otherhost.com/abs/path/sub')
177
        self.assertRaises(PathNotChild, s.relpath, 'sftp://user@host.com:33/abs/path/sub')
178
        self.assertRaises(PathNotChild, s.relpath, 'sftp://user@host.com/~/rel/path/sub')
1185.49.19 by John Arbash Meinel
Testing that sftp.base gets properly sanitized
179
1185.49.25 by John Arbash Meinel
Added a couple more test cases, just in case.
180
        # Make sure it works when we don't supply a username
1534.1.8 by Robert Collins
Update SFTP Urls as per mailing list thread.
181
        s = SFTPTransport('sftp://host.com/abs/path', clone_from=fake)
182
        self.assertEquals(s.relpath('sftp://host.com/abs/path/sub'), 'sub')
1185.49.25 by John Arbash Meinel
Added a couple more test cases, just in case.
183
184
        # Make sure it works when parts of the path will be url encoded
185
        # TODO: These may be incorrect, we might need to urllib.urlencode() before
186
        # we pass the paths into the SFTPTransport constructor
187
        s = SFTPTransport('sftp://host.com/dev/,path', clone_from=fake)
188
        self.assertEquals(s.relpath('sftp://host.com/dev/,path/sub'), 'sub')
189
        s = SFTPTransport('sftp://host.com/dev/%path', clone_from=fake)
190
        self.assertEquals(s.relpath('sftp://host.com/dev/%path/sub'), 'sub')
191
1185.33.58 by Martin Pool
[patch] Better error when sftp urls are given with invalid port numbers (Matthieu Moy)
192
    def test_parse_invalid_url(self):
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
193
        from bzrlib.transport.sftp import SFTPTransport, TransportError
1185.33.58 by Martin Pool
[patch] Better error when sftp urls are given with invalid port numbers (Matthieu Moy)
194
        try:
195
            s = SFTPTransport('sftp://lilypond.org:~janneke/public_html/bzr/gub',
196
                              clone_from=fake)
197
            self.fail('expected exception not raised')
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
198
        except TransportError, e:
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
199
            self.assertEquals(str(e),
200
                    'Transport error: '
1910.15.8 by Andrew Bennetts
Put url in 'invalid port number' message on a new line.
201
                    'invalid port number ~janneke in url:\n'
1910.15.1 by Andrew Bennetts
More tests for abspath and clone behaviour
202
                    'sftp://lilypond.org:~janneke/public_html/bzr/gub ')
1185.33.58 by Martin Pool
[patch] Better error when sftp urls are given with invalid port numbers (Matthieu Moy)
203
2013.1.2 by John Arbash Meinel
Add a test that we can always fall back to the paramiko vendor
204
    def test_get_paramiko_vendor(self):
205
        """Test that if no 'ssh' is available we get builtin paramiko"""
206
        from bzrlib.transport import ssh
207
        # set '.' as the only location in the path, forcing no 'ssh' to exist
208
        orig_vendor = ssh._ssh_vendor
209
        orig_path = set_or_unset_env('PATH', '.')
210
        try:
211
            # No vendor defined yet, query for one
212
            ssh._ssh_vendor = None
213
            vendor = ssh._get_ssh_vendor()
214
            self.assertIsInstance(vendor, ssh.ParamikoVendor)
215
        finally:
216
            set_or_unset_env('PATH', orig_path)
217
            ssh._ssh_vendor = orig_vendor
218
1986.1.10 by Robert Collins
Merge from bzr.dev, fixing found bugs handling 'has('/')' in MemoryTransport and SFTP transports.
219
    def test_abspath_root_sibling_server(self):
220
        from bzrlib.transport.sftp import SFTPSiblingAbsoluteServer
221
        server = SFTPSiblingAbsoluteServer()
222
        server.setUp()
223
        try:
224
            transport = get_transport(server.get_url())
225
            self.assertFalse(transport.abspath('/').endswith('/~/'))
226
            self.assertTrue(transport.abspath('/').endswith('/'))
227
            del transport
228
        finally:
229
            server.tearDown()
230
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
231
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
232
class SFTPBranchTest(TestCaseWithSFTPServer):
233
    """Test some stuff when accessing a bzr Branch over sftp"""
234
235
    def test_lock_file(self):
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
236
        # old format branches use a special lock file on sftp.
237
        b = self.make_branch('', format=bzrdir.BzrDirFormat6())
238
        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
239
        self.failUnlessExists('.bzr/')
240
        self.failUnlessExists('.bzr/branch-format')
241
        self.failUnlessExists('.bzr/branch-lock')
242
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
243
        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
244
        b.lock_write()
245
        self.failUnlessExists('.bzr/branch-lock.write-lock')
246
        b.unlock()
1185.31.33 by John Arbash Meinel
A couple more path.join statements needed changing.
247
        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
248
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.
249
    def test_push_support(self):
250
        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.
251
        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.
252
        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.
253
        t.add('foo')
254
        t.commit('foo', rev_id='a1')
255
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.
256
        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.
257
        b2.pull(b)
258
259
        self.assertEquals(b2.revision_history(), ['a1'])
260
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.
261
        open('a/foo', 'wt').write('something new in foo\n')
262
        t.commit('new', rev_id='a2')
263
        b2.pull(b)
264
265
        self.assertEquals(b2.revision_history(), ['a1', 'a2'])
266
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
267
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
268
class SSHVendorConnection(TestCaseWithSFTPServer):
269
    """Test that the ssh vendors can all connect.
270
271
    Verify that a full-handshake (SSH over loopback TCP) sftp connection works.
272
273
    We have 3 sftp implementations in the test suite:
274
      'loopback': Doesn't use ssh, just uses a local socket. Most tests are
275
                  done this way to save the handshaking time, so it is not
276
                  tested again here
277
      'none':     This uses paramiko's built-in ssh client and server, and layers
278
                  sftp on top of it.
279
      None:       If 'ssh' exists on the machine, then it will be spawned as a
280
                  child process.
281
    """
1547.1.4 by Robey Pointer
add a single full-handshake test to verify that sftp-over-ssh works
282
    
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
283
    def setUp(self):
284
        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.
285
        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
286
287
        def create_server():
288
            """Just a wrapper so that when created, it will set _vendor"""
289
            # SFTPFullAbsoluteServer can handle any vendor,
290
            # it just needs to be set between the time it is instantiated
291
            # and the time .setUp() is called
292
            server = SFTPFullAbsoluteServer()
293
            server._vendor = self._test_vendor
294
            return server
295
        self._test_vendor = 'loopback'
296
        self.transport_server = create_server
297
        f = open('a_file', 'wb')
298
        try:
299
            f.write('foobar\n')
300
        finally:
301
            f.close()
302
303
    def set_vendor(self, vendor):
304
        self._test_vendor = vendor
305
306
    def test_connection_paramiko(self):
1951.1.8 by Andrew Bennetts
Make _get_ssh_vendor return the vendor object, rather than just a string.
307
        from bzrlib.transport import ssh
308
        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
309
        t = self.get_transport()
310
        self.assertEqual('foobar\n', t.get('a_file').read())
311
312
    def test_connection_vendor(self):
313
        raise TestSkipped("We don't test spawning real ssh,"
314
                          " because it prompts for a password."
315
                          " Enable this test if we figure out"
316
                          " how to prevent this.")
317
        self.set_vendor(None)
318
        t = self.get_transport()
319
        self.assertEqual('foobar\n', t.get('a_file').read())
320
321
322
class SSHVendorBadConnection(TestCaseWithTransport):
323
    """Test that the ssh vendors handle bad connection properly
324
325
    We don't subclass TestCaseWithSFTPServer, because we don't actually
326
    need an SFTP connection.
327
    """
328
329
    def setUp(self):
330
        if not paramiko_loaded:
331
            raise TestSkipped('you must have paramiko to run this test')
332
        super(SSHVendorBadConnection, self).setUp()
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
333
        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
334
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
335
        # open a random port, so we know nobody else is using it
336
        # but don't actually listen on the port.
337
        s = socket.socket()
338
        s.bind(('localhost', 0))
339
        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
340
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
341
        orig_vendor = bzrlib.transport.ssh._ssh_vendor
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
342
        def reset():
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
343
            bzrlib.transport.ssh._ssh_vendor = orig_vendor
1185.49.35 by John Arbash Meinel
Update tests to use a truly unused port
344
            s.close()
345
        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
346
347
    def set_vendor(self, vendor):
1951.1.10 by Andrew Bennetts
Move register_ssh_vendor, _ssh_vendor and _get_ssh_vendor into ssh.py
348
        import bzrlib.transport.ssh
349
        bzrlib.transport.ssh._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
350
351
    def test_bad_connection_paramiko(self):
352
        """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.
353
        from bzrlib.transport import ssh
354
        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
355
        self.assertRaises(errors.ConnectionError,
356
                          bzrlib.transport.get_transport, self.bogus_url)
357
358
    def test_bad_connection_ssh(self):
359
        """None => auto-detect vendor"""
360
        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
361
        # This is how I would normally test the connection code
362
        # it makes it very clear what we are testing.
363
        # However, 'ssh' will create stipple on the output, so instead
364
        # I'm using run_bzr_subprocess, and parsing the output
365
        # try:
366
        #     t = bzrlib.transport.get_transport(self.bogus_url)
367
        # except errors.ConnectionError:
368
        #     # Correct error
369
        #     pass
370
        # except errors.NameError, e:
371
        #     if 'SSHException' in str(e):
372
        #         raise TestSkipped('Known NameError bug in paramiko 1.6.1')
373
        #     raise
374
        # else:
375
        #     self.fail('Excepted ConnectionError to be raised')
376
377
        out, err = self.run_bzr_subprocess('log', self.bogus_url, retcode=3)
378
        self.assertEqual('', out)
379
        if "NameError: global name 'SSHException'" in err:
380
            # We aren't fixing this bug, because it is a bug in
381
            # paramiko, but we know about it, so we don't have to
382
            # fail the test
383
            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
384
        self.assertContainsRe(err, r'bzr: ERROR: Unable to connect to SSH host'
385
                                   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
386
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
387
388
class SFTPLatencyKnob(TestCaseWithSFTPServer):
389
    """Test that the testing SFTPServer's latency knob works."""
390
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
391
    def test_latency_knob_slows_transport(self):
392
        # change the latency knob to 500ms. We take about 40ms for a 
1871.1.3 by Robert Collins
proof of concept slowsocket wrapper.
393
        # loopback connection ordinarily.
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
394
        start_time = time.time()
395
        self.get_server().add_latency = 0.5
396
        transport = self.get_transport()
397
        with_latency_knob_time = time.time() - start_time
398
        self.assertTrue(with_latency_knob_time > 0.4)
399
400
    def test_default(self):
401
        # This test is potentially brittle: under extremely high machine load
402
        # it could fail, but that is quite unlikely
403
        start_time = time.time()
404
        transport = self.get_transport()
405
        regular_time = time.time() - start_time
406
        self.assertTrue(regular_time < 0.5)
407
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
408
409
class FakeSocket(object):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
410
    """Fake socket object used to test the SocketDelay wrapper without
411
    using a real socket.
412
    """
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
413
414
    def __init__(self):
415
        self._data = ""
416
417
    def send(self, data, flags=0):
418
        self._data += data
419
        return len(data)
420
421
    def sendall(self, data, flags=0):
422
        self._data += data
423
        return len(data)
424
425
    def recv(self, size, flags=0):
426
        if size < len(self._data):
427
            result = self._data[:size]
428
            self._data = self._data[size:]
429
            return result
430
        else:
431
            result = self._data
432
            self._data = ""
433
            return result
434
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
435
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
436
class TestSocketDelay(TestCase):
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
437
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
438
    def setUp(self):
439
        TestCase.setUp(self)
1993.2.2 by John Arbash Meinel
Skip tests that require paramiko (or think they do)
440
        if not paramiko_loaded:
441
            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
442
443
    def test_delay(self):
444
        from bzrlib.transport.sftp import SocketDelay
445
        sending = FakeSocket()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
446
        receiving = SocketDelay(sending, 0.1, bandwidth=1000000,
447
                                really_sleep=False)
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
448
        # check that simulated time is charged only per round-trip:
449
        t1 = SocketDelay.simulated_time
450
        receiving.send("connect1")
451
        self.assertEqual(sending.recv(1024), "connect1")
452
        t2 = SocketDelay.simulated_time
453
        self.assertAlmostEqual(t2 - t1, 0.1)
454
        receiving.send("connect2")
455
        self.assertEqual(sending.recv(1024), "connect2")
456
        sending.send("hello")
457
        self.assertEqual(receiving.recv(1024), "hello")
458
        t3 = SocketDelay.simulated_time
459
        self.assertAlmostEqual(t3 - t2, 0.1)
460
        sending.send("hello")
461
        self.assertEqual(receiving.recv(1024), "hello")
462
        sending.send("hello")
463
        self.assertEqual(receiving.recv(1024), "hello")
464
        sending.send("hello")
465
        self.assertEqual(receiving.recv(1024), "hello")
466
        t4 = SocketDelay.simulated_time
467
        self.assertAlmostEqual(t4, t3)
468
469
    def test_bandwidth(self):
470
        from bzrlib.transport.sftp import SocketDelay
471
        sending = FakeSocket()
1874.1.9 by Carl Friedrich Bolz
Try to fix all the issues outline by john and Robert.
472
        receiving = SocketDelay(sending, 0, bandwidth=8.0/(1024*1024),
473
                                really_sleep=False)
1874.1.2 by Carl Friedrich Bolz
Refined the SocketDelay to charge latency only once per round-trip and to
474
        # check that simulated time is charged only per round-trip:
475
        t1 = SocketDelay.simulated_time
476
        receiving.send("connect")
477
        self.assertEqual(sending.recv(1024), "connect")
478
        sending.send("a" * 100)
479
        self.assertEqual(receiving.recv(1024), "a" * 100)
480
        t2 = SocketDelay.simulated_time
481
        self.assertAlmostEqual(t2 - t1, 100 + 7)
482
1874.1.3 by Carl Friedrich Bolz
Merge bzr.dev.
483