~bzr-pqm/bzr/bzr.dev

5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2010, 2011 Canonical Ltd
5017.3.1 by Vincent Ladeuil
Create a tests.test_server.TestServer class out of transport.Server (while retaining the later for some special non-tests usages).
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
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
17
import errno
5247.1.1 by Vincent Ladeuil
Merge previous attempt into current trunk
18
import socket
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
19
import SocketServer
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
20
import sys
21
import threading
5247.1.1 by Vincent Ladeuil
Merge previous attempt into current trunk
22
23
5017.3.1 by Vincent Ladeuil
Create a tests.test_server.TestServer class out of transport.Server (while retaining the later for some special non-tests usages).
24
from bzrlib import (
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
25
    osutils,
5017.3.1 by Vincent Ladeuil
Create a tests.test_server.TestServer class out of transport.Server (while retaining the later for some special non-tests usages).
26
    transport,
5017.3.15 by Vincent Ladeuil
Fix missing import.
27
    urlutils,
5017.3.1 by Vincent Ladeuil
Create a tests.test_server.TestServer class out of transport.Server (while retaining the later for some special non-tests usages).
28
    )
5017.3.19 by Vincent Ladeuil
Move TestingPathFilteringServer to bzrlib.tests.test_server
29
from bzrlib.transport import (
5017.3.20 by Vincent Ladeuil
Move TestingChrootServer to bzrlib.tests.test_server
30
    chroot,
5017.3.19 by Vincent Ladeuil
Move TestingPathFilteringServer to bzrlib.tests.test_server
31
    pathfilter,
32
    )
5247.3.36 by Vincent Ladeuil
Start refactoring the smart server to control which thread it runs in.
33
from bzrlib.smart import (
34
    medium,
35
    server,
36
    )
5017.3.1 by Vincent Ladeuil
Create a tests.test_server.TestServer class out of transport.Server (while retaining the later for some special non-tests usages).
37
38
5247.5.17 by Vincent Ladeuil
Add some basic debug tracing controlled by -Ethreads.
39
def debug_threads():
40
    # FIXME: There is a dependency loop between bzrlib.tests and
41
    # bzrlib.tests.test_server that needs to be fixed. In the mean time
42
    # defining this function is enough for our needs. -- vila 20100611
43
    from bzrlib import tests
44
    return 'threads' in tests.selftest_debug_flags
45
46
5017.3.1 by Vincent Ladeuil
Create a tests.test_server.TestServer class out of transport.Server (while retaining the later for some special non-tests usages).
47
class TestServer(transport.Server):
48
    """A Transport Server dedicated to tests.
49
50
    The TestServer interface provides a server for a given transport. We use
51
    these servers as loopback testing tools. For any given transport the
52
    Servers it provides must either allow writing, or serve the contents
53
    of os.getcwdu() at the time start_server is called.
54
55
    Note that these are real servers - they must implement all the things
56
    that we want bzr transports to take advantage of.
57
    """
58
59
    def get_url(self):
60
        """Return a url for this server.
61
62
        If the transport does not represent a disk directory (i.e. it is
63
        a database like svn, or a memory only transport, it should return
64
        a connection to a newly established resource for this Server.
65
        Otherwise it should return a url that will provide access to the path
66
        that was os.getcwdu() when start_server() was called.
67
68
        Subsequent calls will return the same resource.
69
        """
70
        raise NotImplementedError
71
72
    def get_bogus_url(self):
73
        """Return a url for this protocol, that will fail to connect.
74
75
        This may raise NotImplementedError to indicate that this server cannot
76
        provide bogus urls.
77
        """
78
        raise NotImplementedError
79
80
5017.3.6 by Vincent Ladeuil
Fix some fallouts of moving test servers around.
81
class LocalURLServer(TestServer):
5017.3.3 by Vincent Ladeuil
Move LocalURLServer to bzrlib.tests.test_server
82
    """A pretend server for local transports, using file:// urls.
83
84
    Of course no actual server is required to access the local filesystem, so
85
    this just exists to tell the test code how to get to it.
86
    """
87
88
    def start_server(self):
89
        pass
90
91
    def get_url(self):
92
        """See Transport.Server.get_url."""
93
        return urlutils.local_path_to_url('')
94
95
5017.3.6 by Vincent Ladeuil
Fix some fallouts of moving test servers around.
96
class DecoratorServer(TestServer):
5017.3.2 by Vincent Ladeuil
Move DecoratorServer to test_server.py
97
    """Server for the TransportDecorator for testing with.
98
99
    To use this when subclassing TransportDecorator, override override the
100
    get_decorator_class method.
101
    """
102
103
    def start_server(self, server=None):
104
        """See bzrlib.transport.Server.start_server.
105
106
        :server: decorate the urls given by server. If not provided a
107
        LocalServer is created.
108
        """
109
        if server is not None:
110
            self._made_server = False
111
            self._server = server
112
        else:
