88
93
file(key_file, 'w').write(STUB_SERVER_KEY)
89
94
host_key = paramiko.RSAKey.from_private_key_file(key_file)
90
95
ssh_server.add_server_key(host_key)
96
server = StubServer(self)
92
97
ssh_server.set_subsystem_handler('sftp', paramiko.SFTPServer, StubSFTPServer, root=self._root)
93
98
event = threading.Event()
94
99
ssh_server.start_server(event, server)
99
104
TestCaseInTempDir.setUp(self)
100
105
self._root = self.test_dir
106
self._is_setup = False
102
108
def delayed_setup(self):
103
109
# some tests are just stubs that call setUp and then immediately call
104
110
# tearDwon. so don't create the port listener until get_transport is
105
111
# called and we know we're in an actual test.
106
114
self._listener = SingleListener(self._run_server)
107
115
self._listener.setDaemon(True)
108
116
self._listener.start()
109
117
self._sftp_url = 'sftp://foo:bar@localhost:%d/' % (self._listener.port,)
118
self._is_setup = True
111
120
def tearDown(self):
119
128
class SFTPTransportTest (TestCaseWithSFTPServer, TestTransportMixIn):
132
TestCaseWithSFTPServer.setUp(self)
135
def log(self, *args):
136
"""Override the default log to grab sftp server messages"""
137
TestCaseWithSFTPServer.log(self, *args)
138
if args and args[0].startswith('sftpserver'):
139
self.sftplogs.append(args[0])
123
141
def get_transport(self):
127
143
from bzrlib.transport.sftp import SFTPTransport
128
144
url = self._sftp_url
129
145
return SFTPTransport(url)
172
def test_multiple_connections(self):
173
t = self.get_transport()
174
self.assertEquals(self.sftplogs,
175
['sftpserver - authorizing: foo'
176
, 'sftpserver - channel request: session, 1'])
178
# The second request should reuse the first connection
179
# SingleListener only allows for a single connection,
180
# So the next line fails unless the connection is reused
181
t2 = self.get_transport()
182
self.assertEquals(self.sftplogs, [])
157
185
class FakeSFTPTransport (object):
159
187
fake = FakeSFTPTransport()
162
class SFTPNonServerTest(unittest.TestCase):
190
class SFTPNonServerTest(TestCase):
163
191
def test_parse_url(self):
164
192
from bzrlib.transport.sftp import SFTPTransport
165
193
s = SFTPTransport('sftp://simple.example.com/%2fhome/source', clone_from=fake)
166
194
self.assertEquals(s._host, 'simple.example.com')
167
195
self.assertEquals(s._port, None)
168
196
self.assertEquals(s._path, '/home/source')
169
self.assert_(s._password is None)
197
self.failUnless(s._password is None)
199
self.assertEquals(s.base, 'sftp://simple.example.com/%2Fhome/source')
171
201
s = SFTPTransport('sftp://ro%62ey:h%40t@example.com:2222/relative', clone_from=fake)
172
202
self.assertEquals(s._host, 'example.com')
175
205
self.assertEquals(s._password, 'h@t')
176
206
self.assertEquals(s._path, 'relative')
208
# Base should not keep track of the password
209
self.assertEquals(s.base, 'sftp://robey@example.com:2222/relative')
211
# Double slash should be accepted instead of using %2F
212
s = SFTPTransport('sftp://user@example.com:22//absolute/path', clone_from=fake)
213
self.assertEquals(s._host, 'example.com')
214
self.assertEquals(s._port, 22)
215
self.assertEquals(s._username, 'user')
216
self.assertEquals(s._password, None)
217
self.assertEquals(s._path, '/absolute/path')
219
# Also, don't show the port if it is the default 22
220
self.assertEquals(s.base, 'sftp://user@example.com:22/%2Fabsolute/path')
222
def test_relpath(self):
223
from bzrlib.transport.sftp import SFTPTransport
224
from bzrlib.errors import NonRelativePath
226
s = SFTPTransport('sftp://user@host.com//abs/path', clone_from=fake)
227
self.assertEquals(s.relpath('sftp://user@host.com//abs/path/sub'), 'sub')
228
# Can't test this one, because we actually get an AssertionError
229
# TODO: Consider raising an exception rather than an assert
230
#self.assertRaises(NonRelativePath, s.relpath, 'http://user@host.com//abs/path/sub')
231
self.assertRaises(NonRelativePath, s.relpath, 'sftp://user2@host.com//abs/path/sub')
232
self.assertRaises(NonRelativePath, s.relpath, 'sftp://user@otherhost.com//abs/path/sub')
233
self.assertRaises(NonRelativePath, s.relpath, 'sftp://user@host.com:33//abs/path/sub')
234
self.assertRaises(NonRelativePath, s.relpath, 'sftp://user@host.com/abs/path/sub')
236
# Make sure it works when we don't supply a username
237
s = SFTPTransport('sftp://host.com//abs/path', clone_from=fake)
238
self.assertEquals(s.relpath('sftp://host.com//abs/path/sub'), 'sub')
240
# Make sure it works when parts of the path will be url encoded
241
# TODO: These may be incorrect, we might need to urllib.urlencode() before
242
# we pass the paths into the SFTPTransport constructor
243
s = SFTPTransport('sftp://host.com/dev/,path', clone_from=fake)
244
self.assertEquals(s.relpath('sftp://host.com/dev/,path/sub'), 'sub')
245
s = SFTPTransport('sftp://host.com/dev/%path', clone_from=fake)
246
self.assertEquals(s.relpath('sftp://host.com/dev/%path/sub'), 'sub')
178
248
def test_parse_invalid_url(self):
179
249
from bzrlib.transport.sftp import SFTPTransport, SFTPTransportError