/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2009, 2010 Canonical Ltd
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
16
"""
17
FTP test server.
18
19
Based on pyftpdlib: http://code.google.com/p/pyftpdlib/
20
"""
21
22
import errno
6686.1.4 by Jelmer Vernooij
Fix logging, add release note entry.
23
import logging
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
24
import os
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
25
import pyftpdlib
6686.1.4 by Jelmer Vernooij
Fix logging, add release note entry.
26
import sys
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
27
from pyftpdlib.authorizers import (
28
    AuthorizerError,
29
    DummyAuthorizer,
30
    )
31
from pyftpdlib.filesystems import AbstractedFS
32
from pyftpdlib.handlers import (
33
    FTPHandler,
34
    proto_cmds,
35
    )
36
from pyftpdlib.servers import FTPServer
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
37
import select
38
import threading
39
40
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
41
from breezy import (
3508.1.18 by Vincent Ladeuil
Final tweaks.
42
    osutils,
4731.2.9 by Vincent Ladeuil
Implement a new -Ethreads to better track the leaks.
43
    tests,
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
44
    trace,
45
    )
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
46
from breezy.tests import test_server
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
47
48
6686.1.4 by Jelmer Vernooij
Fix logging, add release note entry.
49
class NullHandler(logging.Handler):
50
51
    def emit(self, record):
52
        pass
53
54
# Shut up very verbose pyftpdlib
55
logging.getLogger('pyftpdlib').addHandler(NullHandler())
56
57
5947.1.1 by Vincent Ladeuil
Support pyftplib-0.6.0 as an ftp test server
58
# Convert the pyftplib string version into a tuple to avoid traps in string
59
# comparison.
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
60
pyftplib_version = tuple(map(int, pyftpdlib.__ver__.split('.')))
61
62
63
class AnonymousWithWriteAccessAuthorizer(DummyAuthorizer):
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
64
65
    def _check_permissions(self, username, perm):
66
        # Like base implementation but don't warn about write permissions
3508.1.18 by Vincent Ladeuil
Final tweaks.
67
        # assigned to anonymous, since that's exactly our purpose.
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
68
        for p in perm:
69
            if p not in self.read_perms + self.write_perms:
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
70
                raise AuthorizerError('No such permission "%s"' %p)
71
72
73
class BzrConformingFS(AbstractedFS):
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
74
3508.1.20 by Vincent Ladeuil
Test passing for python2.5 and 2.6.
75
    def chmod(self, path, mode):
76
        return os.chmod(path, mode)
77
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
78
    def listdir(self, path):
79
        """List the content of a directory."""
3508.1.18 by Vincent Ladeuil
Final tweaks.
80
        return [osutils.safe_utf8(s) for s in os.listdir(path)]
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
81
3508.1.11 by Vincent Ladeuil
Tests passing for python2.5 and python2.6 (and python2.4 :).
82
    def fs2ftp(self, fspath):
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
83
        p = AbstractedFS.fs2ftp(self, osutils.safe_unicode(fspath))
3508.1.18 by Vincent Ladeuil
Final tweaks.
84
        return osutils.safe_utf8(p)
85
4935.1.1 by Vincent Ladeuil
Support Unicode paths for ftp transport (encoded as utf8).
86
    def ftp2fs(self, ftppath):
87
        p = osutils.safe_unicode(ftppath)
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
88
        return AbstractedFS.ftp2fs(self, p)
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
89
6686.1.4 by Jelmer Vernooij
Fix logging, add release note entry.
90
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
91
class BzrConformingFTPHandler(FTPHandler):
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
92
93
    abstracted_fs = BzrConformingFS
94
6686.1.3 by Jelmer Vernooij
Fix ftp tests.
95
    def __init__(self, conn, server, ioloop=None):
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
96
        FTPHandler.__init__(self, conn, server)
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
97
        self.authorizer = server.authorizer
98
99
    def ftp_SIZE(self, path):
100
        # bzr is overly picky here, but we want to make the test suite pass
101
        # first. This may need to be revisited -- vila 20090226
102
        line = self.fs.fs2ftp(path)