113
            self._made_server = True
114
            self._server = LocalURLServer()
115
            self._server.start_server()
116
117
    def stop_server(self):
118
        if self._made_server:
119
            self._server.stop_server()
120
121
    def get_decorator_class(self):
122
        """Return the class of the decorators we should be constructing."""
123
        raise NotImplementedError(self.get_decorator_class)
124
125
    def get_url_prefix(self):
126
        """What URL prefix does this decorator produce?"""
127
        return self.get_decorator_class()._get_url_prefix()
128
129
    def get_bogus_url(self):
130
        """See bzrlib.transport.Server.get_bogus_url."""
131
        return self.get_url_prefix() + self._server.get_bogus_url()
132
133
    def get_url(self):
134
        """See bzrlib.transport.Server.get_url."""
135
        return self.get_url_prefix() + self._server.get_url()
136
137
5017.3.8 by Vincent Ladeuil
Move BrokenRenameServer to bzrlib.tests.test_server
138
class BrokenRenameServer(DecoratorServer):
139
    """Server for the BrokenRenameTransportDecorator for testing with."""
140
141
    def get_decorator_class(self):
142
        from bzrlib.transport import brokenrename
143
        return brokenrename.BrokenRenameTransportDecorator
144
145
5017.3.7 by Vincent Ladeuil
Move FakeNFSServer to bzrlib.tests.test_server
146
class FakeNFSServer(DecoratorServer):
147
    """Server for the FakeNFSTransportDecorator for testing with."""
148
149
    def get_decorator_class(self):
150
        from bzrlib.transport import fakenfs
151
        return fakenfs.FakeNFSTransportDecorator
152
153
5017.3.9 by Vincent Ladeuil
Move FakeVFATServer to bzrlib.tests.test_server
154
class FakeVFATServer(DecoratorServer):
155
    """A server that suggests connections through FakeVFATTransportDecorator
156
157
    For use in testing.
158
    """
159
160
    def get_decorator_class(self):
161
        from bzrlib.transport import fakevfat
5017.3.14 by Vincent Ladeuil
Fix some missing prefixes.
162
        return fakevfat.FakeVFATTransportDecorator
5017.3.9 by Vincent Ladeuil
Move FakeVFATServer to bzrlib.tests.test_server
163
164
5017.3.11 by Vincent Ladeuil
Move LogDecoratorServer to bzrlib.tests.test_server
165
class LogDecoratorServer(DecoratorServer):
166
    """Server for testing."""
167
168
    def get_decorator_class(self):
169
        from bzrlib.transport import log
170
        return log.TransportLogDecorator
171
172
5017.3.12 by Vincent Ladeuil
Move NoSmartTransportServer to bzrlib.tests.test_server
173
class NoSmartTransportServer(DecoratorServer):
174
    """Server for the NoSmartTransportDecorator for testing with."""
175
176
    def get_decorator_class(self):
177
        from bzrlib.transport import nosmart
5017.3.14 by Vincent Ladeuil
Fix some missing prefixes.
178
        return nosmart.NoSmartTransportDecorator
5017.3.12 by Vincent Ladeuil
Move NoSmartTransportServer to bzrlib.tests.test_server
179
180
5017.3.5 by Vincent Ladeuil
Move ReadonlyServer to bzrlib.tests.readonly
181
class ReadonlyServer(DecoratorServer):
182
    """Server for the ReadonlyTransportDecorator for testing with."""
183
184
    def get_decorator_class(self):
185
        from bzrlib.transport import readonly
186
        return readonly.ReadonlyTransportDecorator
187
188
5017.3.10 by Vincent Ladeuil
Move TraceServer to bzrlib.tests.test_server
189
class TraceServer(DecoratorServer):
190
    """Server for the TransportTraceDecorator for testing with."""
191
192
    def get_decorator_class(self):
193
        from bzrlib.transport import trace
5017.3.14 by Vincent Ladeuil
Fix some missing prefixes.
194
        return trace.TransportTraceDecorator
5017.3.10 by Vincent Ladeuil
Move TraceServer to bzrlib.tests.test_server
195
196
5017.3.13 by Vincent Ladeuil
Move UnlistableServer to bzrlib.tests.test_server
197
class UnlistableServer(DecoratorServer):
198
    """Server for the UnlistableTransportDecorator for testing with."""
199
200
    def get_decorator_class(self):
201
        from bzrlib.transport import unlistable
202
        return unlistable.UnlistableTransportDecorator
203
204
5017.3.19 by Vincent Ladeuil
Move TestingPathFilteringServer to bzrlib.tests.test_server
205
class TestingPathFilteringServer(pathfilter.PathFilteringServer):
206
207
    def __init__(self):
5017.3.20 by Vincent Ladeuil
Move TestingChrootServer to bzrlib.tests.test_server
208
        """TestingPathFilteringServer is not usable until start_server
209
        is called."""
