/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
2
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.
7
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.
12
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
20
import unittest
21
22
from bzrlib.selftest import TestCaseInTempDir
23
from bzrlib.selftest.testtransport import TestTransportMixIn
24
25
try:
26
    import paramiko
27
    from stub_sftp import StubServer, StubSFTPServer
28
    paramiko_loaded = True
29
except ImportError:
30
    paramiko_loaded = False
31
32
33
STUB_SERVER_KEY = """
34
-----BEGIN RSA PRIVATE KEY-----
35
MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz
36
oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/
37
d8ufMCkjeXsQkKqFbAlQcnWMCRnOoPHS3I4vi6hmnDDeeYTSRvfLbW0fhwIBIwKB
38
gBIiOqZYaoqbeD9OS9z2K9KR2atlTxGxOJPXiP4ESqP3NVScWNwyZ3NXHpyrJLa0
39
EbVtzsQhLn6rF+TzXnOlcipFvjsem3iYzCpuChfGQ6SovTcOjHV9z+hnpXvQ/fon
40
soVRZY65wKnF7IAoUwTmJS9opqgrN6kRgCd3DASAMd1bAkEA96SBVWFt/fJBNJ9H
41
tYnBKZGw0VeHOYmVYbvMSstssn8un+pQpUm9vlG/bp7Oxd/m+b9KWEh2xPfv6zqU
42
avNwHwJBANqzGZa/EpzF4J8pGti7oIAPUIDGMtfIcmqNXVMckrmzQ2vTfqtkEZsA
43
4rE1IERRyiJQx6EJsz21wJmGV9WJQ5kCQQDwkS0uXqVdFzgHO6S++tjmjYcxwr3g
44
H0CoFYSgbddOT6miqRskOQF3DZVkJT3kyuBgU2zKygz52ukQZMqxCb1fAkASvuTv
45
qfpH87Qq5kQhNKdbbwbmd2NxlNabazPijWuphGTdW0VfJdWfklyS2Kr+iqrs/5wV
46
HhathJt636Eg7oIjAkA8ht3MQ+XSl9yIJIS8gVpbPxSw5OMfw0PjVE7tBdQruiSc
47
nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7
48
-----END RSA PRIVATE KEY-----
49
"""
50
    
51
52
class SingleListener (threading.Thread):
53
    def __init__(self, callback):
54
        threading.Thread.__init__(self)
55
        self._callback = callback
56
        self._socket = socket.socket()
1185.40.10 by Robey Pointer
set REUSEADDR on the listen socket in sftp transport tests, and delay opening the listening socket until we know the test is really going to run (some tests are currently stubs)
57
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1185.40.8 by Robey Pointer
modification of a patch by alexey shamrin to make more of the transport tests pass on windows
58
        self._socket.bind(('localhost', 0))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
59
        self._socket.listen(1)
60
        self.port = self._socket.getsockname()[1]
61
        self.stop_event = threading.Event()
62
63
    def run(self):
64
        s, _ = self._socket.accept()
65
        # now close the listen socket
66
        self._socket.close()
67
        self._callback(s, self.stop_event)
68
    
69
    def stop(self):
70
        self.stop_event.set()
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
71
        # We should consider waiting for the other thread
72
        # to stop, because otherwise we get spurious
73
        #   bzr: ERROR: Socket exception: Connection reset by peer (54)
74
        # because the test suite finishes before the thread has a chance
75
        # to close. (Especially when only running a few tests)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
76
        
77
        
78
class TestCaseWithSFTPServer (TestCaseInTempDir):
79
    """
80
    Execute a test case with a stub SFTP server, serving files from the local
81
    filesystem over the loopback network.
82
    """
83
    
84
    def _run_server(self, s, stop_event):
85
        ssh_server = paramiko.Transport(s)
86
        key_file = os.path.join(self._root, 'test_rsa.key')
87
        file(key_file, 'w').write(STUB_SERVER_KEY)
88
        host_key = paramiko.RSAKey.from_private_key_file(key_file)
89
        ssh_server.add_server_key(host_key)
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
90
        server = StubServer(self)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
91
        ssh_server.set_subsystem_handler('sftp', paramiko.SFTPServer, StubSFTPServer, root=self._root)
92
        event = threading.Event()
93
        ssh_server.start_server(event, server)
94
        event.wait(5.0)
95
        stop_event.wait(30.0)
96
97
    def setUp(self):
98
        TestCaseInTempDir.setUp(self)
99
        self._root = self.test_dir
100
1185.40.10 by Robey Pointer
set REUSEADDR on the listen socket in sftp transport tests, and delay opening the listening socket until we know the test is really going to run (some tests are currently stubs)
101
    def delayed_setup(self):
102
        # some tests are just stubs that call setUp and then immediately call
103
        # tearDwon.  so don't create the port listener until get_transport is
104
        # called and we know we're in an actual test.
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
105
        self._listener = SingleListener(self._run_server)
106
        self._listener.setDaemon(True)
107
        self._listener.start()        
108
        self._sftp_url = 'sftp://foo:bar@localhost:%d/' % (self._listener.port,)
