113
113
('TestingTCPServer', 'TestingThreadingTCPServer')]
115
# Set by load_tests()
118
115
def get_server(self, server_class=None, connection_handler_class=None):
119
116
if server_class is not None:
120
117
self.server_class = server_class
202
199
self.assertRaises(CantConnect, server.stop_server)
204
201
def test_server_crash_while_responding(self):
205
sync = threading.Event()
202
# We want to ensure the exception has been caught
203
caught = threading.Event()
205
# The thread that will serve the client, this needs to be an attribute
206
# so the handler below can modify it when it's executed (it's
207
# instantiated when the request is processed)
208
self.connection_thread = None
207
210
class FailToRespond(Exception):
210
213
class FailingDuringResponseHandler(TCPConnectionHandler):
212
def handle_connection(self):
213
req = self.readline()
214
threading.currentThread().set_sync_event(sync)
215
def handle_connection(request):
216
req = request.readline()
217
# Capture the thread and make it use 'caught' so we can wait on
218
# the even that will be set when the exception is caught. We
219
# also capture the thread to know where to look.
220
self.connection_thread = threading.currentThread()
221
self.connection_thread.set_sync_event(caught)
215
222
raise FailToRespond()
217
224
server = self.get_server(
219
226
client = self.get_client()
220
227
client.connect((server.host, server.port))
221
228
client.write('ping\n')
229
# Wait for the exception to be caught
223
231
self.assertEqual('', client.read()) # connection closed
224
self.assertRaises(FailToRespond, server.pending_exception)
232
# Check that the connection thread did catch the exception,
233
# http://pad.lv/869366 was wrongly checking the server thread which
234
# works for TestingTCPServer where the connection is handled in the
235
# same thread than the server one but is racy for
236
# TestingThreadingTCPServer where the server thread may be in a
237
# blocking accept() call (or not).
239
self.connection_thread.pending_exception()
240
except FailToRespond:
241
# Great, the test succeeded
244
# If the exception is not in the connection thread anymore, it's in
246
server.server.stopped.wait()
247
# The exception is available now
248
self.assertRaises(FailToRespond, server.pending_exception)
226
250
def test_exception_swallowed_while_serving(self):
227
sync = threading.Event()
251
# We need to ensure the exception has been caught
252
caught = threading.Event()
254
# The thread that will serve the client, this needs to be an attribute
255
# so the handler below can access it when it's executed (it's
256
# instantiated when the request is processed)
257
self.connection_thread = None
229
258
class CantServe(Exception):
232
261
class FailingWhileServingConnectionHandler(TCPConnectionHandler):
235
# We want to sync with the thread that is serving the
237
threading.currentThread().set_sync_event(sync)
264
# Capture the thread and make it use 'caught' so we can wait on
265
# the even that will be set when the exception is caught. We
266
# also capture the thread to know where to look.
267
self.connection_thread = threading.currentThread()
268
self.connection_thread.set_sync_event(caught)
238
269
raise CantServe()
240
271
server = self.get_server(
244
275
client = self.get_client()
245
276
# Connect to the server so the exception is raised there
246
277
client.connect((server.host, server.port))
247
# Wait for the exception to propagate.
278
# Wait for the exception to be caught
249
280
self.assertEqual('', client.read()) # connection closed
250
281
# The connection wasn't served properly but the exception should have
282
# been swallowed (see test_server_crash_while_responding remark about
283
# http://pad.lv/869366 explaining why we can't check the server thread
284
# here). More precisely, the exception *has* been caught and captured
285
# but it is cleared when joining the thread (or trying to acquire the
286
# exception) and as such won't propagate to the server thread.
287
self.connection_thread.pending_exception()
252
288
server.pending_exception()
254
290
def test_handle_request_closes_if_it_doesnt_process(self):