5017.3.19 by Vincent Ladeuil
Move TestingPathFilteringServer to bzrlib.tests.test_server
210
211
    def start_server(self, backing_server=None):
212
        """Setup the Chroot on backing_server."""
213
        if backing_server is not None:
214
            self.backing_transport = transport.get_transport(
215
                backing_server.get_url())
216
        else:
217
            self.backing_transport = transport.get_transport('.')
218
        self.backing_transport.clone('added-by-filter').ensure_base()
219
        self.filter_func = lambda x: 'added-by-filter/' + x
220
        super(TestingPathFilteringServer, self).start_server()
221
5017.3.20 by Vincent Ladeuil
Move TestingChrootServer to bzrlib.tests.test_server
222
    def get_bogus_url(self):
223
        raise NotImplementedError
224
225
226
class TestingChrootServer(chroot.ChrootServer):
227
228
    def __init__(self):
229
        """TestingChrootServer is not usable until start_server is called."""
230
        super(TestingChrootServer, self).__init__(None)
231
232
    def start_server(self, backing_server=None):
233
        """Setup the Chroot on backing_server."""
234
        if backing_server is not None:
235
            self.backing_transport = transport.get_transport(
236
                backing_server.get_url())
237
        else:
238
            self.backing_transport = transport.get_transport('.')
239
        super(TestingChrootServer, self).start_server()
240
241
    def get_bogus_url(self):
242
        raise NotImplementedError
243
5017.3.19 by Vincent Ladeuil
Move TestingPathFilteringServer to bzrlib.tests.test_server
244
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
245
class ThreadWithException(threading.Thread):
246
    """A catching exception thread.
247
248
    If an exception occurs during the thread execution, it's caught and
249
    re-raised when the thread is joined().
250
    """
251
252
    def __init__(self, *args, **kwargs):
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
253
        # There are cases where the calling thread must wait, yet, if an
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
254
        # exception occurs, the event should be set so the caller is not
5247.2.5 by Vincent Ladeuil
Some cleanups.
255
        # blocked. The main example is a calling thread that want to wait for
256
        # the called thread to be in a given state before continuing.
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
257
        try:
258
            event = kwargs.pop('event')
259
        except KeyError:
260
            # If the caller didn't pass a specific event, create our own
261
            event = threading.Event()
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
262
        super(ThreadWithException, self).__init__(*args, **kwargs)
5247.5.30 by Vincent Ladeuil
Better explain ThreadWithException.set_ready_event and why it's needed.
263
        self.set_ready_event(event)
5247.3.10 by Vincent Ladeuil
Test errors during server life.
264
        self.exception = None
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
265
        self.ignored_exceptions = None # see set_ignored_exceptions
5247.3.10 by Vincent Ladeuil
Test errors during server life.
266
5247.5.18 by Vincent Ladeuil
Compatibility with python 2.5 and 2.4 for ThreadWithException.name.
267
    # compatibility thunk for python-2.4 and python-2.5...
5247.5.19 by Vincent Ladeuil
Cough, the compatibility thunk should not be installed for 2.6.
268
    if sys.version_info < (2, 6):
269
        name = property(threading.Thread.getName, threading.Thread.setName)
5247.5.18 by Vincent Ladeuil
Compatibility with python 2.5 and 2.4 for ThreadWithException.name.
270
5247.5.30 by Vincent Ladeuil
Better explain ThreadWithException.set_ready_event and why it's needed.
271
    def set_ready_event(self, event):
272
        """Set the ``ready`` event used to synchronize exception catching.
273
274
        When the thread uses an event to synchronize itself with another thread
275
        (setting it when the other thread can wake up from a ``wait`` call),
276
        the event must be set after catching an exception or the other thread
277
        will hang.
278
279
        Some threads require multiple events and should set the relevant one
280
        when appropriate.
281
        """
5247.2.5 by Vincent Ladeuil
Some cleanups.
282
        self.ready = event
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
283
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
284
    def set_ignored_exceptions(self, ignored):
285
        """Declare which exceptions will be ignored.
286
287
        :param ignored: Can be either:
288
           - None: all exceptions will be raised,
289
           - an exception class: the instances of this class will be ignored,
290
           - a tuple of exception classes: the instances of any class of the
291
             list will be ignored,
5247.5.6 by Vincent Ladeuil
Just pass the exception object to simplify.
292
           - a callable: that will be passed the exception object
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
293
             and should return True if the exception should be ignored
294
        """
295
        if ignored is None:
296
            self.ignored_exceptions = None
5247.5.6 by Vincent Ladeuil
Just pass the exception object to simplify.
297
        elif isinstance(ignored, (Exception, tuple)):
298
            self.ignored_exceptions = lambda e: isinstance(e, ignored)
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
299
        else:
300
            self.ignored_exceptions = ignored
301
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
302
    def run(self):
303
        """Overrides Thread.run to capture any exception."""
5247.2.5 by Vincent Ladeuil
Some cleanups.
304
        self.ready.clear()
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
305
        try:
5247.3.19 by Vincent Ladeuil
Fix python-2.4 incompatibility.
306
            try:
307
                super(ThreadWithException, self).run()
308
            except:
309
                self.exception = sys.exc_info()
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
310
        finally:
311
            # Make sure the calling thread is released
5247.2.5 by Vincent Ladeuil
Some cleanups.
312
            self.ready.set()
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
313
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
314
5560.1.2 by Vincent Ladeuil
Oops, remove debug value.
315
    def join(self, timeout=5):
5247.2.3 by Vincent Ladeuil
join(timeout=0) is useful to check for an exception without stopping the thread.
316
        """Overrides Thread.join to raise any exception caught.
317
318
319
        Calling join(timeout=0) will raise the caught exception or return None
5247.3.10 by Vincent Ladeuil
Test errors during server life.
320
        if the thread is still alive.
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
321
322
        The default timeout is set to 5 and should expire only when a thread
323
        serving a client connection is hung.
5247.2.3 by Vincent Ladeuil
join(timeout=0) is useful to check for an exception without stopping the thread.
324
        """
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
325
        super(ThreadWithException, self).join(timeout)
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
326
        if self.exception is not None:
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
327
            exc_class, exc_value, exc_tb = self.exception
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
328
            self.exception = None # The exception should be raised only once
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
329
            if (self.ignored_exceptions is None
5247.5.6 by Vincent Ladeuil
Just pass the exception object to simplify.
330
                or not self.ignored_exceptions(exc_value)):
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
331
                # Raise non ignored exceptions
332
                raise exc_class, exc_value, exc_tb
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
333
        if timeout and self.isAlive():
334
            # The timeout expired without joining the thread, the thread is
335
            # therefore stucked and that's a failure as far as the test is
336
            # concerned. We used to hang here.
5247.2.37 by Vincent Ladeuil
Don't make leaking tests fail on hung threads, there are only a few left.
337
338
            # FIXME: we need to kill the thread, but as far as the test is
339
            # concerned, raising an assertion is too strong. On most of the
340
            # platforms, this doesn't occur, so just mentioning the problem is
341
            # enough for now -- vila 2010824
342
            sys.stderr.write('thread %s hung\n' % (self.name,))
343
            #raise AssertionError('thread %s hung' % (self.name,))
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
344
345
    def pending_exception(self):
346
        """Raise the caught exception.
347
348
        This does nothing if no exception occurred.
349
        """
350
        self.join(timeout=0)
5247.2.2 by Vincent Ladeuil
Implement a thread that can re-raise exceptions.
351
352
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
353
class TestingTCPServerMixin:
354
    """Mixin to support running SocketServer.TCPServer in a thread.
355
356
    Tests are connecting from the main thread, the server has to be run in a
357
    separate thread.
358
    """
359
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
360
    def __init__(self):
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
361
        self.started = threading.Event()
5247.5.31 by Vincent Ladeuil
Use a boolean for server.serving, a threading.Event() is not needed here.
362
        self.serving = None
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
363
        self.stopped = threading.Event()
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
364
        # We collect the resources used by the clients so we can release them
365
        # when shutting down
366
        self.clients = []
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
367
        self.ignored_exceptions = None
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
368
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
369
    def server_bind(self):
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
370
        self.socket.bind(self.server_address)
371
        self.server_address = self.socket.getsockname()
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
372
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
373
    def serve(self):
5247.5.31 by Vincent Ladeuil
Use a boolean for server.serving, a threading.Event() is not needed here.
374
        self.serving = True
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
375
        self.stopped.clear()
376
        # We are listening and ready to accept connections
377
        self.started.set()
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
378
        try:
5247.5.31 by Vincent Ladeuil
Use a boolean for server.serving, a threading.Event() is not needed here.
379
            while self.serving:
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
380
                # Really a connection but the python framework is generic and
381
                # call them requests
382
                self.handle_request()
383
            # Let's close the listening socket
384
            self.server_close()
385
        finally:
386
            self.stopped.set()
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
387
5247.5.10 by Vincent Ladeuil
Fix broken test.
388
    def handle_request(self):
389
        """Handle one request.
390
391
        The python version swallows some socket exceptions and we don't use
392
        timeout, so we override it to better control the server behavior.
393
        """
394
        request, client_address = self.get_request()
395
        if self.verify_request(request, client_address):
396
            try:
397
                self.process_request(request, client_address)
398
            except:
399
                self.handle_error(request, client_address)
400
                self.close_request(request)
401
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
402
    def get_request(self):
403
        return self.socket.accept()
404
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
405
    def verify_request(self, request, client_address):
406
        """Verify the request.
407
408
        Return True if we should proceed with this request, False if we should
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
409
        not even touch a single byte in the socket ! This is useful when we
410
        stop the server with a dummy last connection.
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
411
        """
