test_poller.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. import sys
  2. import unittest
  3. import errno
  4. import select
  5. from supervisor.tests.base import Mock
  6. from supervisor.poller import SelectPoller, PollPoller, KQueuePoller
  7. from supervisor.poller import implements_poll, implements_kqueue
  8. from supervisor.tests.base import DummyOptions
  9. # this base class is used instead of unittest.TestCase to hide
  10. # a TestCase subclass from test runner when the implementation is
  11. # not available
  12. SkipTestCase = object
  13. class BasePollerTests(unittest.TestCase):
  14. def _makeOne(self, options):
  15. from supervisor.poller import BasePoller
  16. return BasePoller(options)
  17. def test_register_readable(self):
  18. inst = self._makeOne(None)
  19. self.assertRaises(NotImplementedError, inst.register_readable, None)
  20. def test_register_writable(self):
  21. inst = self._makeOne(None)
  22. self.assertRaises(NotImplementedError, inst.register_writable, None)
  23. def test_unregister(self):
  24. inst = self._makeOne(None)
  25. self.assertRaises(NotImplementedError, inst.unregister, None)
  26. def test_poll(self):
  27. inst = self._makeOne(None)
  28. self.assertRaises(NotImplementedError, inst.poll, None)
  29. def test_before_daemonize(self):
  30. inst = self._makeOne(None)
  31. self.assertEqual(inst.before_daemonize(), None)
  32. def test_after_daemonize(self):
  33. inst = self._makeOne(None)
  34. self.assertEqual(inst.after_daemonize(), None)
  35. class SelectPollerTests(unittest.TestCase):
  36. def _makeOne(self, options):
  37. return SelectPoller(options)
  38. def test_register_readable(self):
  39. poller = self._makeOne(DummyOptions())
  40. poller.register_readable(6)
  41. poller.register_readable(7)
  42. self.assertEqual(sorted(poller.readables), [6,7])
  43. def test_register_writable(self):
  44. poller = self._makeOne(DummyOptions())
  45. poller.register_writable(6)
  46. poller.register_writable(7)
  47. self.assertEqual(sorted(poller.writables), [6,7])
  48. def test_unregister(self):
  49. poller = self._makeOne(DummyOptions())
  50. poller.register_readable(6)
  51. poller.register_readable(7)
  52. poller.register_writable(8)
  53. poller.register_writable(9)
  54. poller.unregister(6)
  55. poller.unregister(9)
  56. poller.unregister(100) # not registered, ignore error
  57. self.assertEqual(list(poller.readables), [7])
  58. self.assertEqual(list(poller.writables), [8])
  59. def test_poll_returns_readables_and_writables(self):
  60. _select = DummySelect(result={'readables': [6],
  61. 'writables': [8]})
  62. poller = self._makeOne(DummyOptions())
  63. poller._select = _select
  64. poller.register_readable(6)
  65. poller.register_readable(7)
  66. poller.register_writable(8)
  67. readables, writables = poller.poll(1)
  68. self.assertEqual(readables, [6])
  69. self.assertEqual(writables, [8])
  70. def test_poll_ignores_eintr(self):
  71. _select = DummySelect(error=errno.EINTR)
  72. options = DummyOptions()
  73. poller = self._makeOne(options)
  74. poller._select = _select
  75. poller.register_readable(6)
  76. poller.poll(1)
  77. self.assertEqual(options.logger.data[0], 'EINTR encountered in poll')
  78. def test_poll_ignores_ebadf(self):
  79. _select = DummySelect(error=errno.EBADF)
  80. options = DummyOptions()
  81. poller = self._makeOne(options)
  82. poller._select = _select
  83. poller.register_readable(6)
  84. poller.poll(1)
  85. self.assertEqual(options.logger.data[0], 'EBADF encountered in poll')
  86. self.assertEqual(list(poller.readables), [])
  87. self.assertEqual(list(poller.writables), [])
  88. def test_poll_uncaught_exception(self):
  89. _select = DummySelect(error=errno.EPERM)
  90. options = DummyOptions()
  91. poller = self._makeOne(options)
  92. poller._select = _select
  93. poller.register_readable(6)
  94. self.assertRaises(select.error, poller.poll, 1)
  95. if implements_kqueue():
  96. KQueuePollerTestsBase = unittest.TestCase
  97. else:
  98. KQueuePollerTestsBase = SkipTestCase
  99. class KQueuePollerTests(KQueuePollerTestsBase):
  100. def _makeOne(self, options):
  101. return KQueuePoller(options)
  102. def test_register_readable(self):
  103. kqueue = DummyKQueue()
  104. poller = self._makeOne(DummyOptions())
  105. poller._kqueue = kqueue
  106. poller.register_readable(6)
  107. self.assertEqual(list(poller.readables), [6])
  108. self.assertEqual(len(kqueue.registered_kevents), 1)
  109. self.assertReadEventAdded(kqueue.registered_kevents[0], 6)
  110. def test_register_writable(self):
  111. kqueue = DummyKQueue()
  112. poller = self._makeOne(DummyOptions())
  113. poller._kqueue = kqueue
  114. poller.register_writable(7)
  115. self.assertEqual(list(poller.writables), [7])
  116. self.assertEqual(len(kqueue.registered_kevents), 1)
  117. self.assertWriteEventAdded(kqueue.registered_kevents[0], 7)
  118. def test_unregister(self):
  119. kqueue = DummyKQueue()
  120. poller = self._makeOne(DummyOptions())
  121. poller._kqueue = kqueue
  122. poller.register_writable(7)
  123. poller.register_readable(8)
  124. poller.unregister(7)
  125. poller.unregister(100) # not registered, ignore error
  126. self.assertEqual(list(poller.writables), [])
  127. self.assertEqual(list(poller.readables), [8])
  128. self.assertWriteEventAdded(kqueue.registered_kevents[0], 7)
  129. self.assertReadEventAdded(kqueue.registered_kevents[1], 8)
  130. self.assertDeletedEvent(kqueue.registered_kevents[2], 7)
  131. def test_poll_returns_readables_and_writables(self):
  132. kqueue = DummyKQueue(result=[(6, select.KQ_FILTER_READ),
  133. (7, select.KQ_FILTER_READ),
  134. (8, select.KQ_FILTER_WRITE)])
  135. poller = self._makeOne(DummyOptions())
  136. poller._kqueue = kqueue
  137. poller.register_readable(6)
  138. poller.register_readable(7)
  139. poller.register_writable(8)
  140. readables, writables = poller.poll(1000)
  141. self.assertEqual(readables, [6,7])
  142. self.assertEqual(writables, [8])
  143. def test_poll_ignores_eintr(self):
  144. kqueue = DummyKQueue(raise_errno_poll=errno.EINTR)
  145. options = DummyOptions()
  146. poller = self._makeOne(options)
  147. poller._kqueue = kqueue
  148. poller.register_readable(6)
  149. poller.poll(1000)
  150. self.assertEqual(options.logger.data[0], 'EINTR encountered in poll')
  151. def test_register_readable_and_writable_ignores_ebadf(self):
  152. _kqueue = DummyKQueue(raise_errno_register=errno.EBADF)
  153. options = DummyOptions()
  154. poller = self._makeOne(options)
  155. poller._kqueue = _kqueue
  156. poller.register_readable(6)
  157. poller.register_writable(7)
  158. self.assertEqual(options.logger.data[0],
  159. 'EBADF encountered in kqueue. Invalid file descriptor 6')
  160. self.assertEqual(options.logger.data[1],
  161. 'EBADF encountered in kqueue. Invalid file descriptor 7')
  162. def test_register_uncaught_exception(self):
  163. _kqueue = DummyKQueue(raise_errno_register=errno.ENOMEM)
  164. options = DummyOptions()
  165. poller = self._makeOne(options)
  166. poller._kqueue = _kqueue
  167. self.assertRaises(OSError, poller.register_readable, 5)
  168. def test_poll_uncaught_exception(self):
  169. kqueue = DummyKQueue(raise_errno_poll=errno.EINVAL)
  170. options = DummyOptions()
  171. poller = self._makeOne(options)
  172. poller._kqueue = kqueue
  173. poller.register_readable(6)
  174. self.assertRaises(OSError, poller.poll, 1000)
  175. def test_before_daemonize_closes_kqueue(self):
  176. mock_kqueue = Mock()
  177. options = DummyOptions()
  178. poller = self._makeOne(options)
  179. poller._kqueue = mock_kqueue
  180. poller.before_daemonize()
  181. mock_kqueue.close.assert_called_once_with()
  182. self.assertEqual(poller._kqueue, None)
  183. def test_after_daemonize_restores_kqueue(self):
  184. options = DummyOptions()
  185. poller = self._makeOne(options)
  186. poller.readables = [1]
  187. poller.writables = [3]
  188. poller.register_readable = Mock()
  189. poller.register_writable = Mock()
  190. poller.after_daemonize()
  191. self.assertTrue(isinstance(poller._kqueue, select.kqueue))
  192. poller.register_readable.assert_called_with(1)
  193. poller.register_writable.assert_called_with(3)
  194. def assertReadEventAdded(self, kevent, fd):
  195. self.assertKevent(kevent, fd, select.KQ_FILTER_READ, select.KQ_EV_ADD)
  196. def assertWriteEventAdded(self, kevent, fd):
  197. self.assertKevent(kevent, fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD)
  198. def assertDeletedEvent(self, kevent, fd):
  199. self.assertKevent(kevent, fd, select.KQ_FILTER_READ | select.KQ_FILTER_WRITE,
  200. select.KQ_EV_DELETE)
  201. def assertKevent(self, kevent, ident, filter, flags):
  202. self.assertEqual(kevent.ident, ident)
  203. self.assertEqual(kevent.filter, filter)
  204. self.assertEqual(kevent.flags, flags)
  205. if implements_poll():
  206. PollerPollTestsBase = unittest.TestCase
  207. else:
  208. PollerPollTestsBase = SkipTestCase
  209. class PollerPollTests(PollerPollTestsBase):
  210. def _makeOne(self, options):
  211. return PollPoller(options)
  212. def test_register_readable(self):
  213. select_poll = DummySelectPoll()
  214. poller = self._makeOne(DummyOptions())
  215. poller._poller = select_poll
  216. poller.register_readable(6)
  217. poller.register_readable(7)
  218. self.assertEqual(select_poll.registered_as_readable, [6,7])
  219. def test_register_writable(self):
  220. select_poll = DummySelectPoll()
  221. poller = self._makeOne(DummyOptions())
  222. poller._poller = select_poll
  223. poller.register_writable(6)
  224. self.assertEqual(select_poll.registered_as_writable, [6])
  225. def test_poll_returns_readables_and_writables(self):
  226. select_poll = DummySelectPoll(result=[(6, select.POLLIN),
  227. (7, select.POLLPRI),
  228. (8, select.POLLOUT),
  229. (9, select.POLLHUP)])
  230. poller = self._makeOne(DummyOptions())
  231. poller._poller = select_poll
  232. poller.register_readable(6)
  233. poller.register_readable(7)
  234. poller.register_writable(8)
  235. poller.register_readable(9)
  236. readables, writables = poller.poll(1000)
  237. self.assertEqual(readables, [6,7,9])
  238. self.assertEqual(writables, [8])
  239. def test_poll_ignores_eintr(self):
  240. select_poll = DummySelectPoll(error=errno.EINTR)
  241. options = DummyOptions()
  242. poller = self._makeOne(options)
  243. poller._poller = select_poll
  244. poller.register_readable(9)
  245. poller.poll(1000)
  246. self.assertEqual(options.logger.data[0], 'EINTR encountered in poll')
  247. def test_poll_uncaught_exception(self):
  248. select_poll = DummySelectPoll(error=errno.EBADF)
  249. options = DummyOptions()
  250. poller = self._makeOne(options)
  251. poller._poller = select_poll
  252. poller.register_readable(9)
  253. self.assertRaises(select.error, poller.poll, 1000)
  254. def test_poll_ignores_and_unregisters_closed_fd(self):
  255. select_poll = DummySelectPoll(result=[(6, select.POLLNVAL),
  256. (7, select.POLLPRI)])
  257. poller = self._makeOne(DummyOptions())
  258. poller._poller = select_poll
  259. poller.register_readable(6)
  260. poller.register_readable(7)
  261. readables, writables = poller.poll(1000)
  262. self.assertEqual(readables, [7])
  263. self.assertEqual(select_poll.unregistered, [6])
  264. class DummySelect(object):
  265. '''
  266. Fake implementation of select.select()
  267. '''
  268. def __init__(self, result=None, error=None):
  269. result = result or {}
  270. self.readables = result.get('readables', [])
  271. self.writables = result.get('writables', [])
  272. self.error = error
  273. def select(self, r, w, x, timeout):
  274. if self.error:
  275. raise select.error(self.error)
  276. return self.readables, self.writables, []
  277. class DummySelectPoll(object):
  278. '''
  279. Fake implementation of select.poll()
  280. '''
  281. def __init__(self, result=None, error=None):
  282. self.result = result or []
  283. self.error = error
  284. self.registered_as_readable = []
  285. self.registered_as_writable = []
  286. self.unregistered = []
  287. def register(self, fd, eventmask):
  288. if eventmask == select.POLLIN | select.POLLPRI | select.POLLHUP:
  289. self.registered_as_readable.append(fd)
  290. elif eventmask == select.POLLOUT:
  291. self.registered_as_writable.append(fd)
  292. else:
  293. raise ValueError("Registered a fd on unknown eventmask: '{0}'".format(eventmask))
  294. def unregister(self, fd):
  295. self.unregistered.append(fd)
  296. def poll(self, timeout):
  297. if self.error:
  298. raise select.error(self.error)
  299. return self.result
  300. class DummyKQueue(object):
  301. '''
  302. Fake implementation of select.kqueue()
  303. '''
  304. def __init__(self, result=None, raise_errno_poll=None, raise_errno_register=None):
  305. self.result = result or []
  306. self.errno_poll = raise_errno_poll
  307. self.errno_register = raise_errno_register
  308. self.registered_kevents = []
  309. self.registered_flags = []
  310. def control(self, kevents, max_events, timeout=None):
  311. if kevents is None: # being called on poll()
  312. self.assert_max_events_on_poll(max_events)
  313. self.raise_error(self.errno_poll)
  314. return self.build_result()
  315. self.assert_max_events_on_register(max_events)
  316. self.raise_error(self.errno_register)
  317. self.registered_kevents.extend(kevents)
  318. def raise_error(self, err):
  319. if not err: return
  320. ex = OSError()
  321. ex.errno = err
  322. raise ex
  323. def build_result(self):
  324. return [FakeKEvent(ident, filter) for ident,filter in self.result]
  325. def assert_max_events_on_poll(self, max_events):
  326. assert max_events == KQueuePoller.max_events, (
  327. "`max_events` parameter of `kqueue.control() should be %d"
  328. % KQueuePoller.max_events)
  329. def assert_max_events_on_register(self, max_events):
  330. assert max_events == 0, (
  331. "`max_events` parameter of `kqueue.control()` should be 0 on register")
  332. class FakeKEvent(object):
  333. def __init__(self, ident, filter):
  334. self.ident = ident
  335. self.filter = filter
  336. def test_suite():
  337. return unittest.findTestCases(sys.modules[__name__])
  338. if __name__ == '__main__':
  339. unittest.main(defaultTest='test_suite')