/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2010, 2011 Canonical Ltd
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
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.10 by Vincent Ladeuil
Test errors during server life.
17
import errno
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
18
import socket
19
import SocketServer
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
20
import threading
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
21
22
from bzrlib import (
23
    osutils,
24
    tests,
25
    )
26
from bzrlib.tests import test_server
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
27
from bzrlib.tests.scenarios import load_tests_apply_scenarios
28
29
30
load_tests = load_tests_apply_scenarios
5247.3.14 by Vincent Ladeuil
Use a proper load_tests.
31
32
5247.5.25 by Vincent Ladeuil
Move tests related to TestThreadWithException in test_test_server.
33
class TestThreadWithException(tests.TestCase):
34
35
    def test_start_and_join_smoke_test(self):
36
        def do_nothing():
37
            pass
38
39
        tt = test_server.ThreadWithException(target=do_nothing)
40
        tt.start()
41
        tt.join()
42
43
    def test_exception_is_re_raised(self):
44
        class MyException(Exception):
45
            pass
46
47
        def raise_my_exception():
48
            raise MyException()
49
50
        tt = test_server.ThreadWithException(target=raise_my_exception)
51
        tt.start()
52
        self.assertRaises(MyException, tt.join)
53
54
    def test_join_when_no_exception(self):
55
        resume = threading.Event()
56
        class MyException(Exception):
57
            pass
58
59
        def raise_my_exception():
60
            # Wait for the test to tell us to resume
61
            resume.wait()
62
            # Now we can raise
63
            raise MyException()
64
65
        tt = test_server.ThreadWithException(target=raise_my_exception)
66
        tt.start()
67
        tt.join(timeout=0)
68
        self.assertIs(None, tt.exception)
69
        resume.set()
70
        self.assertRaises(MyException, tt.join)
71
72
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
73
class TCPClient(object):
74
75
    def __init__(self):
76
        self.sock = None
77
78
    def connect(self, addr):
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
79
        if self.sock is not None:
80
            raise AssertionError('Already connected to %r'
81
                                 % (self.sock.getsockname(),))
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
82
        self.sock = osutils.connect_socket(addr)
83
84
    def disconnect(self):
85
        if self.sock is not None:
5247.3.10 by Vincent Ladeuil
Test errors during server life.
86
            try:
87
                self.sock.shutdown(socket.SHUT_RDWR)
88
                self.sock.close()
89
            except socket.error, e:
90
                if e[0] in (errno.EBADF, errno.ENOTCONN):
91
                    # Right, the socket is already down
92
                    pass
93
                else:
94
                    raise
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
95
            self.sock = None
96
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
97
    def write(self, s):
98
        return self.sock.sendall(s)
99
100
    def read(self, bufsize=4096):
101
        return self.sock.recv(bufsize)
102
103
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
104
class TCPConnectionHandler(SocketServer.StreamRequestHandler):
105
106
    def handle(self):
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
107
        self.done = False
108
        self.handle_connection()
109
        while not self.done:
110
            self.handle_connection()
111
112
    def handle_connection(self):
113
        req = self.rfile.readline()
114
        if not req:
115
            self.done = True
116
        elif req == 'ping\n':
117
            self.wfile.write('pong\n')
118
        else:
119
            raise ValueError('[%s] not understood' % req)
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
120
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
121
122
class TestTCPServerInAThread(tests.TestCase):
123
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
124
    scenarios = [ 
125
        (name, {'server_class': getattr(test_server, name)})
126
        for name in
127
        ('TestingTCPServer', 'TestingThreadingTCPServer')]
128
5247.3.14 by Vincent Ladeuil
Use a proper load_tests.
129
    # Set by load_tests()
130
    server_class = None
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
131
5247.3.10 by Vincent Ladeuil
Test errors during server life.
132
    def get_server(self, server_class=None, connection_handler_class=None):
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
133
        if server_class is not None:
134
            self.server_class = server_class
5247.3.10 by Vincent Ladeuil
Test errors during server life.
135
        if connection_handler_class is None:
136
            connection_handler_class = TCPConnectionHandler
5247.3.13 by Vincent Ladeuil
Really test against a threading server and properly shutdown socket and threads.
137
        server =  test_server.TestingTCPServerInAThread(
138
            ('localhost', 0), self.server_class, connection_handler_class)
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
139
        server.start_server()
140
        self.addCleanup(server.stop_server)
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
141
        return server
142
143
    def get_client(self):
144
        client = TCPClient()
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
145
        self.addCleanup(client.disconnect)
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
146
        return client
147
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
148
    def get_server_connection(self, server, conn_rank):
149
        return server.server.clients[conn_rank]
150
151
    def assertClientAddr(self, client, server, conn_rank):
152
        conn = self.get_server_connection(server, conn_rank)
153
        self.assertEquals(client.sock.getsockname(), conn[1])
154
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
155
    def test_start_stop(self):
156
        server = self.get_server()
157
        client = self.get_client()
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
158
        server.stop_server()
159
        # since the server doesn't accept connections anymore attempting to
160
        # connect should fail
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
161
        client = self.get_client()
