blob: 1123c251ebd4ad29e9e031ed29db36a8936f458b [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
77 while n > 0:
Guido van Rossum36e0a922007-07-20 04:05:57 +000078 r, w, e = select.select([conn], [], [])
79 if r:
80 data = conn.recv(10)
Guido van Rossum36e0a922007-07-20 04:05:57 +000081 # keep everything except for the newline terminator
82 buf.write(data.replace(b'\n', b''))
83 if b'\n' in data:
84 break
Guido van Rossumb5a755e2007-07-18 18:15:48 +000085 n -= 1
86 time.sleep(0.01)
87
88 conn.close()
89 finally:
90 serv.close()
91 evt.set()
92
Charles-François Natalie78cbec2011-08-24 23:24:05 +020093def bind_af_aware(sock, addr):
94 """Helper function to bind a socket according to its family."""
Charles-François Natalie3540b42011-08-25 00:50:41 +020095 if HAS_UNIX_SOCKETS and sock.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +020096 # Make sure the path doesn't exist.
97 unlink(addr)
98 sock.bind(addr)
99
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000100
101class HelperFunctionTests(unittest.TestCase):
102 def test_readwriteexc(self):
103 # Check exception handling behavior of read, write and _exception
104
105 # check that ExitNow exceptions in the object handler method
106 # bubbles all the way up through asyncore read/write/_exception calls
107 tr1 = exitingdummy()
108 self.assertRaises(asyncore.ExitNow, asyncore.read, tr1)
109 self.assertRaises(asyncore.ExitNow, asyncore.write, tr1)
110 self.assertRaises(asyncore.ExitNow, asyncore._exception, tr1)
111
112 # check that an exception other than ExitNow in the object handler
113 # method causes the handle_error method to get called
114 tr2 = crashingdummy()
115 asyncore.read(tr2)
116 self.assertEqual(tr2.error_handled, True)
117
118 tr2 = crashingdummy()
119 asyncore.write(tr2)
120 self.assertEqual(tr2.error_handled, True)
121
122 tr2 = crashingdummy()
123 asyncore._exception(tr2)
124 self.assertEqual(tr2.error_handled, True)
125
Guido van Rossum806c2462007-08-06 23:33:07 +0000126 # asyncore.readwrite uses constants in the select module that
127 # are not present in Windows systems (see this thread:
128 # http://mail.python.org/pipermail/python-list/2001-October/109973.html)
129 # These constants should be present as long as poll is available
130
Ezio Melotti63c46402010-07-27 22:03:33 +0000131 @unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
132 def test_readwrite(self):
133 # Check that correct methods are called by readwrite()
Guido van Rossum806c2462007-08-06 23:33:07 +0000134
Ezio Melotti63c46402010-07-27 22:03:33 +0000135 attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
R. David Murray78532ba2009-04-12 15:35:44 +0000136
Ezio Melotti63c46402010-07-27 22:03:33 +0000137 expected = (
138 (select.POLLIN, 'read'),
139 (select.POLLPRI, 'expt'),
140 (select.POLLOUT, 'write'),
141 (select.POLLERR, 'closed'),
142 (select.POLLHUP, 'closed'),
143 (select.POLLNVAL, 'closed'),
144 )
R. David Murray78532ba2009-04-12 15:35:44 +0000145
Ezio Melotti63c46402010-07-27 22:03:33 +0000146 class testobj:
147 def __init__(self):
148 self.read = False
149 self.write = False
150 self.closed = False
151 self.expt = False
152 self.error_handled = False
Guido van Rossum806c2462007-08-06 23:33:07 +0000153
Ezio Melotti63c46402010-07-27 22:03:33 +0000154 def handle_read_event(self):
155 self.read = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000156
Ezio Melotti63c46402010-07-27 22:03:33 +0000157 def handle_write_event(self):
158 self.write = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000159
Ezio Melotti63c46402010-07-27 22:03:33 +0000160 def handle_close(self):
161 self.closed = True
Josiah Carlson9f2f8332008-07-07 05:04:12 +0000162
Ezio Melotti63c46402010-07-27 22:03:33 +0000163 def handle_expt_event(self):
164 self.expt = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000165
Ezio Melotti63c46402010-07-27 22:03:33 +0000166 def handle_error(self):
167 self.error_handled = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000168
Ezio Melotti63c46402010-07-27 22:03:33 +0000169 for flag, expectedattr in expected:
170 tobj = testobj()
171 self.assertEqual(getattr(tobj, expectedattr), False)
172 asyncore.readwrite(tobj, flag)
R. David Murray78532ba2009-04-12 15:35:44 +0000173
Ezio Melotti63c46402010-07-27 22:03:33 +0000174 # Only the attribute modified by the routine we expect to be
175 # called should be True.
176 for attr in attributes:
177 self.assertEqual(getattr(tobj, attr), attr==expectedattr)
Guido van Rossum806c2462007-08-06 23:33:07 +0000178
Ezio Melotti63c46402010-07-27 22:03:33 +0000179 # check that ExitNow exceptions in the object handler method
180 # bubbles all the way up through asyncore readwrite call
181 tr1 = exitingdummy()
182 self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
Guido van Rossum806c2462007-08-06 23:33:07 +0000183
Ezio Melotti63c46402010-07-27 22:03:33 +0000184 # check that an exception other than ExitNow in the object handler
185 # method causes the handle_error method to get called
186 tr2 = crashingdummy()
187 self.assertEqual(tr2.error_handled, False)
188 asyncore.readwrite(tr2, flag)
189 self.assertEqual(tr2.error_handled, True)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000190
191 def test_closeall(self):
192 self.closeall_check(False)
193
194 def test_closeall_default(self):
195 self.closeall_check(True)
196
197 def closeall_check(self, usedefault):
198 # Check that close_all() closes everything in a given map
199
200 l = []
201 testmap = {}
202 for i in range(10):
203 c = dummychannel()
204 l.append(c)
205 self.assertEqual(c.socket.closed, False)
206 testmap[i] = c
207
208 if usedefault:
209 socketmap = asyncore.socket_map
210 try:
211 asyncore.socket_map = testmap
212 asyncore.close_all()
213 finally:
214 testmap, asyncore.socket_map = asyncore.socket_map, socketmap
215 else:
216 asyncore.close_all(testmap)
217
218 self.assertEqual(len(testmap), 0)
219
220 for c in l:
221 self.assertEqual(c.socket.closed, True)
222
223 def test_compact_traceback(self):
224 try:
225 raise Exception("I don't like spam!")
226 except:
227 real_t, real_v, real_tb = sys.exc_info()
228 r = asyncore.compact_traceback()
229 else:
230 self.fail("Expected exception")
231
232 (f, function, line), t, v, info = r
233 self.assertEqual(os.path.split(f)[-1], 'test_asyncore.py')
234 self.assertEqual(function, 'test_compact_traceback')
235 self.assertEqual(t, real_t)
236 self.assertEqual(v, real_v)
237 self.assertEqual(info, '[%s|%s|%s]' % (f, function, line))
238
239
240class DispatcherTests(unittest.TestCase):
241 def setUp(self):
242 pass
243
244 def tearDown(self):
245 asyncore.close_all()
246
247 def test_basic(self):
248 d = asyncore.dispatcher()
249 self.assertEqual(d.readable(), True)
250 self.assertEqual(d.writable(), True)
251
252 def test_repr(self):
253 d = asyncore.dispatcher()
254 self.assertEqual(repr(d), '<asyncore.dispatcher at %#x>' % id(d))
255
256 def test_log(self):
257 d = asyncore.dispatcher()
258
259 # capture output of dispatcher.log() (to stderr)
260 fp = StringIO()
261 stderr = sys.stderr
262 l1 = "Lovely spam! Wonderful spam!"
263 l2 = "I don't like spam!"
264 try:
265 sys.stderr = fp
266 d.log(l1)
267 d.log(l2)
268 finally:
269 sys.stderr = stderr
270
271 lines = fp.getvalue().splitlines()
Ezio Melotti63c46402010-07-27 22:03:33 +0000272 self.assertEqual(lines, ['log: %s' % l1, 'log: %s' % l2])
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000273
274 def test_log_info(self):
275 d = asyncore.dispatcher()
276
277 # capture output of dispatcher.log_info() (to stdout via print)
278 fp = StringIO()
279 stdout = sys.stdout
280 l1 = "Have you got anything without spam?"
281 l2 = "Why can't she have egg bacon spam and sausage?"
282 l3 = "THAT'S got spam in it!"
283 try:
284 sys.stdout = fp
285 d.log_info(l1, 'EGGS')
286 d.log_info(l2)
287 d.log_info(l3, 'SPAM')
288 finally:
289 sys.stdout = stdout
290
291 lines = fp.getvalue().splitlines()
R. David Murray847f30e2009-04-13 01:22:04 +0000292 expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000293
Ezio Melotti63c46402010-07-27 22:03:33 +0000294 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000295
296 def test_unhandled(self):
297 d = asyncore.dispatcher()
R. David Murray78532ba2009-04-12 15:35:44 +0000298 d.ignore_log_types = ()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000299
300 # capture output of dispatcher.log_info() (to stdout via print)
301 fp = StringIO()
302 stdout = sys.stdout
303 try:
304 sys.stdout = fp
305 d.handle_expt()
306 d.handle_read()
307 d.handle_write()
308 d.handle_connect()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000309 finally:
310 sys.stdout = stdout
311
312 lines = fp.getvalue().splitlines()
R. David Murray78532ba2009-04-12 15:35:44 +0000313 expected = ['warning: unhandled incoming priority event',
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000314 'warning: unhandled read event',
315 'warning: unhandled write event',
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000316 'warning: unhandled connect event']
Ezio Melotti63c46402010-07-27 22:03:33 +0000317 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000318
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +0000319 def test_issue_8594(self):
320 # XXX - this test is supposed to be removed in next major Python
321 # version
322 d = asyncore.dispatcher(socket.socket())
323 # make sure the error message no longer refers to the socket
324 # object but the dispatcher instance instead
Ezio Melottied3a7d22010-12-01 02:32:32 +0000325 self.assertRaisesRegex(AttributeError, 'dispatcher instance',
326 getattr, d, 'foo')
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +0000327 # cheap inheritance with the underlying socket is supposed
328 # to still work but a DeprecationWarning is expected
329 with warnings.catch_warnings(record=True) as w:
330 warnings.simplefilter("always")
331 family = d.family
332 self.assertEqual(family, socket.AF_INET)
Ezio Melotti63c46402010-07-27 22:03:33 +0000333 self.assertEqual(len(w), 1)
Giampaolo Rodolà8d2dc852010-05-06 18:06:30 +0000334 self.assertTrue(issubclass(w[0].category, DeprecationWarning))
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000335
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000336 def test_strerror(self):
337 # refers to bug #8573
338 err = asyncore._strerror(errno.EPERM)
339 if hasattr(os, 'strerror'):
340 self.assertEqual(err, os.strerror(errno.EPERM))
341 err = asyncore._strerror(-1)
Giampaolo Rodolàd2751fb2011-02-25 20:05:48 +0000342 self.assertTrue(err != "")
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000343
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000344
345class dispatcherwithsend_noread(asyncore.dispatcher_with_send):
346 def readable(self):
347 return False
348
349 def handle_connect(self):
350 pass
351
352class DispatcherWithSendTests(unittest.TestCase):
353 usepoll = False
354
355 def setUp(self):
356 pass
357
358 def tearDown(self):
359 asyncore.close_all()
360
Victor Stinner45df8202010-04-28 22:31:17 +0000361 @unittest.skipUnless(threading, 'Threading required for this test.')
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000362 @support.reap_threads
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000363 def test_send(self):
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000364 evt = threading.Event()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000365 sock = socket.socket()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000366 sock.settimeout(3)
367 port = support.bind_port(sock)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000368
Christian Heimes5e696852008-04-09 08:37:03 +0000369 cap = BytesIO()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000370 args = (evt, cap, sock)
371 t = threading.Thread(target=capture_server, args=args)
372 t.start()
373 try:
374 # wait a little longer for the server to initialize (it sometimes
375 # refuses connections on slow machines without this wait)
376 time.sleep(0.2)
Guido van Rossum806c2462007-08-06 23:33:07 +0000377
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000378 data = b"Suppose there isn't a 16-ton weight?"
379 d = dispatcherwithsend_noread()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000380 d.create_socket()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000381 d.connect((HOST, port))
Guido van Rossum806c2462007-08-06 23:33:07 +0000382
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000383 # give time for socket to connect
384 time.sleep(0.1)
Guido van Rossum806c2462007-08-06 23:33:07 +0000385
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000386 d.send(data)
387 d.send(data)
388 d.send(b'\n')
Guido van Rossum806c2462007-08-06 23:33:07 +0000389
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000390 n = 1000
391 while d.out_buffer and n > 0:
392 asyncore.poll()
393 n -= 1
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000394
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000395 evt.wait()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000396
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000397 self.assertEqual(cap.getvalue(), data*2)
398 finally:
399 t.join()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000400
401
402class DispatcherWithSendTests_UsePoll(DispatcherWithSendTests):
403 usepoll = True
404
Ezio Melotti63c46402010-07-27 22:03:33 +0000405@unittest.skipUnless(hasattr(asyncore, 'file_wrapper'),
406 'asyncore.file_wrapper required')
407class FileWrapperTest(unittest.TestCase):
408 def setUp(self):
409 self.d = b"It's not dead, it's sleeping!"
Brett Cannon2d562f82010-10-29 22:40:44 +0000410 with open(TESTFN, 'wb') as file:
411 file.write(self.d)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000412
Ezio Melotti63c46402010-07-27 22:03:33 +0000413 def tearDown(self):
414 unlink(TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000415
Ezio Melotti63c46402010-07-27 22:03:33 +0000416 def test_recv(self):
417 fd = os.open(TESTFN, os.O_RDONLY)
418 w = asyncore.file_wrapper(fd)
419 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000420
Ezio Melotti63c46402010-07-27 22:03:33 +0000421 self.assertNotEqual(w.fd, fd)
422 self.assertNotEqual(w.fileno(), fd)
423 self.assertEqual(w.recv(13), b"It's not dead")
424 self.assertEqual(w.read(6), b", it's")
425 w.close()
426 self.assertRaises(OSError, w.read, 1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000427
Ezio Melotti63c46402010-07-27 22:03:33 +0000428 def test_send(self):
429 d1 = b"Come again?"
430 d2 = b"I want to buy some cheese."
431 fd = os.open(TESTFN, os.O_WRONLY | os.O_APPEND)
432 w = asyncore.file_wrapper(fd)
433 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000434
Ezio Melotti63c46402010-07-27 22:03:33 +0000435 w.write(d1)
436 w.send(d2)
437 w.close()
Brett Cannon2d562f82010-10-29 22:40:44 +0000438 with open(TESTFN, 'rb') as file:
439 self.assertEqual(file.read(), self.d + d1 + d2)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000440
Georg Brandlcbb0ae42010-07-28 08:19:35 +0000441 @unittest.skipUnless(hasattr(asyncore, 'file_dispatcher'),
442 'asyncore.file_dispatcher required')
443 def test_dispatcher(self):
444 fd = os.open(TESTFN, os.O_RDONLY)
445 data = []
446 class FileDispatcher(asyncore.file_dispatcher):
447 def handle_read(self):
448 data.append(self.recv(29))
449 s = FileDispatcher(fd)
450 os.close(fd)
451 asyncore.loop(timeout=0.01, use_poll=True, count=2)
452 self.assertEqual(b"".join(data), self.d)
453
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000454
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000455class BaseTestHandler(asyncore.dispatcher):
456
457 def __init__(self, sock=None):
458 asyncore.dispatcher.__init__(self, sock)
459 self.flag = False
460
461 def handle_accept(self):
462 raise Exception("handle_accept not supposed to be called")
463
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000464 def handle_accepted(self):
465 raise Exception("handle_accepted not supposed to be called")
466
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000467 def handle_connect(self):
468 raise Exception("handle_connect not supposed to be called")
469
470 def handle_expt(self):
471 raise Exception("handle_expt not supposed to be called")
472
473 def handle_close(self):
474 raise Exception("handle_close not supposed to be called")
475
476 def handle_error(self):
477 raise
478
479
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200480class BaseServer(asyncore.dispatcher):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000481 """A server which listens on an address and dispatches the
482 connection to a handler.
483 """
484
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200485 def __init__(self, family, addr, handler=BaseTestHandler):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000486 asyncore.dispatcher.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200487 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000488 self.set_reuse_addr()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200489 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000490 self.listen(5)
491 self.handler = handler
492
493 @property
494 def address(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200495 return self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000496
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000497 def handle_accepted(self, sock, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000498 self.handler(sock)
499
500 def handle_error(self):
501 raise
502
503
504class BaseClient(BaseTestHandler):
505
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200506 def __init__(self, family, address):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000507 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200508 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000509 self.connect(address)
510
511 def handle_connect(self):
512 pass
513
514
515class BaseTestAPI(unittest.TestCase):
516
517 def tearDown(self):
518 asyncore.close_all()
519
520 def loop_waiting_for_flag(self, instance, timeout=5):
521 timeout = float(timeout) / 100
522 count = 100
523 while asyncore.socket_map and count > 0:
524 asyncore.loop(timeout=0.01, count=1, use_poll=self.use_poll)
525 if instance.flag:
526 return
527 count -= 1
528 time.sleep(timeout)
529 self.fail("flag not set")
530
531 def test_handle_connect(self):
532 # make sure handle_connect is called on connect()
533
534 class TestClient(BaseClient):
535 def handle_connect(self):
536 self.flag = True
537
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200538 server = BaseServer(self.family, self.addr)
539 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000540 self.loop_waiting_for_flag(client)
541
542 def test_handle_accept(self):
543 # make sure handle_accept() is called when a client connects
544
545 class TestListener(BaseTestHandler):
546
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200547 def __init__(self, family, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000548 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200549 self.create_socket(family)
550 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000551 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200552 self.address = self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000553
554 def handle_accept(self):
555 self.flag = True
556
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200557 server = TestListener(self.family, self.addr)
558 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000559 self.loop_waiting_for_flag(server)
560
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000561 def test_handle_accepted(self):
562 # make sure handle_accepted() is called when a client connects
563
564 class TestListener(BaseTestHandler):
565
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200566 def __init__(self, family, addr):
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000567 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200568 self.create_socket(family)
569 bind_af_aware(self.socket, addr)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000570 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200571 self.address = self.socket.getsockname()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000572
573 def handle_accept(self):
574 asyncore.dispatcher.handle_accept(self)
575
576 def handle_accepted(self, sock, addr):
Benjamin Petersond6868b42010-10-31 17:34:34 +0000577 sock.close()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000578 self.flag = True
579
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200580 server = TestListener(self.family, self.addr)
581 client = BaseClient(self.family, server.address)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000582 self.loop_waiting_for_flag(server)
583
584
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000585 def test_handle_read(self):
586 # make sure handle_read is called on data received
587
588 class TestClient(BaseClient):
589 def handle_read(self):
590 self.flag = True
591
592 class TestHandler(BaseTestHandler):
593 def __init__(self, conn):
594 BaseTestHandler.__init__(self, conn)
595 self.send(b'x' * 1024)
596
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200597 server = BaseServer(self.family, self.addr, TestHandler)
598 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000599 self.loop_waiting_for_flag(client)
600
601 def test_handle_write(self):
602 # make sure handle_write is called
603
604 class TestClient(BaseClient):
605 def handle_write(self):
606 self.flag = True
607
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200608 server = BaseServer(self.family, self.addr)
609 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000610 self.loop_waiting_for_flag(client)
611
612 def test_handle_close(self):
613 # make sure handle_close is called when the other end closes
614 # the connection
615
616 class TestClient(BaseClient):
617
618 def handle_read(self):
619 # in order to make handle_close be called we are supposed
620 # to make at least one recv() call
621 self.recv(1024)
622
623 def handle_close(self):
624 self.flag = True
625 self.close()
626
627 class TestHandler(BaseTestHandler):
628 def __init__(self, conn):
629 BaseTestHandler.__init__(self, conn)
630 self.close()
631
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200632 server = BaseServer(self.family, self.addr, TestHandler)
633 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000634 self.loop_waiting_for_flag(client)
635
Charles-François Natalid4621192011-10-29 12:45:56 +0200636 def test_handle_close_after_conn_broken(self):
637 # Check that ECONNRESET/EPIPE is correctly handled (issues #5661 and
638 # #11265).
639
640 data = b'\0' * 128
641
642 class TestClient(BaseClient):
643
644 def handle_write(self):
645 self.send(data)
646
647 def handle_close(self):
648 self.flag = True
649 self.close()
650
Charles-François Natalifea6cb02011-10-29 14:29:39 +0200651 def handle_expt(self):
652 self.flag = True
653 self.close()
654
Charles-François Natalid4621192011-10-29 12:45:56 +0200655 class TestHandler(BaseTestHandler):
656
657 def handle_read(self):
658 self.recv(len(data))
659 self.close()
660
661 def writable(self):
662 return False
663
664 server = BaseServer(self.family, self.addr, TestHandler)
665 client = TestClient(self.family, server.address)
666 self.loop_waiting_for_flag(client)
667
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000668 @unittest.skipIf(sys.platform.startswith("sunos"),
669 "OOB support is broken on Solaris")
670 def test_handle_expt(self):
671 # Make sure handle_expt is called on OOB data received.
672 # Note: this might fail on some platforms as OOB data is
673 # tenuously supported and rarely used.
Charles-François Natalie3540b42011-08-25 00:50:41 +0200674 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200675 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000676
677 class TestClient(BaseClient):
678 def handle_expt(self):
Charles-François Natalicf85c302011-11-02 20:30:59 +0100679 self.socket.recv(1024, socket.MSG_OOB)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000680 self.flag = True
681
682 class TestHandler(BaseTestHandler):
683 def __init__(self, conn):
684 BaseTestHandler.__init__(self, conn)
685 self.socket.send(bytes(chr(244), 'latin-1'), socket.MSG_OOB)
686
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200687 server = BaseServer(self.family, self.addr, TestHandler)
688 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000689 self.loop_waiting_for_flag(client)
690
691 def test_handle_error(self):
692
693 class TestClient(BaseClient):
694 def handle_write(self):
695 1.0 / 0
696 def handle_error(self):
697 self.flag = True
698 try:
699 raise
700 except ZeroDivisionError:
701 pass
702 else:
703 raise Exception("exception not raised")
704
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200705 server = BaseServer(self.family, self.addr)
706 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000707 self.loop_waiting_for_flag(client)
708
709 def test_connection_attributes(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200710 server = BaseServer(self.family, self.addr)
711 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000712
713 # we start disconnected
714 self.assertFalse(server.connected)
715 self.assertTrue(server.accepting)
Giampaolo Rodolà340d7d22010-05-12 00:33:15 +0000716 # this can't be taken for granted across all platforms
717 #self.assertFalse(client.connected)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000718 self.assertFalse(client.accepting)
719
720 # execute some loops so that client connects to server
721 asyncore.loop(timeout=0.01, use_poll=self.use_poll, count=100)
722 self.assertFalse(server.connected)
723 self.assertTrue(server.accepting)
724 self.assertTrue(client.connected)
725 self.assertFalse(client.accepting)
726
727 # disconnect the client
728 client.close()
729 self.assertFalse(server.connected)
730 self.assertTrue(server.accepting)
731 self.assertFalse(client.connected)
732 self.assertFalse(client.accepting)
733
734 # stop serving
735 server.close()
736 self.assertFalse(server.connected)
737 self.assertFalse(server.accepting)
738
739 def test_create_socket(self):
740 s = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200741 s.create_socket(self.family)
742 self.assertEqual(s.socket.family, self.family)
Antoine Pitroub1c54962010-10-14 15:05:38 +0000743 SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
744 self.assertEqual(s.socket.type, socket.SOCK_STREAM | SOCK_NONBLOCK)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000745
746 def test_bind(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200747 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200748 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000749 s1 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200750 s1.create_socket(self.family)
751 s1.bind(self.addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000752 s1.listen(5)
753 port = s1.socket.getsockname()[1]
754
755 s2 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200756 s2.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000757 # EADDRINUSE indicates the socket was correctly bound
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200758 self.assertRaises(socket.error, s2.bind, (self.addr[0], port))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000759
760 def test_set_reuse_addr(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200761 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200762 self.skipTest("Not applicable to AF_UNIX sockets.")
763 sock = socket.socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000764 try:
765 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
766 except socket.error:
767 unittest.skip("SO_REUSEADDR not supported on this platform")
768 else:
769 # if SO_REUSEADDR succeeded for sock we expect asyncore
770 # to do the same
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200771 s = asyncore.dispatcher(socket.socket(self.family))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000772 self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
773 socket.SO_REUSEADDR))
Benjamin Petersond6868b42010-10-31 17:34:34 +0000774 s.socket.close()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200775 s.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000776 s.set_reuse_addr()
777 self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
778 socket.SO_REUSEADDR))
779 finally:
780 sock.close()
781
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100782 @unittest.skipUnless(threading, 'Threading required for this test.')
783 @support.reap_threads
784 def test_quick_connect(self):
785 # see: http://bugs.python.org/issue10340
Giampaolo Rodola'466a54f2012-03-23 13:29:01 +0100786 if self.family in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
787 server = BaseServer(self.family, self.addr)
788 t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
789 count=500))
790 t.start()
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100791
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100792
Giampaolo Rodola'c7ea19f2012-03-23 15:09:58 +0100793 s = socket.socket(self.family, socket.SOCK_STREAM)
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100794 s.settimeout(.2)
Ezio Melotti9a381c72010-07-27 22:24:13 +0000795 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
796 struct.pack('ii', 1, 0))
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100797 try:
798 s.connect(server.address)
799 except socket.error:
800 pass
801 finally:
802 s.close()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000803
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200804class TestAPI_UseIPv4Sockets(BaseTestAPI):
805 family = socket.AF_INET
806 addr = (HOST, 0)
807
808@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 support required')
809class TestAPI_UseIPv6Sockets(BaseTestAPI):
810 family = socket.AF_INET6
811 addr = ('::1', 0)
812
Charles-François Natalie3540b42011-08-25 00:50:41 +0200813@unittest.skipUnless(HAS_UNIX_SOCKETS, 'Unix sockets required')
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200814class TestAPI_UseUnixSockets(BaseTestAPI):
Charles-François Natalia045c052011-08-25 01:22:50 +0200815 if HAS_UNIX_SOCKETS:
816 family = socket.AF_UNIX
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200817 addr = support.TESTFN
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200818
819 def tearDown(self):
820 unlink(self.addr)
821 BaseTestAPI.tearDown(self)
822
823class TestAPI_UseIPv4Select(TestAPI_UseIPv4Sockets):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000824 use_poll = False
825
826@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200827class TestAPI_UseIPv4Poll(TestAPI_UseIPv4Sockets):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000828 use_poll = True
829
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200830class TestAPI_UseIPv6Select(TestAPI_UseIPv6Sockets):
831 use_poll = False
832
833@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
834class TestAPI_UseIPv6Poll(TestAPI_UseIPv6Sockets):
835 use_poll = True
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000836
Charles-François Natali39648d12011-10-31 12:08:09 +0100837class TestAPI_UseUnixSocketsSelect(TestAPI_UseUnixSockets):
838 use_poll = False
839
840@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
841class TestAPI_UseUnixSocketsPoll(TestAPI_UseUnixSockets):
842 use_poll = True
843
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000844def test_main():
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000845 tests = [HelperFunctionTests, DispatcherTests, DispatcherWithSendTests,
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200846 DispatcherWithSendTests_UsePoll, FileWrapperTest,
847 TestAPI_UseIPv4Select, TestAPI_UseIPv4Poll, TestAPI_UseIPv6Select,
Charles-François Natali39648d12011-10-31 12:08:09 +0100848 TestAPI_UseIPv6Poll, TestAPI_UseUnixSocketsSelect,
849 TestAPI_UseUnixSocketsPoll]
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000850 run_unittest(*tests)
851
852if __name__ == "__main__":
853 test_main()