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