/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4988.10.5 by John Arbash Meinel
Merge bzr.dev 5021 to resolve NEWS
1
# Copyright (C) 2005, 2006, 2008, 2009, 2010 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
16
17
"""
18
A stub SFTP server for loopback SFTP testing.
19
Adapted from the one in paramiko's unit tests.
20
"""
21
22
import os
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
23
import paramiko
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
24
import select
25
import socket
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
26
import SocketServer
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
27
import sys
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
28
import threading
29
import time
1666.1.6 by Robert Collins
Make knit the default format.
30
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
31
from bzrlib import (
32
    osutils,
33
    trace,
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
34
    urlutils,
35
    )
36
from bzrlib.transport import (
37
    ssh,
38
    )
5017.3.34 by Vincent Ladeuil
-s bt.per_branch passing
39
from bzrlib.tests import test_server
40
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
41
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
42
class StubServer(paramiko.ServerInterface):
1666.1.6 by Robert Collins
Make knit the default format.
43
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
44
    def __init__(self, test_case_server):
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
45
        paramiko.ServerInterface.__init__(self)
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
46
        self.log = test_case_server.log
1185.49.10 by John Arbash Meinel
Use a weakref dictionary to enable re-use of a connection (for sftp).
47
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
48
    def check_auth_password(self, username, password):
49
        # all are allowed
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
50
        self.log('sftpserver - authorizing: %s' % (username,))
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
51
        return paramiko.AUTH_SUCCESSFUL
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
52
53
    def check_channel_request(self, kind, chanid):
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
54
        self.log('sftpserver - channel request: %s, %s' % (kind, chanid))
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
55
        return paramiko.OPEN_SUCCEEDED
56
57
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
58
class StubSFTPHandle(paramiko.SFTPHandle):
59
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
60
    def stat(self):
61
        try:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
62
            return paramiko.SFTPAttributes.from_stat(
63
                os.fstat(self.readfile.fileno()))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
64
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
65
            return paramiko.SFTPServer.convert_errno(e.errno)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
66
67
    def chattr(self, attr):
68
        # python doesn't have equivalents to fchown or fchmod, so we have to
69
        # use the stored filename
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
70
        trace.mutter('Changing permissions on %s to %s', self.filename, attr)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
71
        try:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
72
            paramiko.SFTPServer.set_file_attr(self.filename, attr)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
73
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
74
            return paramiko.SFTPServer.convert_errno(e.errno)
75
76
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
77
class StubSFTPServer(paramiko.SFTPServerInterface):
1666.1.6 by Robert Collins
Make knit the default format.
78
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
79
    def __init__(self, server, root, home=None):
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
80
        paramiko.SFTPServerInterface.__init__(self, server)
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
81
        # All paths are actually relative to 'root'.
82
        # this is like implementing chroot().
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
83
        self.root = root
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
84
        if home is None:
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
85
            self.home = ''
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
86
        else:
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
87
            if not home.startswith(self.root):
88
                raise AssertionError(
89
                    "home must be a subdirectory of root (%s vs %s)"
90
                    % (home, root))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
91
            self.home = home[len(self.root):]
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
92
        if self.home.startswith('/'):
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
93
            self.home = self.home[1:]
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
94
        server.log('sftpserver - new connection')
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
95
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
96
    def _realpath(self, path):
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
97
        # paths returned from self.canonicalize() always start with
98
        # a path separator. So if 'root' is just '/', this would cause
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
99
        # a double slash at the beginning '//home/dir'.
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
100
        if self.root == '/':
101
            return self.canonicalize(path)
102
        return self.root + self.canonicalize(path)
103
104
    if sys.platform == 'win32':
105
        def canonicalize(self, path):
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
106
            # Win32 sftp paths end up looking like
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
107
            #     sftp://host@foo/h:/foo/bar
108
            # which means absolute paths look like:
109
            #     /h:/foo/bar
110
            # and relative paths stay the same:
111
            #     foo/bar
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
112
            # win32 needs to use the Unicode APIs. so we require the
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
113
            # paths to be utf8 (Linux just uses bytestreams)
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
114
            thispath = path.decode('utf8')
115
            if path.startswith('/'):
1711.5.4 by John Arbash Meinel
Update stub_sftp based on Robey's comments.
116
                # Abspath H:/foo/bar
117
                return os.path.normpath(thispath[1:])
118
            else:
119
                return os.path.normpath(os.path.join(self.home, thispath))
120
    else:
121
        def canonicalize(self, path):
122
            if os.path.isabs(path):
123
                return os.path.normpath(path)
124
            else:
125
                return os.path.normpath('/' + os.path.join(self.home, path))
1524.1.1 by Robert Collins
Test sftp with relative, absolute-in-homedir and absolute-not-in-homedir
126
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
127
    def chattr(self, path, attr):
128
        try:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
129
            paramiko.SFTPServer.set_file_attr(path, attr)
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
130
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
131
            return paramiko.SFTPServer.convert_errno(e.errno)
132
        return paramiko.SFTP_OK
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
133
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
134
    def list_folder(self, path):
135
        path = self._realpath(path)
136
        try:
137
            out = [ ]
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
138
            # TODO: win32 incorrectly lists paths with non-ascii if path is not
5278.1.2 by Martin Pool
Don't say 'Linux' except when specifically talking about the kernel
139
            # unicode. However on unix the server should only deal with
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
140
            # bytestreams and posix.listdir does the right thing
1711.5.1 by John Arbash Meinel
Get most SFTP tests to pass. StubSFTPServer now talks the same path protocol that SFTPTransport talks. on win32
141
            if sys.platform == 'win32':
142
                flist = [f.encode('utf8') for f in os.listdir(path)]
143
            else:
144
                flist = os.listdir(path)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
145
            for fname in flist:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
146
                attr = paramiko.SFTPAttributes.from_stat(
147
                    os.stat(osutils.pathjoin(path, fname)))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
148
                attr.filename = fname
149
                out.append(attr)
150
            return out
151
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
152
            return paramiko.SFTPServer.convert_errno(e.errno)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
153
154
    def stat(self, path):
155
        path = self._realpath(path)
156
        try:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
157
            return paramiko.SFTPAttributes.from_stat(os.stat(path))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
158
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
159
            return paramiko.SFTPServer.convert_errno(e.errno)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
160
161
    def lstat(self, path):
162
        path = self._realpath(path)
163
        try:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
164
            return paramiko.SFTPAttributes.from_stat(os.lstat(path))
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
165
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
166
            return paramiko.SFTPServer.convert_errno(e.errno)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
167
168
    def open(self, path, flags, attr):
169
        path = self._realpath(path)
170
        try:
1963.2.4 by Robey Pointer
remove usage of hasattr
171
            flags |= getattr(os, 'O_BINARY', 0)
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
172
            if getattr(attr, 'st_mode', None):
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
173
                fd = os.open(path, flags, attr.st_mode)
174
            else:
1988.1.1 by John Arbash Meinel
Restore mode bit tests for sftp, and track down bugs
175
                # os.open() defaults to 0777 which is
176
                # an odd default mode for files
177
                fd = os.open(path, flags, 0666)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
178
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
179
            return paramiko.SFTPServer.convert_errno(e.errno)
1685.1.72 by Wouter van Heyst
StubSFTPServer should use bytestreams rather than unicode
180
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
181
        if (flags & os.O_CREAT) and (attr is not None):
1185.58.10 by John Arbash Meinel
[patch] Robey Pointer to fix sftp server using umask for files (failing tests for directories)
182
            attr._flags &= ~attr.FLAG_PERMISSIONS
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
183
            paramiko.SFTPServer.set_file_attr(path, attr)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
184
        if flags & os.O_WRONLY:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
185
            fstr = 'wb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
186
        elif flags & os.O_RDWR:
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
187
            fstr = 'rb+'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
188
        else:
189
            # O_RDONLY (== 0)
1185.31.51 by John Arbash Meinel
Setting binary flags for sftp.
190
            fstr = 'rb'
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
191
        try:
192
            f = os.fdopen(fd, fstr)
1711.3.1 by John Arbash Meinel
opening a dir instead of a file raises an IOError, not OSError
193
        except (IOError, OSError), e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
194
            return paramiko.SFTPServer.convert_errno(e.errno)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
195
        fobj = StubSFTPHandle()
196
        fobj.filename = path
197
        fobj.readfile = f
198
        fobj.writefile = f
199
        return fobj
200
201
    def remove(self, path):
202
        path = self._realpath(path)
203
        try:
204
            os.remove(path)
205
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
206
            return paramiko.SFTPServer.convert_errno(e.errno)
207
        return paramiko.SFTP_OK
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
208
209
    def rename(self, oldpath, newpath):
210
        oldpath = self._realpath(oldpath)
211
        newpath = self._realpath(newpath)
212
        try:
213
            os.rename(oldpath, newpath)