5247.5.31 by Vincent Ladeuil
Use a boolean for server.serving, a threading.Event() is not needed here.
412
        return self.serving
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
413
5247.3.10 by Vincent Ladeuil
Test errors during server life.
414
    def handle_error(self, request, client_address):
415
        # Stop serving and re-raise the last exception seen
5247.5.31 by Vincent Ladeuil
Use a boolean for server.serving, a threading.Event() is not needed here.
416
        self.serving = False
5247.6.8 by Vincent Ladeuil
Explain why we left some code commented: useful in rare debug cases.
417
        # The following can be used for debugging purposes, it will display the
418
        # exception and the traceback just when it occurs instead of waiting
419
        # for the thread to be joined.
420
421
        # SocketServer.BaseServer.handle_error(self, request, client_address)
5247.3.10 by Vincent Ladeuil
Test errors during server life.
422
        raise
423
5247.5.7 by Vincent Ladeuil
Factor out socket exception handling during server shutdown.
424
    def ignored_exceptions_during_shutdown(self, e):
425
        if sys.platform == 'win32':
5247.2.40 by Vincent Ladeuil
Catch EPIPE during test server shutdown.
426
            accepted_errnos = [errno.EBADF,
427
                               errno.EPIPE,
428
                               errno.WSAEBADF,
429
                               errno.WSAECONNRESET,
430
                               errno.WSAENOTCONN,
431
                               errno.WSAESHUTDOWN,
432
                               ]
5247.5.7 by Vincent Ladeuil
Factor out socket exception handling during server shutdown.
433
        else:
5247.2.40 by Vincent Ladeuil
Catch EPIPE during test server shutdown.
434
            accepted_errnos = [errno.EBADF,
435
                               errno.ECONNRESET,
436
                               errno.ENOTCONN,
437
                               errno.EPIPE,
438
                               ]
5247.5.7 by Vincent Ladeuil
Factor out socket exception handling during server shutdown.
439
        if isinstance(e, socket.error) and e[0] in accepted_errnos:
440
            return True
441
        return False
442
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
443
    # The following methods are called by the main thread
444
445
    def stop_client_connections(self):
446
        while self.clients:
447
            c = self.clients.pop()
448
            self.shutdown_client(c)
449
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
450
    def shutdown_socket(self, sock):
451
        """Properly shutdown a socket.
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
452
453
        This should be called only when no other thread is trying to use the
454
        socket.
455
        """
456
        try:
457
            sock.shutdown(socket.SHUT_RDWR)
458
            sock.close()
5247.5.7 by Vincent Ladeuil
Factor out socket exception handling during server shutdown.
459
        except Exception, e:
460
            if self.ignored_exceptions(e):
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
461
                pass
462
            else:
463
                raise
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
464
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
465
    # The following methods are called by the main thread
466
467
    def set_ignored_exceptions(self, thread, ignored_exceptions):
468
        self.ignored_exceptions = ignored_exceptions
469
        thread.set_ignored_exceptions(self.ignored_exceptions)
470
471
    def _pending_exception(self, thread):
472
        """Raise server uncaught exception.
473
474
        Daughter classes can override this if they use daughter threads.
475
        """
476
        thread.pending_exception()
477
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
478
479
class TestingTCPServer(TestingTCPServerMixin, SocketServer.TCPServer):
480
481
    def __init__(self, server_address, request_handler_class):
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
482
        TestingTCPServerMixin.__init__(self)
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
483
        SocketServer.TCPServer.__init__(self, server_address,
484
                                        request_handler_class)
485
486
    def get_request(self):
487
        """Get the request and client address from the socket."""
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
488
        sock, addr = TestingTCPServerMixin.get_request(self)
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
489
        self.clients.append((sock, addr))
490
        return sock, addr
491
492
    # The following methods are called by the main thread
493
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
494
    def shutdown_client(self, client):
495
        sock, addr = client
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
496
        self.shutdown_socket(sock)
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
497
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
498
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
499
class TestingThreadingTCPServer(TestingTCPServerMixin,
500
                                SocketServer.ThreadingTCPServer):
501
502
    def __init__(self, server_address, request_handler_class):
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
503
        TestingTCPServerMixin.__init__(self)
504
        SocketServer.ThreadingTCPServer.__init__(self, server_address,
505
                                                 request_handler_class)
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
506
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
507
    def get_request (self):
508
        """Get the request and client address from the socket."""
5247.5.32 by Vincent Ladeuil
Fix the sibling_class hack, we now know that we need only two methods
509
        sock, addr = TestingTCPServerMixin.get_request(self)
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
510
        # The thread is not create yet, it will be updated in process_request
511
        self.clients.append((sock, addr, None))
512
        return sock, addr
513
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
514
    def process_request_thread(self, started, stopped, request, client_address):
515
        started.set()
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
516
        SocketServer.ThreadingTCPServer.process_request_thread(
517
            self, request, client_address)
518
        self.close_request(request)
519
        stopped.set()