103
        if self.fs.isdir(self.fs.realpath(path)):
104
            why = "%s is a directory" % line
105
            self.log('FAIL SIZE "%s". %s.' % (line, why))
106
            self.respond("550 %s."  %why)
107
        else:
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
108
            FTPHandler.ftp_SIZE(self, path)
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
109
110
    def ftp_NLST(self, path):
111
        # bzr is overly picky here, but we want to make the test suite pass
112
        # first. This may need to be revisited -- vila 20090226
113
        line = self.fs.fs2ftp(path)
114
        if self.fs.isfile(self.fs.realpath(path)):
115
            why = "Not a directory: %s" % line
4725.3.3 by Vincent Ladeuil
Fix test failure at the root without cleaning up ftp APPE.
116
            self.log('FAIL NLST "%s". %s.' % (line, why))
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
117
            self.respond("550 %s."  %why)
118
        else:
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
119
            FTPHandler.ftp_NLST(self, path)
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
120
6437.51.1 by Vincent Ladeuil
Support pyftpdlib >= 0.7.0
121
    def log_cmd(self, cmd, arg, respcode, respstr):
122
        # base class version choke on unicode, the alternative is to just
123
        # provide an empty implementation and relies on the client to do
124
        # the logging for debugging purposes. Not worth the trouble so far
125
        # -- vila 20110607
126
        if cmd in ("DELE", "RMD", "RNFR", "RNTO", "MKD"):
127
            line = '"%s" %s' % (' '.join([cmd, unicode(arg)]).strip(), respcode)
128
            self.log(line)
129
130
131
# An empty password is valid, hence the arg is neither mandatory nor forbidden
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
132
proto_cmds['PASS']['arg'] = None
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
133
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
134
class ftp_server(FTPServer):
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
135
136
    def __init__(self, address, handler, authorizer):
6686.1.2 by Jelmer Vernooij
Initial work to get pyftpdlib to work again.
137
        FTPServer.__init__(self, address, handler)
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
138
        self.authorizer = authorizer
3508.1.17 by Vincent Ladeuil
Allows empty passwords with pyftpdlib ftp test server.
139
        # Worth backporting upstream ?
3508.1.11 by Vincent Ladeuil
Tests passing for python2.5 and python2.6 (and python2.4 :).
140
        self.addr = self.socket.getsockname()
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
141
142
5017.3.16 by Vincent Ladeuil
Fix imports for ftp_server/pyftpdlib_based.py
143
class FTPTestServer(test_server.TestServer):
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
144
    """Common code for FTP server facilities."""
145
146
    def __init__(self):
147
        self._root = None
148
        self._ftp_server = None
149
        self._port = None
150
        self._async_thread = None
151
        # ftp server logs
152
        self.logs = []
3508.1.11 by Vincent Ladeuil
Tests passing for python2.5 and python2.6 (and python2.4 :).
153
        self._ftpd_running = False
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
154
155
    def get_url(self):
156
        """Calculate an ftp url to this server."""
3508.1.13 by Vincent Ladeuil
Fix last failing tests under python2.6.
157
        return 'ftp://anonymous@localhost:%d/' % (self._port)
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
158
159
    def get_bogus_url(self):
160
        """Return a URL which cannot be connected to."""
161
        return 'ftp://127.0.0.1:1/'
162
163
    def log(self, message):
3508.1.18 by Vincent Ladeuil
Final tweaks.
164
        """This is used by ftp_server to log connections, etc."""
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
165
        self.logs.append(message)
166
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
167
    def start_server(self, vfs_server=None):
5017.3.16 by Vincent Ladeuil
Fix imports for ftp_server/pyftpdlib_based.py
168
        if not (vfs_server is None or isinstance(vfs_server,
169
                                                 test_server.LocalURLServer)):
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
170
            raise AssertionError(
171
                "FTPServer currently assumes local transport, got %s"
172
                % vfs_server)
6619.3.26 by Martin
Fix fallout from 2to3 getcwdu transformation and other test uses
173
        self._root = osutils.getcwd()
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
174
175
        address = ('localhost', 0) # bind to a random port
176
        authorizer = AnonymousWithWriteAccessAuthorizer()