214
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
215
            return paramiko.SFTPServer.convert_errno(e.errno)
216
        return paramiko.SFTP_OK
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
217
218
    def mkdir(self, path, attr):
219
        path = self._realpath(path)
220
        try:
1540.1.5 by John Arbash Meinel
Bugfix to allow using paramiko > 1.5.2
221
            # Using getattr() in case st_mode is None or 0
222
            # both evaluate to False
1540.1.9 by John Arbash Meinel
Cleanup getattr() code, since getattr(None, '', None) still works
223
            if getattr(attr, 'st_mode', None):
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
224
                os.mkdir(path, attr.st_mode)
225
            else:
226
                os.mkdir(path)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
227
            if attr is not None:
1185.58.11 by John Arbash Meinel
Made the StubSFTPServer use umask even for mkdir()
228
                attr._flags &= ~attr.FLAG_PERMISSIONS
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
229
                paramiko.SFTPServer.set_file_attr(path, attr)
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
230
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
231
            return paramiko.SFTPServer.convert_errno(e.errno)
232
        return paramiko.SFTP_OK
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
233
234
    def rmdir(self, path):
235
        path = self._realpath(path)
236
        try:
237
            os.rmdir(path)
238
        except OSError, e:
4797.11.1 by Vincent Ladeuil
Fix test.stub_sftp imports.
239
            return paramiko.SFTPServer.convert_errno(e.errno)
240
        return paramiko.SFTP_OK
1185.16.127 by Martin Pool
[patch] paramiko sftp tests (robey)
241
242
    # removed: chattr, symlink, readlink
243
    # (nothing in bzr's sftp transport uses those)
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
244
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
245
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
246
# ------------- server test implementation --------------
247
248
STUB_SERVER_KEY = """
249
-----BEGIN RSA PRIVATE KEY-----
250
MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz
251
oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/
252
d8ufMCkjeXsQkKqFbAlQcnWMCRnOoPHS3I4vi6hmnDDeeYTSRvfLbW0fhwIBIwKB
253
gBIiOqZYaoqbeD9OS9z2K9KR2atlTxGxOJPXiP4ESqP3NVScWNwyZ3NXHpyrJLa0
254
EbVtzsQhLn6rF+TzXnOlcipFvjsem3iYzCpuChfGQ6SovTcOjHV9z+hnpXvQ/fon
255
soVRZY65wKnF7IAoUwTmJS9opqgrN6kRgCd3DASAMd1bAkEA96SBVWFt/fJBNJ9H
256
tYnBKZGw0VeHOYmVYbvMSstssn8un+pQpUm9vlG/bp7Oxd/m+b9KWEh2xPfv6zqU
257
avNwHwJBANqzGZa/EpzF4J8pGti7oIAPUIDGMtfIcmqNXVMckrmzQ2vTfqtkEZsA
258
4rE1IERRyiJQx6EJsz21wJmGV9WJQ5kCQQDwkS0uXqVdFzgHO6S++tjmjYcxwr3g
259
H0CoFYSgbddOT6miqRskOQF3DZVkJT3kyuBgU2zKygz52ukQZMqxCb1fAkASvuTv
260
qfpH87Qq5kQhNKdbbwbmd2NxlNabazPijWuphGTdW0VfJdWfklyS2Kr+iqrs/5wV
261
HhathJt636Eg7oIjAkA8ht3MQ+XSl9yIJIS8gVpbPxSw5OMfw0PjVE7tBdQruiSc
262
nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7
263
-----END RSA PRIVATE KEY-----
264
"""
265
266
267
class SocketDelay(object):
268
    """A socket decorator to make TCP appear slower.
269
270
    This changes recv, send, and sendall to add a fixed latency to each python
271
    call if a new roundtrip is detected. That is, when a recv is called and the
272
    flag new_roundtrip is set, latency is charged. Every send and send_all
273
    sets this flag.
274
275
    In addition every send, sendall and recv sleeps a bit per character send to
276
    simulate bandwidth.
277
278
    Not all methods are implemented, this is deliberate as this class is not a
279
    replacement for the builtin sockets layer. fileno is not implemented to
280
    prevent the proxy being bypassed.
281
    """
282
283
    simulated_time = 0
284
    _proxied_arguments = dict.fromkeys([
285
        "close", "getpeername", "getsockname", "getsockopt", "gettimeout",
286
        "setblocking", "setsockopt", "settimeout", "shutdown"])
287
288
    def __init__(self, sock, latency, bandwidth=1.0,
289
                 really_sleep=True):