520
521
    def process_request(self, request, client_address):
522
        """Start a new thread to process the request."""
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
523
        started = threading.Event()
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
524
        stopped = threading.Event()
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
525
        t = ThreadWithException(
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
526
            event=stopped,
5247.5.17 by Vincent Ladeuil
Add some basic debug tracing controlled by -Ethreads.
527
            name='%s -> %s' % (client_address, self.server_address),
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
528
            target = self.process_request_thread,
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
529
            args = (started, stopped, request, client_address))
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
530
        # Update the client description
531
        self.clients.pop()
532
        self.clients.append((request, client_address, t))
5560.1.5 by Vincent Ladeuil
Fix spelling mistake.
533
        # Propagate the exception handler since we must use the same one as
5560.1.1 by Vincent Ladeuil
Catch the bogus ssl exception for closed sockets.
534
        # TestingTCPServer for connections running in their own threads.
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
535
        t.set_ignored_exceptions(self.ignored_exceptions)
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
536
        t.start()
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
537
        started.wait()
5247.5.17 by Vincent Ladeuil
Add some basic debug tracing controlled by -Ethreads.
538
        if debug_threads():
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
539
            sys.stderr.write('Client thread %s started\n' % (t.name,))
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
540
        # If an exception occured during the thread start, it will get raised.
541
        t.pending_exception()
542
543
    # The following methods are called by the main thread
544
545
    def shutdown_client(self, client):
5247.5.2 by Vincent Ladeuil
Cosmetic change.
546
        sock, addr, connection_thread = client
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
547
        self.shutdown_socket(sock)
5247.5.2 by Vincent Ladeuil
Cosmetic change.
548
        if connection_thread is not None:
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
549
            # The thread has been created only if the request is processed but
550
            # after the connection is inited. This could happen during server
551
            # shutdown. If an exception occurred in the thread it will be
552
            # re-raised
5247.5.17 by Vincent Ladeuil
Add some basic debug tracing controlled by -Ethreads.
553
            if debug_threads():
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
554
                sys.stderr.write('Client thread %s will be joined\n'
555
                                 % (connection_thread.name,))
5247.5.2 by Vincent Ladeuil
Cosmetic change.
556
            connection_thread.join()
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
557
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
558
    def set_ignored_exceptions(self, thread, ignored_exceptions):
559
        TestingTCPServerMixin.set_ignored_exceptions(self, thread,
560
                                                     ignored_exceptions)
561
        for sock, addr, connection_thread in self.clients:
562
            if connection_thread is not None:
563
                connection_thread.set_ignored_exceptions(
564
                    self.ignored_exceptions)
565
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
566
    def _pending_exception(self, thread):
567
        for sock, addr, connection_thread in self.clients:
568
            if connection_thread is not None:
569
                connection_thread.pending_exception()
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
570
        TestingTCPServerMixin._pending_exception(self, thread)
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
571
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
572
5247.3.14 by Vincent Ladeuil
Use a proper load_tests.
573
class TestingTCPServerInAThread(transport.Server):
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
574
    """A server in a thread that re-raise thread exceptions."""
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
575
576
    def __init__(self, server_address, server_class, request_handler_class):
577
        self.server_class = server_class
578
        self.request_handler_class = request_handler_class
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
579
        self.host, self.port = server_address
5247.3.10 by Vincent Ladeuil
Test errors during server life.
580
        self.server = None
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
581
        self._server_thread = None
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
582
5247.3.14 by Vincent Ladeuil
Use a proper load_tests.
583
    def __repr__(self):
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
584
        return "%s(%s:%s)" % (self.__class__.__name__, self.host, self.port)
5247.3.14 by Vincent Ladeuil
Use a proper load_tests.
585
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
586
    def create_server(self):
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
587
        return self.server_class((self.host, self.port),
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
588
                                 self.request_handler_class)
589
590
    def start_server(self):
591
        self.server = self.create_server()
592
        self._server_thread = ThreadWithException(
5247.5.17 by Vincent Ladeuil
Add some basic debug tracing controlled by -Ethreads.
593
            event=self.server.started,
594
            target=self.run_server)
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
595
        self._server_thread.start()
596
        # Wait for the server thread to start (i.e release the lock)
597
        self.server.started.wait()
598
        # Get the real address, especially the port
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
599
        self.host, self.port = self.server.server_address
5247.5.18 by Vincent Ladeuil
Compatibility with python 2.5 and 2.4 for ThreadWithException.name.
600
        self._server_thread.name = self.server.server_address
601
        if debug_threads():
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
602
            sys.stderr.write('Server thread %s started\n'
603
                             % (self._server_thread.name,))
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
604
        # If an exception occured during the server start, it will get raised,
605
        # otherwise, the server is blocked on its accept() call.
606
        self._server_thread.pending_exception()
5247.3.10 by Vincent Ladeuil
Test errors during server life.
607
        # From now on, we'll use a different event to ensure the server can set
