/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/stub_sftp.py

  • Committer: Jelmer Vernooij
  • Date: 2020-02-18 01:57:45 UTC
  • mto: This revision was merged to the branch mainline in revision 7493.
  • Revision ID: jelmer@jelmer.uk-20200218015745-q2ss9tsk74h4nh61
drop use of future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2008, 2009, 2010 Robey Pointer <robey@lag.net>, Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008-2011 Robey Pointer <robey@lag.net>, Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
21
21
 
22
22
import os
23
23
import paramiko
24
 
import select
25
24
import socket
 
25
import socketserver
26
26
import sys
27
 
import threading
28
27
import time
29
28
 
30
 
from bzrlib import (
 
29
from .. import (
31
30
    osutils,
32
31
    trace,
33
32
    urlutils,
34
33
    )
35
 
from bzrlib.transport import (
 
34
from ..transport import (
36
35
    ssh,
37
36
    )
38
 
from bzrlib.tests import test_server
39
 
 
40
 
 
41
 
class StubServer (paramiko.ServerInterface):
42
 
 
43
 
    def __init__(self, test_case):
 
37
from . import test_server
 
38
 
 
39
 
 
40
class StubServer(paramiko.ServerInterface):
 
41
 
 
42
    def __init__(self, test_case_server):
44
43
        paramiko.ServerInterface.__init__(self)
45
 
        self._test_case = test_case
 
44
        self.log = test_case_server.log
46
45
 
47
46
    def check_auth_password(self, username, password):
48
47
        # all are allowed
49
 
        self._test_case.log('sftpserver - authorizing: %s' % (username,))
 
48
        self.log('sftpserver - authorizing: %s' % (username,))
50
49
        return paramiko.AUTH_SUCCESSFUL
51
50
 
52
51
    def check_channel_request(self, kind, chanid):
53
 
        self._test_case.log(
54
 
            'sftpserver - channel request: %s, %s' % (kind, chanid))
 
52
        self.log('sftpserver - channel request: %s, %s' % (kind, chanid))
55
53
        return paramiko.OPEN_SUCCEEDED
56
54
 
57
55
 
58
 
class StubSFTPHandle (paramiko.SFTPHandle):
 
56
class StubSFTPHandle(paramiko.SFTPHandle):
 
57
 
59
58
    def stat(self):
60
59
        try:
61
60
            return paramiko.SFTPAttributes.from_stat(
62
61
                os.fstat(self.readfile.fileno()))
63
 
        except OSError, e:
 
62
        except OSError as e:
64
63
            return paramiko.SFTPServer.convert_errno(e.errno)
65
64
 
66
65
    def chattr(self, attr):
69
68
        trace.mutter('Changing permissions on %s to %s', self.filename, attr)
70
69
        try:
71
70
            paramiko.SFTPServer.set_file_attr(self.filename, attr)
72
 
        except OSError, e:
 
71
        except OSError as e:
73
72
            return paramiko.SFTPServer.convert_errno(e.errno)
74
73
 
75
74
 
76
 
class StubSFTPServer (paramiko.SFTPServerInterface):
 
75
class StubSFTPServer(paramiko.SFTPServerInterface):
77
76
 
78
77
    def __init__(self, server, root, home=None):
79
78
        paramiko.SFTPServerInterface.__init__(self, server)
90
89
            self.home = home[len(self.root):]
91
90
        if self.home.startswith('/'):
92
91
            self.home = self.home[1:]
93
 
        server._test_case.log('sftpserver - new connection')
 
92
        server.log('sftpserver - new connection')
94
93
 
95
94
    def _realpath(self, path):
96
95
        # paths returned from self.canonicalize() always start with
119
118
    else:
120
119
        def canonicalize(self, path):
121
120
            if os.path.isabs(path):
122
 
                return os.path.normpath(path)
 
121
                return osutils.normpath(path)
123
122
            else:
124
 
                return os.path.normpath('/' + os.path.join(self.home, path))
 
123
                return osutils.normpath('/' + os.path.join(self.home, path))
125
124
 
126
125
    def chattr(self, path, attr):
127
126
        try:
128
127
            paramiko.SFTPServer.set_file_attr(path, attr)
129
 
        except OSError, e:
 
128
        except OSError as e:
130
129
            return paramiko.SFTPServer.convert_errno(e.errno)
131
130
        return paramiko.SFTP_OK
132
131
 
133
132
    def list_folder(self, path):
134
133
        path = self._realpath(path)
135
134
        try:
136
 
            out = [ ]
 
135
            out = []
137
136
            # TODO: win32 incorrectly lists paths with non-ascii if path is not
138
 
            # unicode. However on Linux the server should only deal with
 
137
            # unicode. However on unix the server should only deal with
139
138
            # bytestreams and posix.listdir does the right thing
140
139
            if sys.platform == 'win32':
141
140
                flist = [f.encode('utf8') for f in os.listdir(path)]
147
146
                attr.filename = fname
148
147
                out.append(attr)
149
148
            return out
150
 
        except OSError, e:
 
149
        except OSError as e:
151
150
            return paramiko.SFTPServer.convert_errno(e.errno)
152
151
 
153
152
    def stat(self, path):
154
153
        path = self._realpath(path)
155
154
        try:
156
155
            return paramiko.SFTPAttributes.from_stat(os.stat(path))
157
 
        except OSError, e:
 
156
        except OSError as e:
158
157
            return paramiko.SFTPServer.convert_errno(e.errno)
159
158
 
160
159
    def lstat(self, path):
161
160
        path = self._realpath(path)
162
161
        try:
163
162
            return paramiko.SFTPAttributes.from_stat(os.lstat(path))
164
 
        except OSError, e:
 
163
        except OSError as e:
165
164
            return paramiko.SFTPServer.convert_errno(e.errno)
166
165
 
167
166
    def open(self, path, flags, attr):
173
172
            else:
174
173
                # os.open() defaults to 0777 which is
175
174
                # an odd default mode for files
176
 
                fd = os.open(path, flags, 0666)
177
 
        except OSError, e:
 
175
                fd = os.open(path, flags, 0o666)
 
176
        except OSError as e:
178
177
            return paramiko.SFTPServer.convert_errno(e.errno)
179
178
 
180
179
        if (flags & os.O_CREAT) and (attr is not None):
189
188
            fstr = 'rb'
190
189
        try:
191
190
            f = os.fdopen(fd, fstr)
192
 
        except (IOError, OSError), e:
 
191
        except (IOError, OSError) as e:
193
192
            return paramiko.SFTPServer.convert_errno(e.errno)
194
193
        fobj = StubSFTPHandle()
195
194
        fobj.filename = path
201
200
        path = self._realpath(path)
202
201
        try:
203
202
            os.remove(path)
204
 
        except OSError, e:
 
203
        except OSError as e:
205
204
            return paramiko.SFTPServer.convert_errno(e.errno)
206
205
        return paramiko.SFTP_OK
207
206
 
210
209
        newpath = self._realpath(newpath)
211
210
        try:
212
211
            os.rename(oldpath, newpath)
213
 
        except OSError, e:
214
 
            return paramiko.SFTPServer.convert_errno(e.errno)
215
 
        return paramiko.SFTP_OK
 
212
        except OSError as e:
 
213
            return paramiko.SFTPServer.convert_errno(e.errno)
 
214
        return paramiko.SFTP_OK
 
215
 
 
216
    def symlink(self, target_path, path):
 
217
        path = self._realpath(path)
 
218
        try:
 
219
            os.symlink(target_path, path)
 
220
        except OSError as e:
 
221
            return paramiko.SFTPServer.convert_errno(e.errno)
 
222
        return paramiko.SFTP_OK
 
223
 
 
224
    def readlink(self, path):
 
225
        path = self._realpath(path)
 
226
        try:
 
227
            target_path = os.readlink(path)
 
228
        except OSError as e:
 
229
            return paramiko.SFTPServer.convert_errno(e.errno)
 
230
        return target_path
216
231
 
217
232
    def mkdir(self, path, attr):
218
233
        path = self._realpath(path)
226
241
            if attr is not None:
227
242
                attr._flags &= ~attr.FLAG_PERMISSIONS
228
243
                paramiko.SFTPServer.set_file_attr(path, attr)
229
 
        except OSError, e:
 
244
        except OSError as e:
230
245
            return paramiko.SFTPServer.convert_errno(e.errno)
231
246
        return paramiko.SFTP_OK
232
247
 
234
249
        path = self._realpath(path)
235
250
        try:
236
251
            os.rmdir(path)
237
 
        except OSError, e:
 
252
        except OSError as e:
238
253
            return paramiko.SFTPServer.convert_errno(e.errno)
239
254
        return paramiko.SFTP_OK
240
255
 
241
 
    # removed: chattr, symlink, readlink
 
256
    # removed: chattr
242
257
    # (nothing in bzr's sftp transport uses those)
243
258
 
 
259
 
244
260
# ------------- server test implementation --------------
245
261
 
246
 
STUB_SERVER_KEY = """
 
262
STUB_SERVER_KEY = """\
247
263
-----BEGIN RSA PRIVATE KEY-----
248
264
MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz
249
265
oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/
262
278
"""
263
279
 
264
280
 
265
 
class SocketListener(threading.Thread):
266
 
 
267
 
    def __init__(self, callback):
268
 
        threading.Thread.__init__(self)
269
 
        self._callback = callback
270
 
        self._socket = socket.socket()
271
 
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
272
 
        self._socket.bind(('localhost', 0))
273
 
        self._socket.listen(1)
274
 
        self.host, self.port = self._socket.getsockname()[:2]
275
 
        self._stop_event = threading.Event()
276
 
 
277
 
    def stop(self):
278
 
        # called from outside this thread
279
 
        self._stop_event.set()
280
 
        # use a timeout here, because if the test fails, the server thread may
281
 
        # never notice the stop_event.
282
 
        self.join(5.0)
283
 
        self._socket.close()
284
 
 
285
 
    def run(self):
286
 
        trace.mutter('SocketListener %r has started', self)
287
 
        while True:
288
 
            readable, writable_unused, exception_unused = \
289
 
                select.select([self._socket], [], [], 0.1)
290
 
            if self._stop_event.isSet():
291
 
                trace.mutter('SocketListener %r has stopped', self)
292
 
                return
293
 
            if len(readable) == 0:
294
 
                continue
295
 
            try:
296
 
                s, addr_unused = self._socket.accept()
297
 
                trace.mutter('SocketListener %r has accepted connection %r',
298
 
                    self, s)
299
 
                # because the loopback socket is inline, and transports are
300
 
                # never explicitly closed, best to launch a new thread.
301
 
                threading.Thread(target=self._callback, args=(s,)).start()
302
 
            except socket.error, x:
303
 
                sys.excepthook(*sys.exc_info())
304
 
                trace.warning('Socket error during accept() '
305
 
                              'within unit test server thread: %r' % x)
306
 
            except Exception, x:
307
 
                # probably a failed test; unit test thread will log the
308
 
                # failure/error
309
 
                sys.excepthook(*sys.exc_info())
310
 
                trace.warning(
311
 
                    'Exception from within unit test server thread: %r' % x)
312
 
 
313
 
 
314
281
class SocketDelay(object):
315
282
    """A socket decorator to make TCP appear slower.
316
283
 
386
353
        return bytes_sent
387
354
 
388
355
 
389
 
class SFTPServer(test_server.TestServer):
 
356
class TestingSFTPConnectionHandler(socketserver.BaseRequestHandler):
 
357
 
 
358
    def setup(self):
 
359
        self.wrap_for_latency()
 
360
        tcs = self.server.test_case_server
 
361
        ptrans = paramiko.Transport(self.request)
 
362
        self.paramiko_transport = ptrans
 
363
        # Set it to a channel under 'bzr' so that we get debug info
 
364
        ptrans.set_log_channel('brz.paramiko.transport')
 
365
        ptrans.add_server_key(tcs.get_host_key())
 
366
        ptrans.set_subsystem_handler('sftp', paramiko.SFTPServer,
 
367
                                     StubSFTPServer, root=tcs._root,
 
368
                                     home=tcs._server_homedir)
 
369
        server = tcs._server_interface(tcs)
 
370
        # This blocks until the key exchange has been done
 
371
        ptrans.start_server(None, server)
 
372
 
 
373
    def finish(self):
 
374
        # Wait for the conversation to finish, when the paramiko.Transport
 
375
        # thread finishes
 
376
        # TODO: Consider timing out after XX seconds rather than hanging.
 
377
        #       Also we could check paramiko_transport.active and possibly
 
378
        #       paramiko_transport.getException().
 
379
        self.paramiko_transport.join()
 
380
 
 
381
    def wrap_for_latency(self):
 
382
        tcs = self.server.test_case_server
 
383
        if tcs.add_latency:
 
384
            # Give the socket (which the request really is) a latency adding
 
385
            # decorator.
 
386
            self.request = SocketDelay(self.request, tcs.add_latency)
 
387
 
 
388
 
 
389
class TestingSFTPWithoutSSHConnectionHandler(TestingSFTPConnectionHandler):
 
390
 
 
391
    def setup(self):
 
392
        self.wrap_for_latency()
 
393
        # Re-import these as locals, so that they're still accessible during
 
394
        # interpreter shutdown (when all module globals get set to None, leading
 
395
        # to confusing errors like "'NoneType' object has no attribute 'error'".
 
396
 
 
397
        class FakeChannel(object):
 
398
            def get_transport(self):
 
399
                return self
 
400
 
 
401
            def get_log_channel(self):
 
402
                return 'brz.paramiko'
 
403
 
 
404
            def get_name(self):
 
405
                return '1'
 
406
 
 
407
            def get_hexdump(self):
 
408
                return False
 
409
 
 
410
            def close(self):
 
411
                pass
 
412
 
 
413
        tcs = self.server.test_case_server
 
414
        sftp_server = paramiko.SFTPServer(
 
415
            FakeChannel(), 'sftp', StubServer(tcs), StubSFTPServer,
 
416
            root=tcs._root, home=tcs._server_homedir)
 
417
        self.sftp_server = sftp_server
 
418
        sys_stderr = sys.stderr  # Used in error reporting during shutdown
 
419
        try:
 
420
            sftp_server.start_subsystem(
 
421
                'sftp', None, ssh.SocketAsChannelAdapter(self.request))
 
422
        except socket.error as e:
 
423
            if (len(e.args) > 0) and (e.args[0] == errno.EPIPE):
 
424
                # it's okay for the client to disconnect abruptly
 
425
                # (bug in paramiko 1.6: it should absorb this exception)
 
426
                pass
 
427
            else:
 
428
                raise
 
429
        except Exception as e:
 
430
            # This typically seems to happen during interpreter shutdown, so
 
431
            # most of the useful ways to report this error won't work.
 
432
            # Writing the exception type, and then the text of the exception,
 
433
            # seems to be the best we can do.
 
434
            # FIXME: All interpreter shutdown errors should have been related
 
435
            # to daemon threads, cleanup needed -- vila 20100623
 
436
            sys_stderr.write('\nEXCEPTION %r: ' % (e.__class__,))
 
437
            sys_stderr.write('%s\n\n' % (e,))
 
438
 
 
439
    def finish(self):
 
440
        self.sftp_server.finish_subsystem()
 
441
 
 
442
 
 
443
class TestingSFTPServer(test_server.TestingThreadingTCPServer):
 
444
 
 
445
    def __init__(self, server_address, request_handler_class, test_case_server):
 
446
        test_server.TestingThreadingTCPServer.__init__(
 
447
            self, server_address, request_handler_class)
 
448
        self.test_case_server = test_case_server
 
449
 
 
450
 
 
451
class SFTPServer(test_server.TestingTCPServerInAThread):
390
452
    """Common code for SFTP server facilities."""
391
453
 
392
454
    def __init__(self, server_interface=StubServer):
 
455
        self.host = '127.0.0.1'
 
456
        self.port = 0
 
457
        super(SFTPServer, self).__init__((self.host, self.port),
 
458
                                         TestingSFTPServer,
 
459
                                         TestingSFTPConnectionHandler)
393
460
        self._original_vendor = None
394
 
        self._homedir = None
395
 
        self._server_homedir = None
396
 
        self._listener = None
397
 
        self._root = None
398
461
        self._vendor = ssh.ParamikoVendor()
399
462
        self._server_interface = server_interface
400
 
        # sftp server logs
 
463
        self._host_key = None
401
464
        self.logs = []
402
465
        self.add_latency = 0
 
466
        self._homedir = None
 
467
        self._server_homedir = None
 
468
        self._root = None
403
469
 
404
470
    def _get_sftp_url(self, path):
405
471
        """Calculate an sftp url to this server for path."""
406
 
        return 'sftp://foo:bar@%s:%d/%s' % (self._listener.host,
407
 
                                            self._listener.port, path)
 
472
        return "sftp://foo:bar@%s:%s/%s" % (self.host, self.port, path)
408
473
 
409
474
    def log(self, message):
410
475
        """StubServer uses this to log when a new server is created."""
411
476
        self.logs.append(message)
412
477
 
413
 
    def _run_server_entry(self, sock):
414
 
        """Entry point for all implementations of _run_server.
415
 
 
416
 
        If self.add_latency is > 0.000001 then sock is given a latency adding
417
 
        decorator.
418
 
        """
419
 
        if self.add_latency > 0.000001:
420
 
            sock = SocketDelay(sock, self.add_latency)
421
 
        return self._run_server(sock)
422
 
 
423
 
    def _run_server(self, s):
424
 
        ssh_server = paramiko.Transport(s)
425
 
        key_file = osutils.pathjoin(self._homedir, 'test_rsa.key')
426
 
        f = open(key_file, 'w')
427
 
        f.write(STUB_SERVER_KEY)
428
 
        f.close()
429
 
        host_key = paramiko.RSAKey.from_private_key_file(key_file)
430
 
        ssh_server.add_server_key(host_key)
431
 
        server = self._server_interface(self)
432
 
        ssh_server.set_subsystem_handler('sftp', paramiko.SFTPServer,
433
 
                                         StubSFTPServer, root=self._root,
434
 
                                         home=self._server_homedir)
435
 
        event = threading.Event()
436
 
        ssh_server.start_server(event, server)
437
 
        event.wait(5.0)
 
478
    def create_server(self):
 
479
        server = self.server_class((self.host, self.port),
 
480
                                   self.request_handler_class,
 
481
                                   self)
 
482
        return server
 
483
 
 
484
    def get_host_key(self):
 
485
        if self._host_key is None:
 
486
            key_file = osutils.pathjoin(self._homedir, 'test_rsa.key')
 
487
            f = open(key_file, 'w')
 
488
            try:
 
489
                f.write(STUB_SERVER_KEY)
 
490
            finally:
 
491
                f.close()
 
492
            self._host_key = paramiko.RSAKey.from_private_key_file(key_file)
 
493
        return self._host_key
438
494
 
439
495
    def start_server(self, backing_server=None):
440
496
        # XXX: TODO: make sftpserver back onto backing_server rather than local
441
497
        # disk.
442
 
        if not (backing_server is None or
443
 
                isinstance(backing_server, test_server.LocalURLServer)):
 
498
        if not (backing_server is None
 
499
                or isinstance(backing_server, test_server.LocalURLServer)):
444
500
            raise AssertionError(
445
501
                'backing_server should not be %r, because this can only serve '
446
502
                'the local current working directory.' % (backing_server,))
447
503
        self._original_vendor = ssh._ssh_vendor_manager._cached_ssh_vendor
448
504
        ssh._ssh_vendor_manager._cached_ssh_vendor = self._vendor
449
 
        # FIXME: the following block should certainly just be self._homedir =
450
 
        # osutils.getcwd() but that fails badly on Unix -- vila 20100224
 
505
        self._homedir = osutils.getcwd()
451
506
        if sys.platform == 'win32':
452
 
            # Win32 needs to use the UNICODE api
453
 
            self._homedir = os.getcwdu()
 
507
            # Normalize the path or it will be wrongly escaped
 
508
            self._homedir = osutils.normpath(self._homedir)
454
509
        else:
455
 
            # But Linux SFTP servers should just deal in bytestreams
456
 
            self._homedir = os.getcwd()
 
510
            self._homedir = self._homedir
457
511
        if self._server_homedir is None:
458
512
            self._server_homedir = self._homedir
459
513
        self._root = '/'
460
514
        if sys.platform == 'win32':
461
515
            self._root = ''
462
 
        self._listener = SocketListener(self._run_server_entry)
463
 
        self._listener.setDaemon(True)
464
 
        self._listener.start()
 
516
        super(SFTPServer, self).start_server()
465
517
 
466
518
    def stop_server(self):
467
 
        self._listener.stop()
468
 
        ssh._ssh_vendor_manager._cached_ssh_vendor = self._original_vendor
 
519
        try:
 
520
            super(SFTPServer, self).stop_server()
 
521
        finally:
 
522
            ssh._ssh_vendor_manager._cached_ssh_vendor = self._original_vendor
469
523
 
470
524
    def get_bogus_url(self):
471
 
        """See bzrlib.transport.Server.get_bogus_url."""
472
 
        # this is chosen to try to prevent trouble with proxies, wierd dns, etc
 
525
        """See breezy.transport.Server.get_bogus_url."""
 
526
        # this is chosen to try to prevent trouble with proxies, weird dns, etc
473
527
        # we bind a random socket, so that we get a guaranteed unused port
474
528
        # we just never listen on that port
475
529
        s = socket.socket()
481
535
    """A test server for sftp transports, using absolute urls and ssh."""
482
536
 
483
537
    def get_url(self):
484
 
        """See bzrlib.transport.Server.get_url."""
 
538
        """See breezy.transport.Server.get_url."""
485
539
        homedir = self._homedir
486
540
        if sys.platform != 'win32':
487
541
            # Remove the initial '/' on all platforms but win32
495
549
    def __init__(self):
496
550
        super(SFTPServerWithoutSSH, self).__init__()
497
551
        self._vendor = ssh.LoopbackVendor()
498
 
 
499
 
    def _run_server(self, sock):
500
 
        # Re-import these as locals, so that they're still accessible during
501
 
        # interpreter shutdown (when all module globals get set to None, leading
502
 
        # to confusing errors like "'NoneType' object has no attribute 'error'".
503
 
        class FakeChannel(object):
504
 
            def get_transport(self):
505
 
                return self
506
 
            def get_log_channel(self):
507
 
                return 'paramiko'
508
 
            def get_name(self):
509
 
                return '1'
510
 
            def get_hexdump(self):
511
 
                return False
512
 
            def close(self):
513
 
                pass
514
 
 
515
 
        server = paramiko.SFTPServer(
516
 
            FakeChannel(), 'sftp', StubServer(self), StubSFTPServer,
517
 
            root=self._root, home=self._server_homedir)
518
 
        try:
519
 
            server.start_subsystem(
520
 
                'sftp', None, ssh.SocketAsChannelAdapter(sock))
521
 
        except socket.error, e:
522
 
            if (len(e.args) > 0) and (e.args[0] == errno.EPIPE):
523
 
                # it's okay for the client to disconnect abruptly
524
 
                # (bug in paramiko 1.6: it should absorb this exception)
525
 
                pass
526
 
            else:
527
 
                raise
528
 
        except Exception, e:
529
 
            # This typically seems to happen during interpreter shutdown, so
530
 
            # most of the useful ways to report this error are won't work.
531
 
            # Writing the exception type, and then the text of the exception,
532
 
            # seems to be the best we can do.
533
 
            import sys
534
 
            sys.stderr.write('\nEXCEPTION %r: ' % (e.__class__,))
535
 
            sys.stderr.write('%s\n\n' % (e,))
536
 
        server.finish_subsystem()
 
552
        self.request_handler_class = TestingSFTPWithoutSSHConnectionHandler
 
553
 
 
554
    def get_host_key():
 
555
        return None
537
556
 
538
557
 
539
558
class SFTPAbsoluteServer(SFTPServerWithoutSSH):
540
559
    """A test server for sftp transports, using absolute urls."""
541
560
 
542
561
    def get_url(self):
543
 
        """See bzrlib.transport.Server.get_url."""
 
562
        """See breezy.transport.Server.get_url."""
544
563
        homedir = self._homedir
545
564
        if sys.platform != 'win32':
546
565
            # Remove the initial '/' on all platforms but win32
552
571
    """A test server for sftp transports, using homedir relative urls."""
553
572
 
554
573
    def get_url(self):
555
 
        """See bzrlib.transport.Server.get_url."""
556
 
        return self._get_sftp_url("~/")
 
574
        """See breezy.transport.Server.get_url."""
 
575
        return self._get_sftp_url("%7E/")
557
576
 
558
577
 
559
578
class SFTPSiblingAbsoluteServer(SFTPAbsoluteServer):
562
581
    It does this by serving from a deeply-nested directory that doesn't exist.
563
582
    """
564
583
 
565
 
    def start_server(self, backing_server=None):
566
 
        self._server_homedir = '/dev/noone/runs/tests/here'
567
 
        super(SFTPSiblingAbsoluteServer, self).start_server(backing_server)
568
 
 
 
584
    def create_server(self):
 
585
        # FIXME: Can't we do that in a cleaner way ? -- vila 20100623
 
586
        server = super(SFTPSiblingAbsoluteServer, self).create_server()
 
587
        server._server_homedir = '/dev/noone/runs/tests/here'
 
588
        return server