blob: f822024aa04294b88323e44892ce359c5aeb6d3a [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
Christian Heimes4fbc72b2008-03-22 00:47:35 +00008import sys
Victor Stinner125b2ba2011-06-29 17:20:02 +02009import time
Christian Heimes4fbc72b2008-03-22 00:47:35 +000010import unittest
11
Christian Heimes4fbc72b2008-03-22 00:47:35 +000012if not hasattr(select, "kqueue"):
Benjamin Petersone549ead2009-03-28 21:42:05 +000013 raise unittest.SkipTest("test works only on BSD")
Christian Heimes4fbc72b2008-03-22 00:47:35 +000014
15class TestKQueue(unittest.TestCase):
16 def test_create_queue(self):
17 kq = select.kqueue()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000018 self.assertTrue(kq.fileno() > 0, kq.fileno())
19 self.assertTrue(not kq.closed)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000020 kq.close()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000021 self.assertTrue(kq.closed)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000022 self.assertRaises(ValueError, kq.fileno)
23
24 def test_create_event(self):
Mark Dickinsona56c4672009-01-27 18:17:45 +000025 from operator import lt, le, gt, ge
Victor Stinner46b20912011-06-29 14:59:10 +020026
27 fd = os.open(os.devnull, os.O_WRONLY)
28 self.addCleanup(os.close, fd)
29
Christian Heimes4fbc72b2008-03-22 00:47:35 +000030 ev = select.kevent(fd)
31 other = select.kevent(1000)
32 self.assertEqual(ev.ident, fd)
33 self.assertEqual(ev.filter, select.KQ_FILTER_READ)
34 self.assertEqual(ev.flags, select.KQ_EV_ADD)
35 self.assertEqual(ev.fflags, 0)
36 self.assertEqual(ev.data, 0)
37 self.assertEqual(ev.udata, 0)
38 self.assertEqual(ev, ev)
39 self.assertNotEqual(ev, other)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000040 self.assertTrue(ev < other)
41 self.assertTrue(other >= ev)
Mark Dickinsona56c4672009-01-27 18:17:45 +000042 for op in lt, le, gt, ge:
43 self.assertRaises(TypeError, op, ev, None)
44 self.assertRaises(TypeError, op, ev, 1)
45 self.assertRaises(TypeError, op, ev, "ev")
Christian Heimes4fbc72b2008-03-22 00:47:35 +000046
47 ev = select.kevent(fd, select.KQ_FILTER_WRITE)
48 self.assertEqual(ev.ident, fd)
49 self.assertEqual(ev.filter, select.KQ_FILTER_WRITE)
50 self.assertEqual(ev.flags, select.KQ_EV_ADD)
51 self.assertEqual(ev.fflags, 0)
52 self.assertEqual(ev.data, 0)
53 self.assertEqual(ev.udata, 0)
54 self.assertEqual(ev, ev)
55 self.assertNotEqual(ev, other)
56
57 ev = select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_ONESHOT)
58 self.assertEqual(ev.ident, fd)
59 self.assertEqual(ev.filter, select.KQ_FILTER_WRITE)
60 self.assertEqual(ev.flags, select.KQ_EV_ONESHOT)
61 self.assertEqual(ev.fflags, 0)
62 self.assertEqual(ev.data, 0)
63 self.assertEqual(ev.udata, 0)
64 self.assertEqual(ev, ev)
65 self.assertNotEqual(ev, other)
66
67 ev = select.kevent(1, 2, 3, 4, 5, 6)
68 self.assertEqual(ev.ident, 1)
69 self.assertEqual(ev.filter, 2)
70 self.assertEqual(ev.flags, 3)
71 self.assertEqual(ev.fflags, 4)
72 self.assertEqual(ev.data, 5)
73 self.assertEqual(ev.udata, 6)
74 self.assertEqual(ev, ev)
75 self.assertNotEqual(ev, other)
76
Charles-François Natali6ddd2652013-08-02 10:21:20 +020077 bignum = 0x7fff
78 ev = select.kevent(bignum, 1, 2, 3, bignum - 1, bignum)
Antoine Pitroud83f1e62009-11-04 21:10:38 +000079 self.assertEqual(ev.ident, bignum)
80 self.assertEqual(ev.filter, 1)
81 self.assertEqual(ev.flags, 2)
82 self.assertEqual(ev.fflags, 3)
Charles-François Natali6ddd2652013-08-02 10:21:20 +020083 self.assertEqual(ev.data, bignum - 1)
Antoine Pitroud83f1e62009-11-04 21:10:38 +000084 self.assertEqual(ev.udata, bignum)
85 self.assertEqual(ev, ev)
86 self.assertNotEqual(ev, other)
87
R David Murray90f7afd2014-10-12 12:39:46 -040088 # Issue 11973
89 bignum = 0xffff
90 ev = select.kevent(0, 1, bignum)
91 self.assertEqual(ev.ident, 0)
92 self.assertEqual(ev.filter, 1)
93 self.assertEqual(ev.flags, bignum)
94 self.assertEqual(ev.fflags, 0)
95 self.assertEqual(ev.data, 0)
96 self.assertEqual(ev.udata, 0)
97 self.assertEqual(ev, ev)
98 self.assertNotEqual(ev, other)
99
100 # Issue 11973
101 bignum = 0xffffffff
102 ev = select.kevent(0, 1, 2, bignum)
103 self.assertEqual(ev.ident, 0)
104 self.assertEqual(ev.filter, 1)
105 self.assertEqual(ev.flags, 2)
106 self.assertEqual(ev.fflags, bignum)
107 self.assertEqual(ev.data, 0)
108 self.assertEqual(ev.udata, 0)
109 self.assertEqual(ev, ev)
110 self.assertNotEqual(ev, other)
111
112
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000113 def test_queue_event(self):
114 serverSocket = socket.socket()
115 serverSocket.bind(('127.0.0.1', 0))
Charles-François Natali6e204602014-07-23 19:28:13 +0100116 serverSocket.listen()
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000117 client = socket.socket()
118 client.setblocking(False)
119 try:
120 client.connect(('127.0.0.1', serverSocket.getsockname()[1]))
Andrew Svetlov0832af62012-12-18 23:10:48 +0200121 except OSError as e:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000122 self.assertEqual(e.args[0], errno.EINPROGRESS)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000123 else:
124 #raise AssertionError("Connect should have raised EINPROGRESS")
125 pass # FreeBSD doesn't raise an exception here
126 server, addr = serverSocket.accept()
127
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000128 kq = select.kqueue()
129 kq2 = select.kqueue.fromfd(kq.fileno())
130
131 ev = select.kevent(server.fileno(),
132 select.KQ_FILTER_WRITE,
133 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
134 kq.control([ev], 0)
135 ev = select.kevent(server.fileno(),
136 select.KQ_FILTER_READ,
137 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
138 kq.control([ev], 0)
139 ev = select.kevent(client.fileno(),
140 select.KQ_FILTER_WRITE,
141 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
142 kq2.control([ev], 0)
143 ev = select.kevent(client.fileno(),
144 select.KQ_FILTER_READ,
145 select.KQ_EV_ADD | select.KQ_EV_ENABLE)
146 kq2.control([ev], 0)
147
148 events = kq.control(None, 4, 1)
Charles-Francois Natali7a03e2d2013-03-31 20:36:57 +0200149 events = set((e.ident, e.filter) for e in events)
150 self.assertEqual(events, set([
151 (client.fileno(), select.KQ_FILTER_WRITE),
152 (server.fileno(), select.KQ_FILTER_WRITE)]))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000153
154 client.send(b"Hello!")
155 server.send(b"world!!!")
156
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000157 # We may need to call it several times
Mark Dickinson3dfe55b2009-01-24 16:22:21 +0000158 for i in range(10):
159 events = kq.control(None, 4, 1)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000160 if len(events) == 4:
161 break
Mark Dickinson3dfe55b2009-01-24 16:22:21 +0000162 time.sleep(1.0)
163 else:
164 self.fail('timeout waiting for event notifications')
165
Charles-Francois Natali7a03e2d2013-03-31 20:36:57 +0200166 events = set((e.ident, e.filter) for e in events)
167 self.assertEqual(events, set([
168 (client.fileno(), select.KQ_FILTER_WRITE),
169 (client.fileno(), select.KQ_FILTER_READ),
170 (server.fileno(), select.KQ_FILTER_WRITE),
171 (server.fileno(), select.KQ_FILTER_READ)]))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000172
173 # Remove completely client, and server read part
174 ev = select.kevent(client.fileno(),
175 select.KQ_FILTER_WRITE,
176 select.KQ_EV_DELETE)
177 kq.control([ev], 0)
178 ev = select.kevent(client.fileno(),
179 select.KQ_FILTER_READ,
180 select.KQ_EV_DELETE)
181 kq.control([ev], 0)
182 ev = select.kevent(server.fileno(),
183 select.KQ_FILTER_READ,
184 select.KQ_EV_DELETE)
185 kq.control([ev], 0, 0)
186
187 events = kq.control([], 4, 0.99)
Charles-Francois Natali7a03e2d2013-03-31 20:36:57 +0200188 events = set((e.ident, e.filter) for e in events)
189 self.assertEqual(events, set([
190 (server.fileno(), select.KQ_FILTER_WRITE)]))
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000191
192 client.close()
193 server.close()
194 serverSocket.close()
195
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000196 def testPair(self):
197 kq = select.kqueue()
198 a, b = socket.socketpair()
199
200 a.send(b'foo')
201 event1 = select.kevent(a, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
202 event2 = select.kevent(b, select.KQ_FILTER_READ, select.KQ_EV_ADD | select.KQ_EV_ENABLE)
203 r = kq.control([event1, event2], 1, 1)
204 self.assertTrue(r)
205 self.assertFalse(r[0].flags & select.KQ_EV_ERROR)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000206 self.assertEqual(b.recv(r[0].data), b'foo')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000207
208 a.close()
209 b.close()
210 kq.close()
211
Victor Stinner13423c32013-08-22 00:19:50 +0200212 def test_close(self):
213 open_file = open(__file__, "rb")
214 self.addCleanup(open_file.close)
215 fd = open_file.fileno()
216 kqueue = select.kqueue()
217
218 # test fileno() method and closed attribute
219 self.assertIsInstance(kqueue.fileno(), int)
220 self.assertFalse(kqueue.closed)
221
222 # test close()
223 kqueue.close()
224 self.assertTrue(kqueue.closed)
225 self.assertRaises(ValueError, kqueue.fileno)
226
227 # close() can be called more than once
228 kqueue.close()
229
230 # operations must fail with ValueError("I/O operation on closed ...")
231 self.assertRaises(ValueError, kqueue.control, None, 4)
232
Victor Stinnerdaf45552013-08-28 00:53:59 +0200233 def test_fd_non_inheritable(self):
234 kqueue = select.kqueue()
235 self.addCleanup(kqueue.close)
236 self.assertEqual(os.get_inheritable(kqueue.fileno()), False)
237
Victor Stinner13423c32013-08-22 00:19:50 +0200238
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000239if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500240 unittest.main()