blob: ef966bf0f5608087f3f545c3f083e57f359cb4a7 [file] [log] [blame]
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +00001# Test case for the os.poll() function
Fred Drake004d5e62000-10-23 17:22:08 +00002
Serhiy Storchakab1973c22013-08-20 20:38:21 +03003import os
Christian Heimes06888972013-08-20 22:09:41 +02004import subprocess
Serhiy Storchakab1973c22013-08-20 20:38:21 +03005import random
6import select
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02007import threading
Serhiy Storchakab1973c22013-08-20 20:38:21 +03008import time
9import unittest
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +020010from test.support import TESTFN, run_unittest, reap_threads, cpython_only
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000011
12try:
13 select.poll
14except AttributeError:
Brett Cannoncd8efa32012-11-14 15:16:53 -050015 raise unittest.SkipTest("select.poll not defined")
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000016
17
18def find_ready_matching(ready, flag):
19 match = []
20 for fd, mode in ready:
21 if mode & flag:
22 match.append(fd)
23 return match
24
Thomas Wouters89f507f2006-12-13 04:49:30 +000025class PollTests(unittest.TestCase):
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000026
Thomas Wouters89f507f2006-12-13 04:49:30 +000027 def test_poll1(self):
28 # Basic functional test of poll object
29 # Create a bunch of pipe and test that poll works with them.
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000030
Thomas Wouters89f507f2006-12-13 04:49:30 +000031 p = select.poll()
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000032
Thomas Wouters89f507f2006-12-13 04:49:30 +000033 NUM_PIPES = 12
Guido van Rossumbdab7d32007-07-11 20:43:16 +000034 MSG = b" This is a test."
Thomas Wouters89f507f2006-12-13 04:49:30 +000035 MSG_LEN = len(MSG)
36 readers = []
37 writers = []
38 r2w = {}
39 w2r = {}
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000040
Thomas Wouters89f507f2006-12-13 04:49:30 +000041 for i in range(NUM_PIPES):
42 rd, wr = os.pipe()
Christian Heimes4fbc72b2008-03-22 00:47:35 +000043 p.register(rd)
44 p.modify(rd, select.POLLIN)
Thomas Wouters89f507f2006-12-13 04:49:30 +000045 p.register(wr, select.POLLOUT)
46 readers.append(rd)
47 writers.append(wr)
48 r2w[rd] = wr
49 w2r[wr] = rd
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000050
Thomas Wouters89f507f2006-12-13 04:49:30 +000051 bufs = []
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000052
Thomas Wouters89f507f2006-12-13 04:49:30 +000053 while writers:
54 ready = p.poll()
55 ready_writers = find_ready_matching(ready, select.POLLOUT)
56 if not ready_writers:
Collin Winter3add4d72007-08-29 23:37:32 +000057 raise RuntimeError("no pipes ready for writing")
Thomas Wouters89f507f2006-12-13 04:49:30 +000058 wr = random.choice(ready_writers)
59 os.write(wr, MSG)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000060
Thomas Wouters89f507f2006-12-13 04:49:30 +000061 ready = p.poll()
62 ready_readers = find_ready_matching(ready, select.POLLIN)
63 if not ready_readers:
Collin Winter3add4d72007-08-29 23:37:32 +000064 raise RuntimeError("no pipes ready for reading")
Thomas Wouters89f507f2006-12-13 04:49:30 +000065 rd = random.choice(ready_readers)
66 buf = os.read(rd, MSG_LEN)
67 self.assertEqual(len(buf), MSG_LEN)
68 bufs.append(buf)
69 os.close(r2w[rd]) ; os.close( rd )
70 p.unregister( r2w[rd] )
71 p.unregister( rd )
72 writers.remove(r2w[rd])
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000073
Thomas Wouters89f507f2006-12-13 04:49:30 +000074 self.assertEqual(bufs, [MSG] * NUM_PIPES)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000075
Richard Oudkerk53dff0c2012-12-09 16:05:20 +000076 def test_poll_unit_tests(self):
Thomas Wouters89f507f2006-12-13 04:49:30 +000077 # returns NVAL for invalid file descriptor
Richard Oudkerk53dff0c2012-12-09 16:05:20 +000078 FD, w = os.pipe()
79 os.close(FD)
80 os.close(w)
Thomas Wouters89f507f2006-12-13 04:49:30 +000081 p = select.poll()
82 p.register(FD)
83 r = p.poll()
84 self.assertEqual(r[0], (FD, select.POLLNVAL))
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000085
Serhiy Storchaka5b10b982019-03-05 10:06:26 +020086 with open(TESTFN, 'w') as f:
87 fd = f.fileno()
88 p = select.poll()
89 p.register(f)
90 r = p.poll()
91 self.assertEqual(r[0][0], fd)
Thomas Wouters89f507f2006-12-13 04:49:30 +000092 r = p.poll()
93 self.assertEqual(r[0], (fd, select.POLLNVAL))
94 os.unlink(TESTFN)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +000095
Thomas Wouters89f507f2006-12-13 04:49:30 +000096 # type error for invalid arguments
97 p = select.poll()
98 self.assertRaises(TypeError, p.register, p)
99 self.assertRaises(TypeError, p.unregister, p)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000100
Thomas Wouters89f507f2006-12-13 04:49:30 +0000101 # can't unregister non-existent object
102 p = select.poll()
103 self.assertRaises(KeyError, p.unregister, 3)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000104
Thomas Wouters89f507f2006-12-13 04:49:30 +0000105 # Test error cases
106 pollster = select.poll()
107 class Nope:
108 pass
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000109
Thomas Wouters89f507f2006-12-13 04:49:30 +0000110 class Almost:
111 def fileno(self):
112 return 'fileno'
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000113
Thomas Wouters89f507f2006-12-13 04:49:30 +0000114 self.assertRaises(TypeError, pollster.register, Nope(), 0)
115 self.assertRaises(TypeError, pollster.register, Almost(), 0)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000116
Thomas Wouters89f507f2006-12-13 04:49:30 +0000117 # Another test case for poll(). This is copied from the test case for
118 # select(), modified to use poll() instead.
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000119
Thomas Wouters89f507f2006-12-13 04:49:30 +0000120 def test_poll2(self):
121 cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done'
Richard Oudkerk07c34bf2012-12-09 16:05:22 +0000122 proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
123 bufsize=0)
Martin Panter3cf0b252016-08-12 11:59:52 +0000124 proc.__enter__()
125 self.addCleanup(proc.__exit__, None, None, None)
Richard Oudkerk07c34bf2012-12-09 16:05:22 +0000126 p = proc.stdout
Thomas Wouters89f507f2006-12-13 04:49:30 +0000127 pollster = select.poll()
128 pollster.register( p, select.POLLIN )
129 for tout in (0, 1000, 2000, 4000, 8000, 16000) + (-1,)*10:
130 fdlist = pollster.poll(tout)
131 if (fdlist == []):
132 continue
133 fd, flags = fdlist[0]
134 if flags & select.POLLHUP:
135 line = p.readline()
Richard Oudkerk07c34bf2012-12-09 16:05:22 +0000136 if line != b"":
Thomas Wouters89f507f2006-12-13 04:49:30 +0000137 self.fail('error: pipe seems to be closed, but still returns data')
138 continue
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000139
Thomas Wouters89f507f2006-12-13 04:49:30 +0000140 elif flags & select.POLLIN:
141 line = p.readline()
142 if not line:
143 break
Richard Oudkerk07c34bf2012-12-09 16:05:22 +0000144 self.assertEqual(line, b'testing...\n')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000145 continue
146 else:
147 self.fail('Unexpected return value from select.poll: %s' % fdlist)
Andrew M. Kuchling3227cc82000-08-25 01:18:45 +0000148
Thomas Wouters89f507f2006-12-13 04:49:30 +0000149 def test_poll3(self):
150 # test int overflow
151 pollster = select.poll()
152 pollster.register(1)
Neal Norwitz0f46bbf2005-11-03 05:00:25 +0000153
Guido van Rossume2a383d2007-01-15 16:59:06 +0000154 self.assertRaises(OverflowError, pollster.poll, 1 << 64)
Neal Norwitz0f46bbf2005-11-03 05:00:25 +0000155
Thomas Wouters89f507f2006-12-13 04:49:30 +0000156 x = 2 + 3
157 if x != 5:
158 self.fail('Overflow must have occurred')
Tim Peters536cf992005-12-25 23:18:31 +0000159
Serhiy Storchaka5da107a2013-12-14 19:12:02 +0200160 # Issues #15989, #17919
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +0300161 self.assertRaises(ValueError, pollster.register, 0, -1)
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200162 self.assertRaises(OverflowError, pollster.register, 0, 1 << 64)
Serhiy Storchaka7cb7bcf2018-07-26 13:22:16 +0300163 self.assertRaises(ValueError, pollster.modify, 1, -1)
Serhiy Storchaka5cfc79d2014-02-07 10:06:39 +0200164 self.assertRaises(OverflowError, pollster.modify, 1, 1 << 64)
165
166 @cpython_only
167 def test_poll_c_limits(self):
168 from _testcapi import USHRT_MAX, INT_MAX, UINT_MAX
169 pollster = select.poll()
170 pollster.register(1)
171
172 # Issues #15989, #17919
173 self.assertRaises(OverflowError, pollster.register, 0, USHRT_MAX + 1)
Serhiy Storchaka5da107a2013-12-14 19:12:02 +0200174 self.assertRaises(OverflowError, pollster.modify, 1, USHRT_MAX + 1)
175 self.assertRaises(OverflowError, pollster.poll, INT_MAX + 1)
176 self.assertRaises(OverflowError, pollster.poll, UINT_MAX + 1)
Serhiy Storchaka78980432013-01-15 01:12:17 +0200177
Serhiy Storchakab1973c22013-08-20 20:38:21 +0300178 @reap_threads
179 def test_threaded_poll(self):
180 r, w = os.pipe()
181 self.addCleanup(os.close, r)
182 self.addCleanup(os.close, w)
183 rfds = []
184 for i in range(10):
185 fd = os.dup(r)
186 self.addCleanup(os.close, fd)
187 rfds.append(fd)
188 pollster = select.poll()
189 for fd in rfds:
190 pollster.register(fd, select.POLLIN)
191
192 t = threading.Thread(target=pollster.poll)
193 t.start()
194 try:
195 time.sleep(0.5)
196 # trigger ufds array reallocation
197 for fd in rfds:
198 pollster.unregister(fd)
199 pollster.register(w, select.POLLOUT)
200 self.assertRaises(RuntimeError, pollster.poll)
201 finally:
202 # and make the call to poll() from the thread return
203 os.write(w, b'spam')
204 t.join()
205
Pablo Galindo2c15b292017-10-17 15:14:41 +0100206 @unittest.skipUnless(threading, 'Threading required for this test.')
207 @reap_threads
208 def test_poll_blocks_with_negative_ms(self):
Riccardo Coccioli6cfa9272017-10-17 21:45:07 +0200209 for timeout_ms in [None, -1000, -1, -1.0, -0.1, -1e-100]:
Pablo Galindo2c15b292017-10-17 15:14:41 +0100210 # Create two file descriptors. This will be used to unlock
211 # the blocking call to poll.poll inside the thread
212 r, w = os.pipe()
213 pollster = select.poll()
214 pollster.register(r, select.POLLIN)
215
216 poll_thread = threading.Thread(target=pollster.poll, args=(timeout_ms,))
217 poll_thread.start()
218 poll_thread.join(timeout=0.1)
219 self.assertTrue(poll_thread.is_alive())
220
221 # Write to the pipe so pollster.poll unblocks and the thread ends.
222 os.write(w, b'spam')
223 poll_thread.join()
224 self.assertFalse(poll_thread.is_alive())
225 os.close(r)
226 os.close(w)
227
Serhiy Storchakab1973c22013-08-20 20:38:21 +0300228
Thomas Wouters89f507f2006-12-13 04:49:30 +0000229def test_main():
230 run_unittest(PollTests)
Neal Norwitz0f46bbf2005-11-03 05:00:25 +0000231
Thomas Wouters89f507f2006-12-13 04:49:30 +0000232if __name__ == '__main__':
233 test_main()