• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Test case for the os.poll() function
2
3import os
4import random
5import select
6try:
7    import threading
8except ImportError:
9    threading = None
10import time
11import unittest
12from test.test_support import TESTFN, run_unittest, reap_threads, cpython_only
13
14try:
15    select.poll
16except AttributeError:
17    raise unittest.SkipTest, "select.poll not defined -- skipping test_poll"
18
19
20def find_ready_matching(ready, flag):
21    match = []
22    for fd, mode in ready:
23        if mode & flag:
24            match.append(fd)
25    return match
26
27class PollTests(unittest.TestCase):
28
29    def test_poll1(self):
30        # Basic functional test of poll object
31        # Create a bunch of pipe and test that poll works with them.
32
33        p = select.poll()
34
35        NUM_PIPES = 12
36        MSG = " This is a test."
37        MSG_LEN = len(MSG)
38        readers = []
39        writers = []
40        r2w = {}
41        w2r = {}
42
43        for i in range(NUM_PIPES):
44            rd, wr = os.pipe()
45            p.register(rd)
46            p.modify(rd, select.POLLIN)
47            p.register(wr, select.POLLOUT)
48            readers.append(rd)
49            writers.append(wr)
50            r2w[rd] = wr
51            w2r[wr] = rd
52
53        bufs = []
54
55        while writers:
56            ready = p.poll()
57            ready_writers = find_ready_matching(ready, select.POLLOUT)
58            if not ready_writers:
59                raise RuntimeError, "no pipes ready for writing"
60            wr = random.choice(ready_writers)
61            os.write(wr, MSG)
62
63            ready = p.poll()
64            ready_readers = find_ready_matching(ready, select.POLLIN)
65            if not ready_readers:
66                raise RuntimeError, "no pipes ready for reading"
67            rd = random.choice(ready_readers)
68            buf = os.read(rd, MSG_LEN)
69            self.assertEqual(len(buf), MSG_LEN)
70            bufs.append(buf)
71            os.close(r2w[rd]) ; os.close( rd )
72            p.unregister( r2w[rd] )
73            p.unregister( rd )
74            writers.remove(r2w[rd])
75
76        self.assertEqual(bufs, [MSG] * NUM_PIPES)
77
78    def poll_unit_tests(self):
79        # returns NVAL for invalid file descriptor
80        FD = 42
81        try:
82            os.close(FD)
83        except OSError:
84            pass
85        p = select.poll()
86        p.register(FD)
87        r = p.poll()
88        self.assertEqual(r[0], (FD, select.POLLNVAL))
89
90        f = open(TESTFN, 'w')
91        fd = f.fileno()
92        p = select.poll()
93        p.register(f)
94        r = p.poll()
95        self.assertEqual(r[0][0], fd)
96        f.close()
97        r = p.poll()
98        self.assertEqual(r[0], (fd, select.POLLNVAL))
99        os.unlink(TESTFN)
100
101        # type error for invalid arguments
102        p = select.poll()
103        self.assertRaises(TypeError, p.register, p)
104        self.assertRaises(TypeError, p.unregister, p)
105
106        # can't unregister non-existent object
107        p = select.poll()
108        self.assertRaises(KeyError, p.unregister, 3)
109
110        # Test error cases
111        pollster = select.poll()
112        class Nope:
113            pass
114
115        class Almost:
116            def fileno(self):
117                return 'fileno'
118
119        self.assertRaises(TypeError, pollster.register, Nope(), 0)
120        self.assertRaises(TypeError, pollster.register, Almost(), 0)
121
122    # Another test case for poll().  This is copied from the test case for
123    # select(), modified to use poll() instead.
124
125    def test_poll2(self):
126        cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done'
127        p = os.popen(cmd, 'r')
128        pollster = select.poll()
129        pollster.register( p, select.POLLIN )
130        for tout in (0, 1000, 2000, 4000, 8000, 16000) + (-1,)*10:
131            fdlist = pollster.poll(tout)
132            if (fdlist == []):
133                continue
134            fd, flags = fdlist[0]
135            if flags & select.POLLHUP:
136                line = p.readline()
137                if line != "":
138                    self.fail('error: pipe seems to be closed, but still returns data')
139                continue
140
141            elif flags & select.POLLIN:
142                line = p.readline()
143                if not line:
144                    break
145                continue
146            else:
147                self.fail('Unexpected return value from select.poll: %s' % fdlist)
148        p.close()
149
150    def test_poll3(self):
151        # test int overflow
152        pollster = select.poll()
153        pollster.register(1)
154
155        self.assertRaises(OverflowError, pollster.poll, 1L << 64)
156
157        x = 2 + 3
158        if x != 5:
159            self.fail('Overflow must have occurred')
160
161        # Issues #15989, #17919
162        self.assertRaises(OverflowError, pollster.register, 0, -1)
163        self.assertRaises(OverflowError, pollster.register, 0, 1 << 64)
164        self.assertRaises(OverflowError, pollster.modify, 1, -1)
165        self.assertRaises(OverflowError, pollster.modify, 1, 1 << 64)
166
167    @cpython_only
168    def test_poll_c_limits(self):
169        from _testcapi import USHRT_MAX, INT_MAX, UINT_MAX
170        pollster = select.poll()
171        pollster.register(1)
172
173        # Issues #15989, #17919
174        self.assertRaises(OverflowError, pollster.register, 0, USHRT_MAX + 1)
175        self.assertRaises(OverflowError, pollster.modify, 1, USHRT_MAX + 1)
176        self.assertRaises(OverflowError, pollster.poll, INT_MAX + 1)
177        self.assertRaises(OverflowError, pollster.poll, UINT_MAX + 1)
178
179    @unittest.skipUnless(threading, 'Threading required for this test.')
180    @reap_threads
181    def test_threaded_poll(self):
182        r, w = os.pipe()
183        self.addCleanup(os.close, r)
184        self.addCleanup(os.close, w)
185        rfds = []
186        for i in range(10):
187            fd = os.dup(r)
188            self.addCleanup(os.close, fd)
189            rfds.append(fd)
190        pollster = select.poll()
191        for fd in rfds:
192            pollster.register(fd, select.POLLIN)
193
194        t = threading.Thread(target=pollster.poll)
195        t.start()
196        try:
197            time.sleep(0.5)
198            # trigger ufds array reallocation
199            for fd in rfds:
200                pollster.unregister(fd)
201            pollster.register(w, select.POLLOUT)
202            self.assertRaises(RuntimeError, pollster.poll)
203        finally:
204            # and make the call to poll() from the thread return
205            os.write(w, b'spam')
206            t.join()
207
208
209def test_main():
210    run_unittest(PollTests)
211
212if __name__ == '__main__':
213    test_main()
214