109
        
110
    def tearDown(self):
1185.40.10 by Robey Pointer
set REUSEADDR on the listen socket in sftp transport tests, and delay opening the listening socket until we know the test is really going to run (some tests are currently stubs)
111
        try:
112
            self._listener.stop()
113
        except AttributeError:
114
            pass
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
115
        TestCaseInTempDir.tearDown(self)
116
117
        
118
class SFTPTransportTest (TestCaseWithSFTPServer, TestTransportMixIn):
119
    readonly = False
1185.40.10 by Robey Pointer
set REUSEADDR on the listen socket in sftp transport tests, and delay opening the listening socket until we know the test is really going to run (some tests are currently stubs)
120
    setup = True
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
121
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
122
    def setUp(self):
123
        TestCaseWithSFTPServer.setUp(self)
124
        self.sftplogs = []
125
126
    def log(self, *args):
127
        """Override the default log to grab sftp server messages"""
128
        TestCaseWithSFTPServer.log(self, *args)
129
        if args and args[0].startswith('sftpserver'):
130
            self.sftplogs.append(args[0])
131
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
132
    def get_transport(self):
1185.40.10 by Robey Pointer
set REUSEADDR on the listen socket in sftp transport tests, and delay opening the listening socket until we know the test is really going to run (some tests are currently stubs)
133
        if self.setup:
134
            self.delayed_setup()
135
            self.setup = False
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
136
        from bzrlib.transport.sftp import SFTPTransport
137
        url = self._sftp_url
138
        return SFTPTransport(url)
139
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
140
    def test_sftp_locks(self):
141
        from bzrlib.errors import LockError
142
        t = self.get_transport()
143
144
        l = t.lock_write('bogus')
145
        self.failUnlessExists('bogus.write-lock')
146
147
        # Don't wait for the lock, locking an already locked
148
        # file should raise an assert
149
        self.assertRaises(LockError, t.lock_write, 'bogus')
150
151
        l.unlock()
152
        self.failIf(os.path.lexists('bogus.write-lock'))
153
154
        open('something.write-lock', 'wb').write('fake lock\n')
155
        self.assertRaises(LockError, t.lock_write, 'something')
156
        os.remove('something.write-lock')
157
158
        l = t.lock_write('something')
159
160
        l2 = t.lock_write('bogus')
161
162
        l.unlock()
163
        l2.unlock()
164
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
165
    def test_multiple_connections(self):
166
        t = self.get_transport()
167
        self.assertEquals(self.sftplogs, 
168
                ['sftpserver - authorizing: foo'
169
               , 'sftpserver - channel request: session, 1'])
170
        self.sftplogs = []
171
        # The second request should reuse the first connection
172
        # SingleListener only allows for a single connection,
173
        # So the next line fails unless the connection is reused
174
        t2 = self.get_transport()
175
        self.assertEquals(self.sftplogs, [])
176
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
177
178
class FakeSFTPTransport (object):
179
    _sftp = object()
180
fake = FakeSFTPTransport()
181
182
183
class SFTPNonServerTest (unittest.TestCase):
184
    def test_parse_url(self):
185
        from bzrlib.transport.sftp import SFTPTransport
186
        s = SFTPTransport('sftp://simple.example.com/%2fhome/source', clone_from=fake)
187
        self.assertEquals(s._host, 'simple.example.com')
188
        self.assertEquals(s._port, 22)
189
        self.assertEquals(s._path, '/home/source')
190
        self.assert_(s._password is None)
191
        
192
        s = SFTPTransport('sftp://ro%62ey:h%40t@example.com:2222/relative', clone_from=fake)
193
        self.assertEquals(s._host, 'example.com')
194
        self.assertEquals(s._port, 2222)
195
        self.assertEquals(s._username, 'robey')
196
        self.assertEquals(s._password, 'h@t')
197
        self.assertEquals(s._path, 'relative')
198
        
199
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
200
class SFTPBranchTest(TestCaseWithSFTPServer):
201
    """Test some stuff when accessing a bzr Branch over sftp"""
202
203
    def test_lock_file(self):
204
        """Make sure that a Branch accessed over sftp tries to lock itself."""
205
        from bzrlib.branch import Branch
206
207
        b = Branch.initialize(self._sftp_url)
208
        self.failUnlessExists('.bzr/')
209
        self.failUnlessExists('.bzr/branch-format')
210
        self.failUnlessExists('.bzr/branch-lock')
211
212
        self.failIf(os.path.lexists('.bzr/branch-lock.write-lock'))
213
        b.lock_write()
214
        self.failUnlessExists('.bzr/branch-lock.write-lock')
215
        b.unlock()
216
        self.failIf(os.path.lexists('.bzr/branch-lock.write-lock'))
217
218
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
219
if not paramiko_loaded:
1185.49.3 by John Arbash Meinel
Added a form of locking to sftp branches. Refactored _sftp_open_exclusive to take a relative path
220
    # TODO: Skip these
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
221
    del SFTPTransportTest
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
222
    del SFTPNonServerTest
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
    del SFTPBranchTest