14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Copyright (c) 2001-2006 Twisted Matrix Laboratories.
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
34adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Permission is hereby granted, free of charge, to any person obtaining
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# a copy of this software and associated documentation files (the
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# "Software"), to deal in the Software without restriction, including
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# without limitation the rights to use, copy, modify, merge, publish,
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# distribute, sublicense, and/or sell copies of the Software, and to
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# permit persons to whom the Software is furnished to do so, subject to
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# the following conditions:
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# The above copyright notice and this permission notice shall be
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# included in all copies or substantial portions of the Software.
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""
224adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoTests for epoll wrapper.
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport socket
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport errno
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport time
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport select
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport unittest
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom test import test_support
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif not hasattr(select, "epoll"):
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    raise unittest.SkipTest("test works only on Linux 2.6")
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaotry:
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    select.epoll()
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoexcept IOError, e:
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if e.errno == errno.ENOSYS:
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise unittest.SkipTest("kernel doesn't support epoll()")
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    raise
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass TestEPoll(unittest.TestCase):
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def setUp(self):
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.serverSocket = socket.socket()
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.serverSocket.bind(('127.0.0.1', 0))
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.serverSocket.listen(1)
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.connections = [self.serverSocket]
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def tearDown(self):
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for skt in self.connections:
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            skt.close()
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def _connected_pair(self):
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        client = socket.socket()
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        client.setblocking(False)
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            client.connect(('127.0.0.1', self.serverSocket.getsockname()[1]))
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except socket.error, e:
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertEqual(e.args[0], errno.EINPROGRESS)
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise AssertionError("Connect should have raised EINPROGRESS")
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        server, addr = self.serverSocket.accept()
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.connections.extend((client, server))
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return client, server
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_create(self):
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep = select.epoll(16)
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except OSError, e:
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise AssertionError(str(e))
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertTrue(ep.fileno() > 0, ep.fileno())
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertTrue(not ep.closed)
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.close()
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertTrue(ep.closed)
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(ValueError, ep.fileno)
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_badcreate(self):
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(TypeError, select.epoll, 1, 2, 3)
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(TypeError, select.epoll, 'foo')
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(TypeError, select.epoll, None)
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(TypeError, select.epoll, ())
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(TypeError, select.epoll, ['foo'])
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(TypeError, select.epoll, {})
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_add(self):
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        server, client = self._connected_pair()
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep = select.epoll(2)
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.register(server.fileno(), select.EPOLLIN | select.EPOLLOUT)
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.register(client.fileno(), select.EPOLLIN | select.EPOLLOUT)
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        finally:
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.close()
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # adding by object w/ fileno works, too.
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep = select.epoll(2)
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.register(server, select.EPOLLIN | select.EPOLLOUT)
1014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.register(client, select.EPOLLIN | select.EPOLLOUT)
1024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        finally:
1034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.close()
1044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep = select.epoll(2)
1064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
1074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # TypeError: argument must be an int, or have a fileno() method.
1084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertRaises(TypeError, ep.register, object(),
1094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                select.EPOLLIN | select.EPOLLOUT)
1104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertRaises(TypeError, ep.register, None,
1114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                select.EPOLLIN | select.EPOLLOUT)
1124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # ValueError: file descriptor cannot be a negative integer (-1)
1134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertRaises(ValueError, ep.register, -1,
1144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                select.EPOLLIN | select.EPOLLOUT)
1154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # IOError: [Errno 9] Bad file descriptor
1164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertRaises(IOError, ep.register, 10000,
1174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                select.EPOLLIN | select.EPOLLOUT)
1184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            # registering twice also raises an exception
1194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.register(server, select.EPOLLIN | select.EPOLLOUT)
1204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertRaises(IOError, ep.register, server,
1214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                select.EPOLLIN | select.EPOLLOUT)
1224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        finally:
1234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep.close()
1244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_fromfd(self):
1264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        server, client = self._connected_pair()
1274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep = select.epoll(2)
1294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep2 = select.epoll.fromfd(ep.fileno())
1304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep2.register(server.fileno(), select.EPOLLIN | select.EPOLLOUT)
1324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep2.register(client.fileno(), select.EPOLLIN | select.EPOLLOUT)
1334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events = ep.poll(1, 4)
1354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events2 = ep2.poll(0.9, 4)
1364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(len(events), 2)
1374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(len(events2), 2)
1384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.close()
1404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
1414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            ep2.poll(1, 4)
1424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except IOError, e:
1434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.assertEqual(e.args[0], errno.EBADF, e)
1444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.fail("epoll on closed fd didn't raise EBADF")
1464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_control_and_wait(self):
1484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        client, server = self._connected_pair()
1494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep = select.epoll(16)
1514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.register(server.fileno(),
1524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
1534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.register(client.fileno(),
1544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                   select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
1554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        now = time.time()
1574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events = ep.poll(1, 4)
1584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        then = time.time()
1594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertFalse(then - now > 0.1, then - now)
1604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events.sort()
1624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        expected = [(client.fileno(), select.EPOLLOUT),
1634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    (server.fileno(), select.EPOLLOUT)]
1644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        expected.sort()
1654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(events, expected)
1674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertFalse(then - now > 0.01, then - now)
1684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        now = time.time()
1704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events = ep.poll(timeout=2.1, maxevents=4)
1714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        then = time.time()
1724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertFalse(events)
1734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        client.send("Hello!")
1754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        server.send("world!!!")
1764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        now = time.time()
1784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events = ep.poll(1, 4)
1794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        then = time.time()
1804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertFalse(then - now > 0.01)
1814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events.sort()
1834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        expected = [(client.fileno(), select.EPOLLIN | select.EPOLLOUT),
1844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    (server.fileno(), select.EPOLLIN | select.EPOLLOUT)]
1854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        expected.sort()
1864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(events, expected)
1884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.unregister(client.fileno())
1904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.modify(server.fileno(), select.EPOLLOUT)
1914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        now = time.time()
1924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events = ep.poll(1, 4)
1934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        then = time.time()
1944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertFalse(then - now > 0.01)
1954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        expected = [(server.fileno(), select.EPOLLOUT)]
1974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(events, expected)
1984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_errors(self):
2004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(ValueError, select.epoll, -2)
2014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(ValueError, select.epoll().register, -1,
2024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                          select.EPOLLIN)
2034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_unregister_closed(self):
2054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        server, client = self._connected_pair()
2064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        fd = server.fileno()
2074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep = select.epoll(16)
2084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.register(server)
2094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        now = time.time()
2114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        events = ep.poll(1, 4)
2124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        then = time.time()
2134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertFalse(then - now > 0.01)
2144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        server.close()
2164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ep.unregister(fd)
2174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef test_main():
2194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    test_support.run_unittest(TestEPoll)
2204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif __name__ == "__main__":
2224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    test_main()
223