608
        # its exception
5247.5.30 by Vincent Ladeuil
Better explain ThreadWithException.set_ready_event and why it's needed.
609
        self._server_thread.set_ready_event(self.server.stopped)
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
610
611
    def run_server(self):
612
        self.server.serve()
613
614
    def stop_server(self):
615
        if self.server is None:
616
            return
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
617
        try:
618
            # The server has been started successfully, shut it down now.  As
5247.5.10 by Vincent Ladeuil
Fix broken test.
619
            # soon as we stop serving, no more connection are accepted except
620
            # one to get out of the blocking listen.
5247.5.7 by Vincent Ladeuil
Factor out socket exception handling during server shutdown.
621
            self.set_ignored_exceptions(
622
                self.server.ignored_exceptions_during_shutdown)
5247.5.31 by Vincent Ladeuil
Use a boolean for server.serving, a threading.Event() is not needed here.
623
            self.server.serving = False
5247.5.17 by Vincent Ladeuil
Add some basic debug tracing controlled by -Ethreads.
624
            if debug_threads():
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
625
                sys.stderr.write('Server thread %s will be joined\n'
626
                                 % (self._server_thread.name,))
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
627
            # The server is listening for a last connection, let's give it:
628
            last_conn = None
629
            try:
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
630
                last_conn = osutils.connect_socket((self.host, self.port))
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
631
            except socket.error, e:
632
                # But ignore connection errors as the point is to unblock the
633
                # server thread, it may happen that it's not blocked or even
634
                # not started.
635
                pass
5560.1.1 by Vincent Ladeuil
Catch the bogus ssl exception for closed sockets.
636
            # We start shutting down the clients while the server itself is
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
637
            # shutting down.
638
            self.server.stop_client_connections()
639
            # Now we wait for the thread running self.server.serve() to finish
640
            self.server.stopped.wait()
641
            if last_conn is not None:
642
                # Close the last connection without trying to use it. The
643
                # server will not process a single byte on that socket to avoid
644
                # complications (SSL starts with a handshake for example).
645
                last_conn.close()
5247.3.10 by Vincent Ladeuil
Test errors during server life.
646
            # Check for any exception that could have occurred in the server
647
            # thread
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
648
            try:
649
                self._server_thread.join()
650
            except Exception, e:
651
                if self.server.ignored_exceptions(e):
652
                    pass
653
                else:
654
                    raise
5247.3.10 by Vincent Ladeuil
Test errors during server life.
655
        finally:
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
656
            # Make sure we can be called twice safely, note that this means
657
            # that we will raise a single exception even if several occurred in
658
            # the various threads involved.
5247.3.10 by Vincent Ladeuil
Test errors during server life.
659
            self.server = None
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
660
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
661
    def set_ignored_exceptions(self, ignored_exceptions):
662
        """Install an exception handler for the server."""
663
        self.server.set_ignored_exceptions(self._server_thread,
664
                                           ignored_exceptions)
665
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
666
    def pending_exception(self):
667
        """Raise uncaught exception in the server."""
668
        self.server._pending_exception(self._server_thread)
669
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
670
5247.3.38 by Vincent Ladeuil
Fix the last remaining failures.
671
class TestingSmartConnectionHandler(SocketServer.BaseRequestHandler,
672
                                    medium.SmartServerSocketStreamMedium):
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
673
674
    def __init__(self, request, client_address, server):
675
        medium.SmartServerSocketStreamMedium.__init__(
676
            self, request, server.backing_transport,
677
            server.root_client_path)
678
        request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
679
        SocketServer.BaseRequestHandler.__init__(self, request, client_address,
680
                                                 server)
681
682
    def handle(self):
683
        while not self.finished:
684
            server_protocol = self._build_protocol()
685
            self._serve_one_request(server_protocol)
686
687
688
class TestingSmartServer(TestingThreadingTCPServer, server.SmartTCPServer):
689
690
    def __init__(self, server_address, request_handler_class,
691
                 backing_transport, root_client_path):
692
        TestingThreadingTCPServer.__init__(self, server_address,
693
                                           request_handler_class)
694
        server.SmartTCPServer.__init__(self, backing_transport,
695
                                       root_client_path)
5247.3.38 by Vincent Ladeuil
Fix the last remaining failures.
696
    def serve(self):
697
        self.run_server_started_hooks()
698
        try:
699
            TestingThreadingTCPServer.serve(self)
700
        finally:
701
            self.run_server_stopped_hooks()
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
702
703
    def get_url(self):
704
        """Return the url of the server"""
705
        return "bzr://%s:%d/" % self.server_address
706
707
708
class SmartTCPServer_for_testing(TestingTCPServerInAThread):
5017.3.18 by Vincent Ladeuil
Move SmartTCPServer_for_testing and friends to bzrlib.tests.test_server
709
    """Server suitable for use by transport tests.
710
711
    This server is backed by the process's cwd.
712
    """
