blob: d05462b7efce3582c5d5f8511910eef3d9a637da [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à82e02b52010-05-18 20:11:58 +00008import errno
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +01009import struct
Guido van Rossumb5a755e2007-07-18 18:15:48 +000010
Benjamin Petersonee8712c2008-05-20 21:35:26 +000011from test import support
Christian Heimes5e696852008-04-09 08:37:03 +000012from io import BytesIO
Guido van Rossumb5a755e2007-07-18 18:15:48 +000013
Steve Dower22d06982016-09-06 19:38:15 -070014if support.PGO:
15 raise unittest.SkipTest("test is not helpful for PGO")
16
Victor Stinner45df8202010-04-28 22:31:17 +000017try:
18 import threading
19except ImportError:
20 threading = None
21
Giampaolo Rodola'3cb09062013-05-16 15:21:53 +020022TIMEOUT = 3
Charles-François Natalie3540b42011-08-25 00:50:41 +020023HAS_UNIX_SOCKETS = hasattr(socket, 'AF_UNIX')
24
Guido van Rossumb5a755e2007-07-18 18:15:48 +000025class dummysocket:
26 def __init__(self):
27 self.closed = False
28
29 def close(self):
30 self.closed = True
31
32 def fileno(self):
33 return 42
34
35class dummychannel:
36 def __init__(self):
37 self.socket = dummysocket()
38
Josiah Carlsond74900e2008-07-07 04:15:08 +000039 def close(self):
40 self.socket.close()
41
Guido van Rossumb5a755e2007-07-18 18:15:48 +000042class exitingdummy:
43 def __init__(self):
44 pass
45
46 def handle_read_event(self):
47 raise asyncore.ExitNow()
48
49 handle_write_event = handle_read_event
Josiah Carlson91823c72008-07-11 23:26:37 +000050 handle_close = handle_read_event
Guido van Rossumb5a755e2007-07-18 18:15:48 +000051 handle_expt_event = handle_read_event
52
53class crashingdummy:
54 def __init__(self):
55 self.error_handled = False
56
57 def handle_read_event(self):
58 raise Exception()
59
60 handle_write_event = handle_read_event
Josiah Carlson91823c72008-07-11 23:26:37 +000061 handle_close = handle_read_event
Guido van Rossumb5a755e2007-07-18 18:15:48 +000062 handle_expt_event = handle_read_event
63
64 def handle_error(self):
65 self.error_handled = True
66
67# used when testing senders; just collects what it gets until newline is sent
Christian Heimes5e696852008-04-09 08:37:03 +000068def capture_server(evt, buf, serv):
Guido van Rossumb5a755e2007-07-18 18:15:48 +000069 try:
Charles-François Natali6e204602014-07-23 19:28:13 +010070 serv.listen()
Guido van Rossumb5a755e2007-07-18 18:15:48 +000071 conn, addr = serv.accept()
72 except socket.timeout:
73 pass
74 else:
75 n = 200
Kristján Valur Jónssonb2e58182012-04-06 14:37:45 +000076 start = time.time()
77 while n > 0 and time.time() - start < 3.0:
78 r, w, e = select.select([conn], [], [], 0.1)
Guido van Rossum36e0a922007-07-20 04:05:57 +000079 if r:
Kristján Valur Jónssonb2e58182012-04-06 14:37:45 +000080 n -= 1
Guido van Rossum36e0a922007-07-20 04:05:57 +000081 data = conn.recv(10)
Guido van Rossum36e0a922007-07-20 04:05:57 +000082 # keep everything except for the newline terminator
83 buf.write(data.replace(b'\n', b''))
84 if b'\n' in data:
85 break
Guido van Rossumb5a755e2007-07-18 18:15:48 +000086 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.
Victor Stinner252d40e2014-06-27 22:44:40 +020097 support.unlink(addr)
Xavier de Gayee88ed052016-12-14 11:52:28 +010098 support.bind_unix_socket(sock, addr)
99 else:
100 sock.bind(addr)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200101
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000102
103class HelperFunctionTests(unittest.TestCase):
104 def test_readwriteexc(self):
105 # Check exception handling behavior of read, write and _exception
106
107 # check that ExitNow exceptions in the object handler method
108 # bubbles all the way up through asyncore read/write/_exception calls
109 tr1 = exitingdummy()
110 self.assertRaises(asyncore.ExitNow, asyncore.read, tr1)
111 self.assertRaises(asyncore.ExitNow, asyncore.write, tr1)
112 self.assertRaises(asyncore.ExitNow, asyncore._exception, tr1)
113
114 # check that an exception other than ExitNow in the object handler
115 # method causes the handle_error method to get called
116 tr2 = crashingdummy()
117 asyncore.read(tr2)
118 self.assertEqual(tr2.error_handled, True)
119
120 tr2 = crashingdummy()
121 asyncore.write(tr2)
122 self.assertEqual(tr2.error_handled, True)
123
124 tr2 = crashingdummy()
125 asyncore._exception(tr2)
126 self.assertEqual(tr2.error_handled, True)
127
Guido van Rossum806c2462007-08-06 23:33:07 +0000128 # asyncore.readwrite uses constants in the select module that
129 # are not present in Windows systems (see this thread:
130 # http://mail.python.org/pipermail/python-list/2001-October/109973.html)
131 # These constants should be present as long as poll is available
132
Ezio Melotti63c46402010-07-27 22:03:33 +0000133 @unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
134 def test_readwrite(self):
135 # Check that correct methods are called by readwrite()
Guido van Rossum806c2462007-08-06 23:33:07 +0000136
Ezio Melotti63c46402010-07-27 22:03:33 +0000137 attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
R. David Murray78532ba2009-04-12 15:35:44 +0000138
Ezio Melotti63c46402010-07-27 22:03:33 +0000139 expected = (
140 (select.POLLIN, 'read'),
141 (select.POLLPRI, 'expt'),
142 (select.POLLOUT, 'write'),
143 (select.POLLERR, 'closed'),
144 (select.POLLHUP, 'closed'),
145 (select.POLLNVAL, 'closed'),
146 )
R. David Murray78532ba2009-04-12 15:35:44 +0000147
Ezio Melotti63c46402010-07-27 22:03:33 +0000148 class testobj:
149 def __init__(self):
150 self.read = False
151 self.write = False
152 self.closed = False
153 self.expt = False
154 self.error_handled = False
Guido van Rossum806c2462007-08-06 23:33:07 +0000155
Ezio Melotti63c46402010-07-27 22:03:33 +0000156 def handle_read_event(self):
157 self.read = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000158
Ezio Melotti63c46402010-07-27 22:03:33 +0000159 def handle_write_event(self):
160 self.write = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000161
Ezio Melotti63c46402010-07-27 22:03:33 +0000162 def handle_close(self):
163 self.closed = True
Josiah Carlson9f2f8332008-07-07 05:04:12 +0000164
Ezio Melotti63c46402010-07-27 22:03:33 +0000165 def handle_expt_event(self):
166 self.expt = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000167
Ezio Melotti63c46402010-07-27 22:03:33 +0000168 def handle_error(self):
169 self.error_handled = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000170
Ezio Melotti63c46402010-07-27 22:03:33 +0000171 for flag, expectedattr in expected:
172 tobj = testobj()
173 self.assertEqual(getattr(tobj, expectedattr), False)
174 asyncore.readwrite(tobj, flag)
R. David Murray78532ba2009-04-12 15:35:44 +0000175
Ezio Melotti63c46402010-07-27 22:03:33 +0000176 # Only the attribute modified by the routine we expect to be
177 # called should be True.
178 for attr in attributes:
179 self.assertEqual(getattr(tobj, attr), attr==expectedattr)
Guido van Rossum806c2462007-08-06 23:33:07 +0000180
Ezio Melotti63c46402010-07-27 22:03:33 +0000181 # check that ExitNow exceptions in the object handler method
182 # bubbles all the way up through asyncore readwrite call
183 tr1 = exitingdummy()
184 self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
Guido van Rossum806c2462007-08-06 23:33:07 +0000185
Ezio Melotti63c46402010-07-27 22:03:33 +0000186 # check that an exception other than ExitNow in the object handler
187 # method causes the handle_error method to get called
188 tr2 = crashingdummy()
189 self.assertEqual(tr2.error_handled, False)
190 asyncore.readwrite(tr2, flag)
191 self.assertEqual(tr2.error_handled, True)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000192
193 def test_closeall(self):
194 self.closeall_check(False)
195
196 def test_closeall_default(self):
197 self.closeall_check(True)
198
199 def closeall_check(self, usedefault):
200 # Check that close_all() closes everything in a given map
201
202 l = []
203 testmap = {}
204 for i in range(10):
205 c = dummychannel()
206 l.append(c)
207 self.assertEqual(c.socket.closed, False)
208 testmap[i] = c
209
210 if usedefault:
211 socketmap = asyncore.socket_map
212 try:
213 asyncore.socket_map = testmap
214 asyncore.close_all()
215 finally:
216 testmap, asyncore.socket_map = asyncore.socket_map, socketmap
217 else:
218 asyncore.close_all(testmap)
219
220 self.assertEqual(len(testmap), 0)
221
222 for c in l:
223 self.assertEqual(c.socket.closed, True)
224
225 def test_compact_traceback(self):
226 try:
227 raise Exception("I don't like spam!")
228 except:
229 real_t, real_v, real_tb = sys.exc_info()
230 r = asyncore.compact_traceback()
231 else:
232 self.fail("Expected exception")
233
234 (f, function, line), t, v, info = r
235 self.assertEqual(os.path.split(f)[-1], 'test_asyncore.py')
236 self.assertEqual(function, 'test_compact_traceback')
237 self.assertEqual(t, real_t)
238 self.assertEqual(v, real_v)
239 self.assertEqual(info, '[%s|%s|%s]' % (f, function, line))
240
241
242class DispatcherTests(unittest.TestCase):
243 def setUp(self):
244 pass
245
246 def tearDown(self):
247 asyncore.close_all()
248
249 def test_basic(self):
250 d = asyncore.dispatcher()
251 self.assertEqual(d.readable(), True)
252 self.assertEqual(d.writable(), True)
253
254 def test_repr(self):
255 d = asyncore.dispatcher()
256 self.assertEqual(repr(d), '<asyncore.dispatcher at %#x>' % id(d))
257
258 def test_log(self):
259 d = asyncore.dispatcher()
260
261 # capture output of dispatcher.log() (to stderr)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000262 l1 = "Lovely spam! Wonderful spam!"
263 l2 = "I don't like spam!"
Victor Stinner252d40e2014-06-27 22:44:40 +0200264 with support.captured_stderr() as stderr:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000265 d.log(l1)
266 d.log(l2)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000267
Victor Stinner252d40e2014-06-27 22:44:40 +0200268 lines = stderr.getvalue().splitlines()
Ezio Melotti63c46402010-07-27 22:03:33 +0000269 self.assertEqual(lines, ['log: %s' % l1, 'log: %s' % l2])
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000270
271 def test_log_info(self):
272 d = asyncore.dispatcher()
273
274 # capture output of dispatcher.log_info() (to stdout via print)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000275 l1 = "Have you got anything without spam?"
276 l2 = "Why can't she have egg bacon spam and sausage?"
277 l3 = "THAT'S got spam in it!"
Victor Stinner252d40e2014-06-27 22:44:40 +0200278 with support.captured_stdout() as stdout:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000279 d.log_info(l1, 'EGGS')
280 d.log_info(l2)
281 d.log_info(l3, 'SPAM')
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000282
Victor Stinner252d40e2014-06-27 22:44:40 +0200283 lines = stdout.getvalue().splitlines()
R. David Murray847f30e2009-04-13 01:22:04 +0000284 expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
Ezio Melotti63c46402010-07-27 22:03:33 +0000285 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000286
287 def test_unhandled(self):
288 d = asyncore.dispatcher()
R. David Murray78532ba2009-04-12 15:35:44 +0000289 d.ignore_log_types = ()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000290
291 # capture output of dispatcher.log_info() (to stdout via print)
Victor Stinner252d40e2014-06-27 22:44:40 +0200292 with support.captured_stdout() as stdout:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000293 d.handle_expt()
294 d.handle_read()
295 d.handle_write()
296 d.handle_connect()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000297
Victor Stinner252d40e2014-06-27 22:44:40 +0200298 lines = stdout.getvalue().splitlines()
R. David Murray78532ba2009-04-12 15:35:44 +0000299 expected = ['warning: unhandled incoming priority event',
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000300 'warning: unhandled read event',
301 'warning: unhandled write event',
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000302 'warning: unhandled connect event']
Ezio Melotti63c46402010-07-27 22:03:33 +0000303 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000304
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000305 def test_strerror(self):
306 # refers to bug #8573
307 err = asyncore._strerror(errno.EPERM)
308 if hasattr(os, 'strerror'):
309 self.assertEqual(err, os.strerror(errno.EPERM))
310 err = asyncore._strerror(-1)
Giampaolo Rodolàd2751fb2011-02-25 20:05:48 +0000311 self.assertTrue(err != "")
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000312
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000313
314class dispatcherwithsend_noread(asyncore.dispatcher_with_send):
315 def readable(self):
316 return False
317
318 def handle_connect(self):
319 pass
320
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000321
Antoine Pitrou0f1155c2014-04-19 21:07:16 +0200322class DispatcherWithSendTests(unittest.TestCase):
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000323 def setUp(self):
324 pass
325
326 def tearDown(self):
327 asyncore.close_all()
328
Victor Stinner45df8202010-04-28 22:31:17 +0000329 @unittest.skipUnless(threading, 'Threading required for this test.')
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000330 @support.reap_threads
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000331 def test_send(self):
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000332 evt = threading.Event()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000333 sock = socket.socket()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000334 sock.settimeout(3)
335 port = support.bind_port(sock)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000336
Christian Heimes5e696852008-04-09 08:37:03 +0000337 cap = BytesIO()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000338 args = (evt, cap, sock)
339 t = threading.Thread(target=capture_server, args=args)
340 t.start()
341 try:
342 # wait a little longer for the server to initialize (it sometimes
343 # refuses connections on slow machines without this wait)
344 time.sleep(0.2)
Guido van Rossum806c2462007-08-06 23:33:07 +0000345
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000346 data = b"Suppose there isn't a 16-ton weight?"
347 d = dispatcherwithsend_noread()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000348 d.create_socket()
Victor Stinner252d40e2014-06-27 22:44:40 +0200349 d.connect((support.HOST, port))
Guido van Rossum806c2462007-08-06 23:33:07 +0000350
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000351 # give time for socket to connect
352 time.sleep(0.1)
Guido van Rossum806c2462007-08-06 23:33:07 +0000353
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000354 d.send(data)
355 d.send(data)
356 d.send(b'\n')
Guido van Rossum806c2462007-08-06 23:33:07 +0000357
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000358 n = 1000
359 while d.out_buffer and n > 0:
360 asyncore.poll()
361 n -= 1
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000362
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000363 evt.wait()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000364
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000365 self.assertEqual(cap.getvalue(), data*2)
366 finally:
Giampaolo Rodola'3cb09062013-05-16 15:21:53 +0200367 t.join(timeout=TIMEOUT)
368 if t.is_alive():
369 self.fail("join() timed out")
370
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000371
Ezio Melotti63c46402010-07-27 22:03:33 +0000372@unittest.skipUnless(hasattr(asyncore, 'file_wrapper'),
373 'asyncore.file_wrapper required')
374class FileWrapperTest(unittest.TestCase):
375 def setUp(self):
376 self.d = b"It's not dead, it's sleeping!"
Victor Stinner252d40e2014-06-27 22:44:40 +0200377 with open(support.TESTFN, 'wb') as file:
Brett Cannon2d562f82010-10-29 22:40:44 +0000378 file.write(self.d)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000379
Ezio Melotti63c46402010-07-27 22:03:33 +0000380 def tearDown(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200381 support.unlink(support.TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000382
Ezio Melotti63c46402010-07-27 22:03:33 +0000383 def test_recv(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200384 fd = os.open(support.TESTFN, os.O_RDONLY)
Ezio Melotti63c46402010-07-27 22:03:33 +0000385 w = asyncore.file_wrapper(fd)
386 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000387
Ezio Melotti63c46402010-07-27 22:03:33 +0000388 self.assertNotEqual(w.fd, fd)
389 self.assertNotEqual(w.fileno(), fd)
390 self.assertEqual(w.recv(13), b"It's not dead")
391 self.assertEqual(w.read(6), b", it's")
392 w.close()
393 self.assertRaises(OSError, w.read, 1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000394
Ezio Melotti63c46402010-07-27 22:03:33 +0000395 def test_send(self):
396 d1 = b"Come again?"
397 d2 = b"I want to buy some cheese."
Victor Stinner252d40e2014-06-27 22:44:40 +0200398 fd = os.open(support.TESTFN, os.O_WRONLY | os.O_APPEND)
Ezio Melotti63c46402010-07-27 22:03:33 +0000399 w = asyncore.file_wrapper(fd)
400 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000401
Ezio Melotti63c46402010-07-27 22:03:33 +0000402 w.write(d1)
403 w.send(d2)
404 w.close()
Victor Stinner252d40e2014-06-27 22:44:40 +0200405 with open(support.TESTFN, 'rb') as file:
Brett Cannon2d562f82010-10-29 22:40:44 +0000406 self.assertEqual(file.read(), self.d + d1 + d2)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000407
Georg Brandlcbb0ae42010-07-28 08:19:35 +0000408 @unittest.skipUnless(hasattr(asyncore, 'file_dispatcher'),
409 'asyncore.file_dispatcher required')
410 def test_dispatcher(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200411 fd = os.open(support.TESTFN, os.O_RDONLY)
Georg Brandlcbb0ae42010-07-28 08:19:35 +0000412 data = []
413 class FileDispatcher(asyncore.file_dispatcher):
414 def handle_read(self):
415 data.append(self.recv(29))
416 s = FileDispatcher(fd)
417 os.close(fd)
418 asyncore.loop(timeout=0.01, use_poll=True, count=2)
419 self.assertEqual(b"".join(data), self.d)
420
Victor Stinner4d4c69d2014-06-27 23:52:03 +0200421 def test_resource_warning(self):
422 # Issue #11453
423 fd = os.open(support.TESTFN, os.O_RDONLY)
424 f = asyncore.file_wrapper(fd)
Victor Stinner623138c2014-07-29 01:01:09 +0200425
426 os.close(fd)
Victor Stinner4d4c69d2014-06-27 23:52:03 +0200427 with support.check_warnings(('', ResourceWarning)):
428 f = None
429 support.gc_collect()
430
431 def test_close_twice(self):
432 fd = os.open(support.TESTFN, os.O_RDONLY)
433 f = asyncore.file_wrapper(fd)
Victor Stinner623138c2014-07-29 01:01:09 +0200434 os.close(fd)
435
Victor Stinner4d4c69d2014-06-27 23:52:03 +0200436 f.close()
437 self.assertEqual(f.fd, -1)
438 # calling close twice should not fail
439 f.close()
440
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000441
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000442class BaseTestHandler(asyncore.dispatcher):
443
444 def __init__(self, sock=None):
445 asyncore.dispatcher.__init__(self, sock)
446 self.flag = False
447
448 def handle_accept(self):
449 raise Exception("handle_accept not supposed to be called")
450
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000451 def handle_accepted(self):
452 raise Exception("handle_accepted not supposed to be called")
453
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000454 def handle_connect(self):
455 raise Exception("handle_connect not supposed to be called")
456
457 def handle_expt(self):
458 raise Exception("handle_expt not supposed to be called")
459
460 def handle_close(self):
461 raise Exception("handle_close not supposed to be called")
462
463 def handle_error(self):
464 raise
465
466
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200467class BaseServer(asyncore.dispatcher):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000468 """A server which listens on an address and dispatches the
469 connection to a handler.
470 """
471
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200472 def __init__(self, family, addr, handler=BaseTestHandler):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000473 asyncore.dispatcher.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200474 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000475 self.set_reuse_addr()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200476 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000477 self.listen(5)
478 self.handler = handler
479
480 @property
481 def address(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200482 return self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000483
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000484 def handle_accepted(self, sock, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000485 self.handler(sock)
486
487 def handle_error(self):
488 raise
489
490
491class BaseClient(BaseTestHandler):
492
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200493 def __init__(self, family, address):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000494 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200495 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000496 self.connect(address)
497
498 def handle_connect(self):
499 pass
500
501
Ezio Melotti47236db2013-01-10 05:28:52 +0200502class BaseTestAPI:
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000503
504 def tearDown(self):
505 asyncore.close_all()
506
507 def loop_waiting_for_flag(self, instance, timeout=5):
508 timeout = float(timeout) / 100
509 count = 100
510 while asyncore.socket_map and count > 0:
511 asyncore.loop(timeout=0.01, count=1, use_poll=self.use_poll)
512 if instance.flag:
513 return
514 count -= 1
515 time.sleep(timeout)
516 self.fail("flag not set")
517
518 def test_handle_connect(self):
519 # make sure handle_connect is called on connect()
520
521 class TestClient(BaseClient):
522 def handle_connect(self):
523 self.flag = True
524
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200525 server = BaseServer(self.family, self.addr)
526 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000527 self.loop_waiting_for_flag(client)
528
529 def test_handle_accept(self):
530 # make sure handle_accept() is called when a client connects
531
532 class TestListener(BaseTestHandler):
533
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200534 def __init__(self, family, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000535 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200536 self.create_socket(family)
537 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000538 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200539 self.address = self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000540
541 def handle_accept(self):
542 self.flag = True
543
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200544 server = TestListener(self.family, self.addr)
545 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000546 self.loop_waiting_for_flag(server)
547
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000548 def test_handle_accepted(self):
549 # make sure handle_accepted() is called when a client connects
550
551 class TestListener(BaseTestHandler):
552
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200553 def __init__(self, family, addr):
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000554 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200555 self.create_socket(family)
556 bind_af_aware(self.socket, addr)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000557 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200558 self.address = self.socket.getsockname()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000559
560 def handle_accept(self):
561 asyncore.dispatcher.handle_accept(self)
562
563 def handle_accepted(self, sock, addr):
Benjamin Petersond6868b42010-10-31 17:34:34 +0000564 sock.close()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000565 self.flag = True
566
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200567 server = TestListener(self.family, self.addr)
568 client = BaseClient(self.family, server.address)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000569 self.loop_waiting_for_flag(server)
570
571
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000572 def test_handle_read(self):
573 # make sure handle_read is called on data received
574
575 class TestClient(BaseClient):
576 def handle_read(self):
577 self.flag = True
578
579 class TestHandler(BaseTestHandler):
580 def __init__(self, conn):
581 BaseTestHandler.__init__(self, conn)
582 self.send(b'x' * 1024)
583
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200584 server = BaseServer(self.family, self.addr, TestHandler)
585 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000586 self.loop_waiting_for_flag(client)
587
588 def test_handle_write(self):
589 # make sure handle_write is called
590
591 class TestClient(BaseClient):
592 def handle_write(self):
593 self.flag = True
594
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200595 server = BaseServer(self.family, self.addr)
596 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000597 self.loop_waiting_for_flag(client)
598
599 def test_handle_close(self):
600 # make sure handle_close is called when the other end closes
601 # the connection
602
603 class TestClient(BaseClient):
604
605 def handle_read(self):
606 # in order to make handle_close be called we are supposed
607 # to make at least one recv() call
608 self.recv(1024)
609
610 def handle_close(self):
611 self.flag = True
612 self.close()
613
614 class TestHandler(BaseTestHandler):
615 def __init__(self, conn):
616 BaseTestHandler.__init__(self, conn)
617 self.close()
618
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200619 server = BaseServer(self.family, self.addr, TestHandler)
620 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000621 self.loop_waiting_for_flag(client)
622
Charles-François Natalid4621192011-10-29 12:45:56 +0200623 def test_handle_close_after_conn_broken(self):
624 # Check that ECONNRESET/EPIPE is correctly handled (issues #5661 and
625 # #11265).
626
627 data = b'\0' * 128
628
629 class TestClient(BaseClient):
630
631 def handle_write(self):
632 self.send(data)
633
634 def handle_close(self):
635 self.flag = True
636 self.close()
637
Charles-François Natalifea6cb02011-10-29 14:29:39 +0200638 def handle_expt(self):
639 self.flag = True
640 self.close()
641
Charles-François Natalid4621192011-10-29 12:45:56 +0200642 class TestHandler(BaseTestHandler):
643
644 def handle_read(self):
645 self.recv(len(data))
646 self.close()
647
648 def writable(self):
649 return False
650
651 server = BaseServer(self.family, self.addr, TestHandler)
652 client = TestClient(self.family, server.address)
653 self.loop_waiting_for_flag(client)
654
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000655 @unittest.skipIf(sys.platform.startswith("sunos"),
656 "OOB support is broken on Solaris")
657 def test_handle_expt(self):
658 # Make sure handle_expt is called on OOB data received.
659 # Note: this might fail on some platforms as OOB data is
660 # tenuously supported and rarely used.
Charles-François Natalie3540b42011-08-25 00:50:41 +0200661 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200662 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000663
Ned Deily1d391f92017-03-04 06:19:05 -0500664 if sys.platform == "darwin" and self.use_poll:
665 self.skipTest("poll may fail on macOS; see issue #28087")
666
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000667 class TestClient(BaseClient):
668 def handle_expt(self):
Charles-François Natalicf85c302011-11-02 20:30:59 +0100669 self.socket.recv(1024, socket.MSG_OOB)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000670 self.flag = True
671
672 class TestHandler(BaseTestHandler):
673 def __init__(self, conn):
674 BaseTestHandler.__init__(self, conn)
675 self.socket.send(bytes(chr(244), 'latin-1'), socket.MSG_OOB)
676
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200677 server = BaseServer(self.family, self.addr, TestHandler)
678 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000679 self.loop_waiting_for_flag(client)
680
681 def test_handle_error(self):
682
683 class TestClient(BaseClient):
684 def handle_write(self):
685 1.0 / 0
686 def handle_error(self):
687 self.flag = True
688 try:
689 raise
690 except ZeroDivisionError:
691 pass
692 else:
693 raise Exception("exception not raised")
694
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200695 server = BaseServer(self.family, self.addr)
696 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000697 self.loop_waiting_for_flag(client)
698
699 def test_connection_attributes(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200700 server = BaseServer(self.family, self.addr)
701 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000702
703 # we start disconnected
704 self.assertFalse(server.connected)
705 self.assertTrue(server.accepting)
Giampaolo Rodolà340d7d22010-05-12 00:33:15 +0000706 # this can't be taken for granted across all platforms
707 #self.assertFalse(client.connected)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000708 self.assertFalse(client.accepting)
709
710 # execute some loops so that client connects to server
711 asyncore.loop(timeout=0.01, use_poll=self.use_poll, count=100)
712 self.assertFalse(server.connected)
713 self.assertTrue(server.accepting)
714 self.assertTrue(client.connected)
715 self.assertFalse(client.accepting)
716
717 # disconnect the client
718 client.close()
719 self.assertFalse(server.connected)
720 self.assertTrue(server.accepting)
721 self.assertFalse(client.connected)
722 self.assertFalse(client.accepting)
723
724 # stop serving
725 server.close()
726 self.assertFalse(server.connected)
727 self.assertFalse(server.accepting)
728
729 def test_create_socket(self):
730 s = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200731 s.create_socket(self.family)
732 self.assertEqual(s.socket.family, self.family)
Antoine Pitroub1c54962010-10-14 15:05:38 +0000733 SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
Victor Stinnerdaf45552013-08-28 00:53:59 +0200734 sock_type = socket.SOCK_STREAM | SOCK_NONBLOCK
735 if hasattr(socket, 'SOCK_CLOEXEC'):
736 self.assertIn(s.socket.type,
737 (sock_type | socket.SOCK_CLOEXEC, sock_type))
738 else:
739 self.assertEqual(s.socket.type, sock_type)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000740
741 def test_bind(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200742 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200743 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000744 s1 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200745 s1.create_socket(self.family)
746 s1.bind(self.addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000747 s1.listen(5)
748 port = s1.socket.getsockname()[1]
749
750 s2 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200751 s2.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000752 # EADDRINUSE indicates the socket was correctly bound
Andrew Svetlov0832af62012-12-18 23:10:48 +0200753 self.assertRaises(OSError, s2.bind, (self.addr[0], port))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000754
755 def test_set_reuse_addr(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200756 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200757 self.skipTest("Not applicable to AF_UNIX sockets.")
758 sock = socket.socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000759 try:
760 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200761 except OSError:
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000762 unittest.skip("SO_REUSEADDR not supported on this platform")
763 else:
764 # if SO_REUSEADDR succeeded for sock we expect asyncore
765 # to do the same
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200766 s = asyncore.dispatcher(socket.socket(self.family))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000767 self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
768 socket.SO_REUSEADDR))
Benjamin Petersond6868b42010-10-31 17:34:34 +0000769 s.socket.close()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200770 s.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000771 s.set_reuse_addr()
772 self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
773 socket.SO_REUSEADDR))
774 finally:
775 sock.close()
776
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100777 @unittest.skipUnless(threading, 'Threading required for this test.')
778 @support.reap_threads
779 def test_quick_connect(self):
780 # see: http://bugs.python.org/issue10340
Giampaolo Rodola'466a54f2012-03-23 13:29:01 +0100781 if self.family in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
782 server = BaseServer(self.family, self.addr)
783 t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
784 count=500))
785 t.start()
Giampaolo Rodola'3cb09062013-05-16 15:21:53 +0200786 def cleanup():
787 t.join(timeout=TIMEOUT)
788 if t.is_alive():
789 self.fail("join() timed out")
790 self.addCleanup(cleanup)
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100791
Giampaolo Rodola'c7ea19f2012-03-23 15:09:58 +0100792 s = socket.socket(self.family, socket.SOCK_STREAM)
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100793 s.settimeout(.2)
Ezio Melotti9a381c72010-07-27 22:24:13 +0000794 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
795 struct.pack('ii', 1, 0))
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100796 try:
797 s.connect(server.address)
Andrew Svetlov0832af62012-12-18 23:10:48 +0200798 except OSError:
Giampaolo Rodola'a3481e72012-03-23 15:07:07 +0100799 pass
800 finally:
801 s.close()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000802
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200803class TestAPI_UseIPv4Sockets(BaseTestAPI):
804 family = socket.AF_INET
Victor Stinner252d40e2014-06-27 22:44:40 +0200805 addr = (support.HOST, 0)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200806
807@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 support required')
808class TestAPI_UseIPv6Sockets(BaseTestAPI):
809 family = socket.AF_INET6
Victor Stinner252d40e2014-06-27 22:44:40 +0200810 addr = (support.HOSTv6, 0)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200811
Charles-François Natalie3540b42011-08-25 00:50:41 +0200812@unittest.skipUnless(HAS_UNIX_SOCKETS, 'Unix sockets required')
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200813class TestAPI_UseUnixSockets(BaseTestAPI):
Charles-François Natalia045c052011-08-25 01:22:50 +0200814 if HAS_UNIX_SOCKETS:
815 family = socket.AF_UNIX
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200816 addr = support.TESTFN
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200817
818 def tearDown(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200819 support.unlink(self.addr)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200820 BaseTestAPI.tearDown(self)
821
Ezio Melotti47236db2013-01-10 05:28:52 +0200822class TestAPI_UseIPv4Select(TestAPI_UseIPv4Sockets, unittest.TestCase):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000823 use_poll = False
824
825@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200826class TestAPI_UseIPv4Poll(TestAPI_UseIPv4Sockets, unittest.TestCase):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000827 use_poll = True
828
Ezio Melotti47236db2013-01-10 05:28:52 +0200829class TestAPI_UseIPv6Select(TestAPI_UseIPv6Sockets, unittest.TestCase):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200830 use_poll = False
831
832@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200833class TestAPI_UseIPv6Poll(TestAPI_UseIPv6Sockets, unittest.TestCase):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200834 use_poll = True
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000835
Ezio Melotti47236db2013-01-10 05:28:52 +0200836class TestAPI_UseUnixSocketsSelect(TestAPI_UseUnixSockets, unittest.TestCase):
Charles-François Natali39648d12011-10-31 12:08:09 +0100837 use_poll = False
838
839@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200840class TestAPI_UseUnixSocketsPoll(TestAPI_UseUnixSockets, unittest.TestCase):
Charles-François Natali39648d12011-10-31 12:08:09 +0100841 use_poll = True
842
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000843if __name__ == "__main__":
Ezio Melotti47236db2013-01-10 05:28:52 +0200844 unittest.main()