290
        """
291
        :param bandwith: simulated bandwith (MegaBit)
292
        :param really_sleep: If set to false, the SocketDelay will just
293
        increase a counter, instead of calling time.sleep. This is useful for
294
        unittesting the SocketDelay.
295
        """
296
        self.sock = sock
297
        self.latency = latency
298
        self.really_sleep = really_sleep
299
        self.time_per_byte = 1 / (bandwidth / 8.0 * 1024 * 1024)
300
        self.new_roundtrip = False
301
302
    def sleep(self, s):
303
        if self.really_sleep:
304
            time.sleep(s)
305
        else:
306
            SocketDelay.simulated_time += s
307
308
    def __getattr__(self, attr):
309
        if attr in SocketDelay._proxied_arguments:
310
            return getattr(self.sock, attr)
311
        raise AttributeError("'SocketDelay' object has no attribute %r" %
312
                             attr)
313
314
    def dup(self):
315
        return SocketDelay(self.sock.dup(), self.latency, self.time_per_byte,
316
                           self._sleep)
317
318
    def recv(self, *args):
319
        data = self.sock.recv(*args)
320
        if data and self.new_roundtrip:
321
            self.new_roundtrip = False
322
            self.sleep(self.latency)
323
        self.sleep(len(data) * self.time_per_byte)
324
        return data
325
326
    def sendall(self, data, flags=0):
327
        if not self.new_roundtrip:
328
            self.new_roundtrip = True
329
            self.sleep(self.latency)
330
        self.sleep(len(data) * self.time_per_byte)
331
        return self.sock.sendall(data, flags)
332
333
    def send(self, data, flags=0):
334
        if not self.new_roundtrip:
335
            self.new_roundtrip = True
336
            self.sleep(self.latency)
337
        bytes_sent = self.sock.send(data, flags)
338
        self.sleep(bytes_sent * self.time_per_byte)
339
        return bytes_sent
340
341
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
342
class TestingSFTPConnectionHandler(SocketServer.BaseRequestHandler):
343
344
    def setup(self):
345
        self.wrap_for_latency()
346
        tcs = self.server.test_case_server
5397.2.10 by John Arbash Meinel
refactor a little bit, so it is clearer what is going on.
347
        ptrans = paramiko.Transport(self.request)
348
        self.paramiko_transport = ptrans
5397.2.3 by John Arbash Meinel
Do it a different way by overriding the logging chosen
349
        # Set it to a channel under 'bzr' so that we get debug info
5397.2.10 by John Arbash Meinel
refactor a little bit, so it is clearer what is going on.
350
        ptrans.set_log_channel('bzr.paramiko.transport')
351
        ptrans.add_server_key(tcs.get_host_key())
352
        ptrans.set_subsystem_handler('sftp', paramiko.SFTPServer,
353
                                     StubSFTPServer, root=tcs._root,
354
                                     home=tcs._server_homedir)
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
355
        server = tcs._server_interface(tcs)
5397.2.1 by John Arbash Meinel
Instead of time.sleep() wait for paramiko to actually finish.
356
        # This blocks until the key exchange has been done
5397.2.10 by John Arbash Meinel
refactor a little bit, so it is clearer what is going on.
357
        ptrans.start_server(None, server)
358
359
    def finish(self):
360
        # Wait for the conversation to finish, when the paramiko.Transport
361
        # thread finishes
362
        # TODO: Consider timing out after XX seconds rather than hanging.
363
        #       Also we could check paramiko_transport.active and possibly
364
        #       paramiko_transport.getException().
365
        self.paramiko_transport.join()
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
366
367
    def wrap_for_latency(self):
368
        tcs = self.server.test_case_server
369
        if tcs.add_latency:
370
            # Give the socket (which the request really is) a latency adding
371
            # decorator.
372
            self.request = SocketDelay(self.request, tcs.add_latency)
373
374
375
class TestingSFTPWithoutSSHConnectionHandler(TestingSFTPConnectionHandler):
376
377
    def setup(self):
378
        self.wrap_for_latency()
379
        # Re-import these as locals, so that they're still accessible during
380
        # interpreter shutdown (when all module globals get set to None, leading
381
        # to confusing errors like "'NoneType' object has no attribute 'error'".
382
        class FakeChannel(object):
383
            def get_transport(self):
384
                return self
385
            def get_log_channel(self):
5397.2.11 by John Arbash Meinel
Add a .finish method to the sftp version as well.
386
                return 'bzr.paramiko'
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
387
            def get_name(self):