5247.3.18 by Vincent Ladeuil
Fix some fallouts from previous fixes, all tests passing (no more http leaks).
162
        self.assertRaises(socket.error,
163
                          client.connect, (server.host, server.port))
5247.3.8 by Vincent Ladeuil
Start implementing a TCP server running in its own thread (using
164
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
165
    def test_client_talks_server_respond(self):
166
        server = self.get_server()
167
        client = self.get_client()
5247.3.18 by Vincent Ladeuil
Fix some fallouts from previous fixes, all tests passing (no more http leaks).
168
        client.connect((server.host, server.port))
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
169
        self.assertIs(None, client.write('ping\n'))
170
        resp = client.read()
5247.3.12 by Vincent Ladeuil
Spawn a thread for each connection from a client.
171
        self.assertClientAddr(client, server, 0)
5247.3.9 by Vincent Ladeuil
Ensure a simple dialog can occur between a client and a server.
172
        self.assertEquals('pong\n', resp)
5247.3.10 by Vincent Ladeuil
Test errors during server life.
173
174
    def test_server_fails_to_start(self):
175
        class CantStart(Exception):
176
            pass
177
178
        class CantStartServer(test_server.TestingTCPServer):
179
180
            def server_bind(self):
181
                raise CantStart()
182
183
        # The exception is raised in the main thread
184
        self.assertRaises(CantStart,
185
                          self.get_server, server_class=CantStartServer)
186
5247.5.10 by Vincent Ladeuil
Fix broken test.
187
    def test_server_fails_while_serving_or_stopping(self):
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
188
        class CantConnect(Exception):
5247.3.10 by Vincent Ladeuil
Test errors during server life.
189
            pass
190
191
        class FailingConnectionHandler(TCPConnectionHandler):
192
193
            def handle(self):
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
194
                raise CantConnect()
5247.3.10 by Vincent Ladeuil
Test errors during server life.
195
196
        server = self.get_server(
197
            connection_handler_class=FailingConnectionHandler)
198
        # The server won't fail until a client connect
199
        client = self.get_client()
5247.3.18 by Vincent Ladeuil
Fix some fallouts from previous fixes, all tests passing (no more http leaks).
200
        client.connect((server.host, server.port))
5247.3.10 by Vincent Ladeuil
Test errors during server life.
201
        try:
202
            # Now we must force the server to answer by sending the request and
203
            # waiting for some answer. But since we don't control when the
204
            # server thread will be given cycles, we don't control either
205
            # whether our reads or writes may hang.
206
            client.sock.settimeout(0.1)
207
            client.write('ping\n')
208
            client.read()
209
        except socket.error:
210
            pass
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
211
        # Now the server has raised the exception in its own thread
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
212
        self.assertRaises(CantConnect, server.stop_server)
5247.3.11 by Vincent Ladeuil
Start implementing the threading variants.
213
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
214
    def test_server_crash_while_responding(self):
215
        sync = threading.Event()
216
        sync.clear()
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
217
        class FailToRespond(Exception):
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
218
            pass
219
220
        class FailingDuringResponseHandler(TCPConnectionHandler):
221
222
            def handle_connection(self):
223
                req = self.rfile.readline()
5247.5.30 by Vincent Ladeuil
Better explain ThreadWithException.set_ready_event and why it's needed.
224
                threading.currentThread().set_ready_event(sync)
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
225
                raise FailToRespond()
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
226
227
        server = self.get_server(
228
            connection_handler_class=FailingDuringResponseHandler)
229
        client = self.get_client()
5247.3.21 by Vincent Ladeuil
Merge propagate-exceptions into http-leaks
230
        client.connect((server.host, server.port))
5247.5.3 by Vincent Ladeuil
Fix exception raising only once for a given ThreadWithException.
231
        client.write('ping\n')
232
        sync.wait()
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
233
        self.assertRaises(FailToRespond, server.pending_exception)
234
235
    def test_exception_swallowed_while_serving(self):
236
        sync = threading.Event()
237
        sync.clear()
238
        class CantServe(Exception):
239
            pass
240
241
        class FailingWhileServingConnectionHandler(TCPConnectionHandler):
242
243
            def handle(self):
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
244
                # We want to sync with the thread that is serving the
245
                # connection.
5247.5.30 by Vincent Ladeuil
Better explain ThreadWithException.set_ready_event and why it's needed.
246
                threading.currentThread().set_ready_event(sync)
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
247
                raise CantServe()
248
249
        server = self.get_server(
250
            connection_handler_class=FailingWhileServingConnectionHandler)
251
        # Install the exception swallower
252
        server.set_ignored_exceptions(CantServe)
253
        client = self.get_client()
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
254
        # Connect to the server so the exception is raised there
5247.3.21 by Vincent Ladeuil
Merge propagate-exceptions into http-leaks
255
        client.connect((server.host, server.port))
5247.5.9 by Vincent Ladeuil
Use a better sync for test_exception_swallowed_while_serving test.
256
        # Wait for the exception to propagate.
5247.5.4 by Vincent Ladeuil
Implement an execption handling mechanism that can be injected in ThreadWithException.
257
        sync.wait()
258
        # The connection wasn't served properly but the exception should have
259
        # been swallowed.
260
        server.pending_exception()