87
87
('TestingTCPServer', 'TestingThreadingTCPServer')]
92
89
def get_server(self, server_class=None, connection_handler_class=None):
93
90
if server_class is not None:
94
91
self.server_class = server_class
172
169
self.assertRaises(CantConnect, server.stop_server)
174
171
def test_server_crash_while_responding(self):
175
sync = threading.Event()
172
# We want to ensure the exception has been caught
173
caught = threading.Event()
175
# The thread that will serve the client, this needs to be an attribute
176
# so the handler below can modify it when it's executed (it's
177
# instantiated when the request is processed)
178
self.connection_thread = None
177
180
class FailToRespond(Exception):
180
183
class FailingDuringResponseHandler(TCPConnectionHandler):
182
def handle_connection(self):
183
req = self.rfile.readline()
184
threading.currentThread().set_sync_event(sync)
185
def handle_connection(request):
186
req = request.rfile.readline()
187
# Capture the thread and make it use 'caught' so we can wait on
188
# the even that will be set when the exception is caught. We
189
# also capture the thread to know where to look.
190
self.connection_thread = threading.currentThread()
191
self.connection_thread.set_sync_event(caught)
185
192
raise FailToRespond()
187
194
server = self.get_server(
189
196
client = self.get_client()
190
197
client.connect((server.host, server.port))
191
198
client.write('ping\n')
193
self.assertRaises(FailToRespond, server.pending_exception)
199
# Wait for the exception to be caught
201
# Check that the connection thread did catch the exception,
202
# http://pad.lv/869366 was wrongly checking the server thread which
203
# works for TestingTCPServer where the connection is handled in the
204
# same thread than the server one but is racy for
205
# TestingThreadingTCPServer where the server thread may be in a
206
# blocking accept() call (or not).
208
self.connection_thread.pending_exception()
209
except FailToRespond:
210
# Great, the test succeeded
213
# If the exception is not in the connection thread anymore, it's in
215
server.server.stopped.wait()
216
# The exception is available now
217
self.assertRaises(FailToRespond, server.pending_exception)
195
219
def test_exception_swallowed_while_serving(self):
196
sync = threading.Event()
220
# We need to ensure the exception has been caught
221
caught = threading.Event()
223
# The thread that will serve the client, this needs to be an attribute
224
# so the handler below can access it when it's executed (it's
225
# instantiated when the request is processed)
226
self.connection_thread = None
198
227
class CantServe(Exception):
201
230
class FailingWhileServingConnectionHandler(TCPConnectionHandler):
204
# We want to sync with the thread that is serving the
206
threading.currentThread().set_sync_event(sync)
233
# Capture the thread and make it use 'caught' so we can wait on
234
# the even that will be set when the exception is caught. We
235
# also capture the thread to know where to look.
236
self.connection_thread = threading.currentThread()
237
self.connection_thread.set_sync_event(caught)
207
238
raise CantServe()
209
240
server = self.get_server(
213
244
client = self.get_client()
214
245
# Connect to the server so the exception is raised there
215
246
client.connect((server.host, server.port))
216
# Wait for the exception to propagate.
247
# Wait for the exception to be caught
218
249
# The connection wasn't served properly but the exception should have
250
# been swallowed (see test_server_crash_while_responding remark about
251
# http://pad.lv/869366 explaining why we can't check the server thread
252
# here). More precisely, the exception *has* been caught and captured
253
# but it is cleared when joining the thread (or trying to acquire the
254
# exception) and as such won't propagate to the server thread.
255
self.connection_thread.pending_exception()
220
256
server.pending_exception()