29
from stub_sftp import StubServer, StubSFTPServer
30
29
paramiko_loaded = True
31
30
except ImportError:
32
31
paramiko_loaded = False
34
# XXX: 20051124 jamesh
35
# The tests currently pop up a password prompt when an external ssh
36
# is used. This forces the use of the paramiko implementation.
38
import bzrlib.transport.sftp
39
bzrlib.transport.sftp._ssh_vendor = 'none'
43
-----BEGIN RSA PRIVATE KEY-----
44
MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz
45
oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/
46
d8ufMCkjeXsQkKqFbAlQcnWMCRnOoPHS3I4vi6hmnDDeeYTSRvfLbW0fhwIBIwKB
47
gBIiOqZYaoqbeD9OS9z2K9KR2atlTxGxOJPXiP4ESqP3NVScWNwyZ3NXHpyrJLa0
48
EbVtzsQhLn6rF+TzXnOlcipFvjsem3iYzCpuChfGQ6SovTcOjHV9z+hnpXvQ/fon
49
soVRZY65wKnF7IAoUwTmJS9opqgrN6kRgCd3DASAMd1bAkEA96SBVWFt/fJBNJ9H
50
tYnBKZGw0VeHOYmVYbvMSstssn8un+pQpUm9vlG/bp7Oxd/m+b9KWEh2xPfv6zqU
51
avNwHwJBANqzGZa/EpzF4J8pGti7oIAPUIDGMtfIcmqNXVMckrmzQ2vTfqtkEZsA
52
4rE1IERRyiJQx6EJsz21wJmGV9WJQ5kCQQDwkS0uXqVdFzgHO6S++tjmjYcxwr3g
53
H0CoFYSgbddOT6miqRskOQF3DZVkJT3kyuBgU2zKygz52ukQZMqxCb1fAkASvuTv
54
qfpH87Qq5kQhNKdbbwbmd2NxlNabazPijWuphGTdW0VfJdWfklyS2Kr+iqrs/5wV
55
HhathJt636Eg7oIjAkA8ht3MQ+XSl9yIJIS8gVpbPxSw5OMfw0PjVE7tBdQruiSc
56
nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7
57
-----END RSA PRIVATE KEY-----
61
class SingleListener (threading.Thread):
63
def __init__(self, callback):
64
threading.Thread.__init__(self)
65
self._callback = callback
66
self._socket = socket.socket()
67
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
68
self._socket.bind(('localhost', 0))
69
self._socket.listen(1)
70
self.port = self._socket.getsockname()[1]
71
self.stop_event = threading.Event()
74
s, _ = self._socket.accept()
75
# now close the listen socket
77
self._callback(s, self.stop_event)
81
# We should consider waiting for the other thread
82
# to stop, because otherwise we get spurious
83
# bzr: ERROR: Socket exception: Connection reset by peer (54)
84
# because the test suite finishes before the thread has a chance
85
# to close. (Especially when only running a few tests)
88
34
class TestCaseWithSFTPServer(TestCaseInTempDir):
90
Execute a test case with a stub SFTP server, serving files from the local
91
filesystem over the loopback network.
94
def _run_server(self, s, stop_event):
95
ssh_server = paramiko.Transport(s)
96
key_file = os.path.join(self._root, 'test_rsa.key')
97
file(key_file, 'w').write(STUB_SERVER_KEY)
98
host_key = paramiko.RSAKey.from_private_key_file(key_file)
99
ssh_server.add_server_key(host_key)
100
server = StubServer(self)
101
if self._override_home is None:
104
home = self._override_home
105
ssh_server.set_subsystem_handler('sftp', paramiko.SFTPServer,
106
StubSFTPServer, root='/',
108
event = threading.Event()
109
ssh_server.start_server(event, server)
111
stop_event.wait(30.0)
35
"""A test case base class that provides a sftp server on localhost."""
114
38
super(TestCaseWithSFTPServer, self).setUp()
39
from bzrlib.transport.sftp import SFTPAbsoluteServer, SFTPHomeDirServer
40
if getattr(self, '_get_remote_is_absolute', None) is None:
41
self._get_remote_is_absolute = True
42
if self._get_remote_is_absolute:
43
self.server = SFTPAbsoluteServer()
45
self.server = SFTPHomeDirServer()
47
self._sftp_url = self.server.get_url()
115
48
self._root = self.test_dir
116
49
# Set to a string in setUp to give sftp server a new homedir.
117
50
self._override_home = None
118
51
self._is_setup = False
119
self._get_remote_is_absolute = True
120
52
self.sftplogs = []
122
def delayed_setup(self):
123
# some tests are just stubs that call setUp and then immediately call
124
# tearDwon. so don't create the port listener until get_transport is
125
# called and we know we're in an actual test.
128
self._listener = SingleListener(self._run_server)
129
self._listener.setDaemon(True)
130
self._listener.start()
131
self._sftp_url = self._get_sftp_url("%%2f%s" %
132
bzrlib.transport.urlescape(self._root[1:]))
133
self._is_setup = True
135
def _get_sftp_url(self, path):
136
"""Calculate a sftp url to this server for path."""
137
return 'sftp://foo:bar@localhost:%d/%s' % (self._listener.port, path)
139
54
def get_remote_url(self, relpath_to_test_root):
141
if self._get_remote_is_absolute:
142
return self._get_sftp_url("%%2f%s" %
143
bzrlib.transport.urlescape(self._root[1:]
145
+ relpath_to_test_root))
147
return self._get_sftp_url(
148
bzrlib.transport.urlescape(relpath_to_test_root))
56
return self._sftp_url + '/' + relpath_to_test_root
150
58
def tearDown(self):
152
self._listener.stop()
153
except AttributeError:
155
TestCaseInTempDir.tearDown(self)
60
self.server.tearDown()
62
TestCaseInTempDir.tearDown(self)
157
64
def get_transport(self, path=None):
158
65
"""Return a transport relative to self._test_root."""
160
from bzrlib.transport.sftp import SFTPTransport
66
from bzrlib.transport import get_transport
67
transport = get_transport(self._sftp_url)
163
if self._get_remote_is_absolute:
166
url = self._get_sftp_url('')
168
url = self._get_sftp_url(path)
169
return SFTPTransport(url)
171
def log(self, *args):
172
"""Override the default log to grab sftp server messages"""
173
TestCaseInTempDir.log(self, *args)
174
if args and args[0].startswith('sftpserver'):
175
self.sftplogs.append(args[0])
178
class SFTPTransportTestMixin (TestTransportMixIn):
71
return transport.clone(path)
74
class SFTPLockTests (TestCaseWithSFTPServer):
181
76
def test_sftp_locks(self):
182
77
from bzrlib.errors import LockError
206
101
def test_multiple_connections(self):
207
102
t = self.get_transport()
208
self.assertEquals(self.sftplogs,
103
self.assertEquals(self.server.logs,
209
104
['sftpserver - authorizing: foo'
210
105
, 'sftpserver - channel request: session, 1'])
106
self.server.logs = []
212
107
# The second request should reuse the first connection
213
108
# SingleListener only allows for a single connection,
214
109
# So the next line fails unless the connection is reused
215
110
t2 = self.get_transport()
216
self.assertEquals(self.sftplogs, [])
219
class SFTPTransportTestAbsolute(TestCaseWithSFTPServer, SFTPTransportTestMixin):
220
"""Test the SFTP transport with %2f based abs paths."""
111
self.assertEquals(self.server.logs, [])
223
114
class SFTPTransportTestAbsoluteSibling(TestCaseWithSFTPServer,
224
SFTPTransportTestMixin):
225
116
"""Test the SFTP transport with %2f based sibling paths to $HOME."""
119
self._override_home = '/dev/noone/runs/tests/here'
228
120
super(SFTPTransportTestAbsoluteSibling, self).setUp()
229
self._override_home = '/dev/noone/runs/tests/here'
232
class SFTPTransportTestRelative(TestCaseWithSFTPServer, SFTPTransportTestMixin):
123
class SFTPTransportTestRelative(TestCaseWithSFTPServer):
233
124
"""Test the SFTP transport with homedir based relative paths."""
236
super(SFTPTransportTestRelative, self).setUp()
237
self._get_remote_is_absolute = False
240
class SFTPTransportRemotePathTest(TestCaseWithSFTPServer):
242
126
def test__remote_path(self):
243
127
t = self.get_transport()
244
128
# try what is currently used: