31
30
load_tests = load_tests_apply_scenarios
34
def portable_socket_pair():
35
"""Return a pair of TCP sockets connected to each other.
37
Unlike socket.socketpair, this should work on Windows.
39
listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
40
listen_sock.bind(('127.0.0.1', 0))
42
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
43
client_sock.connect(listen_sock.getsockname())
44
server_sock, addr = listen_sock.accept()
46
return server_sock, client_sock
49
33
class TCPClient(object):
51
35
def __init__(self):
85
69
while not self.done:
86
70
self.handle_connection()
89
# TODO: We should be buffering any extra data sent, etc. However, in
90
# practice, we don't send extra content, so we haven't bothered
91
# to implement it yet.
92
req = self.request.recv(4096)
93
# An empty string is allowed, to indicate the end of the connection
94
if not req or (req.endswith('\n') and req.count('\n') == 1):
96
raise ValueError('[%r] not a simple line' % (req,))
98
72
def handle_connection(self):
73
req = self.rfile.readline()
102
76
elif req == 'ping\n':
103
self.request.sendall('pong\n')
77
self.wfile.write('pong\n')
105
79
raise ValueError('[%s] not understood' % req)
108
82
class TestTCPServerInAThread(tests.TestCase):
111
85
(name, {'server_class': getattr(test_server, name)})
113
87
('TestingTCPServer', 'TestingThreadingTCPServer')]
120
94
self.server_class = server_class
121
95
if connection_handler_class is None:
122
96
connection_handler_class = TCPConnectionHandler
123
server = test_server.TestingTCPServerInAThread(
97
server = test_server.TestingTCPServerInAThread(
124
98
('localhost', 0), self.server_class, connection_handler_class)
125
99
server.start_server()
126
100
self.addCleanup(server.stop_server)
184
158
# The server won't fail until a client connect
185
159
client = self.get_client()
186
160
client.connect((server.host, server.port))
187
# We make sure the server wants to handle a request, but the request is
188
# guaranteed to fail. However, the server should make sure that the
189
# connection gets closed, and stop_server should then raise the
190
# original exception.
191
client.write('ping\n')
193
self.assertEqual('', client.read())
194
except socket.error, e:
195
# On Windows, failing during 'handle' means we get
196
# 'forced-close-of-connection'. Possibly because we haven't
197
# processed the write request before we close the socket.
198
WSAECONNRESET = 10054
199
if e.errno in (WSAECONNRESET,):
162
# Now we must force the server to answer by sending the request and
163
# waiting for some answer. But since we don't control when the
164
# server thread will be given cycles, we don't control either
165
# whether our reads or writes may hang.
166
client.sock.settimeout(0.1)
167
client.write('ping\n')
201
171
# Now the server has raised the exception in its own thread
202
172
self.assertRaises(CantConnect, server.stop_server)
246
215
client.connect((server.host, server.port))
247
216
# Wait for the exception to propagate.
249
self.assertEqual('', client.read()) # connection closed
250
218
# The connection wasn't served properly but the exception should have
251
219
# been swallowed.
252
220
server.pending_exception()
254
def test_handle_request_closes_if_it_doesnt_process(self):
255
server = self.get_server()
256
client = self.get_client()
257
server.server.serving = False
258
client.connect((server.host, server.port))
259
self.assertEqual('', client.read())
262
class TestTestingSmartServer(tests.TestCase):
264
def test_sets_client_timeout(self):
265
server = test_server.TestingSmartServer(('localhost', 0), None, None,
266
root_client_path='/no-such-client/path')
267
self.assertEqual(test_server._DEFAULT_TESTING_CLIENT_TIMEOUT,
268
server._client_timeout)
269
sock = socket.socket()
270
h = server._make_handler(sock)
271
self.assertEqual(test_server._DEFAULT_TESTING_CLIENT_TIMEOUT,
275
class FakeServer(object):
276
"""Minimal implementation to pass to TestingSmartConnectionHandler"""
277
backing_transport = None
278
root_client_path = '/'
281
class TestTestingSmartConnectionHandler(tests.TestCase):
283
def test_connection_timeout_suppressed(self):
284
self.overrideAttr(test_server, '_DEFAULT_TESTING_CLIENT_TIMEOUT', 0.01)
286
server_sock, client_sock = portable_socket_pair()
287
# This should timeout quickly, but not generate an exception.
288
handler = test_server.TestingSmartConnectionHandler(server_sock,
289
server_sock.getpeername(), s)
291
def test_connection_shutdown_while_serving_no_error(self):
293
server_sock, client_sock = portable_socket_pair()
294
class ShutdownConnectionHandler(
295
test_server.TestingSmartConnectionHandler):
297
def _build_protocol(self):
299
return super(ShutdownConnectionHandler, self)._build_protocol()
300
# This should trigger shutdown after the entering _build_protocol, and
301
# we should exit cleanly, without raising an exception.
302
handler = ShutdownConnectionHandler(server_sock,
303
server_sock.getpeername(), s)