/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/tests/test_server.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2018-11-16 18:59:44 UTC
  • mfrom: (7143.15.15 more-cleanups)
  • Revision ID: breezy.the.bot@gmail.com-20181116185944-biefv1sub37qfybm
Sprinkle some PEP8iness.

Merged from https://code.launchpad.net/~jelmer/brz/more-cleanups/+merge/358611

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2010 Canonical Ltd
 
1
# Copyright (C) 2010, 2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from bzrlib import (
 
17
import errno
 
18
import socket
 
19
try:
 
20
    import socketserver
 
21
except ImportError:
 
22
    import SocketServer as socketserver
 
23
import sys
 
24
import threading
 
25
 
 
26
 
 
27
from breezy import (
 
28
    cethread,
 
29
    errors,
 
30
    osutils,
18
31
    transport,
19
32
    urlutils,
20
33
    )
21
 
from bzrlib.transport import (
 
34
from breezy.transport import (
22
35
    chroot,
23
36
    pathfilter,
24
37
    )
25
 
from bzrlib.smart import server
 
38
from breezy.bzr.smart import (
 
39
    medium,
 
40
    server,
 
41
    )
 
42
 
 
43
 
 
44
def debug_threads():
 
45
    # FIXME: There is a dependency loop between breezy.tests and
 
46
    # breezy.tests.test_server that needs to be fixed. In the mean time
 
47
    # defining this function is enough for our needs. -- vila 20100611
 
48
    from breezy import tests
 
49
    return 'threads' in tests.selftest_debug_flags
26
50
 
27
51
 
28
52
class TestServer(transport.Server):
31
55
    The TestServer interface provides a server for a given transport. We use
32
56
    these servers as loopback testing tools. For any given transport the
33
57
    Servers it provides must either allow writing, or serve the contents
34
 
    of os.getcwdu() at the time start_server is called.
 
58
    of osutils.getcwd() at the time start_server is called.
35
59
 
36
60
    Note that these are real servers - they must implement all the things
37
61
    that we want bzr transports to take advantage of.
44
68
        a database like svn, or a memory only transport, it should return
45
69
        a connection to a newly established resource for this Server.
46
70
        Otherwise it should return a url that will provide access to the path
47
 
        that was os.getcwdu() when start_server() was called.
 
71
        that was osutils.getcwd() when start_server() was called.
48
72
 
49
73
        Subsequent calls will return the same resource.
50
74
        """
82
106
    """
83
107
 
84
108
    def start_server(self, server=None):
85
 
        """See bzrlib.transport.Server.start_server.
 
109
        """See breezy.transport.Server.start_server.
86
110
 
87
111
        :server: decorate the urls given by server. If not provided a
88
112
        LocalServer is created.
108
132
        return self.get_decorator_class()._get_url_prefix()
109
133
 
110
134
    def get_bogus_url(self):
111
 
        """See bzrlib.transport.Server.get_bogus_url."""
 
135
        """See breezy.transport.Server.get_bogus_url."""
112
136
        return self.get_url_prefix() + self._server.get_bogus_url()
113
137
 
114
138
    def get_url(self):
115
 
        """See bzrlib.transport.Server.get_url."""
 
139
        """See breezy.transport.Server.get_url."""
116
140
        return self.get_url_prefix() + self._server.get_url()
117
141
 
118
142
 
120
144
    """Server for the BrokenRenameTransportDecorator for testing with."""
121
145
 
122
146
    def get_decorator_class(self):
123
 
        from bzrlib.transport import brokenrename
 
147
        from breezy.transport import brokenrename
124
148
        return brokenrename.BrokenRenameTransportDecorator
125
149
 
126
150
 
128
152
    """Server for the FakeNFSTransportDecorator for testing with."""
129
153
 
130
154
    def get_decorator_class(self):
131
 
        from bzrlib.transport import fakenfs
 
155
        from breezy.transport import fakenfs
132
156
        return fakenfs.FakeNFSTransportDecorator
133
157
 
134
158
 
139
163
    """
140
164
 
141
165
    def get_decorator_class(self):
142
 
        from bzrlib.transport import fakevfat
 
166
        from breezy.transport import fakevfat
143
167
        return fakevfat.FakeVFATTransportDecorator
144
168
 
145
169
 
147
171
    """Server for testing."""
148
172
 
149
173
    def get_decorator_class(self):
150
 
        from bzrlib.transport import log
 
174
        from breezy.transport import log
151
175
        return log.TransportLogDecorator
152
176
 
153
177
 
155
179
    """Server for the NoSmartTransportDecorator for testing with."""
156
180
 
157
181
    def get_decorator_class(self):
158
 
        from bzrlib.transport import nosmart
 
182
        from breezy.transport import nosmart
159
183
        return nosmart.NoSmartTransportDecorator
160
184
 
161
185
 
163
187
    """Server for the ReadonlyTransportDecorator for testing with."""
164
188
 
165
189
    def get_decorator_class(self):
166
 
        from bzrlib.transport import readonly
 
190
        from breezy.transport import readonly
167
191
        return readonly.ReadonlyTransportDecorator
168
192
 
169
193
 
171
195
    """Server for the TransportTraceDecorator for testing with."""
172
196
 
173
197
    def get_decorator_class(self):
174
 
        from bzrlib.transport import trace
 
198
        from breezy.transport import trace
175
199
        return trace.TransportTraceDecorator
176
200
 
177
201
 
179
203
    """Server for the UnlistableTransportDecorator for testing with."""
180
204
 
181
205
    def get_decorator_class(self):
182
 
        from bzrlib.transport import unlistable
 
206
        from breezy.transport import unlistable
183
207
        return unlistable.UnlistableTransportDecorator
184
208
 
185
209
 
192
216
    def start_server(self, backing_server=None):
193
217
        """Setup the Chroot on backing_server."""
194
218
        if backing_server is not None:
195
 
            self.backing_transport = transport.get_transport(
 
219
            self.backing_transport = transport.get_transport_from_url(
196
220
                backing_server.get_url())
197
221
        else:
198
 
            self.backing_transport = transport.get_transport('.')
 
222
            self.backing_transport = transport.get_transport_from_path('.')
199
223
        self.backing_transport.clone('added-by-filter').ensure_base()
200
224
        self.filter_func = lambda x: 'added-by-filter/' + x
201
225
        super(TestingPathFilteringServer, self).start_server()
213
237
    def start_server(self, backing_server=None):
214
238
        """Setup the Chroot on backing_server."""
215
239
        if backing_server is not None:
216
 
            self.backing_transport = transport.get_transport(
 
240
            self.backing_transport = transport.get_transport_from_url(
217
241
                backing_server.get_url())
218
242
        else:
219
 
            self.backing_transport = transport.get_transport('.')
 
243
            self.backing_transport = transport.get_transport_from_path('.')
220
244
        super(TestingChrootServer, self).start_server()
221
245
 
222
246
    def get_bogus_url(self):
223
247
        raise NotImplementedError
224
248
 
225
249
 
226
 
class SmartTCPServer_for_testing(server.SmartTCPServer):
 
250
class TestThread(cethread.CatchingExceptionThread):
 
251
 
 
252
    def join(self, timeout=5):
 
253
        """Overrides to use a default timeout.
 
254
 
 
255
        The default timeout is set to 5 and should expire only when a thread
 
256
        serving a client connection is hung.
 
257
        """
 
258
        super(TestThread, self).join(timeout)
 
259
        if timeout and self.isAlive():
 
260
            # The timeout expired without joining the thread, the thread is
 
261
            # therefore stucked and that's a failure as far as the test is
 
262
            # concerned. We used to hang here.
 
263
 
 
264
            # FIXME: we need to kill the thread, but as far as the test is
 
265
            # concerned, raising an assertion is too strong. On most of the
 
266
            # platforms, this doesn't occur, so just mentioning the problem is
 
267
            # enough for now -- vila 2010824
 
268
            sys.stderr.write('thread %s hung\n' % (self.name,))
 
269
            # raise AssertionError('thread %s hung' % (self.name,))
 
270
 
 
271
 
 
272
class TestingTCPServerMixin(object):
 
273
    """Mixin to support running socketserver.TCPServer in a thread.
 
274
 
 
275
    Tests are connecting from the main thread, the server has to be run in a
 
276
    separate thread.
 
277
    """
 
278
 
 
279
    def __init__(self):
 
280
        self.started = threading.Event()
 
281
        self.serving = None
 
282
        self.stopped = threading.Event()
 
283
        # We collect the resources used by the clients so we can release them
 
284
        # when shutting down
 
285
        self.clients = []
 
286
        self.ignored_exceptions = None
 
287
 
 
288
    def server_bind(self):
 
289
        self.socket.bind(self.server_address)
 
290
        self.server_address = self.socket.getsockname()
 
291
 
 
292
    def serve(self):
 
293
        self.serving = True
 
294
        # We are listening and ready to accept connections
 
295
        self.started.set()
 
296
        try:
 
297
            while self.serving:
 
298
                # Really a connection but the python framework is generic and
 
299
                # call them requests
 
300
                self.handle_request()
 
301
            # Let's close the listening socket
 
302
            self.server_close()
 
303
        finally:
 
304
            self.stopped.set()
 
305
 
 
306
    def handle_request(self):
 
307
        """Handle one request.
 
308
 
 
309
        The python version swallows some socket exceptions and we don't use
 
310
        timeout, so we override it to better control the server behavior.
 
311
        """
 
312
        request, client_address = self.get_request()
 
313
        if self.verify_request(request, client_address):
 
314
            try:
 
315
                self.process_request(request, client_address)
 
316
            except BaseException:
 
317
                self.handle_error(request, client_address)
 
318
        else:
 
319
            self.close_request(request)
 
320
 
 
321
    def get_request(self):
 
322
        return self.socket.accept()
 
323
 
 
324
    def verify_request(self, request, client_address):
 
325
        """Verify the request.
 
326
 
 
327
        Return True if we should proceed with this request, False if we should
 
328
        not even touch a single byte in the socket ! This is useful when we
 
329
        stop the server with a dummy last connection.
 
330
        """
 
331
        return self.serving
 
332
 
 
333
    def handle_error(self, request, client_address):
 
334
        # Stop serving and re-raise the last exception seen
 
335
        self.serving = False
 
336
        # The following can be used for debugging purposes, it will display the
 
337
        # exception and the traceback just when it occurs instead of waiting
 
338
        # for the thread to be joined.
 
339
        # socketserver.BaseServer.handle_error(self, request, client_address)
 
340
 
 
341
        # We call close_request manually, because we are going to raise an
 
342
        # exception. The socketserver implementation calls:
 
343
        #   handle_error(...)
 
344
        #   close_request(...)
 
345
        # But because we raise the exception, close_request will never be
 
346
        # triggered. This helps client not block waiting for a response when
 
347
        # the server gets an exception.
 
348
        self.close_request(request)
 
349
        raise
 
350
 
 
351
    def ignored_exceptions_during_shutdown(self, e):
 
352
        if sys.platform == 'win32':
 
353
            accepted_errnos = [errno.EBADF,
 
354
                               errno.EPIPE,
 
355
                               errno.WSAEBADF,
 
356
                               errno.WSAECONNRESET,
 
357
                               errno.WSAENOTCONN,
 
358
                               errno.WSAESHUTDOWN,
 
359
                               ]
 
360
        else:
 
361
            accepted_errnos = [errno.EBADF,
 
362
                               errno.ECONNRESET,
 
363
                               errno.ENOTCONN,
 
364
                               errno.EPIPE,
 
365
                               ]
 
366
        if isinstance(e, socket.error) and e.errno in accepted_errnos:
 
367
            return True
 
368
        return False
 
369
 
 
370
    # The following methods are called by the main thread
 
371
 
 
372
    def stop_client_connections(self):
 
373
        while self.clients:
 
374
            c = self.clients.pop()
 
375
            self.shutdown_client(c)
 
376
 
 
377
    def shutdown_socket(self, sock):
 
378
        """Properly shutdown a socket.
 
379
 
 
380
        This should be called only when no other thread is trying to use the
 
381
        socket.
 
382
        """
 
383
        try:
 
384
            sock.shutdown(socket.SHUT_RDWR)
 
385
            sock.close()
 
386
        except Exception as e:
 
387
            if self.ignored_exceptions(e):
 
388
                pass
 
389
            else:
 
390
                raise
 
391
 
 
392
    # The following methods are called by the main thread
 
393
 
 
394
    def set_ignored_exceptions(self, thread, ignored_exceptions):
 
395
        self.ignored_exceptions = ignored_exceptions
 
396
        thread.set_ignored_exceptions(self.ignored_exceptions)
 
397
 
 
398
    def _pending_exception(self, thread):
 
399
        """Raise server uncaught exception.
 
400
 
 
401
        Daughter classes can override this if they use daughter threads.
 
402
        """
 
403
        thread.pending_exception()
 
404
 
 
405
 
 
406
class TestingTCPServer(TestingTCPServerMixin, socketserver.TCPServer):
 
407
 
 
408
    def __init__(self, server_address, request_handler_class):
 
409
        TestingTCPServerMixin.__init__(self)
 
410
        socketserver.TCPServer.__init__(self, server_address,
 
411
                                        request_handler_class)
 
412
 
 
413
    def get_request(self):
 
414
        """Get the request and client address from the socket."""
 
415
        sock, addr = TestingTCPServerMixin.get_request(self)
 
416
        self.clients.append((sock, addr))
 
417
        return sock, addr
 
418
 
 
419
    # The following methods are called by the main thread
 
420
 
 
421
    def shutdown_client(self, client):
 
422
        sock, addr = client
 
423
        self.shutdown_socket(sock)
 
424
 
 
425
 
 
426
class TestingThreadingTCPServer(TestingTCPServerMixin,
 
427
                                socketserver.ThreadingTCPServer):
 
428
 
 
429
    def __init__(self, server_address, request_handler_class):
 
430
        TestingTCPServerMixin.__init__(self)
 
431
        socketserver.ThreadingTCPServer.__init__(self, server_address,
 
432
                                                 request_handler_class)
 
433
 
 
434
    def get_request(self):
 
435
        """Get the request and client address from the socket."""
 
436
        sock, addr = TestingTCPServerMixin.get_request(self)
 
437
        # The thread is not created yet, it will be updated in process_request
 
438
        self.clients.append((sock, addr, None))
 
439
        return sock, addr
 
440
 
 
441
    def process_request_thread(self, started, detached, stopped,
 
442
                               request, client_address):
 
443
        started.set()
 
444
        # We will be on our own once the server tells us we're detached
 
445
        detached.wait()
 
446
        socketserver.ThreadingTCPServer.process_request_thread(
 
447
            self, request, client_address)
 
448
        self.close_request(request)
 
449
        stopped.set()
 
450
 
 
451
    def process_request(self, request, client_address):
 
452
        """Start a new thread to process the request."""
 
453
        started = threading.Event()
 
454
        detached = threading.Event()
 
455
        stopped = threading.Event()
 
456
        t = TestThread(
 
457
            sync_event=stopped,
 
458
            name='%s -> %s' % (client_address, self.server_address),
 
459
            target=self.process_request_thread,
 
460
            args=(started, detached, stopped, request, client_address))
 
461
        # Update the client description
 
462
        self.clients.pop()
 
463
        self.clients.append((request, client_address, t))
 
464
        # Propagate the exception handler since we must use the same one as
 
465
        # TestingTCPServer for connections running in their own threads.
 
466
        t.set_ignored_exceptions(self.ignored_exceptions)
 
467
        t.start()
 
468
        started.wait()
 
469
        # If an exception occured during the thread start, it will get raised.
 
470
        t.pending_exception()
 
471
        if debug_threads():
 
472
            sys.stderr.write('Client thread %s started\n' % (t.name,))
 
473
        # Tell the thread, it's now on its own for exception handling.
 
474
        detached.set()
 
475
 
 
476
    # The following methods are called by the main thread
 
477
 
 
478
    def shutdown_client(self, client):
 
479
        sock, addr, connection_thread = client
 
480
        self.shutdown_socket(sock)
 
481
        if connection_thread is not None:
 
482
            # The thread has been created only if the request is processed but
 
483
            # after the connection is inited. This could happen during server
 
484
            # shutdown. If an exception occurred in the thread it will be
 
485
            # re-raised
 
486
            if debug_threads():
 
487
                sys.stderr.write('Client thread %s will be joined\n'
 
488
                                 % (connection_thread.name,))
 
489
            connection_thread.join()
 
490
 
 
491
    def set_ignored_exceptions(self, thread, ignored_exceptions):
 
492
        TestingTCPServerMixin.set_ignored_exceptions(self, thread,
 
493
                                                     ignored_exceptions)
 
494
        for sock, addr, connection_thread in self.clients:
 
495
            if connection_thread is not None:
 
496
                connection_thread.set_ignored_exceptions(
 
497
                    self.ignored_exceptions)
 
498
 
 
499
    def _pending_exception(self, thread):
 
500
        for sock, addr, connection_thread in self.clients:
 
501
            if connection_thread is not None:
 
502
                connection_thread.pending_exception()
 
503
        TestingTCPServerMixin._pending_exception(self, thread)
 
504
 
 
505
 
 
506
class TestingTCPServerInAThread(transport.Server):
 
507
    """A server in a thread that re-raise thread exceptions."""
 
508
 
 
509
    def __init__(self, server_address, server_class, request_handler_class):
 
510
        self.server_class = server_class
 
511
        self.request_handler_class = request_handler_class
 
512
        self.host, self.port = server_address
 
513
        self.server = None
 
514
        self._server_thread = None
 
515
 
 
516
    def __repr__(self):
 
517
        return "%s(%s:%s)" % (self.__class__.__name__, self.host, self.port)
 
518
 
 
519
    def create_server(self):
 
520
        return self.server_class((self.host, self.port),
 
521
                                 self.request_handler_class)
 
522
 
 
523
    def start_server(self):
 
524
        self.server = self.create_server()
 
525
        self._server_thread = TestThread(
 
526
            sync_event=self.server.started,
 
527
            target=self.run_server)
 
528
        self._server_thread.start()
 
529
        # Wait for the server thread to start (i.e. release the lock)
 
530
        self.server.started.wait()
 
531
        # Get the real address, especially the port
 
532
        self.host, self.port = self.server.server_address
 
533
        self._server_thread.name = self.server.server_address
 
534
        if debug_threads():
 
535
            sys.stderr.write('Server thread %s started\n'
 
536
                             % (self._server_thread.name,))
 
537
        # If an exception occured during the server start, it will get raised,
 
538
        # otherwise, the server is blocked on its accept() call.
 
539
        self._server_thread.pending_exception()
 
540
        # From now on, we'll use a different event to ensure the server can set
 
541
        # its exception
 
542
        self._server_thread.set_sync_event(self.server.stopped)
 
543
 
 
544
    def run_server(self):
 
545
        self.server.serve()
 
546
 
 
547
    def stop_server(self):
 
548
        if self.server is None:
 
549
            return
 
550
        try:
 
551
            # The server has been started successfully, shut it down now.  As
 
552
            # soon as we stop serving, no more connection are accepted except
 
553
            # one to get out of the blocking listen.
 
554
            self.set_ignored_exceptions(
 
555
                self.server.ignored_exceptions_during_shutdown)
 
556
            self.server.serving = False
 
557
            if debug_threads():
 
558
                sys.stderr.write('Server thread %s will be joined\n'
 
559
                                 % (self._server_thread.name,))
 
560
            # The server is listening for a last connection, let's give it:
 
561
            last_conn = None
 
562
            try:
 
563
                last_conn = osutils.connect_socket((self.host, self.port))
 
564
            except socket.error:
 
565
                # But ignore connection errors as the point is to unblock the
 
566
                # server thread, it may happen that it's not blocked or even
 
567
                # not started.
 
568
                pass
 
569
            # We start shutting down the clients while the server itself is
 
570
            # shutting down.
 
571
            self.server.stop_client_connections()
 
572
            # Now we wait for the thread running self.server.serve() to finish
 
573
            self.server.stopped.wait()
 
574
            if last_conn is not None:
 
575
                # Close the last connection without trying to use it. The
 
576
                # server will not process a single byte on that socket to avoid
 
577
                # complications (SSL starts with a handshake for example).
 
578
                last_conn.close()
 
579
            # Check for any exception that could have occurred in the server
 
580
            # thread
 
581
            try:
 
582
                self._server_thread.join()
 
583
            except Exception as e:
 
584
                if self.server.ignored_exceptions(e):
 
585
                    pass
 
586
                else:
 
587
                    raise
 
588
        finally:
 
589
            # Make sure we can be called twice safely, note that this means
 
590
            # that we will raise a single exception even if several occurred in
 
591
            # the various threads involved.
 
592
            self.server = None
 
593
 
 
594
    def set_ignored_exceptions(self, ignored_exceptions):
 
595
        """Install an exception handler for the server."""
 
596
        self.server.set_ignored_exceptions(self._server_thread,
 
597
                                           ignored_exceptions)
 
598
 
 
599
    def pending_exception(self):
 
600
        """Raise uncaught exception in the server."""
 
601
        self.server._pending_exception(self._server_thread)
 
602
 
 
603
 
 
604
class TestingSmartConnectionHandler(socketserver.BaseRequestHandler,
 
605
                                    medium.SmartServerSocketStreamMedium):
 
606
 
 
607
    def __init__(self, request, client_address, server):
 
608
        medium.SmartServerSocketStreamMedium.__init__(
 
609
            self, request, server.backing_transport,
 
610
            server.root_client_path,
 
611
            timeout=_DEFAULT_TESTING_CLIENT_TIMEOUT)
 
612
        request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
 
613
        socketserver.BaseRequestHandler.__init__(self, request, client_address,
 
614
                                                 server)
 
615
 
 
616
    def handle(self):
 
617
        try:
 
618
            while not self.finished:
 
619
                server_protocol = self._build_protocol()
 
620
                self._serve_one_request(server_protocol)
 
621
        except errors.ConnectionTimeout:
 
622
            # idle connections aren't considered a failure of the server
 
623
            return
 
624
 
 
625
 
 
626
_DEFAULT_TESTING_CLIENT_TIMEOUT = 60.0
 
627
 
 
628
 
 
629
class TestingSmartServer(TestingThreadingTCPServer, server.SmartTCPServer):
 
630
 
 
631
    def __init__(self, server_address, request_handler_class,
 
632
                 backing_transport, root_client_path):
 
633
        TestingThreadingTCPServer.__init__(self, server_address,
 
634
                                           request_handler_class)
 
635
        server.SmartTCPServer.__init__(
 
636
            self, backing_transport,
 
637
            root_client_path, client_timeout=_DEFAULT_TESTING_CLIENT_TIMEOUT)
 
638
 
 
639
    def serve(self):
 
640
        self.run_server_started_hooks()
 
641
        try:
 
642
            TestingThreadingTCPServer.serve(self)
 
643
        finally:
 
644
            self.run_server_stopped_hooks()
 
645
 
 
646
    def get_url(self):
 
647
        """Return the url of the server"""
 
648
        return "bzr://%s:%d/" % self.server_address
 
649
 
 
650
 
 
651
class SmartTCPServer_for_testing(TestingTCPServerInAThread):
227
652
    """Server suitable for use by transport tests.
228
653
 
229
654
    This server is backed by the process's cwd.
230
655
    """
231
656
 
232
657
    def __init__(self, thread_name_suffix=''):
233
 
        super(SmartTCPServer_for_testing, self).__init__(None)
234
658
        self.client_path_extra = None
235
659
        self.thread_name_suffix = thread_name_suffix
 
660
        self.host = '127.0.0.1'
 
661
        self.port = 0
 
662
        super(SmartTCPServer_for_testing, self).__init__(
 
663
            (self.host, self.port),
 
664
            TestingSmartServer,
 
665
            TestingSmartConnectionHandler)
236
666
 
237
 
    def get_backing_transport(self, backing_transport_server):
238
 
        """Get a backing transport from a server we are decorating."""
239
 
        return transport.get_transport(backing_transport_server.get_url())
 
667
    def create_server(self):
 
668
        return self.server_class((self.host, self.port),
 
669
                                 self.request_handler_class,
 
670
                                 self.backing_transport,
 
671
                                 self.root_client_path)
240
672
 
241
673
    def start_server(self, backing_transport_server=None,
242
 
              client_path_extra='/extra/'):
 
674
                     client_path_extra='/extra/'):
243
675
        """Set up server for testing.
244
676
 
245
677
        :param backing_transport_server: backing server to use.  If not
254
686
        """
255
687
        if not client_path_extra.startswith('/'):
256
688
            raise ValueError(client_path_extra)
257
 
        from bzrlib.transport.chroot import ChrootServer
 
689
        self.root_client_path = self.client_path_extra = client_path_extra
 
690
        from breezy.transport.chroot import ChrootServer
258
691
        if backing_transport_server is None:
259
692
            backing_transport_server = LocalURLServer()
260
693
        self.chroot_server = ChrootServer(
261
694
            self.get_backing_transport(backing_transport_server))
262
695
        self.chroot_server.start_server()
263
 
        self.backing_transport = transport.get_transport(
 
696
        self.backing_transport = transport.get_transport_from_url(
264
697
            self.chroot_server.get_url())
265
 
        self.root_client_path = self.client_path_extra = client_path_extra
266
 
        self.start_background_thread(self.thread_name_suffix)
 
698
        super(SmartTCPServer_for_testing, self).start_server()
267
699
 
268
700
    def stop_server(self):
269
 
        self.stop_background_thread()
270
 
        self.chroot_server.stop_server()
 
701
        try:
 
702
            super(SmartTCPServer_for_testing, self).stop_server()
 
703
        finally:
 
704
            self.chroot_server.stop_server()
 
705
 
 
706
    def get_backing_transport(self, backing_transport_server):
 
707
        """Get a backing transport from a server we are decorating."""
 
708
        return transport.get_transport_from_url(
 
709
            backing_transport_server.get_url())
271
710
 
272
711
    def get_url(self):
273
 
        url = super(SmartTCPServer_for_testing, self).get_url()
 
712
        url = self.server.get_url()
274
713
        return url[:-1] + self.client_path_extra
275
714
 
276
715
    def get_bogus_url(self):
284
723
    def get_backing_transport(self, backing_transport_server):
285
724
        """Get a backing transport from a server we are decorating."""
286
725
        url = 'readonly+' + backing_transport_server.get_url()
287
 
        return transport.get_transport(url)
 
726
        return transport.get_transport_from_url(url)
288
727
 
289
728
 
290
729
class SmartTCPServer_for_testing_v2_only(SmartTCPServer_for_testing):
299
738
 
300
739
 
301
740
class ReadonlySmartTCPServer_for_testing_v2_only(
302
 
    SmartTCPServer_for_testing_v2_only):
 
741
        SmartTCPServer_for_testing_v2_only):
303
742
    """Get a readonly server for testing."""
304
743
 
305
744
    def get_backing_transport(self, backing_transport_server):
306
745
        """Get a backing transport from a server we are decorating."""
307
746
        url = 'readonly+' + backing_transport_server.get_url()
308
 
        return transport.get_transport(url)
309
 
 
310
 
 
311
 
 
312
 
 
 
747
        return transport.get_transport_from_url(url)