blob: 3fcedb58ec18a62ba3b97cc1768e87cb668135bd [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
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020010import threading
Guido van Rossumb5a755e2007-07-18 18:15:48 +000011
Benjamin Petersonee8712c2008-05-20 21:35:26 +000012from test import support
Christian Heimes5e696852008-04-09 08:37:03 +000013from io import BytesIO
Guido van Rossumb5a755e2007-07-18 18:15:48 +000014
Steve Dower22d06982016-09-06 19:38:15 -070015if support.PGO:
16 raise unittest.SkipTest("test is not helpful for PGO")
17
Victor Stinner45df8202010-04-28 22:31:17 +000018
Giampaolo Rodola'3cb09062013-05-16 15:21:53 +020019TIMEOUT = 3
Charles-François Natalie3540b42011-08-25 00:50:41 +020020HAS_UNIX_SOCKETS = hasattr(socket, 'AF_UNIX')
21
Guido van Rossumb5a755e2007-07-18 18:15:48 +000022class dummysocket:
23 def __init__(self):
24 self.closed = False
25
26 def close(self):
27 self.closed = True
28
29 def fileno(self):
30 return 42
31
32class dummychannel:
33 def __init__(self):
34 self.socket = dummysocket()
35
Josiah Carlsond74900e2008-07-07 04:15:08 +000036 def close(self):
37 self.socket.close()
38
Guido van Rossumb5a755e2007-07-18 18:15:48 +000039class exitingdummy:
40 def __init__(self):
41 pass
42
43 def handle_read_event(self):
44 raise asyncore.ExitNow()
45
46 handle_write_event = handle_read_event
Josiah Carlson91823c72008-07-11 23:26:37 +000047 handle_close = handle_read_event
Guido van Rossumb5a755e2007-07-18 18:15:48 +000048 handle_expt_event = handle_read_event
49
50class crashingdummy:
51 def __init__(self):
52 self.error_handled = False
53
54 def handle_read_event(self):
55 raise Exception()
56
57 handle_write_event = handle_read_event
Josiah Carlson91823c72008-07-11 23:26:37 +000058 handle_close = handle_read_event
Guido van Rossumb5a755e2007-07-18 18:15:48 +000059 handle_expt_event = handle_read_event
60
61 def handle_error(self):
62 self.error_handled = True
63
64# used when testing senders; just collects what it gets until newline is sent
Christian Heimes5e696852008-04-09 08:37:03 +000065def capture_server(evt, buf, serv):
Guido van Rossumb5a755e2007-07-18 18:15:48 +000066 try:
Charles-François Natali6e204602014-07-23 19:28:13 +010067 serv.listen()
Guido van Rossumb5a755e2007-07-18 18:15:48 +000068 conn, addr = serv.accept()
69 except socket.timeout:
70 pass
71 else:
72 n = 200
Victor Stinner2cf4c202018-12-17 09:36:36 +010073 start = time.monotonic()
74 while n > 0 and time.monotonic() - start < 3.0:
Kristján Valur Jónssonb2e58182012-04-06 14:37:45 +000075 r, w, e = select.select([conn], [], [], 0.1)
Guido van Rossum36e0a922007-07-20 04:05:57 +000076 if r:
Kristján Valur Jónssonb2e58182012-04-06 14:37:45 +000077 n -= 1
Guido van Rossum36e0a922007-07-20 04:05:57 +000078 data = conn.recv(10)
Guido van Rossum36e0a922007-07-20 04:05:57 +000079 # keep everything except for the newline terminator
80 buf.write(data.replace(b'\n', b''))
81 if b'\n' in data:
82 break
Guido van Rossumb5a755e2007-07-18 18:15:48 +000083 time.sleep(0.01)
84
85 conn.close()
86 finally:
87 serv.close()
88 evt.set()
89
Charles-François Natalie78cbec2011-08-24 23:24:05 +020090def bind_af_aware(sock, addr):
91 """Helper function to bind a socket according to its family."""
Charles-François Natalie3540b42011-08-25 00:50:41 +020092 if HAS_UNIX_SOCKETS and sock.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +020093 # Make sure the path doesn't exist.
Victor Stinner252d40e2014-06-27 22:44:40 +020094 support.unlink(addr)
Xavier de Gayee88ed052016-12-14 11:52:28 +010095 support.bind_unix_socket(sock, addr)
96 else:
97 sock.bind(addr)
Charles-François Natalie78cbec2011-08-24 23:24:05 +020098
Guido van Rossumb5a755e2007-07-18 18:15:48 +000099
100class HelperFunctionTests(unittest.TestCase):
101 def test_readwriteexc(self):
102 # Check exception handling behavior of read, write and _exception
103
104 # check that ExitNow exceptions in the object handler method
105 # bubbles all the way up through asyncore read/write/_exception calls
106 tr1 = exitingdummy()
107 self.assertRaises(asyncore.ExitNow, asyncore.read, tr1)
108 self.assertRaises(asyncore.ExitNow, asyncore.write, tr1)
109 self.assertRaises(asyncore.ExitNow, asyncore._exception, tr1)
110
111 # check that an exception other than ExitNow in the object handler
112 # method causes the handle_error method to get called
113 tr2 = crashingdummy()
114 asyncore.read(tr2)
115 self.assertEqual(tr2.error_handled, True)
116
117 tr2 = crashingdummy()
118 asyncore.write(tr2)
119 self.assertEqual(tr2.error_handled, True)
120
121 tr2 = crashingdummy()
122 asyncore._exception(tr2)
123 self.assertEqual(tr2.error_handled, True)
124
Guido van Rossum806c2462007-08-06 23:33:07 +0000125 # asyncore.readwrite uses constants in the select module that
126 # are not present in Windows systems (see this thread:
127 # http://mail.python.org/pipermail/python-list/2001-October/109973.html)
128 # These constants should be present as long as poll is available
129
Ezio Melotti63c46402010-07-27 22:03:33 +0000130 @unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
131 def test_readwrite(self):
132 # Check that correct methods are called by readwrite()
Guido van Rossum806c2462007-08-06 23:33:07 +0000133
Ezio Melotti63c46402010-07-27 22:03:33 +0000134 attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
R. David Murray78532ba2009-04-12 15:35:44 +0000135
Ezio Melotti63c46402010-07-27 22:03:33 +0000136 expected = (
137 (select.POLLIN, 'read'),
138 (select.POLLPRI, 'expt'),
139 (select.POLLOUT, 'write'),
140 (select.POLLERR, 'closed'),
141 (select.POLLHUP, 'closed'),
142 (select.POLLNVAL, 'closed'),
143 )
R. David Murray78532ba2009-04-12 15:35:44 +0000144
Ezio Melotti63c46402010-07-27 22:03:33 +0000145 class testobj:
146 def __init__(self):
147 self.read = False
148 self.write = False
149 self.closed = False
150 self.expt = False
151 self.error_handled = False
Guido van Rossum806c2462007-08-06 23:33:07 +0000152
Ezio Melotti63c46402010-07-27 22:03:33 +0000153 def handle_read_event(self):
154 self.read = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000155
Ezio Melotti63c46402010-07-27 22:03:33 +0000156 def handle_write_event(self):
157 self.write = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000158
Ezio Melotti63c46402010-07-27 22:03:33 +0000159 def handle_close(self):
160 self.closed = True
Josiah Carlson9f2f8332008-07-07 05:04:12 +0000161
Ezio Melotti63c46402010-07-27 22:03:33 +0000162 def handle_expt_event(self):
163 self.expt = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000164
Ezio Melotti63c46402010-07-27 22:03:33 +0000165 def handle_error(self):
166 self.error_handled = True
Guido van Rossum806c2462007-08-06 23:33:07 +0000167
Ezio Melotti63c46402010-07-27 22:03:33 +0000168 for flag, expectedattr in expected:
169 tobj = testobj()
170 self.assertEqual(getattr(tobj, expectedattr), False)
171 asyncore.readwrite(tobj, flag)
R. David Murray78532ba2009-04-12 15:35:44 +0000172
Ezio Melotti63c46402010-07-27 22:03:33 +0000173 # Only the attribute modified by the routine we expect to be
174 # called should be True.
175 for attr in attributes:
176 self.assertEqual(getattr(tobj, attr), attr==expectedattr)
Guido van Rossum806c2462007-08-06 23:33:07 +0000177
Ezio Melotti63c46402010-07-27 22:03:33 +0000178 # check that ExitNow exceptions in the object handler method
179 # bubbles all the way up through asyncore readwrite call
180 tr1 = exitingdummy()
181 self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
Guido van Rossum806c2462007-08-06 23:33:07 +0000182
Ezio Melotti63c46402010-07-27 22:03:33 +0000183 # check that an exception other than ExitNow in the object handler
184 # method causes the handle_error method to get called
185 tr2 = crashingdummy()
186 self.assertEqual(tr2.error_handled, False)
187 asyncore.readwrite(tr2, flag)
188 self.assertEqual(tr2.error_handled, True)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000189
190 def test_closeall(self):
191 self.closeall_check(False)
192
193 def test_closeall_default(self):
194 self.closeall_check(True)
195
196 def closeall_check(self, usedefault):
197 # Check that close_all() closes everything in a given map
198
199 l = []
200 testmap = {}
201 for i in range(10):
202 c = dummychannel()
203 l.append(c)
204 self.assertEqual(c.socket.closed, False)
205 testmap[i] = c
206
207 if usedefault:
208 socketmap = asyncore.socket_map
209 try:
210 asyncore.socket_map = testmap
211 asyncore.close_all()
212 finally:
213 testmap, asyncore.socket_map = asyncore.socket_map, socketmap
214 else:
215 asyncore.close_all(testmap)
216
217 self.assertEqual(len(testmap), 0)
218
219 for c in l:
220 self.assertEqual(c.socket.closed, True)
221
222 def test_compact_traceback(self):
223 try:
224 raise Exception("I don't like spam!")
225 except:
226 real_t, real_v, real_tb = sys.exc_info()
227 r = asyncore.compact_traceback()
228 else:
229 self.fail("Expected exception")
230
231 (f, function, line), t, v, info = r
232 self.assertEqual(os.path.split(f)[-1], 'test_asyncore.py')
233 self.assertEqual(function, 'test_compact_traceback')
234 self.assertEqual(t, real_t)
235 self.assertEqual(v, real_v)
236 self.assertEqual(info, '[%s|%s|%s]' % (f, function, line))
237
238
239class DispatcherTests(unittest.TestCase):
240 def setUp(self):
241 pass
242
243 def tearDown(self):
244 asyncore.close_all()
245
246 def test_basic(self):
247 d = asyncore.dispatcher()
248 self.assertEqual(d.readable(), True)
249 self.assertEqual(d.writable(), True)
250
251 def test_repr(self):
252 d = asyncore.dispatcher()
253 self.assertEqual(repr(d), '<asyncore.dispatcher at %#x>' % id(d))
254
255 def test_log(self):
256 d = asyncore.dispatcher()
257
258 # capture output of dispatcher.log() (to stderr)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000259 l1 = "Lovely spam! Wonderful spam!"
260 l2 = "I don't like spam!"
Victor Stinner252d40e2014-06-27 22:44:40 +0200261 with support.captured_stderr() as stderr:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000262 d.log(l1)
263 d.log(l2)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000264
Victor Stinner252d40e2014-06-27 22:44:40 +0200265 lines = stderr.getvalue().splitlines()
Ezio Melotti63c46402010-07-27 22:03:33 +0000266 self.assertEqual(lines, ['log: %s' % l1, 'log: %s' % l2])
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000267
268 def test_log_info(self):
269 d = asyncore.dispatcher()
270
271 # capture output of dispatcher.log_info() (to stdout via print)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000272 l1 = "Have you got anything without spam?"
273 l2 = "Why can't she have egg bacon spam and sausage?"
274 l3 = "THAT'S got spam in it!"
Victor Stinner252d40e2014-06-27 22:44:40 +0200275 with support.captured_stdout() as stdout:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000276 d.log_info(l1, 'EGGS')
277 d.log_info(l2)
278 d.log_info(l3, 'SPAM')
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000279
Victor Stinner252d40e2014-06-27 22:44:40 +0200280 lines = stdout.getvalue().splitlines()
R. David Murray847f30e2009-04-13 01:22:04 +0000281 expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
Ezio Melotti63c46402010-07-27 22:03:33 +0000282 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000283
284 def test_unhandled(self):
285 d = asyncore.dispatcher()
R. David Murray78532ba2009-04-12 15:35:44 +0000286 d.ignore_log_types = ()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000287
288 # capture output of dispatcher.log_info() (to stdout via print)
Victor Stinner252d40e2014-06-27 22:44:40 +0200289 with support.captured_stdout() as stdout:
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000290 d.handle_expt()
291 d.handle_read()
292 d.handle_write()
293 d.handle_connect()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000294
Victor Stinner252d40e2014-06-27 22:44:40 +0200295 lines = stdout.getvalue().splitlines()
R. David Murray78532ba2009-04-12 15:35:44 +0000296 expected = ['warning: unhandled incoming priority event',
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000297 'warning: unhandled read event',
298 'warning: unhandled write event',
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000299 'warning: unhandled connect event']
Ezio Melotti63c46402010-07-27 22:03:33 +0000300 self.assertEqual(lines, expected)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000301
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000302 def test_strerror(self):
303 # refers to bug #8573
304 err = asyncore._strerror(errno.EPERM)
305 if hasattr(os, 'strerror'):
306 self.assertEqual(err, os.strerror(errno.EPERM))
307 err = asyncore._strerror(-1)
Giampaolo Rodolàd2751fb2011-02-25 20:05:48 +0000308 self.assertTrue(err != "")
Giampaolo Rodolà82e02b52010-05-18 20:11:58 +0000309
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000310
311class dispatcherwithsend_noread(asyncore.dispatcher_with_send):
312 def readable(self):
313 return False
314
315 def handle_connect(self):
316 pass
317
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000318
Antoine Pitrou0f1155c2014-04-19 21:07:16 +0200319class DispatcherWithSendTests(unittest.TestCase):
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000320 def setUp(self):
321 pass
322
323 def tearDown(self):
324 asyncore.close_all()
325
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000326 @support.reap_threads
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000327 def test_send(self):
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000328 evt = threading.Event()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000329 sock = socket.socket()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000330 sock.settimeout(3)
331 port = support.bind_port(sock)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000332
Christian Heimes5e696852008-04-09 08:37:03 +0000333 cap = BytesIO()
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000334 args = (evt, cap, sock)
335 t = threading.Thread(target=capture_server, args=args)
336 t.start()
337 try:
338 # wait a little longer for the server to initialize (it sometimes
339 # refuses connections on slow machines without this wait)
340 time.sleep(0.2)
Guido van Rossum806c2462007-08-06 23:33:07 +0000341
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000342 data = b"Suppose there isn't a 16-ton weight?"
343 d = dispatcherwithsend_noread()
Giampaolo Rodolà103a6d62011-02-25 22:21:22 +0000344 d.create_socket()
Victor Stinner252d40e2014-06-27 22:44:40 +0200345 d.connect((support.HOST, port))
Guido van Rossum806c2462007-08-06 23:33:07 +0000346
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000347 # give time for socket to connect
348 time.sleep(0.1)
Guido van Rossum806c2462007-08-06 23:33:07 +0000349
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000350 d.send(data)
351 d.send(data)
352 d.send(b'\n')
Guido van Rossum806c2462007-08-06 23:33:07 +0000353
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000354 n = 1000
355 while d.out_buffer and n > 0:
356 asyncore.poll()
357 n -= 1
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000358
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000359 evt.wait()
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000360
Antoine Pitrou5ed353c2009-10-27 18:49:23 +0000361 self.assertEqual(cap.getvalue(), data*2)
362 finally:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700363 support.join_thread(t, timeout=TIMEOUT)
Giampaolo Rodola'3cb09062013-05-16 15:21:53 +0200364
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000365
Ezio Melotti63c46402010-07-27 22:03:33 +0000366@unittest.skipUnless(hasattr(asyncore, 'file_wrapper'),
367 'asyncore.file_wrapper required')
368class FileWrapperTest(unittest.TestCase):
369 def setUp(self):
370 self.d = b"It's not dead, it's sleeping!"
Victor Stinner252d40e2014-06-27 22:44:40 +0200371 with open(support.TESTFN, 'wb') as file:
Brett Cannon2d562f82010-10-29 22:40:44 +0000372 file.write(self.d)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000373
Ezio Melotti63c46402010-07-27 22:03:33 +0000374 def tearDown(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200375 support.unlink(support.TESTFN)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000376
Ezio Melotti63c46402010-07-27 22:03:33 +0000377 def test_recv(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200378 fd = os.open(support.TESTFN, os.O_RDONLY)
Ezio Melotti63c46402010-07-27 22:03:33 +0000379 w = asyncore.file_wrapper(fd)
380 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000381
Ezio Melotti63c46402010-07-27 22:03:33 +0000382 self.assertNotEqual(w.fd, fd)
383 self.assertNotEqual(w.fileno(), fd)
384 self.assertEqual(w.recv(13), b"It's not dead")
385 self.assertEqual(w.read(6), b", it's")
386 w.close()
387 self.assertRaises(OSError, w.read, 1)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000388
Ezio Melotti63c46402010-07-27 22:03:33 +0000389 def test_send(self):
390 d1 = b"Come again?"
391 d2 = b"I want to buy some cheese."
Victor Stinner252d40e2014-06-27 22:44:40 +0200392 fd = os.open(support.TESTFN, os.O_WRONLY | os.O_APPEND)
Ezio Melotti63c46402010-07-27 22:03:33 +0000393 w = asyncore.file_wrapper(fd)
394 os.close(fd)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000395
Ezio Melotti63c46402010-07-27 22:03:33 +0000396 w.write(d1)
397 w.send(d2)
398 w.close()
Victor Stinner252d40e2014-06-27 22:44:40 +0200399 with open(support.TESTFN, 'rb') as file:
Brett Cannon2d562f82010-10-29 22:40:44 +0000400 self.assertEqual(file.read(), self.d + d1 + d2)
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000401
Georg Brandlcbb0ae42010-07-28 08:19:35 +0000402 @unittest.skipUnless(hasattr(asyncore, 'file_dispatcher'),
403 'asyncore.file_dispatcher required')
404 def test_dispatcher(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200405 fd = os.open(support.TESTFN, os.O_RDONLY)
Georg Brandlcbb0ae42010-07-28 08:19:35 +0000406 data = []
407 class FileDispatcher(asyncore.file_dispatcher):
408 def handle_read(self):
409 data.append(self.recv(29))
410 s = FileDispatcher(fd)
411 os.close(fd)
412 asyncore.loop(timeout=0.01, use_poll=True, count=2)
413 self.assertEqual(b"".join(data), self.d)
414
Victor Stinner4d4c69d2014-06-27 23:52:03 +0200415 def test_resource_warning(self):
416 # Issue #11453
417 fd = os.open(support.TESTFN, os.O_RDONLY)
418 f = asyncore.file_wrapper(fd)
Victor Stinner623138c2014-07-29 01:01:09 +0200419
420 os.close(fd)
Victor Stinner4d4c69d2014-06-27 23:52:03 +0200421 with support.check_warnings(('', ResourceWarning)):
422 f = None
423 support.gc_collect()
424
425 def test_close_twice(self):
426 fd = os.open(support.TESTFN, os.O_RDONLY)
427 f = asyncore.file_wrapper(fd)
Victor Stinner623138c2014-07-29 01:01:09 +0200428 os.close(fd)
429
Nir Sofferc648a932017-07-25 00:18:06 +0300430 os.close(f.fd) # file_wrapper dupped fd
431 with self.assertRaises(OSError):
432 f.close()
433
Victor Stinner4d4c69d2014-06-27 23:52:03 +0200434 self.assertEqual(f.fd, -1)
435 # calling close twice should not fail
436 f.close()
437
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000438
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000439class BaseTestHandler(asyncore.dispatcher):
440
441 def __init__(self, sock=None):
442 asyncore.dispatcher.__init__(self, sock)
443 self.flag = False
444
445 def handle_accept(self):
446 raise Exception("handle_accept not supposed to be called")
447
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000448 def handle_accepted(self):
449 raise Exception("handle_accepted not supposed to be called")
450
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000451 def handle_connect(self):
452 raise Exception("handle_connect not supposed to be called")
453
454 def handle_expt(self):
455 raise Exception("handle_expt not supposed to be called")
456
457 def handle_close(self):
458 raise Exception("handle_close not supposed to be called")
459
460 def handle_error(self):
461 raise
462
463
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200464class BaseServer(asyncore.dispatcher):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000465 """A server which listens on an address and dispatches the
466 connection to a handler.
467 """
468
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200469 def __init__(self, family, addr, handler=BaseTestHandler):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000470 asyncore.dispatcher.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200471 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000472 self.set_reuse_addr()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200473 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000474 self.listen(5)
475 self.handler = handler
476
477 @property
478 def address(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200479 return self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000480
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000481 def handle_accepted(self, sock, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000482 self.handler(sock)
483
484 def handle_error(self):
485 raise
486
487
488class BaseClient(BaseTestHandler):
489
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200490 def __init__(self, family, address):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000491 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200492 self.create_socket(family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000493 self.connect(address)
494
495 def handle_connect(self):
496 pass
497
498
Ezio Melotti47236db2013-01-10 05:28:52 +0200499class BaseTestAPI:
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000500
501 def tearDown(self):
Victor Stinner11470b62017-04-20 02:55:39 +0200502 asyncore.close_all(ignore_all=True)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000503
504 def loop_waiting_for_flag(self, instance, timeout=5):
505 timeout = float(timeout) / 100
506 count = 100
507 while asyncore.socket_map and count > 0:
508 asyncore.loop(timeout=0.01, count=1, use_poll=self.use_poll)
509 if instance.flag:
510 return
511 count -= 1
512 time.sleep(timeout)
513 self.fail("flag not set")
514
515 def test_handle_connect(self):
516 # make sure handle_connect is called on connect()
517
518 class TestClient(BaseClient):
519 def handle_connect(self):
520 self.flag = True
521
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200522 server = BaseServer(self.family, self.addr)
523 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000524 self.loop_waiting_for_flag(client)
525
526 def test_handle_accept(self):
527 # make sure handle_accept() is called when a client connects
528
529 class TestListener(BaseTestHandler):
530
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200531 def __init__(self, family, addr):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000532 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200533 self.create_socket(family)
534 bind_af_aware(self.socket, addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000535 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200536 self.address = self.socket.getsockname()
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000537
538 def handle_accept(self):
539 self.flag = True
540
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200541 server = TestListener(self.family, self.addr)
542 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000543 self.loop_waiting_for_flag(server)
544
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000545 def test_handle_accepted(self):
546 # make sure handle_accepted() is called when a client connects
547
548 class TestListener(BaseTestHandler):
549
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200550 def __init__(self, family, addr):
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000551 BaseTestHandler.__init__(self)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200552 self.create_socket(family)
553 bind_af_aware(self.socket, addr)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000554 self.listen(5)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200555 self.address = self.socket.getsockname()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000556
557 def handle_accept(self):
558 asyncore.dispatcher.handle_accept(self)
559
560 def handle_accepted(self, sock, addr):
Benjamin Petersond6868b42010-10-31 17:34:34 +0000561 sock.close()
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000562 self.flag = True
563
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200564 server = TestListener(self.family, self.addr)
565 client = BaseClient(self.family, server.address)
Giampaolo Rodolà977c7072010-10-04 21:08:36 +0000566 self.loop_waiting_for_flag(server)
567
568
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000569 def test_handle_read(self):
570 # make sure handle_read is called on data received
571
572 class TestClient(BaseClient):
573 def handle_read(self):
574 self.flag = True
575
576 class TestHandler(BaseTestHandler):
577 def __init__(self, conn):
578 BaseTestHandler.__init__(self, conn)
579 self.send(b'x' * 1024)
580
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200581 server = BaseServer(self.family, self.addr, TestHandler)
582 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000583 self.loop_waiting_for_flag(client)
584
585 def test_handle_write(self):
586 # make sure handle_write is called
587
588 class TestClient(BaseClient):
589 def handle_write(self):
590 self.flag = True
591
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200592 server = BaseServer(self.family, self.addr)
593 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000594 self.loop_waiting_for_flag(client)
595
596 def test_handle_close(self):
597 # make sure handle_close is called when the other end closes
598 # the connection
599
600 class TestClient(BaseClient):
601
602 def handle_read(self):
603 # in order to make handle_close be called we are supposed
604 # to make at least one recv() call
605 self.recv(1024)
606
607 def handle_close(self):
608 self.flag = True
609 self.close()
610
611 class TestHandler(BaseTestHandler):
612 def __init__(self, conn):
613 BaseTestHandler.__init__(self, conn)
614 self.close()
615
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200616 server = BaseServer(self.family, self.addr, TestHandler)
617 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000618 self.loop_waiting_for_flag(client)
619
Charles-François Natalid4621192011-10-29 12:45:56 +0200620 def test_handle_close_after_conn_broken(self):
621 # Check that ECONNRESET/EPIPE is correctly handled (issues #5661 and
622 # #11265).
623
624 data = b'\0' * 128
625
626 class TestClient(BaseClient):
627
628 def handle_write(self):
629 self.send(data)
630
631 def handle_close(self):
632 self.flag = True
633 self.close()
634
Charles-François Natalifea6cb02011-10-29 14:29:39 +0200635 def handle_expt(self):
636 self.flag = True
637 self.close()
638
Charles-François Natalid4621192011-10-29 12:45:56 +0200639 class TestHandler(BaseTestHandler):
640
641 def handle_read(self):
642 self.recv(len(data))
643 self.close()
644
645 def writable(self):
646 return False
647
648 server = BaseServer(self.family, self.addr, TestHandler)
649 client = TestClient(self.family, server.address)
650 self.loop_waiting_for_flag(client)
651
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000652 @unittest.skipIf(sys.platform.startswith("sunos"),
653 "OOB support is broken on Solaris")
654 def test_handle_expt(self):
655 # Make sure handle_expt is called on OOB data received.
656 # Note: this might fail on some platforms as OOB data is
657 # tenuously supported and rarely used.
Charles-François Natalie3540b42011-08-25 00:50:41 +0200658 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200659 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000660
Ned Deilyde046442017-03-04 06:00:37 -0500661 if sys.platform == "darwin" and self.use_poll:
662 self.skipTest("poll may fail on macOS; see issue #28087")
663
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000664 class TestClient(BaseClient):
665 def handle_expt(self):
Charles-François Natalicf85c302011-11-02 20:30:59 +0100666 self.socket.recv(1024, socket.MSG_OOB)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000667 self.flag = True
668
669 class TestHandler(BaseTestHandler):
670 def __init__(self, conn):
671 BaseTestHandler.__init__(self, conn)
672 self.socket.send(bytes(chr(244), 'latin-1'), socket.MSG_OOB)
673
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200674 server = BaseServer(self.family, self.addr, TestHandler)
675 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000676 self.loop_waiting_for_flag(client)
677
678 def test_handle_error(self):
679
680 class TestClient(BaseClient):
681 def handle_write(self):
682 1.0 / 0
683 def handle_error(self):
684 self.flag = True
685 try:
686 raise
687 except ZeroDivisionError:
688 pass
689 else:
690 raise Exception("exception not raised")
691
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200692 server = BaseServer(self.family, self.addr)
693 client = TestClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000694 self.loop_waiting_for_flag(client)
695
696 def test_connection_attributes(self):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200697 server = BaseServer(self.family, self.addr)
698 client = BaseClient(self.family, server.address)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000699
700 # we start disconnected
701 self.assertFalse(server.connected)
702 self.assertTrue(server.accepting)
Giampaolo Rodolà340d7d22010-05-12 00:33:15 +0000703 # this can't be taken for granted across all platforms
704 #self.assertFalse(client.connected)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000705 self.assertFalse(client.accepting)
706
707 # execute some loops so that client connects to server
708 asyncore.loop(timeout=0.01, use_poll=self.use_poll, count=100)
709 self.assertFalse(server.connected)
710 self.assertTrue(server.accepting)
711 self.assertTrue(client.connected)
712 self.assertFalse(client.accepting)
713
714 # disconnect the client
715 client.close()
716 self.assertFalse(server.connected)
717 self.assertTrue(server.accepting)
718 self.assertFalse(client.connected)
719 self.assertFalse(client.accepting)
720
721 # stop serving
722 server.close()
723 self.assertFalse(server.connected)
724 self.assertFalse(server.accepting)
725
726 def test_create_socket(self):
727 s = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200728 s.create_socket(self.family)
Yury Selivanov98181422017-12-18 20:02:54 -0500729 self.assertEqual(s.socket.type, socket.SOCK_STREAM)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200730 self.assertEqual(s.socket.family, self.family)
Yury Selivanov98181422017-12-18 20:02:54 -0500731 self.assertEqual(s.socket.gettimeout(), 0)
732 self.assertFalse(s.socket.get_inheritable())
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000733
734 def test_bind(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200735 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200736 self.skipTest("Not applicable to AF_UNIX sockets.")
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000737 s1 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200738 s1.create_socket(self.family)
739 s1.bind(self.addr)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000740 s1.listen(5)
741 port = s1.socket.getsockname()[1]
742
743 s2 = asyncore.dispatcher()
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200744 s2.create_socket(self.family)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000745 # EADDRINUSE indicates the socket was correctly bound
Andrew Svetlov0832af62012-12-18 23:10:48 +0200746 self.assertRaises(OSError, s2.bind, (self.addr[0], port))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000747
748 def test_set_reuse_addr(self):
Charles-François Natalie3540b42011-08-25 00:50:41 +0200749 if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200750 self.skipTest("Not applicable to AF_UNIX sockets.")
Victor Stinner7b9619a2017-04-19 23:42:46 +0200751
752 with socket.socket(self.family) as sock:
753 try:
754 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
755 except OSError:
756 unittest.skip("SO_REUSEADDR not supported on this platform")
757 else:
758 # if SO_REUSEADDR succeeded for sock we expect asyncore
759 # to do the same
760 s = asyncore.dispatcher(socket.socket(self.family))
761 self.assertFalse(s.socket.getsockopt(socket.SOL_SOCKET,
762 socket.SO_REUSEADDR))
763 s.socket.close()
764 s.create_socket(self.family)
765 s.set_reuse_addr()
766 self.assertTrue(s.socket.getsockopt(socket.SOL_SOCKET,
767 socket.SO_REUSEADDR))
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000768
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100769 @support.reap_threads
770 def test_quick_connect(self):
771 # see: http://bugs.python.org/issue10340
Victor Stinner7b9619a2017-04-19 23:42:46 +0200772 if self.family not in (socket.AF_INET, getattr(socket, "AF_INET6", object())):
773 self.skipTest("test specific to AF_INET and AF_INET6")
Giampaolo Rodola'350c94b2012-03-22 16:17:43 +0100774
Victor Stinner7b9619a2017-04-19 23:42:46 +0200775 server = BaseServer(self.family, self.addr)
Victor Stinnera2c877c2017-04-21 13:51:53 +0200776 # run the thread 500 ms: the socket should be connected in 200 ms
Victor Stinner7b9619a2017-04-19 23:42:46 +0200777 t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1,
Victor Stinnera2c877c2017-04-21 13:51:53 +0200778 count=5))
Victor Stinner7b9619a2017-04-19 23:42:46 +0200779 t.start()
780 try:
781 with socket.socket(self.family, socket.SOCK_STREAM) as s:
782 s.settimeout(.2)
783 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
784 struct.pack('ii', 1, 0))
785
786 try:
787 s.connect(server.address)
788 except OSError:
789 pass
790 finally:
Victor Stinnerb9b69002017-09-14 14:40:56 -0700791 support.join_thread(t, timeout=TIMEOUT)
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000792
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200793class TestAPI_UseIPv4Sockets(BaseTestAPI):
794 family = socket.AF_INET
Victor Stinner252d40e2014-06-27 22:44:40 +0200795 addr = (support.HOST, 0)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200796
797@unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 support required')
798class TestAPI_UseIPv6Sockets(BaseTestAPI):
799 family = socket.AF_INET6
Victor Stinner252d40e2014-06-27 22:44:40 +0200800 addr = (support.HOSTv6, 0)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200801
Charles-François Natalie3540b42011-08-25 00:50:41 +0200802@unittest.skipUnless(HAS_UNIX_SOCKETS, 'Unix sockets required')
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200803class TestAPI_UseUnixSockets(BaseTestAPI):
Charles-François Natalia045c052011-08-25 01:22:50 +0200804 if HAS_UNIX_SOCKETS:
805 family = socket.AF_UNIX
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200806 addr = support.TESTFN
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200807
808 def tearDown(self):
Victor Stinner252d40e2014-06-27 22:44:40 +0200809 support.unlink(self.addr)
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200810 BaseTestAPI.tearDown(self)
811
Ezio Melotti47236db2013-01-10 05:28:52 +0200812class TestAPI_UseIPv4Select(TestAPI_UseIPv4Sockets, unittest.TestCase):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000813 use_poll = False
814
Ezio Melotti9a381c72010-07-27 22:24:13 +0000815@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200816class TestAPI_UseIPv4Poll(TestAPI_UseIPv4Sockets, unittest.TestCase):
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000817 use_poll = True
818
Ezio Melotti47236db2013-01-10 05:28:52 +0200819class TestAPI_UseIPv6Select(TestAPI_UseIPv6Sockets, unittest.TestCase):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200820 use_poll = False
821
822@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200823class TestAPI_UseIPv6Poll(TestAPI_UseIPv6Sockets, unittest.TestCase):
Charles-François Natalie78cbec2011-08-24 23:24:05 +0200824 use_poll = True
Giampaolo Rodolà8fc11782010-05-10 15:40:49 +0000825
Ezio Melotti47236db2013-01-10 05:28:52 +0200826class TestAPI_UseUnixSocketsSelect(TestAPI_UseUnixSockets, unittest.TestCase):
Charles-François Natali39648d12011-10-31 12:08:09 +0100827 use_poll = False
828
829@unittest.skipUnless(hasattr(select, 'poll'), 'select.poll required')
Ezio Melotti47236db2013-01-10 05:28:52 +0200830class TestAPI_UseUnixSocketsPoll(TestAPI_UseUnixSockets, unittest.TestCase):
Charles-François Natali39648d12011-10-31 12:08:09 +0100831 use_poll = True
832
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000833if __name__ == "__main__":
Ezio Melotti47236db2013-01-10 05:28:52 +0200834 unittest.main()