17db96d56Sopenharmony_ci# Copyright (c) 2001-2006 Twisted Matrix Laboratories.
27db96d56Sopenharmony_ci#
37db96d56Sopenharmony_ci# Permission is hereby granted, free of charge, to any person obtaining
47db96d56Sopenharmony_ci# a copy of this software and associated documentation files (the
57db96d56Sopenharmony_ci# "Software"), to deal in the Software without restriction, including
67db96d56Sopenharmony_ci# without limitation the rights to use, copy, modify, merge, publish,
77db96d56Sopenharmony_ci# distribute, sublicense, and/or sell copies of the Software, and to
87db96d56Sopenharmony_ci# permit persons to whom the Software is furnished to do so, subject to
97db96d56Sopenharmony_ci# the following conditions:
107db96d56Sopenharmony_ci#
117db96d56Sopenharmony_ci# The above copyright notice and this permission notice shall be
127db96d56Sopenharmony_ci# included in all copies or substantial portions of the Software.
137db96d56Sopenharmony_ci#
147db96d56Sopenharmony_ci# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
157db96d56Sopenharmony_ci# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
167db96d56Sopenharmony_ci# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
177db96d56Sopenharmony_ci# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
187db96d56Sopenharmony_ci# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
197db96d56Sopenharmony_ci# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
207db96d56Sopenharmony_ci# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
217db96d56Sopenharmony_ci"""
227db96d56Sopenharmony_ciTests for epoll wrapper.
237db96d56Sopenharmony_ci"""
247db96d56Sopenharmony_ciimport errno
257db96d56Sopenharmony_ciimport os
267db96d56Sopenharmony_ciimport select
277db96d56Sopenharmony_ciimport socket
287db96d56Sopenharmony_ciimport time
297db96d56Sopenharmony_ciimport unittest
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ciif not hasattr(select, "epoll"):
327db96d56Sopenharmony_ci    raise unittest.SkipTest("test works only on Linux 2.6")
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_citry:
357db96d56Sopenharmony_ci    select.epoll()
367db96d56Sopenharmony_ciexcept OSError as e:
377db96d56Sopenharmony_ci    if e.errno == errno.ENOSYS:
387db96d56Sopenharmony_ci        raise unittest.SkipTest("kernel doesn't support epoll()")
397db96d56Sopenharmony_ci    raise
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ciclass TestEPoll(unittest.TestCase):
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci    def setUp(self):
447db96d56Sopenharmony_ci        self.serverSocket = socket.create_server(('127.0.0.1', 0))
457db96d56Sopenharmony_ci        self.connections = [self.serverSocket]
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci    def tearDown(self):
487db96d56Sopenharmony_ci        for skt in self.connections:
497db96d56Sopenharmony_ci            skt.close()
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci    def _connected_pair(self):
527db96d56Sopenharmony_ci        client = socket.socket()
537db96d56Sopenharmony_ci        client.setblocking(False)
547db96d56Sopenharmony_ci        try:
557db96d56Sopenharmony_ci            client.connect(('127.0.0.1', self.serverSocket.getsockname()[1]))
567db96d56Sopenharmony_ci        except OSError as e:
577db96d56Sopenharmony_ci            self.assertEqual(e.args[0], errno.EINPROGRESS)
587db96d56Sopenharmony_ci        else:
597db96d56Sopenharmony_ci            raise AssertionError("Connect should have raised EINPROGRESS")
607db96d56Sopenharmony_ci        server, addr = self.serverSocket.accept()
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci        self.connections.extend((client, server))
637db96d56Sopenharmony_ci        return client, server
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci    def test_create(self):
667db96d56Sopenharmony_ci        try:
677db96d56Sopenharmony_ci            ep = select.epoll(16)
687db96d56Sopenharmony_ci        except OSError as e:
697db96d56Sopenharmony_ci            raise AssertionError(str(e))
707db96d56Sopenharmony_ci        self.assertTrue(ep.fileno() > 0, ep.fileno())
717db96d56Sopenharmony_ci        self.assertTrue(not ep.closed)
727db96d56Sopenharmony_ci        ep.close()
737db96d56Sopenharmony_ci        self.assertTrue(ep.closed)
747db96d56Sopenharmony_ci        self.assertRaises(ValueError, ep.fileno)
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci        if hasattr(select, "EPOLL_CLOEXEC"):
777db96d56Sopenharmony_ci            select.epoll(-1, select.EPOLL_CLOEXEC).close()
787db96d56Sopenharmony_ci            select.epoll(flags=select.EPOLL_CLOEXEC).close()
797db96d56Sopenharmony_ci            select.epoll(flags=0).close()
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci    def test_badcreate(self):
827db96d56Sopenharmony_ci        self.assertRaises(TypeError, select.epoll, 1, 2, 3)
837db96d56Sopenharmony_ci        self.assertRaises(TypeError, select.epoll, 'foo')
847db96d56Sopenharmony_ci        self.assertRaises(TypeError, select.epoll, None)
857db96d56Sopenharmony_ci        self.assertRaises(TypeError, select.epoll, ())
867db96d56Sopenharmony_ci        self.assertRaises(TypeError, select.epoll, ['foo'])
877db96d56Sopenharmony_ci        self.assertRaises(TypeError, select.epoll, {})
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ci        self.assertRaises(ValueError, select.epoll, 0)
907db96d56Sopenharmony_ci        self.assertRaises(ValueError, select.epoll, -2)
917db96d56Sopenharmony_ci        self.assertRaises(ValueError, select.epoll, sizehint=-2)
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci        if hasattr(select, "EPOLL_CLOEXEC"):
947db96d56Sopenharmony_ci            self.assertRaises(OSError, select.epoll, flags=12356)
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci    def test_context_manager(self):
977db96d56Sopenharmony_ci        with select.epoll(16) as ep:
987db96d56Sopenharmony_ci            self.assertGreater(ep.fileno(), 0)
997db96d56Sopenharmony_ci            self.assertFalse(ep.closed)
1007db96d56Sopenharmony_ci        self.assertTrue(ep.closed)
1017db96d56Sopenharmony_ci        self.assertRaises(ValueError, ep.fileno)
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci    def test_add(self):
1047db96d56Sopenharmony_ci        server, client = self._connected_pair()
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci        ep = select.epoll(2)
1077db96d56Sopenharmony_ci        try:
1087db96d56Sopenharmony_ci            ep.register(server.fileno(), select.EPOLLIN | select.EPOLLOUT)
1097db96d56Sopenharmony_ci            ep.register(client.fileno(), select.EPOLLIN | select.EPOLLOUT)
1107db96d56Sopenharmony_ci        finally:
1117db96d56Sopenharmony_ci            ep.close()
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci        # adding by object w/ fileno works, too.
1147db96d56Sopenharmony_ci        ep = select.epoll(2)
1157db96d56Sopenharmony_ci        try:
1167db96d56Sopenharmony_ci            ep.register(server, select.EPOLLIN | select.EPOLLOUT)
1177db96d56Sopenharmony_ci            ep.register(client, select.EPOLLIN | select.EPOLLOUT)
1187db96d56Sopenharmony_ci        finally:
1197db96d56Sopenharmony_ci            ep.close()
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci        ep = select.epoll(2)
1227db96d56Sopenharmony_ci        try:
1237db96d56Sopenharmony_ci            # TypeError: argument must be an int, or have a fileno() method.
1247db96d56Sopenharmony_ci            self.assertRaises(TypeError, ep.register, object(),
1257db96d56Sopenharmony_ci                              select.EPOLLIN | select.EPOLLOUT)
1267db96d56Sopenharmony_ci            self.assertRaises(TypeError, ep.register, None,
1277db96d56Sopenharmony_ci                              select.EPOLLIN | select.EPOLLOUT)
1287db96d56Sopenharmony_ci            # ValueError: file descriptor cannot be a negative integer (-1)
1297db96d56Sopenharmony_ci            self.assertRaises(ValueError, ep.register, -1,
1307db96d56Sopenharmony_ci                              select.EPOLLIN | select.EPOLLOUT)
1317db96d56Sopenharmony_ci            # OSError: [Errno 9] Bad file descriptor
1327db96d56Sopenharmony_ci            self.assertRaises(OSError, ep.register, 10000,
1337db96d56Sopenharmony_ci                              select.EPOLLIN | select.EPOLLOUT)
1347db96d56Sopenharmony_ci            # registering twice also raises an exception
1357db96d56Sopenharmony_ci            ep.register(server, select.EPOLLIN | select.EPOLLOUT)
1367db96d56Sopenharmony_ci            self.assertRaises(OSError, ep.register, server,
1377db96d56Sopenharmony_ci                              select.EPOLLIN | select.EPOLLOUT)
1387db96d56Sopenharmony_ci        finally:
1397db96d56Sopenharmony_ci            ep.close()
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_ci    def test_fromfd(self):
1427db96d56Sopenharmony_ci        server, client = self._connected_pair()
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci        with select.epoll(2) as ep:
1457db96d56Sopenharmony_ci            ep2 = select.epoll.fromfd(ep.fileno())
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci            ep2.register(server.fileno(), select.EPOLLIN | select.EPOLLOUT)
1487db96d56Sopenharmony_ci            ep2.register(client.fileno(), select.EPOLLIN | select.EPOLLOUT)
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci            events = ep.poll(1, 4)
1517db96d56Sopenharmony_ci            events2 = ep2.poll(0.9, 4)
1527db96d56Sopenharmony_ci            self.assertEqual(len(events), 2)
1537db96d56Sopenharmony_ci            self.assertEqual(len(events2), 2)
1547db96d56Sopenharmony_ci
1557db96d56Sopenharmony_ci        try:
1567db96d56Sopenharmony_ci            ep2.poll(1, 4)
1577db96d56Sopenharmony_ci        except OSError as e:
1587db96d56Sopenharmony_ci            self.assertEqual(e.args[0], errno.EBADF, e)
1597db96d56Sopenharmony_ci        else:
1607db96d56Sopenharmony_ci            self.fail("epoll on closed fd didn't raise EBADF")
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci    def test_control_and_wait(self):
1637db96d56Sopenharmony_ci        # create the epoll object
1647db96d56Sopenharmony_ci        client, server = self._connected_pair()
1657db96d56Sopenharmony_ci        ep = select.epoll(16)
1667db96d56Sopenharmony_ci        ep.register(server.fileno(),
1677db96d56Sopenharmony_ci                    select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
1687db96d56Sopenharmony_ci        ep.register(client.fileno(),
1697db96d56Sopenharmony_ci                    select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_ci        # EPOLLOUT
1727db96d56Sopenharmony_ci        now = time.monotonic()
1737db96d56Sopenharmony_ci        events = ep.poll(1, 4)
1747db96d56Sopenharmony_ci        then = time.monotonic()
1757db96d56Sopenharmony_ci        self.assertFalse(then - now > 0.1, then - now)
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci        expected = [(client.fileno(), select.EPOLLOUT),
1787db96d56Sopenharmony_ci                    (server.fileno(), select.EPOLLOUT)]
1797db96d56Sopenharmony_ci        self.assertEqual(sorted(events), sorted(expected))
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ci        # no event
1827db96d56Sopenharmony_ci        events = ep.poll(timeout=0.1, maxevents=4)
1837db96d56Sopenharmony_ci        self.assertFalse(events)
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci        # send: EPOLLIN and EPOLLOUT
1867db96d56Sopenharmony_ci        client.sendall(b"Hello!")
1877db96d56Sopenharmony_ci        server.sendall(b"world!!!")
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci        now = time.monotonic()
1907db96d56Sopenharmony_ci        events = ep.poll(1.0, 4)
1917db96d56Sopenharmony_ci        then = time.monotonic()
1927db96d56Sopenharmony_ci        self.assertFalse(then - now > 0.01)
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci        expected = [(client.fileno(), select.EPOLLIN | select.EPOLLOUT),
1957db96d56Sopenharmony_ci                    (server.fileno(), select.EPOLLIN | select.EPOLLOUT)]
1967db96d56Sopenharmony_ci        self.assertEqual(sorted(events), sorted(expected))
1977db96d56Sopenharmony_ci
1987db96d56Sopenharmony_ci        # unregister, modify
1997db96d56Sopenharmony_ci        ep.unregister(client.fileno())
2007db96d56Sopenharmony_ci        ep.modify(server.fileno(), select.EPOLLOUT)
2017db96d56Sopenharmony_ci        now = time.monotonic()
2027db96d56Sopenharmony_ci        events = ep.poll(1, 4)
2037db96d56Sopenharmony_ci        then = time.monotonic()
2047db96d56Sopenharmony_ci        self.assertFalse(then - now > 0.01)
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci        expected = [(server.fileno(), select.EPOLLOUT)]
2077db96d56Sopenharmony_ci        self.assertEqual(events, expected)
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci    def test_errors(self):
2107db96d56Sopenharmony_ci        self.assertRaises(ValueError, select.epoll, -2)
2117db96d56Sopenharmony_ci        self.assertRaises(ValueError, select.epoll().register, -1,
2127db96d56Sopenharmony_ci                          select.EPOLLIN)
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci    def test_unregister_closed(self):
2157db96d56Sopenharmony_ci        server, client = self._connected_pair()
2167db96d56Sopenharmony_ci        fd = server.fileno()
2177db96d56Sopenharmony_ci        ep = select.epoll(16)
2187db96d56Sopenharmony_ci        ep.register(server)
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci        now = time.monotonic()
2217db96d56Sopenharmony_ci        events = ep.poll(1, 4)
2227db96d56Sopenharmony_ci        then = time.monotonic()
2237db96d56Sopenharmony_ci        self.assertFalse(then - now > 0.01)
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci        server.close()
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci        with self.assertRaises(OSError) as cm:
2287db96d56Sopenharmony_ci            ep.unregister(fd)
2297db96d56Sopenharmony_ci        self.assertEqual(cm.exception.errno, errno.EBADF)
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci    def test_close(self):
2327db96d56Sopenharmony_ci        open_file = open(__file__, "rb")
2337db96d56Sopenharmony_ci        self.addCleanup(open_file.close)
2347db96d56Sopenharmony_ci        fd = open_file.fileno()
2357db96d56Sopenharmony_ci        epoll = select.epoll()
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci        # test fileno() method and closed attribute
2387db96d56Sopenharmony_ci        self.assertIsInstance(epoll.fileno(), int)
2397db96d56Sopenharmony_ci        self.assertFalse(epoll.closed)
2407db96d56Sopenharmony_ci
2417db96d56Sopenharmony_ci        # test close()
2427db96d56Sopenharmony_ci        epoll.close()
2437db96d56Sopenharmony_ci        self.assertTrue(epoll.closed)
2447db96d56Sopenharmony_ci        self.assertRaises(ValueError, epoll.fileno)
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci        # close() can be called more than once
2477db96d56Sopenharmony_ci        epoll.close()
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci        # operations must fail with ValueError("I/O operation on closed ...")
2507db96d56Sopenharmony_ci        self.assertRaises(ValueError, epoll.modify, fd, select.EPOLLIN)
2517db96d56Sopenharmony_ci        self.assertRaises(ValueError, epoll.poll, 1.0)
2527db96d56Sopenharmony_ci        self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN)
2537db96d56Sopenharmony_ci        self.assertRaises(ValueError, epoll.unregister, fd)
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_ci    def test_fd_non_inheritable(self):
2567db96d56Sopenharmony_ci        epoll = select.epoll()
2577db96d56Sopenharmony_ci        self.addCleanup(epoll.close)
2587db96d56Sopenharmony_ci        self.assertEqual(os.get_inheritable(epoll.fileno()), False)
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ciif __name__ == "__main__":
2627db96d56Sopenharmony_ci    unittest.main()
263