blob: 454c17be99953c788e7d745ef73c94de47cc7f0a [file] [log] [blame]
Charles-François Natali243d8d82013-09-04 19:02:49 +02001import errno
Guido van Rossum9710ff02013-12-07 15:57:01 -08002import os
Charles-François Natali243d8d82013-09-04 19:02:49 +02003import random
4import selectors
5import signal
6import socket
Victor Stinnerfc6fdb12014-12-17 01:07:56 +01007import sys
Charles-François Natali243d8d82013-09-04 19:02:49 +02008from test import support
Victor Stinner6b0fa702014-01-25 15:04:22 +01009from time import sleep
Charles-François Natali243d8d82013-09-04 19:02:49 +020010import unittest
Guido van Rossumd0786a12013-11-07 08:39:28 -080011import unittest.mock
Victor Stinnerae586492014-09-02 23:18:25 +020012from time import monotonic as time
Charles-François Natali243d8d82013-09-04 19:02:49 +020013try:
14 import resource
15except ImportError:
16 resource = None
17
18
19if hasattr(socket, 'socketpair'):
20 socketpair = socket.socketpair
21else:
22 def socketpair(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
23 with socket.socket(family, type, proto) as l:
24 l.bind((support.HOST, 0))
Charles-François Natali6e204602014-07-23 19:28:13 +010025 l.listen()
Charles-François Natali243d8d82013-09-04 19:02:49 +020026 c = socket.socket(family, type, proto)
27 try:
28 c.connect(l.getsockname())
29 caddr = c.getsockname()
30 while True:
31 a, addr = l.accept()
32 # check that we've got the correct client
33 if addr == caddr:
34 return c, a
35 a.close()
36 except OSError:
37 c.close()
38 raise
39
40
41def find_ready_matching(ready, flag):
42 match = []
43 for key, events in ready:
44 if events & flag:
45 match.append(key.fileobj)
46 return match
47
48
49class BaseSelectorTestCase(unittest.TestCase):
50
Guido van Rossum9710ff02013-12-07 15:57:01 -080051 def make_socketpair(self):
52 rd, wr = socketpair()
53 self.addCleanup(rd.close)
54 self.addCleanup(wr.close)
55 return rd, wr
56
Charles-François Natali243d8d82013-09-04 19:02:49 +020057 def test_register(self):
58 s = self.SELECTOR()
59 self.addCleanup(s.close)
60
Guido van Rossum9710ff02013-12-07 15:57:01 -080061 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +020062
63 key = s.register(rd, selectors.EVENT_READ, "data")
64 self.assertIsInstance(key, selectors.SelectorKey)
65 self.assertEqual(key.fileobj, rd)
66 self.assertEqual(key.fd, rd.fileno())
67 self.assertEqual(key.events, selectors.EVENT_READ)
68 self.assertEqual(key.data, "data")
69
70 # register an unknown event
71 self.assertRaises(ValueError, s.register, 0, 999999)
72
73 # register an invalid FD
74 self.assertRaises(ValueError, s.register, -10, selectors.EVENT_READ)
75
76 # register twice
77 self.assertRaises(KeyError, s.register, rd, selectors.EVENT_READ)
78
79 # register the same FD, but with a different object
80 self.assertRaises(KeyError, s.register, rd.fileno(),
81 selectors.EVENT_READ)
82
83 def test_unregister(self):
84 s = self.SELECTOR()
85 self.addCleanup(s.close)
86
Guido van Rossum9710ff02013-12-07 15:57:01 -080087 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +020088
89 s.register(rd, selectors.EVENT_READ)
90 s.unregister(rd)
91
92 # unregister an unknown file obj
93 self.assertRaises(KeyError, s.unregister, 999999)
94
95 # unregister twice
96 self.assertRaises(KeyError, s.unregister, rd)
97
Guido van Rossum9710ff02013-12-07 15:57:01 -080098 def test_unregister_after_fd_close(self):
99 s = self.SELECTOR()
100 self.addCleanup(s.close)
101 rd, wr = self.make_socketpair()
102 r, w = rd.fileno(), wr.fileno()
103 s.register(r, selectors.EVENT_READ)
104 s.register(w, selectors.EVENT_WRITE)
105 rd.close()
106 wr.close()
107 s.unregister(r)
108 s.unregister(w)
109
Victor Stinner383bff42013-12-09 01:59:07 +0100110 @unittest.skipUnless(os.name == 'posix', "requires posix")
Guido van Rossum9710ff02013-12-07 15:57:01 -0800111 def test_unregister_after_fd_close_and_reuse(self):
112 s = self.SELECTOR()
113 self.addCleanup(s.close)
114 rd, wr = self.make_socketpair()
115 r, w = rd.fileno(), wr.fileno()
116 s.register(r, selectors.EVENT_READ)
117 s.register(w, selectors.EVENT_WRITE)
118 rd2, wr2 = self.make_socketpair()
119 rd.close()
120 wr.close()
121 os.dup2(rd2.fileno(), r)
122 os.dup2(wr2.fileno(), w)
123 self.addCleanup(os.close, r)
124 self.addCleanup(os.close, w)
125 s.unregister(r)
126 s.unregister(w)
127
128 def test_unregister_after_socket_close(self):
129 s = self.SELECTOR()
130 self.addCleanup(s.close)
131 rd, wr = self.make_socketpair()
132 s.register(rd, selectors.EVENT_READ)
133 s.register(wr, selectors.EVENT_WRITE)
134 rd.close()
135 wr.close()
136 s.unregister(rd)
137 s.unregister(wr)
138
Charles-François Natali243d8d82013-09-04 19:02:49 +0200139 def test_modify(self):
140 s = self.SELECTOR()
141 self.addCleanup(s.close)
142
Guido van Rossum9710ff02013-12-07 15:57:01 -0800143 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200144
145 key = s.register(rd, selectors.EVENT_READ)
146
147 # modify events
148 key2 = s.modify(rd, selectors.EVENT_WRITE)
149 self.assertNotEqual(key.events, key2.events)
150 self.assertEqual(key2, s.get_key(rd))
151
152 s.unregister(rd)
153
154 # modify data
155 d1 = object()
156 d2 = object()
157
158 key = s.register(rd, selectors.EVENT_READ, d1)
159 key2 = s.modify(rd, selectors.EVENT_READ, d2)
160 self.assertEqual(key.events, key2.events)
161 self.assertNotEqual(key.data, key2.data)
162 self.assertEqual(key2, s.get_key(rd))
163 self.assertEqual(key2.data, d2)
164
165 # modify unknown file obj
166 self.assertRaises(KeyError, s.modify, 999999, selectors.EVENT_READ)
167
Guido van Rossumd0786a12013-11-07 08:39:28 -0800168 # modify use a shortcut
169 d3 = object()
170 s.register = unittest.mock.Mock()
171 s.unregister = unittest.mock.Mock()
172
173 s.modify(rd, selectors.EVENT_READ, d3)
174 self.assertFalse(s.register.called)
175 self.assertFalse(s.unregister.called)
176
Charles-François Natali243d8d82013-09-04 19:02:49 +0200177 def test_close(self):
178 s = self.SELECTOR()
179 self.addCleanup(s.close)
180
Victor Stinner38dc2502015-01-13 09:58:33 +0100181 mapping = s.get_map()
Guido van Rossum9710ff02013-12-07 15:57:01 -0800182 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200183
184 s.register(rd, selectors.EVENT_READ)
185 s.register(wr, selectors.EVENT_WRITE)
186
187 s.close()
Victor Stinner458fc6f2015-01-13 10:00:55 +0100188 self.assertRaises(RuntimeError, s.get_key, rd)
189 self.assertRaises(RuntimeError, s.get_key, wr)
Victor Stinner38dc2502015-01-13 09:58:33 +0100190 self.assertRaises(KeyError, mapping.__getitem__, rd)
191 self.assertRaises(KeyError, mapping.__getitem__, wr)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200192
193 def test_get_key(self):
194 s = self.SELECTOR()
195 self.addCleanup(s.close)
196
Guido van Rossum9710ff02013-12-07 15:57:01 -0800197 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200198
199 key = s.register(rd, selectors.EVENT_READ, "data")
200 self.assertEqual(key, s.get_key(rd))
201
202 # unknown file obj
203 self.assertRaises(KeyError, s.get_key, 999999)
204
Charles-François Natali4574b492013-10-30 20:31:04 +0100205 def test_get_map(self):
206 s = self.SELECTOR()
207 self.addCleanup(s.close)
208
Guido van Rossum9710ff02013-12-07 15:57:01 -0800209 rd, wr = self.make_socketpair()
Charles-François Natali4574b492013-10-30 20:31:04 +0100210
211 keys = s.get_map()
212 self.assertFalse(keys)
213 self.assertEqual(len(keys), 0)
214 self.assertEqual(list(keys), [])
215 key = s.register(rd, selectors.EVENT_READ, "data")
216 self.assertIn(rd, keys)
217 self.assertEqual(key, keys[rd])
218 self.assertEqual(len(keys), 1)
219 self.assertEqual(list(keys), [rd.fileno()])
220 self.assertEqual(list(keys.values()), [key])
221
222 # unknown file obj
223 with self.assertRaises(KeyError):
224 keys[999999]
225
226 # Read-only mapping
227 with self.assertRaises(TypeError):
228 del keys[rd]
229
Charles-François Natali243d8d82013-09-04 19:02:49 +0200230 def test_select(self):
231 s = self.SELECTOR()
232 self.addCleanup(s.close)
233
Guido van Rossum9710ff02013-12-07 15:57:01 -0800234 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200235
236 s.register(rd, selectors.EVENT_READ)
237 wr_key = s.register(wr, selectors.EVENT_WRITE)
238
239 result = s.select()
240 for key, events in result:
241 self.assertTrue(isinstance(key, selectors.SelectorKey))
242 self.assertTrue(events)
243 self.assertFalse(events & ~(selectors.EVENT_READ |
244 selectors.EVENT_WRITE))
245
246 self.assertEqual([(wr_key, selectors.EVENT_WRITE)], result)
247
248 def test_context_manager(self):
249 s = self.SELECTOR()
250 self.addCleanup(s.close)
251
Guido van Rossum9710ff02013-12-07 15:57:01 -0800252 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200253
254 with s as sel:
255 sel.register(rd, selectors.EVENT_READ)
256 sel.register(wr, selectors.EVENT_WRITE)
257
Victor Stinner458fc6f2015-01-13 10:00:55 +0100258 self.assertRaises(RuntimeError, s.get_key, rd)
259 self.assertRaises(RuntimeError, s.get_key, wr)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200260
261 def test_fileno(self):
262 s = self.SELECTOR()
263 self.addCleanup(s.close)
264
265 if hasattr(s, 'fileno'):
266 fd = s.fileno()
267 self.assertTrue(isinstance(fd, int))
268 self.assertGreaterEqual(fd, 0)
269
270 def test_selector(self):
271 s = self.SELECTOR()
272 self.addCleanup(s.close)
273
274 NUM_SOCKETS = 12
275 MSG = b" This is a test."
276 MSG_LEN = len(MSG)
277 readers = []
278 writers = []
279 r2w = {}
280 w2r = {}
281
282 for i in range(NUM_SOCKETS):
Guido van Rossum9710ff02013-12-07 15:57:01 -0800283 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200284 s.register(rd, selectors.EVENT_READ)
285 s.register(wr, selectors.EVENT_WRITE)
286 readers.append(rd)
287 writers.append(wr)
288 r2w[rd] = wr
289 w2r[wr] = rd
290
291 bufs = []
292
293 while writers:
294 ready = s.select()
295 ready_writers = find_ready_matching(ready, selectors.EVENT_WRITE)
296 if not ready_writers:
297 self.fail("no sockets ready for writing")
298 wr = random.choice(ready_writers)
299 wr.send(MSG)
300
301 for i in range(10):
302 ready = s.select()
303 ready_readers = find_ready_matching(ready,
304 selectors.EVENT_READ)
305 if ready_readers:
306 break
307 # there might be a delay between the write to the write end and
308 # the read end is reported ready
309 sleep(0.1)
310 else:
311 self.fail("no sockets ready for reading")
312 self.assertEqual([w2r[wr]], ready_readers)
313 rd = ready_readers[0]
314 buf = rd.recv(MSG_LEN)
315 self.assertEqual(len(buf), MSG_LEN)
316 bufs.append(buf)
317 s.unregister(r2w[rd])
318 s.unregister(rd)
319 writers.remove(r2w[rd])
320
321 self.assertEqual(bufs, [MSG] * NUM_SOCKETS)
322
Victor Stinnerfc6fdb12014-12-17 01:07:56 +0100323 @unittest.skipIf(sys.platform == 'win32',
324 'select.select() cannot be used with empty fd sets')
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500325 def test_empty_select(self):
Victor Stinner14d45c02015-01-22 09:07:36 +0100326 # Issue #23009: Make sure EpollSelector.select() works when no FD is
327 # registered.
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500328 s = self.SELECTOR()
329 self.addCleanup(s.close)
330 self.assertEqual(s.select(timeout=0), [])
331
Charles-François Natali243d8d82013-09-04 19:02:49 +0200332 def test_timeout(self):
333 s = self.SELECTOR()
334 self.addCleanup(s.close)
335
Guido van Rossum9710ff02013-12-07 15:57:01 -0800336 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200337
338 s.register(wr, selectors.EVENT_WRITE)
339 t = time()
340 self.assertEqual(1, len(s.select(0)))
341 self.assertEqual(1, len(s.select(-1)))
Charles-François Natalic60dd5b2013-10-25 17:56:00 +0200342 self.assertLess(time() - t, 0.5)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200343
344 s.unregister(wr)
345 s.register(rd, selectors.EVENT_READ)
346 t = time()
347 self.assertFalse(s.select(0))
348 self.assertFalse(s.select(-1))
Charles-François Natalic60dd5b2013-10-25 17:56:00 +0200349 self.assertLess(time() - t, 0.5)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200350
Charles-François Natalic60dd5b2013-10-25 17:56:00 +0200351 t0 = time()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200352 self.assertFalse(s.select(1))
Charles-François Natalic60dd5b2013-10-25 17:56:00 +0200353 t1 = time()
Victor Stinner1a048f92013-11-17 23:46:34 +0100354 dt = t1 - t0
Victor Stinner437ffbd2014-12-12 12:57:35 +0100355 # Tolerate 2.0 seconds for very slow buildbots
356 self.assertTrue(0.8 <= dt <= 2.0, dt)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200357
358 @unittest.skipUnless(hasattr(signal, "alarm"),
359 "signal.alarm() required for this test")
Victor Stinnerb3101732015-03-31 12:08:09 +0200360 def test_select_interrupt_exc(self):
361 s = self.SELECTOR()
362 self.addCleanup(s.close)
363
364 rd, wr = self.make_socketpair()
365
366 class InterruptSelect(Exception):
367 pass
368
369 def handler(*args):
370 raise InterruptSelect
371
372 orig_alrm_handler = signal.signal(signal.SIGALRM, handler)
373 self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler)
374 self.addCleanup(signal.alarm, 0)
375
376 signal.alarm(1)
377
378 s.register(rd, selectors.EVENT_READ)
379 t = time()
380 # select() is interrupted by a signal which raises an exception
381 with self.assertRaises(InterruptSelect):
382 s.select(30)
383 # select() was interrupted before the timeout of 30 seconds
384 self.assertLess(time() - t, 5.0)
385
386 @unittest.skipUnless(hasattr(signal, "alarm"),
387 "signal.alarm() required for this test")
388 def test_select_interrupt_noraise(self):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200389 s = self.SELECTOR()
390 self.addCleanup(s.close)
391
Guido van Rossum9710ff02013-12-07 15:57:01 -0800392 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200393
394 orig_alrm_handler = signal.signal(signal.SIGALRM, lambda *args: None)
395 self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler)
396 self.addCleanup(signal.alarm, 0)
397
398 signal.alarm(1)
399
400 s.register(rd, selectors.EVENT_READ)
401 t = time()
Victor Stinnerb3101732015-03-31 12:08:09 +0200402 # select() is interrupted by a signal, but the signal handler doesn't
403 # raise an exception, so select() should by retries with a recomputed
404 # timeout
405 self.assertFalse(s.select(1.5))
406 self.assertGreaterEqual(time() - t, 1.0)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200407
408
409class ScalableSelectorMixIn:
410
Charles-François Natali807ba852013-09-08 12:31:32 +0200411 # see issue #18963 for why it's skipped on older OS X versions
412 @support.requires_mac_ver(10, 5)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200413 @unittest.skipUnless(resource, "Test needs resource module")
414 def test_above_fd_setsize(self):
415 # A scalable implementation should have no problem with more than
416 # FD_SETSIZE file descriptors. Since we don't know the value, we just
417 # try to set the soft RLIMIT_NOFILE to the hard RLIMIT_NOFILE ceiling.
418 soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
419 try:
420 resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard))
421 self.addCleanup(resource.setrlimit, resource.RLIMIT_NOFILE,
422 (soft, hard))
Charles-François Natali889d6462014-07-22 21:25:03 +0100423 NUM_FDS = min(hard, 2**16)
Charles-François Natali9437d7a2013-09-08 11:34:42 +0200424 except (OSError, ValueError):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200425 NUM_FDS = soft
426
427 # guard for already allocated FDs (stdin, stdout...)
428 NUM_FDS -= 32
429
430 s = self.SELECTOR()
431 self.addCleanup(s.close)
432
433 for i in range(NUM_FDS // 2):
434 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800435 rd, wr = self.make_socketpair()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200436 except OSError:
437 # too many FDs, skip - note that we should only catch EMFILE
438 # here, but apparently *BSD and Solaris can fail upon connect()
439 # or bind() with EADDRNOTAVAIL, so let's be safe
440 self.skipTest("FD limit reached")
441
Charles-François Natali243d8d82013-09-04 19:02:49 +0200442 try:
443 s.register(rd, selectors.EVENT_READ)
444 s.register(wr, selectors.EVENT_WRITE)
445 except OSError as e:
446 if e.errno == errno.ENOSPC:
447 # this can be raised by epoll if we go over
448 # fs.epoll.max_user_watches sysctl
449 self.skipTest("FD limit reached")
450 raise
451
452 self.assertEqual(NUM_FDS // 2, len(s.select()))
453
454
455class DefaultSelectorTestCase(BaseSelectorTestCase):
456
457 SELECTOR = selectors.DefaultSelector
458
459
460class SelectSelectorTestCase(BaseSelectorTestCase):
461
462 SELECTOR = selectors.SelectSelector
463
464
465@unittest.skipUnless(hasattr(selectors, 'PollSelector'),
466 "Test needs selectors.PollSelector")
467class PollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
468
469 SELECTOR = getattr(selectors, 'PollSelector', None)
470
471
472@unittest.skipUnless(hasattr(selectors, 'EpollSelector'),
473 "Test needs selectors.EpollSelector")
474class EpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
475
476 SELECTOR = getattr(selectors, 'EpollSelector', None)
477
478
479@unittest.skipUnless(hasattr(selectors, 'KqueueSelector'),
480 "Test needs selectors.KqueueSelector)")
481class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
482
483 SELECTOR = getattr(selectors, 'KqueueSelector', None)
484
485
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100486@unittest.skipUnless(hasattr(selectors, 'DevpollSelector'),
487 "Test needs selectors.DevpollSelector")
488class DevpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
489
490 SELECTOR = getattr(selectors, 'DevpollSelector', None)
491
492
493
Charles-François Natali243d8d82013-09-04 19:02:49 +0200494def test_main():
495 tests = [DefaultSelectorTestCase, SelectSelectorTestCase,
496 PollSelectorTestCase, EpollSelectorTestCase,
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100497 KqueueSelectorTestCase, DevpollSelectorTestCase]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200498 support.run_unittest(*tests)
499 support.reap_children()
500
501
502if __name__ == "__main__":
503 test_main()