388
                return '1'
389
            def get_hexdump(self):
390
                return False
391
            def close(self):
392
                pass
393
394
        tcs = self.server.test_case_server
5397.2.11 by John Arbash Meinel
Add a .finish method to the sftp version as well.
395
        sftp_server = paramiko.SFTPServer(
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
396
            FakeChannel(), 'sftp', StubServer(tcs), StubSFTPServer,
397
            root=tcs._root, home=tcs._server_homedir)
5397.2.11 by John Arbash Meinel
Add a .finish method to the sftp version as well.
398
        self.sftp_server = sftp_server
399
        sys_stderr = sys.stderr # Used in error reporting during shutdown
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
400
        try:
5397.2.11 by John Arbash Meinel
Add a .finish method to the sftp version as well.
401
            sftp_server.start_subsystem(
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
402
                'sftp', None, ssh.SocketAsChannelAdapter(self.request))
403
        except socket.error, e:
404
            if (len(e.args) > 0) and (e.args[0] == errno.EPIPE):
405
                # it's okay for the client to disconnect abruptly
406
                # (bug in paramiko 1.6: it should absorb this exception)
407
                pass
408
            else:
409
                raise
410
        except Exception, e:
411
            # This typically seems to happen during interpreter shutdown, so
412
            # most of the useful ways to report this error won't work.
413
            # Writing the exception type, and then the text of the exception,
414
            # seems to be the best we can do.
415
            # FIXME: All interpreter shutdown errors should have been related
416
            # to daemon threads, cleanup needed -- vila 20100623
5397.2.11 by John Arbash Meinel
Add a .finish method to the sftp version as well.
417
            sys_stderr.write('\nEXCEPTION %r: ' % (e.__class__,))
418
            sys_stderr.write('%s\n\n' % (e,))
419
420
    def finish(self):
421
        self.sftp_server.finish_subsystem()
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
422
423
424
class TestingSFTPServer(test_server.TestingThreadingTCPServer):
425
426
    def __init__(self, server_address, request_handler_class, test_case_server):
427
        test_server.TestingThreadingTCPServer.__init__(
428
            self, server_address, request_handler_class)
429
        self.test_case_server = test_case_server
430
431
432
class SFTPServer(test_server.TestingTCPServerInAThread):
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
433
    """Common code for SFTP server facilities."""
434
435
    def __init__(self, server_interface=StubServer):
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
436
        self.host = '127.0.0.1'
437
        self.port = 0
438
        super(SFTPServer, self).__init__((self.host, self.port),
439
                                         TestingSFTPServer,
440
                                         TestingSFTPConnectionHandler)
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
441
        self._original_vendor = None
442
        self._vendor = ssh.ParamikoVendor()
443
        self._server_interface = server_interface
5247.4.24 by Vincent Ladeuil
Create the ssh host key only once for a given sftp test server.
444
        self._host_key = None
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
445
        self.logs = []
446
        self.add_latency = 0
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
447
        self._homedir = None
448
        self._server_homedir = None
449
        self._root = None
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
450
451
    def _get_sftp_url(self, path):
452
        """Calculate an sftp url to this server for path."""
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
453
        return "sftp://foo:bar@%s:%s/%s" % (self.host, self.port, path)
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
454
455
    def log(self, message):
456
        """StubServer uses this to log when a new server is created."""
457
        self.logs.append(message)
458
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
459
    def create_server(self):
460
        server = self.server_class((self.host, self.port),
461
                                   self.request_handler_class,
462
                                   self)
463
        return server
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
464
5247.4.24 by Vincent Ladeuil
Create the ssh host key only once for a given sftp test server.
465
    def get_host_key(self):
466
        if self._host_key is None:
467
            key_file = osutils.pathjoin(self._homedir, 'test_rsa.key')
468
            f = open(key_file, 'w')
469
            try:
470
                f.write(STUB_SERVER_KEY)
471
            finally:
472
                f.close()
473
            self._host_key = paramiko.RSAKey.from_private_key_file(key_file)
474
        return self._host_key
475
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
476
    def start_server(self, backing_server=None):
477
        # XXX: TODO: make sftpserver back onto backing_server rather than local
478
        # disk.