6437.51.1 by Vincent Ladeuil
Support pyftpdlib >= 0.7.0
177
        authorizer.add_anonymous(self._root, perm='elradfmwM')
3508.1.23 by Vincent Ladeuil
Fix as per Martin's review.
178
        self._ftp_server = ftp_server(address, BzrConformingFTPHandler,
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
179
                                      authorizer)
180
181
        self._port = self._ftp_server.socket.getsockname()[1]
3508.1.12 by Vincent Ladeuil
Don't require patched version for pyftpdlib.
182
        self._ftpd_starting = threading.Lock()
183
        self._ftpd_starting.acquire() # So it can be released by the server
4725.3.2 by Vincent Ladeuil
Cosmetic change.
184
        self._ftpd_thread = threading.Thread(target=self._run_server,)
3508.1.12 by Vincent Ladeuil
Don't require patched version for pyftpdlib.
185
        self._ftpd_thread.start()
4731.2.9 by Vincent Ladeuil
Implement a new -Ethreads to better track the leaks.
186
        if 'threads' in tests.selftest_debug_flags:
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
187
            sys.stderr.write('Thread started: %s\n'
188
                             % (self._ftpd_thread.ident,))
3508.1.12 by Vincent Ladeuil
Don't require patched version for pyftpdlib.
189
        # Wait for the server thread to start (i.e release the lock)
190
        self._ftpd_starting.acquire()
191
        self._ftpd_starting.release()
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
192
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
193
    def stop_server(self):
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
194
        """See breezy.transport.Server.stop_server."""
3508.1.12 by Vincent Ladeuil
Don't require patched version for pyftpdlib.
195
        # Tell the server to stop, but also close the server socket for tests
196
        # that start the server but never initiate a connection. Closing the
197
        # socket should be done first though, to avoid further connections.
3508.1.11 by Vincent Ladeuil
Tests passing for python2.5 and python2.6 (and python2.4 :).
198
        self._ftp_server.close()
3508.1.12 by Vincent Ladeuil
Don't require patched version for pyftpdlib.
199
        self._ftpd_running = False
200
        self._ftpd_thread.join()
4731.2.9 by Vincent Ladeuil
Implement a new -Ethreads to better track the leaks.
201
        if 'threads' in tests.selftest_debug_flags:
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
202
            sys.stderr.write('Thread  joined: %s\n'
203
                             % (self._ftpd_thread.ident,))
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
204
3508.1.11 by Vincent Ladeuil
Tests passing for python2.5 and python2.6 (and python2.4 :).
205
    def _run_server(self):
6437.51.1 by Vincent Ladeuil
Support pyftpdlib >= 0.7.0
206
        """Run the server until stop_server is called.
207
208
        Shut it down properly then.
3508.1.10 by Vincent Ladeuil
Start supporting pyftpdlib as an ftp test server.
209
        """
3508.1.11 by Vincent Ladeuil
Tests passing for python2.5 and python2.6 (and python2.4 :).
210
        self._ftpd_running = True
3508.1.12 by Vincent Ladeuil
Don't require patched version for pyftpdlib.
211
        self._ftpd_starting.release()
212
        while self._ftpd_running:
4725.3.1 by Vincent Ladeuil
Fix test failure and clean up ftp APPE.
213
            try:
6686.1.3 by Jelmer Vernooij
Fix ftp tests.
214
                self._ftp_server.serve_forever(timeout=0.1)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
215
            except select.error as e:
4725.3.1 by Vincent Ladeuil
Fix test failure and clean up ftp APPE.
216
                if e.args[0] != errno.EBADF:
217
                    raise
6686.1.3 by Jelmer Vernooij
Fix ftp tests.
218
        self._ftp_server.close_all()
3508.1.13 by Vincent Ladeuil
Fix last failing tests under python2.6.
219
220
    def add_user(self, user, password):
221
        """Add a user with write access."""
222
        self._ftp_server.authorizer.add_user(user, password, self._root,
6437.51.1 by Vincent Ladeuil
Support pyftpdlib >= 0.7.0
223
                                             perm='elradfmwM')