blob: 998fd9d46496bbc713fc41dda316f7a3dabb02a4 [file] [log] [blame]
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001"""
2Tests for kqueue wrapper.
3"""
Christian Heimes4fbc72b2008-03-22 00:47:35 +00004import errno
Victor Stinner125b2ba2011-06-29 17:20:02 +02005import os
Christian Heimes4fbc72b2008-03-22 00:47:35 +00006import select
Victor Stinner125b2ba2011-06-29 17:20:02 +02007import socket
Victor Stinner125b2ba2011-06-29 17:20:02 +02008import time
Christian Heimes4fbc72b2008-03-22 00:47:35 +00009import unittest
10
Christian Heimes4fbc72b2008-03-22 00:47:35 +000011if not hasattr(select, "kqueue"):
Benjamin Petersone549ead2009-03-28 21:42:05 +000012 raise unittest.SkipTest("test works only on BSD")
Christian Heimes4fbc72b2008-03-22 00:47:35 +000013
14class TestKQueue(unittest.TestCase):
15 def test_create_queue(self):
16 kq = select.kqueue()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000017 self.assertTrue(kq.fileno() > 0, kq.fileno())
18 self.assertTrue(not kq.closed)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000019 kq.close()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000020 self.assertTrue(kq.closed)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000021 self.assertRaises(ValueError, kq.fileno)
22
23 def test_create_event(self):
Mark Dickinsona56c4672009-01-27 18:17:45 +000024 from operator import lt, le, gt, ge
Victor Stinner46b20912011-06-29 14:59:10 +020025
26 fd = os.open(os.devnull, os.O_WRONLY)
27 self.addCleanup(os.close, fd)
28
Christian Heimes4fbc72b2008-03-22 00:47:35 +000029 ev = select.kevent(fd)
30 other = select.kevent(1000)
31 self.assertEqual(ev.ident, fd)
32 self.assertEqual(ev.filter, select.KQ_FILTER_READ)
33 self.assertEqual(ev.flags, select.KQ_EV_ADD)
34 self.assertEqual(ev.fflags, 0)
35 self.assertEqual(ev.data, 0)
36 self.assertEqual(ev.udata, 0)
37 self.assertEqual(ev, ev)
38 self.assertNotEqual(ev, other)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000039 self.assertTrue(ev < other)
40 self.assertTrue(other >= ev)
Mark Dickinsona56c4672009-01-27 18:17:45 +000041 for op in lt, le, gt, ge:
42 self.assertRaises(TypeError, op, ev, None)
43 self.assertRaises(TypeError, op, ev, 1)
44 self.assertRaises(TypeError, op, ev, "ev")
Christian Heimes4fbc72b2008-03-22 00:47:35 +000045
46 ev = select.kevent(fd, select.KQ_FILTER_WRITE)
47 self.assertEqual(ev.ident, fd)
48 self.assertEqual(ev.filter, select.KQ_FILTER_WRITE)
49 self.assertEqual(ev.flags, select.KQ_EV_ADD)
50 self.assertEqual(ev.fflags, 0)
51 self.assertEqual(ev.data, 0)
52 self.assertEqual(ev.udata, 0)
53 self.assertEqual(ev, ev)
54 self.assertNotEqual(ev, other)
55
56 ev = select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_ONESHOT)
57 self.assertEqual(ev.ident, fd)
58 self.assertEqual(ev.filter, select.KQ_FILTER_WRITE)
59 self.assertEqual(ev.flags, select.KQ_EV_ONESHOT)
60 self.assertEqual(ev.fflags, 0)
61 self.assertEqual(ev.data, 0)
62 self.assertEqual(ev.udata, 0)
63 self.assertEqual(ev, ev)
64 self.assertNotEqual(ev, other)
65
66 ev = select.kevent(1, 2, 3, 4, 5, 6)
67 self.assertEqual(ev.ident, 1)
68 self.assertEqual(ev.filter, 2)
69 self.assertEqual(ev.flags, 3)
70 self.assertEqual(ev.fflags, 4)
71 self.assertEqual(ev.data, 5)
72 self.assertEqual(ev.udata, 6)
73 self.assertEqual(ev, ev)
74 self.assertNotEqual(ev, other)
75
Charles-François Natali6ddd2652013-08-02 10:21:20 +020076 bignum = 0x7fff
77 ev = select.kevent(bignum, 1, 2, 3, bignum - 1, bignum)
Antoine Pitroud83f1e62009-11-04 21:10:38 +000078 self.assertEqual(ev.ident, bignum)
79 self.assertEqual(ev.filter, 1)
80 self.assertEqual(ev.flags, 2)
81 self.assertEqual(ev.fflags, 3)
Charles-François Natali6ddd2652013-08-02 10:21:20 +020082 self.assertEqual(ev.data, bignum - 1)
Antoine Pitroud83f1e62009-11-04 21:10:38 +000083 self.assertEqual(ev.udata, bignum)
84 self.assertEqual(ev, ev)
85 self.assertNotEqual(ev, other)
86
R David Murray90f7afd2014-10-12 12:39:46 -040087 # Issue 11973
88 bignum = 0xffff
89 ev = select.kevent(0, 1, bignum)
90 self.assertEqual(ev.ident, 0)
91 self.assertEqual(ev.filter, 1)
92 self.assertEqual(ev.flags, bignum)
93 self.assertEqual(ev.fflags, 0)
94 self.assertEqual(ev.data, 0)
95 self.assertEqual(ev.udata, 0)
96 self.assertEqual(ev, ev)
97 self.assertNotEqual(ev, other)
98
99 # Issue 11973
100 bignum = 0xffffffff
101 ev = select.kevent(0, 1, 2, bignum)
102 self.assertEqual(ev.ident, 0)
103 self.assertEqual(ev.filter, 1)
104 self.assertEqual(ev.flags, 2)
105 self.assertEqual(ev.fflags, bignum)
106 self.assertEqual(ev.data, 0)
107 self.assertEqual(ev.udata, 0)
108 self.assertEqual(ev, ev)
109 self.assertNotEqual(ev, other)
110
111
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000112 def test_queue_event(self):
Giampaolo Rodolaeb7e29f2019-04-09 00:34:02 +0200113 serverSocket = socket.create_server(('127.0.0.1', 0))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000114 client = socket.socket()
115 client.setblocking(False)
116 try:
117 client.connect(('127.0.0.1', serverSocket.getsockname()[1]))
Andrew Svetlov0832af62012-12-18 23:10:48 +0200118 except OSError as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000119 self.assertEqual(e.args[0], errno.EINPROGRESS)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000120 else:
121 #raise AssertionError("Connect should have raised EINPROGRESS")
122 pass # FreeBSD doesn't raise an exception here
123 server, addr = serverSocket.accept()
124
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000125 kq = select.kqueue()
126 kq2 = select.kqueue.fromfd(kq.fileno())
127
128 ev = select.kevent(server.fileno(),
129 select.KQ_FILTER_WRITE,
130 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
131 kq.control([ev], 0)
132 ev = select.kevent(server.fileno(),
133 select.KQ_FILTER_READ,
134 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
135 kq.control([ev], 0)
136 ev = select.kevent(client.fileno(),
137 select.KQ_FILTER_WRITE,
138 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
139 kq2.control([ev], 0)
140 ev = select.kevent(client.fileno(),
141 select.KQ_FILTER_READ,
142 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
143 kq2.control([ev], 0)
144
145 events = kq.control(None, 4, 1)
Charles-Francois Natali7a03e2d2013-03-31 20:36:57 +0200146 events = set((e.ident, e.filter) for e in events)
147 self.assertEqual(events, set([
148 (client.fileno(), select.KQ_FILTER_WRITE),
149 (server.fileno(), select.KQ_FILTER_WRITE)]))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000150
151 client.send(b"Hello!")
152 server.send(b"world!!!")
153
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000154 # We may need to call it several times
Mark Dickinson3dfe55b2009-01-24 16:22:21 +0000155 for i in range(10):
156 events = kq.control(None, 4, 1)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000157 if len(events) == 4:
158 break
Mark Dickinson3dfe55b2009-01-24 16:22:21 +0000159 time.sleep(1.0)
160 else:
161 self.fail('timeout waiting for event notifications')
162
Charles-Francois Natali7a03e2d2013-03-31 20:36:57 +0200163 events = set((e.ident, e.filter) for e in events)
164 self.assertEqual(events, set([
165 (client.fileno(), select.KQ_FILTER_WRITE),
166 (client.fileno(), select.KQ_FILTER_READ),
167 (server.fileno(), select.KQ_FILTER_WRITE),
168 (server.fileno(), select.KQ_FILTER_READ)]))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000169
170 # Remove completely client, and server read part
171 ev = select.kevent(client.fileno(),
172 select.KQ_FILTER_WRITE,
173 select.KQ_EV_DELETE)
174 kq.control([ev], 0)
175 ev = select.kevent(client.fileno(),
176 select.KQ_FILTER_READ,
177 select.KQ_EV_DELETE)
178 kq.control([ev], 0)
179 ev = select.kevent(server.fileno(),
180 select.KQ_FILTER_READ,
181 select.KQ_EV_DELETE)
182 kq.control([ev], 0, 0)
183
184 events = kq.control([], 4, 0.99)
Charles-Francois Natali7a03e2d2013-03-31 20:36:57 +0200185 events = set((e.ident, e.filter) for e in events)
186 self.assertEqual(events, set([
187 (server.fileno(), select.KQ_FILTER_WRITE)]))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000188
189 client.close()
190 server.close()
191 serverSocket.close()
192
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000193 def testPair(self):
194 kq = select.kqueue()
195 a, b = socket.socketpair()
196
197 a.send(b'foo')
198 event1 = select.kevent(a, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
199 event2 = select.kevent(b, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
200 r = kq.control([event1, event2], 1, 1)
201 self.assertTrue(r)
202 self.assertFalse(r[0].flags & select.KQ_EV_ERROR)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000203 self.assertEqual(b.recv(r[0].data), b'foo')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000204
205 a.close()
206 b.close()
207 kq.close()
208
Serhiy Storchakade072102017-10-12 22:17:46 +0300209 def test_issue30058(self):
210 # changelist must be an iterable
211 kq = select.kqueue()
212 a, b = socket.socketpair()
213 ev = select.kevent(a, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
214
215 kq.control([ev], 0)
216 # not a list
217 kq.control((ev,), 0)
218 # __len__ is not consistent with __iter__
219 class BadList:
220 def __len__(self):
221 return 0
222 def __iter__(self):
223 for i in range(100):
224 yield ev
225 kq.control(BadList(), 0)
226 # doesn't have __len__
227 kq.control(iter([ev]), 0)
228
229 a.close()
230 b.close()
231 kq.close()
232
Victor Stinner13423c32013-08-22 00:19:50 +0200233 def test_close(self):
234 open_file = open(__file__, "rb")
235 self.addCleanup(open_file.close)
236 fd = open_file.fileno()
237 kqueue = select.kqueue()
238
239 # test fileno() method and closed attribute
240 self.assertIsInstance(kqueue.fileno(), int)
241 self.assertFalse(kqueue.closed)
242
243 # test close()
244 kqueue.close()
245 self.assertTrue(kqueue.closed)
246 self.assertRaises(ValueError, kqueue.fileno)
247
248 # close() can be called more than once
249 kqueue.close()
250
251 # operations must fail with ValueError("I/O operation on closed ...")
252 self.assertRaises(ValueError, kqueue.control, None, 4)
253
Victor Stinnerdaf45552013-08-28 00:53:59 +0200254 def test_fd_non_inheritable(self):
255 kqueue = select.kqueue()
256 self.addCleanup(kqueue.close)
257 self.assertEqual(os.get_inheritable(kqueue.fileno()), False)
258
Victor Stinner13423c32013-08-22 00:19:50 +0200259
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000260if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500261 unittest.main()