479
        if not (backing_server is None or
5017.3.34 by Vincent Ladeuil
-s bt.per_branch passing
480
                isinstance(backing_server, test_server.LocalURLServer)):
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
481
            raise AssertionError(
5055.1.2 by Vincent Ladeuil
Add a FIXME about using osutils.getcwd()
482
                'backing_server should not be %r, because this can only serve '
483
                'the local current working directory.' % (backing_server,))
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
484
        self._original_vendor = ssh._ssh_vendor_manager._cached_ssh_vendor
485
        ssh._ssh_vendor_manager._cached_ssh_vendor = self._vendor
486
        if sys.platform == 'win32':
487
            # Win32 needs to use the UNICODE api
5055.1.1 by Vincent Ladeuil
Fix bug #526221 and #526353.
488
            self._homedir = os.getcwdu()
5229.1.9 by Vincent Ladeuil
Fix sftp homedir path handling on windows.
489
            # Normalize the path or it will be wrongly escaped
5229.1.7 by Vincent Ladeuil
Fix sftp paths for windows.
490
            self._homedir = osutils.normpath(self._homedir)
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
491
        else:
5278.1.2 by Martin Pool
Don't say 'Linux' except when specifically talking about the kernel
492
            # But unix SFTP servers should just deal in bytestreams
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
493
            self._homedir = os.getcwd()
494
        if self._server_homedir is None:
495
            self._server_homedir = self._homedir
496
        self._root = '/'
497
        if sys.platform == 'win32':
498
            self._root = ''
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
499
        super(SFTPServer, self).start_server()
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
500
501
    def stop_server(self):
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
502
        try:
503
            super(SFTPServer, self).stop_server()
504
        finally:
505
            ssh._ssh_vendor_manager._cached_ssh_vendor = self._original_vendor
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
506
507
    def get_bogus_url(self):
508
        """See bzrlib.transport.Server.get_bogus_url."""
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
509
        # this is chosen to try to prevent trouble with proxies, weird dns, etc
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
510
        # we bind a random socket, so that we get a guaranteed unused port
511
        # we just never listen on that port
512
        s = socket.socket()
513
        s.bind(('localhost', 0))
514
        return 'sftp://%s:%s/' % s.getsockname()
515
516
517
class SFTPFullAbsoluteServer(SFTPServer):
518
    """A test server for sftp transports, using absolute urls and ssh."""
519
520
    def get_url(self):
521
        """See bzrlib.transport.Server.get_url."""
522
        homedir = self._homedir
523
        if sys.platform != 'win32':
524
            # Remove the initial '/' on all platforms but win32
525
            homedir = homedir[1:]
526
        return self._get_sftp_url(urlutils.escape(homedir))
527
528
529
class SFTPServerWithoutSSH(SFTPServer):
530
    """An SFTP server that uses a simple TCP socket pair rather than SSH."""
531
532
    def __init__(self):
533
        super(SFTPServerWithoutSSH, self).__init__()
534
        self._vendor = ssh.LoopbackVendor()
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
535
        self.request_handler_class = TestingSFTPWithoutSSHConnectionHandler
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
536
5247.4.24 by Vincent Ladeuil
Create the ssh host key only once for a given sftp test server.
537
    def get_host_key():
538
        return None
539
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
540
541
class SFTPAbsoluteServer(SFTPServerWithoutSSH):
542
    """A test server for sftp transports, using absolute urls."""
543
544
    def get_url(self):
545
        """See bzrlib.transport.Server.get_url."""
546
        homedir = self._homedir
547
        if sys.platform != 'win32':
548
            # Remove the initial '/' on all platforms but win32
549
            homedir = homedir[1:]
550
        return self._get_sftp_url(urlutils.escape(homedir))
551
552
553
class SFTPHomeDirServer(SFTPServerWithoutSSH):
554
    """A test server for sftp transports, using homedir relative urls."""
555
556
    def get_url(self):
557
        """See bzrlib.transport.Server.get_url."""
558
        return self._get_sftp_url("~/")
559
560
561
class SFTPSiblingAbsoluteServer(SFTPAbsoluteServer):
562
    """A test server for sftp transports where only absolute paths will work.
563
564
    It does this by serving from a deeply-nested directory that doesn't exist.
565
    """
566
5247.4.18 by Vincent Ladeuil
Replace SocketListener by TestingTCPServerInAThread and fallouts,
567
    def create_server(self):
568
        # FIXME: Can't we do that in a cleaner way ? -- vila 20100623
569
        server = super(SFTPSiblingAbsoluteServer, self).create_server()
570
        server._server_homedir = '/dev/noone/runs/tests/here'
571
        return server
4797.11.2 by Vincent Ladeuil
Stop requiring testtools for sftp use.
572