713
    def __init__(self, thread_name_suffix=''):
714
        self.client_path_extra = None
715
        self.thread_name_suffix = thread_name_suffix
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
716
        self.host = '127.0.0.1'
717
        self.port = 0
718
        super(SmartTCPServer_for_testing, self).__init__(
719
                (self.host, self.port),
720
                TestingSmartServer,
5247.3.38 by Vincent Ladeuil
Fix the last remaining failures.
721
                TestingSmartConnectionHandler)
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
722
723
    def create_server(self):
724
        return self.server_class((self.host, self.port),
725
                                 self.request_handler_class,
726
                                 self.backing_transport,
727
                                 self.root_client_path)
728
5017.3.18 by Vincent Ladeuil
Move SmartTCPServer_for_testing and friends to bzrlib.tests.test_server
729
730
    def start_server(self, backing_transport_server=None,
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
731
                     client_path_extra='/extra/'):
5017.3.18 by Vincent Ladeuil
Move SmartTCPServer_for_testing and friends to bzrlib.tests.test_server
732
        """Set up server for testing.
733
734
        :param backing_transport_server: backing server to use.  If not
735
            specified, a LocalURLServer at the current working directory will
736
            be used.
737
        :param client_path_extra: a path segment starting with '/' to append to
738
            the root URL for this server.  For instance, a value of '/foo/bar/'
739
            will mean the root of the backing transport will be published at a
740
            URL like `bzr://127.0.0.1:nnnn/foo/bar/`, rather than
741
            `bzr://127.0.0.1:nnnn/`.  Default value is `extra`, so that tests
742
            by default will fail unless they do the necessary path translation.
743
        """
744
        if not client_path_extra.startswith('/'):
745
            raise ValueError(client_path_extra)
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
746
        self.root_client_path = self.client_path_extra = client_path_extra
5017.3.18 by Vincent Ladeuil
Move SmartTCPServer_for_testing and friends to bzrlib.tests.test_server
747
        from bzrlib.transport.chroot import ChrootServer
748
        if backing_transport_server is None:
749
            backing_transport_server = LocalURLServer()
750
        self.chroot_server = ChrootServer(
751
            self.get_backing_transport(backing_transport_server))
752
        self.chroot_server.start_server()
753
        self.backing_transport = transport.get_transport(
754
            self.chroot_server.get_url())
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
755
        super(SmartTCPServer_for_testing, self).start_server()
756
5247.3.38 by Vincent Ladeuil
Fix the last remaining failures.
757
    def stop_server(self):
5247.3.40 by Vincent Ladeuil
Make sure the chroot server is shut down too.
758
        try:
759
            super(SmartTCPServer_for_testing, self).stop_server()
760
        finally:
761
            self.chroot_server.stop_server()
5247.3.38 by Vincent Ladeuil
Fix the last remaining failures.
762
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
763
    def get_backing_transport(self, backing_transport_server):
764
        """Get a backing transport from a server we are decorating."""
765
        return transport.get_transport(backing_transport_server.get_url())
5017.3.18 by Vincent Ladeuil
Move SmartTCPServer_for_testing and friends to bzrlib.tests.test_server
766
767
    def get_url(self):
5247.3.37 by Vincent Ladeuil
Use TestingTCPServerInAThread for smart test servers, only 4 test failures remaining.
768
        url = self.server.get_url()
5017.3.18 by Vincent Ladeuil
Move SmartTCPServer_for_testing and friends to bzrlib.tests.test_server
769
        return url[:-1] + self.client_path_extra
770
771
    def get_bogus_url(self):
772
        """Return a URL which will fail to connect"""
773
        return 'bzr://127.0.0.1:1/'
774
775
776
class ReadonlySmartTCPServer_for_testing(SmartTCPServer_for_testing):
777
    """Get a readonly server for testing."""
778
779
    def get_backing_transport(self, backing_transport_server):
780
        """Get a backing transport from a server we are decorating."""
781
        url = 'readonly+' + backing_transport_server.get_url()
782
        return transport.get_transport(url)
783
784
785
class SmartTCPServer_for_testing_v2_only(SmartTCPServer_for_testing):
786
    """A variation of SmartTCPServer_for_testing that limits the client to
787
    using RPCs in protocol v2 (i.e. bzr <= 1.5).
788
    """
789
790
    def get_url(self):
791
        url = super(SmartTCPServer_for_testing_v2_only, self).get_url()
792
        url = 'bzr-v2://' + url[len('bzr://'):]
793
        return url
794
795
796
class ReadonlySmartTCPServer_for_testing_v2_only(
797
    SmartTCPServer_for_testing_v2_only):
798
    """Get a readonly server for testing."""
799
800
    def get_backing_transport(self, backing_transport_server):
801
        """Get a backing transport from a server we are decorating."""
802
        url = 'readonly+' + backing_transport_server.get_url()
803
        return transport.get_transport(url)