blob: 57eb4fa5e07407c4bb4b5d5ad267991680cf290b [file] [log] [blame]
Guido van Rossumb5a755e2007-07-18 18:15:48 +00001import asyncore
2import unittest
3import select
4import os
5import socket
Guido van Rossumb5a755e2007-07-18 18:15:48 +00006import sys
7import time
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +00008import warnings
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +00009import errno
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +010010import struct
Guido van Rossumb5a755e2007-07-18 18:15:48 +000011
Benjamin Petersonee8712c2008-05-20 21:35:26 +000012from test import support
13from test.support import TESTFN, run_unittest, unlink
Christian Heimes5e696852008-04-09 08:37:03 +000014from io import BytesIO
15from io import StringIO
Guido van Rossumb5a755e2007-07-18 18:15:48 +000016
Victor Stinner45df8202010-04-28 22:31:17 +000017try:
18 import threading
19except ImportError:
20 threading = None
21
Benjamin Petersonee8712c2008-05-20 21:35:26 +000022HOST = support.HOST
Guido van Rossumb5a755e2007-07-18 18:15:48 +000023
Charles-François Natalie3540b42011-08-25 00:50:41 +020024HAS_UNIX_SOCKETS = hasattr(socket, 'AF_UNIX')
25
Guido van Rossumb5a755e2007-07-18 18:15:48 +000026class dummysocket:
27 def __init__(self):
28 self.closed = False
29
30 def close(self):
31 self.closed = True
32
33 def fileno(self):
34 return 42
35
36class dummychannel:
37 def __init__(self):
38 self.socket = dummysocket()
39
Josiah Carlsond74900e2008-07-07 04:15:08 +000040 def close(self):
41 self.socket.close()
42
Guido van Rossumb5a755e2007-07-18 18:15:48 +000043class exitingdummy:
44 def __init__(self):
45 pass
46
47 def handle_read_event(self):
48 raise asyncore.ExitNow()
49
50 handle_write_event = handle_read_event
Josiah Carlson91823c72008-07-11 23:26:37 +000051 handle_close = handle_read_event
Guido van Rossumb5a755e2007-07-18 18:15:48 +000052 handle_expt_event = handle_read_event
53
54class crashingdummy:
55 def __init__(self):
56 self.error_handled = False
57
58 def handle_read_event(self):
59 raise Exception()
60
61 handle_write_event = handle_read_event
Josiah Carlson91823c72008-07-11 23:26:37 +000062 handle_close = handle_read_event
Guido van Rossumb5a755e2007-07-18 18:15:48 +000063 handle_expt_event = handle_read_event
64
65 def handle_error(self):
66 self.error_handled = True
67
68# used when testing senders; just collects what it gets until newline is sent
Christian Heimes5e696852008-04-09 08:37:03 +000069def capture_server(evt, buf, serv):
Guido van Rossumb5a755e2007-07-18 18:15:48 +000070 try:
Guido van Rossum806c2462007-08-06 23:33:07 +000071 serv.listen(5)
Guido van Rossumb5a755e2007-07-18 18:15:48 +000072 conn, addr = serv.accept()
73 except socket.timeout:
74 pass
75 else:
76 n = 200
Kristján Valur Jónssonb2e58182012-04-06 14:37:45 +000077 start = time.time()
78 while n > 0 and time.time() - start < 3.0:
79 r, w, e = select.select([conn], [], [], 0.1)
Guido van Rossum36e0a922007-07-20 04:05:57 +000080 if r:
Kristján Valur Jónssonb2e58182012-04-06 14:37:45 +000081 n -= 1
Guido van Rossum36e0a922007-07-20 04:05:57 +000082 data = conn.recv(10)
Guido van Rossum36e0a922007-07-20 04:05:57 +000083 # keep everything except for the newline terminator
84 buf.write(data.replace(b'\n', b''))
85 if b'\n' in data:
86 break
Guido van Rossumb5a755e2007-07-18 18:15:48 +000087 time.sleep(0.01)
88
89 conn.close()
90 finally:
91 serv.close()
92 evt.set()
93
Charles-François Natalie78cbec2011-08-24 23:24:05 +020094def bind_af_aware(sock, addr):
95 """Helper function to bind a socket according to its family."""
Charles-François Natalie3540b42011-08-25 00:50:41 +020096 if HAS_UNIX_SOCKETS and sock.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +020097 # Make sure the path doesn't exist.
98 unlink(addr)
99 sock.bind(addr)
100
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000101
102class HelperFunctionTests(unittest.TestCase):
103 def test_readwriteexc(self):
104 # Check exception handling behavior of read, write and _exception
105
106 # check that ExitNow exceptions in the object handler method
107 # bubbles all the way up through asyncore read/write/_exception calls
108 tr1 = exitingdummy()
109 self.assertRaises(asyncore.ExitNow, asyncore.read, tr1)
110 self.assertRaises(asyncore.ExitNow, asyncore.write, tr1)
111 self.assertRaises(asyncore.ExitNow, asyncore._exception, tr1)
112
113 # check that an exception other than ExitNow in the object handler
114 # method causes the handle_error method to get called
115 tr2 = crashingdummy()
116 asyncore.read(tr2)
117 self.assertEqual(tr2.error_handled, True)
118
119 tr2 = crashingdummy()
120 asyncore.write(tr2)
121 self.assertEqual(tr2.error_handled, True)
122
123 tr2 = crashingdummy()
124 asyncore._exception(tr2)
125 self.assertEqual(tr2.error_handled, True)
126
Guido van Rossum806c2462007-08-06 23:33:07 +0000127 # asyncore.readwrite uses constants in the select module that
128 # are not present in Windows systems (see this thread:
129 # http://mail.python.org/pipermail/python-list/2001-October/109973.html)
130 # These constants should be present as long as poll is available
131
Ezio Melotti63c46402010-07-27 22:03:33 +0000132 @unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
133 def test_readwrite(self):
134 # Check that correct methods are called by readwrite()
Guido van Rossum806c2462007-08-06 23:33:07 +0000135
Ezio Melotti63c46402010-07-27 22:03:33 +0000136 attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
R. David Murray78532ba2009-04-12 15:35:44 +0000137
Ezio Melotti63c46402010-07-27 22:03:33 +0000138 expected = (
139 (select.POLLIN, 'read'),
140 (select.POLLPRI, 'expt'),
141 (select.POLLOUT, 'write'),
142 (select.POLLERR, 'closed'),
143 (select.POLLHUP, 'closed'),
144 (select.POLLNVAL, 'closed'),
145 )
R. David Murray78532ba2009-04-12 15:35:44 +0000146
Ezio Melotti63c46402010-07-27 22:03:33 +0000147 class testobj:
148 def __init__(self):
149 self.read = False
150 self.write = False
151 self.closed = False
152 self.expt = False
153 self.error_handled = False
Guido van Rossum806c2462007-08-06 23:33:07 +0000154
Ezio Melotti63c46402010-07-27 22:03:33 +0000155 def handle_read_event(self):
156 self.read = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000157
Ezio Melotti63c46402010-07-27 22:03:33 +0000158 def handle_write_event(self):
159 self.write = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000160
Ezio Melotti63c46402010-07-27 22:03:33 +0000161 def handle_close(self):
162 self.closed = True
Josiah Carlson9f2f8332008-07-07 05:04:12 +0000163
Ezio Melotti63c46402010-07-27 22:03:33 +0000164 def handle_expt_event(self):
165 self.expt = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000166
Ezio Melotti63c46402010-07-27 22:03:33 +0000167 def handle_error(self):
168 self.error_handled = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000169
Ezio Melotti63c46402010-07-27 22:03:33 +0000170 for flag, expectedattr in expected:
171 tobj = testobj()
172 self.assertEqual(getattr(tobj, expectedattr), False)
173 asyncore.readwrite(tobj, flag)
R. David Murray78532ba2009-04-12 15:35:44 +0000174
Ezio Melotti63c46402010-07-27 22:03:33 +0000175 # Only the attribute modified by the routine we expect to be
176 # called should be True.
177 for attr in attributes:
178 self.assertEqual(getattr(tobj, attr), attr==expectedattr)
Guido van Rossum806c2462007-08-06 23:33:07 +0000179
Ezio Melotti63c46402010-07-27 22:03:33 +0000180 # check that ExitNow exceptions in the object handler method
181 # bubbles all the way up through asyncore readwrite call
182 tr1 = exitingdummy()
183 self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
Guido van Rossum806c2462007-08-06 23:33:07 +0000184
Ezio Melotti63c46402010-07-27 22:03:33 +0000185 # check that an exception other than ExitNow in the object handler
186 # method causes the handle_error method to get called
187 tr2 = crashingdummy()
188 self.assertEqual(tr2.error_handled, False)
189 asyncore.readwrite(tr2, flag)
190 self.assertEqual(tr2.error_handled, True)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000191
192 def test_closeall(self):
193 self.closeall_check(False)
194
195 def test_closeall_default(self):
196 self.closeall_check(True)
197
198 def closeall_check(self, usedefault):
199 # Check that close_all() closes everything in a given map
200
201 l = []
202 testmap = {}
203 for i in range(10):
204 c = dummychannel()
205 l.append(c)
206 self.assertEqual(c.socket.closed, False)
207 testmap[i] = c
208
209 if usedefault:
210 socketmap = asyncore.socket_map
211 try:
212 asyncore.socket_map = testmap
213 asyncore.close_all()
214 finally:
215 testmap, asyncore.socket_map = asyncore.socket_map, socketmap
216 else:
217 asyncore.close_all(testmap)
218
219 self.assertEqual(len(testmap), 0)
220
221 for c in l:
222 self.assertEqual(c.socket.closed, True)
223
224 def test_compact_traceback(self):
225 try:
226 raise Exception("I don't like spam!")
227 except:
228 real_t, real_v, real_tb = sys.exc_info()
229 r = asyncore.compact_traceback()
230 else:
231 self.fail("Expected exception")
232
233 (f, function, line), t, v, info = r
234 self.assertEqual(os.path.split(f)[-1], 'test_asyncore.py')
235 self.assertEqual(function, 'test_compact_traceback')
236 self.assertEqual(t, real_t)
237 self.assertEqual(v, real_v)
238 self.assertEqual(info, '[%s|%s|%s]' % (f, function, line))
239
240
241class DispatcherTests(unittest.TestCase):
242 def setUp(self):
243 pass
244
245 def tearDown(self):
246 asyncore.close_all()
247
248 def test_basic(self):
249 d = asyncore.dispatcher()
250 self.assertEqual(d.readable(), True)
251 self.assertEqual(d.writable(), True)
252
253 def test_repr(self):
254 d = asyncore.dispatcher()
255 self.assertEqual(repr(d), '<asyncore.dispatcher at %#x>' % id(d))
256
257 def test_log(self):
258 d = asyncore.dispatcher()
259
260 # capture output of dispatcher.log() (to stderr)
261 fp = StringIO()
262 stderr = sys.stderr
263 l1 = "Lovely spam! Wonderful spam!"
264 l2 = "I don't like spam!"
265 try:
266 sys.stderr = fp
267 d.log(l1)
268 d.log(l2)
269 finally:
270 sys.stderr = stderr
271
272 lines = fp.getvalue().splitlines()
Ezio Melotti63c46402010-07-27 22:03:33 +0000273 self.assertEqual(lines, ['log: %s' % l1, 'log: %s' % l2])
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000274
275 def test_log_info(self):
276 d = asyncore.dispatcher()
277
278 # capture output of dispatcher.log_info() (to stdout via print)
279 fp = StringIO()
280 stdout = sys.stdout
281 l1 = "Have you got anything without spam?"
282 l2 = "Why can't she have egg bacon spam and sausage?"
283 l3 = "THAT'S got spam in it!"
284 try:
285 sys.stdout = fp
286 d.log_info(l1, 'EGGS')
287 d.log_info(l2)
288 d.log_info(l3, 'SPAM')
289 finally:
290 sys.stdout = stdout
291
292 lines = fp.getvalue().splitlines()
R. David Murray847f30e2009-04-13 01:22:04 +0000293 expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000294
Ezio Melotti63c46402010-07-27 22:03:33 +0000295 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000296
297 def test_unhandled(self):
298 d = asyncore.dispatcher()
R. David Murray78532ba2009-04-12 15:35:44 +0000299 d.ignore_log_types = ()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000300
301 # capture output of dispatcher.log_info() (to stdout via print)
302 fp = StringIO()
303 stdout = sys.stdout
304 try:
305 sys.stdout = fp
306 d.handle_expt()
307 d.handle_read()
308 d.handle_write()
309 d.handle_connect()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000310 finally:
311 sys.stdout = stdout
312
313 lines = fp.getvalue().splitlines()
R. David Murray78532ba2009-04-12 15:35:44 +0000314 expected = ['warning: unhandled incoming priority event',
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000315 'warning: unhandled read event',
316 'warning: unhandled write event',
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000317 'warning: unhandled connect event']
Ezio Melotti63c46402010-07-27 22:03:33 +0000318 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000319
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +0000320 def test_issue_8594(self):
321 # XXX - this test is supposed to be removed in next major Python
322 # version
323 d = asyncore.dispatcher(socket.socket())
324 # make sure the error message no longer refers to the socket
325 # object but the dispatcher instance instead
Ezio Melottied3a7d22010-12-01 02:32:32 +0000326 self.assertRaisesRegex(AttributeError, 'dispatcher instance',
327 getattr, d, 'foo')
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +0000328 # cheap inheritance with the underlying socket is supposed
329 # to still work but a DeprecationWarning is expected
330 with warnings.catch_warnings(record=True) as w:
331 warnings.simplefilter("always")
332 family = d.family
333 self.assertEqual(family, socket.AF_INET)
Ezio Melotti63c46402010-07-27 22:03:33 +0000334 self.assertEqual(len(w), 1)
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +0000335 self.assertTrue(issubclass(w[0].category, DeprecationWarning))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000336
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000337 def test_strerror(self):
338 # refers to bug #8573
339 err = asyncore._strerror(errno.EPERM)
340 if hasattr(os, 'strerror'):
341 self.assertEqual(err, os.strerror(errno.EPERM))
342 err = asyncore._strerror(-1)
Giampaolo Rodolàd2751fb2011-02-25 20:05:48 +0000343 self.assertTrue(err != "")
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000344
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000345
346class dispatcherwithsend_noread(asyncore.dispatcher_with_send):
347 def readable(self):
348 return False
349
350 def handle_connect(self):
351 pass
352
353class DispatcherWithSendTests(unittest.TestCase):
354 usepoll = False
355
356 def setUp(self):
357 pass
358
359 def tearDown(self):
360 asyncore.close_all()
361
Victor Stinner45df8202010-04-28 22:31:17 +0000362 @unittest.skipUnless(threading, 'Threading required for this test.')
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000363 @support.reap_threads
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000364 def test_send(self):
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000365 evt = threading.Event()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000366 sock = socket.socket()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000367 sock.settimeout(3)
368 port = support.bind_port(sock)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000369
Christian Heimes5e696852008-04-09 08:37:03 +0000370 cap = BytesIO()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000371 args = (evt, cap, sock)
372 t = threading.Thread(target=capture_server, args=args)
373 t.start()
374 try:
375 # wait a little longer for the server to initialize (it sometimes
376 # refuses connections on slow machines without this wait)
377 time.sleep(0.2)
Guido van Rossum806c2462007-08-06 23:33:07 +0000378
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000379 data = b"Suppose there isn't a 16-ton weight?"
380 d = dispatcherwithsend_noread()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000381 d.create_socket()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000382 d.connect((HOST, port))
Guido van Rossum806c2462007-08-06 23:33:07 +0000383
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000384 # give time for socket to connect
385 time.sleep(0.1)
Guido van Rossum806c2462007-08-06 23:33:07 +0000386
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000387 d.send(data)
388 d.send(data)
389 d.send(b'\n')
Guido van Rossum806c2462007-08-06 23:33:07 +0000390
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000391 n = 1000
392 while d.out_buffer and n > 0:
393 asyncore.poll()
394 n -= 1
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000395
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000396 evt.wait()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000397
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000398 self.assertEqual(cap.getvalue(), data*2)
399 finally:
400 t.join()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000401
402
403class DispatcherWithSendTests_UsePoll(DispatcherWithSendTests):
404 usepoll = True
405
Ezio Melotti63c46402010-07-27 22:03:33 +0000406@unittest.skipUnless(hasattr(asyncore, 'file_wrapper'),
407 'asyncore.file_wrapper required')
408class FileWrapperTest(unittest.TestCase):
409 def setUp(self):
410 self.d = b"It's not dead, it's sleeping!"
Brett Cannon2d562f82010-10-29 22:40:44 +0000411 with open(TESTFN, 'wb') as file:
412 file.write(self.d)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000413
Ezio Melotti63c46402010-07-27 22:03:33 +0000414 def tearDown(self):
415 unlink(TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000416
Ezio Melotti63c46402010-07-27 22:03:33 +0000417 def test_recv(self):
418 fd = os.open(TESTFN, os.O_RDONLY)
419 w = asyncore.file_wrapper(fd)
420 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000421
Ezio Melotti63c46402010-07-27 22:03:33 +0000422 self.assertNotEqual(w.fd, fd)
423 self.assertNotEqual(w.fileno(), fd)
424 self.assertEqual(w.recv(13), b"It's not dead")
425 self.assertEqual(w.read(6), b", it's")
426 w.close()
427 self.assertRaises(OSError, w.read, 1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000428
Ezio Melotti63c46402010-07-27 22:03:33 +0000429 def test_send(self):
430 d1 = b"Come again?"
431 d2 = b"I want to buy some cheese."
432 fd = os.open(TESTFN, os.O_WRONLY | os.O_APPEND)
433 w = asyncore.file_wrapper(fd)
434 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000435
Ezio Melotti63c46402010-07-27 22:03:33 +0000436 w.write(d1)
437 w.send(d2)
438 w.close()
Brett Cannon2d562f82010-10-29 22:40:44 +0000439 with open(TESTFN, 'rb') as file:
440 self.assertEqual(file.read(), self.d + d1 + d2)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000441
Georg Brandlcbb0ae42010-07-28 08:19:35 +0000442 @unittest.skipUnless(hasattr(asyncore, 'file_dispatcher'),
443 'asyncore.file_dispatcher required')
444 def test_dispatcher(self):
445 fd = os.open(TESTFN, os.O_RDONLY)
446 data = []
447 class FileDispatcher(asyncore.file_dispatcher):
448 def handle_read(self):
449 data.append(self.recv(29))
450 s = FileDispatcher(fd)
451 os.close(fd)
452 asyncore.loop(timeout=0.01, use_poll=True, count=2)
453 self.assertEqual(b"".join(data), self.d)
454
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000455
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000456class BaseTestHandler(asyncore.dispatcher):
457
458 def __init__(self, sock=None):
459 asyncore.dispatcher.__init__(self, sock)
460 self.flag = False
461
462 def handle_accept(self):
463 raise Exception("handle_accept not supposed to be called")
464
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000465 def handle_accepted(self):
466 raise Exception("handle_accepted not supposed to be called")
467
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000468 def handle_connect(self):
469 raise Exception("handle_connect not supposed to be called")
470
471 def handle_expt(self):
472 raise Exception("handle_expt not supposed to be called")
473
474 def handle_close(self):
475 raise Exception("handle_close not supposed to be called")
476
477 def handle_error(self):
478 raise
479
480
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200481class BaseServer(asyncore.dispatcher):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000482 """A server which listens on an address and dispatches the
483 connection to a handler.
484 """
485
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200486 def __init__(self, family, addr, handler=BaseTestHandler):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000487 asyncore.dispatcher.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200488 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000489 self.set_reuse_addr()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200490 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000491 self.listen(5)
492 self.handler = handler
493
494 @property
495 def address(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200496 return self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000497
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000498 def handle_accepted(self, sock, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000499 self.handler(sock)
500
501 def handle_error(self):
502 raise
503
504
505class BaseClient(BaseTestHandler):
506
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200507 def __init__(self, family, address):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000508 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200509 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000510 self.connect(address)
511
512 def handle_connect(self):
513 pass
514
515
Ezio Melotti47236db2013-01-10 05:28:52 +0200516class BaseTestAPI:
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000517
518 def tearDown(self):
519 asyncore.close_all()
520
521 def loop_waiting_for_flag(self, instance, timeout=5):
522 timeout = float(timeout) / 100
523 count = 100
524 while asyncore.socket_map and count > 0:
525 asyncore.loop(timeout=0.01, count=1, use_poll=self.use_poll)
526 if instance.flag:
527 return
528 count -= 1
529 time.sleep(timeout)
530 self.fail("flag not set")
531
532 def test_handle_connect(self):
533 # make sure handle_connect is called on connect()
534
535 class TestClient(BaseClient):
536 def handle_connect(self):
537 self.flag = True
538
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200539 server = BaseServer(self.family, self.addr)
540 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000541 self.loop_waiting_for_flag(client)
542
543 def test_handle_accept(self):
544 # make sure handle_accept() is called when a client connects
545
546 class TestListener(BaseTestHandler):
547
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200548 def __init__(self, family, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000549 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200550 self.create_socket(family)
551 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000552 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200553 self.address = self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000554
555 def handle_accept(self):
556 self.flag = True
557
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200558 server = TestListener(self.family, self.addr)
559 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000560 self.loop_waiting_for_flag(server)
561
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000562 def test_handle_accepted(self):
563 # make sure handle_accepted() is called when a client connects
564
565 class TestListener(BaseTestHandler):
566
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200567 def __init__(self, family, addr):
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000568 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200569 self.create_socket(family)
570 bind_af_aware(self.socket, addr)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000571 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200572 self.address = self.socket.getsockname()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000573
574 def handle_accept(self):
575 asyncore.dispatcher.handle_accept(self)
576
577 def handle_accepted(self, sock, addr):
Benjamin Petersond6868b42010-10-31 17:34:34 +0000578 sock.close()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000579 self.flag = True
580
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200581 server = TestListener(self.family, self.addr)
582 client = BaseClient(self.family, server.address)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000583 self.loop_waiting_for_flag(server)
584
585
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000586 def test_handle_read(self):
587 # make sure handle_read is called on data received
588
589 class TestClient(BaseClient):
590 def handle_read(self):
591 self.flag = True
592
593 class TestHandler(BaseTestHandler):
594 def __init__(self, conn):
595 BaseTestHandler.__init__(self, conn)
596 self.send(b'x' * 1024)
597
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200598 server = BaseServer(self.family, self.addr, TestHandler)
599 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000600 self.loop_waiting_for_flag(client)
601
602 def test_handle_write(self):
603 # make sure handle_write is called
604
605 class TestClient(BaseClient):
606 def handle_write(self):
607 self.flag = True
608
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200609 server = BaseServer(self.family, self.addr)
610 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000611 self.loop_waiting_for_flag(client)
612
613 def test_handle_close(self):
614 # make sure handle_close is called when the other end closes
615 # the connection
616
617 class TestClient(BaseClient):
618
619 def handle_read(self):
620 # in order to make handle_close be called we are supposed
621 # to make at least one recv() call
622 self.recv(1024)
623
624 def handle_close(self):
625 self.flag = True
626 self.close()
627
628 class TestHandler(BaseTestHandler):
629 def __init__(self, conn):
630 BaseTestHandler.__init__(self, conn)
631 self.close()
632
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200633 server = BaseServer(self.family, self.addr, TestHandler)
634 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000635 self.loop_waiting_for_flag(client)
636
Charles-François Natalid4621192011-10-29 12:45:56 +0200637 def test_handle_close_after_conn_broken(self):
638 # Check that ECONNRESET/EPIPE is correctly handled (issues #5661 and
639 # #11265).
640
641 data = b'\0' * 128
642
643 class TestClient(BaseClient):
644
645 def handle_write(self):
646 self.send(data)
647
648 def handle_close(self):
649 self.flag = True
650 self.close()
651
Charles-François Natalifea6cb02011-10-29 14:29:39 +0200652 def handle_expt(self):
653 self.flag = True
654 self.close()
655
Charles-François Natalid4621192011-10-29 12:45:56 +0200656 class TestHandler(BaseTestHandler):
657
658 def handle_read(self):
659 self.recv(len(data))
660 self.close()
661
662 def writable(self):
663 return False
664
665 server = BaseServer(self.family, self.addr, TestHandler)
666 client = TestClient(self.family, server.address)
667 self.loop_waiting_for_flag(client)
668
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000669 @unittest.skipIf(sys.platform.startswith("sunos"),
670 "OOB support is broken on Solaris")
671 def test_handle_expt(self):
672 # Make sure handle_expt is called on OOB data received.
673 # Note: this might fail on some platforms as OOB data is
674 # tenuously supported and rarely used.
Charles-François Natalie3540b42011-08-25 00:50:41 +0200675 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200676 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000677
678 class TestClient(BaseClient):
679 def handle_expt(self):
Charles-François Natalicf85c302011-11-02 20:30:59 +0100680 self.socket.recv(1024, socket.MSG_OOB)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000681 self.flag = True
682
683 class TestHandler(BaseTestHandler):
684 def __init__(self, conn):
685 BaseTestHandler.__init__(self, conn)
686 self.socket.send(bytes(chr(244), 'latin-1'), socket.MSG_OOB)
687
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200688 server = BaseServer(self.family, self.addr, TestHandler)
689 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000690 self.loop_waiting_for_flag(client)
691
692 def test_handle_error(self):
693
694 class TestClient(BaseClient):
695 def handle_write(self):
696 1.0 / 0
697 def handle_error(self):
698 self.flag = True
699 try:
700 raise
701 except ZeroDivisionError:
702 pass
703 else:
704 raise Exception("exception not raised")
705
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200706 server = BaseServer(self.family, self.addr)
707 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000708 self.loop_waiting_for_flag(client)
709
710 def test_connection_attributes(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200711 server = BaseServer(self.family, self.addr)
712 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000713
714 # we start disconnected
715 self.assertFalse(server.connected)
716 self.assertTrue(server.accepting)
Giampaolo Rodolà340d7d22010-05-12 00:33:15 +0000717 # this can't be taken for granted across all platforms
718 #self.assertFalse(client.connected)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000719 self.assertFalse(client.accepting)
720
721 # execute some loops so that client connects to server
722 asyncore.loop(timeout=0.01, use_poll=self.use_poll, count=100)
723 self.assertFalse(server.connected)
724 self.assertTrue(server.accepting)
725 self.assertTrue(client.connected)
726 self.assertFalse(client.accepting)
727
728 # disconnect the client
729 client.close()
730 self.assertFalse(server.connected)
731 self.assertTrue(server.accepting)
732 self.assertFalse(client.connected)
733 self.assertFalse(client.accepting)
734
735 # stop serving
736 server.close()
737 self.assertFalse(server.connected)
738 self.assertFalse(server.accepting)
739
740 def test_create_socket(self):
741 s = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200742 s.create_socket(self.family)
743 self.assertEqual(s.socket.family, self.family)
Antoine Pitroub1c54962010-10-14 15:05:38 +0000744 SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
745 self.assertEqual(s.socket.type, socket.SOCK_STREAM | SOCK_NONBLOCK)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000746
747 def test_bind(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200748 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200749 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000750 s1 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200751 s1.create_socket(self.family)
752 s1.bind(self.addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000753 s1.listen(5)
754 port = s1.socket.getsockname()[1]
755
756 s2 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200757 s2.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000758 # EADDRINUSE indicates the socket was correctly bound
Andrew Svetlov0832af62012-12-18 23:10:48 +0200759 self.assertRaises(OSError, s2.bind, (self.addr[0], port))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000760
761 def test_set_reuse_addr(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200762 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200763 self.skipTest("Not applicable to AF_UNIX sockets.")
764 sock = socket.socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000765 try:
766 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200767 except OSError:
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000768 unittest.skip("SO_REUSEADDR not supported on this platform")
769 else:
770 # if SO_REUSEADDR succeeded for sock we expect asyncore
771 # to do the same
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200772 s = asyncore.dispatcher(socket.socket(self.family))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000773 self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
774 socket.SO_REUSEADDR))
Benjamin Petersond6868b42010-10-31 17:34:34 +0000775 s.socket.close()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200776 s.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000777 s.set_reuse_addr()
778 self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
779 socket.SO_REUSEADDR))
780 finally:
781 sock.close()
782
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100783 @unittest.skipUnless(threading, 'Threading required for this test.')
784 @support.reap_threads
785 def test_quick_connect(self):
786 # see: http://bugs.python.org/issue10340
Giampaolo Rodola'466a54f2012-03-23 13:29:01 +0100787 if self.family in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
788 server = BaseServer(self.family, self.addr)
789 t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
790 count=500))
791 t.start()
Charles-François Natali1ea12ff2013-01-13 14:08:01 +0100792 self.addCleanup(t.join)
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100793
Giampaolo Rodola'c7ea19f2012-03-23 15:09:58 +0100794 s = socket.socket(self.family, socket.SOCK_STREAM)
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100795 s.settimeout(.2)
Ezio Melotti9a381c72010-07-27 22:24:13 +0000796 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
797 struct.pack('ii', 1, 0))
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100798 try:
799 s.connect(server.address)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200800 except OSError:
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100801 pass
802 finally:
803 s.close()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000804
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200805class TestAPI_UseIPv4Sockets(BaseTestAPI):
806 family = socket.AF_INET
807 addr = (HOST, 0)
808
809@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 support required')
810class TestAPI_UseIPv6Sockets(BaseTestAPI):
811 family = socket.AF_INET6
812 addr = ('::1', 0)
813
Charles-François Natalie3540b42011-08-25 00:50:41 +0200814@unittest.skipUnless(HAS_UNIX_SOCKETS, 'Unix sockets required')
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200815class TestAPI_UseUnixSockets(BaseTestAPI):
Charles-François Natalia045c052011-08-25 01:22:50 +0200816 if HAS_UNIX_SOCKETS:
817 family = socket.AF_UNIX
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200818 addr = support.TESTFN
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200819
820 def tearDown(self):
821 unlink(self.addr)
822 BaseTestAPI.tearDown(self)
823
Ezio Melotti47236db2013-01-10 05:28:52 +0200824class TestAPI_UseIPv4Select(TestAPI_UseIPv4Sockets, unittest.TestCase):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000825 use_poll = False
826
827@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200828class TestAPI_UseIPv4Poll(TestAPI_UseIPv4Sockets, unittest.TestCase):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000829 use_poll = True
830
Ezio Melotti47236db2013-01-10 05:28:52 +0200831class TestAPI_UseIPv6Select(TestAPI_UseIPv6Sockets, unittest.TestCase):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200832 use_poll = False
833
834@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200835class TestAPI_UseIPv6Poll(TestAPI_UseIPv6Sockets, unittest.TestCase):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200836 use_poll = True
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000837
Ezio Melotti47236db2013-01-10 05:28:52 +0200838class TestAPI_UseUnixSocketsSelect(TestAPI_UseUnixSockets, unittest.TestCase):
Charles-François Natali39648d12011-10-31 12:08:09 +0100839 use_poll = False
840
841@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200842class TestAPI_UseUnixSocketsPoll(TestAPI_UseUnixSockets, unittest.TestCase):
Charles-François Natali39648d12011-10-31 12:08:09 +0100843 use_poll = True
844
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000845if __name__ == "__main__":
Ezio Melotti47236db2013-01-10 05:28:52 +0200846 unittest.main()