test_hub.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. from __future__ import absolute_import
  2. from kombu.async import Hub, READ, WRITE, ERR
  3. from kombu.async.hub import repr_flag, _rcb
  4. from kombu.async.semaphore import DummyLock, LaxBoundedSemaphore
  5. from mock import Mock, call, patch
  6. from celery.five import range
  7. from celery.tests.case import Case
  8. class File(object):
  9. def __init__(self, fd):
  10. self.fd = fd
  11. def fileno(self):
  12. return self.fd
  13. def __eq__(self, other):
  14. if isinstance(other, File):
  15. return self.fd == other.fd
  16. return NotImplemented
  17. def __hash__(self):
  18. return hash(self.fd)
  19. class test_DummyLock(Case):
  20. def test_context(self):
  21. mutex = DummyLock()
  22. with mutex:
  23. pass
  24. class test_LaxBoundedSemaphore(Case):
  25. def test_acquire_release(self):
  26. x = LaxBoundedSemaphore(2)
  27. c1 = Mock()
  28. x.acquire(c1, 1)
  29. self.assertEqual(x.value, 1)
  30. c1.assert_called_with(1)
  31. c2 = Mock()
  32. x.acquire(c2, 2)
  33. self.assertEqual(x.value, 0)
  34. c2.assert_called_with(2)
  35. c3 = Mock()
  36. x.acquire(c3, 3)
  37. self.assertEqual(x.value, 0)
  38. self.assertFalse(c3.called)
  39. x.release()
  40. self.assertEqual(x.value, 1)
  41. c3.assert_called_with(3)
  42. def test_bounded(self):
  43. x = LaxBoundedSemaphore(2)
  44. for i in range(100):
  45. x.release()
  46. self.assertEqual(x.value, 2)
  47. def test_grow_shrink(self):
  48. x = LaxBoundedSemaphore(1)
  49. self.assertEqual(x.initial_value, 1)
  50. cb1 = Mock()
  51. x.acquire(cb1, 1)
  52. cb1.assert_called_with(1)
  53. self.assertEqual(x.value, 0)
  54. cb2 = Mock()
  55. x.acquire(cb2, 2)
  56. self.assertFalse(cb2.called)
  57. self.assertEqual(x.value, 0)
  58. cb3 = Mock()
  59. x.acquire(cb3, 3)
  60. self.assertFalse(cb3.called)
  61. x.grow(2)
  62. cb2.assert_called_with(2)
  63. cb3.assert_called_with(3)
  64. self.assertEqual(x.value, 3)
  65. self.assertEqual(x.initial_value, 3)
  66. self.assertFalse(x._waiting)
  67. x.grow(3)
  68. for i in range(x.initial_value):
  69. self.assertTrue(x.acquire(Mock()))
  70. self.assertFalse(x.acquire(Mock()))
  71. x.clear()
  72. x.shrink(3)
  73. for i in range(x.initial_value):
  74. self.assertTrue(x.acquire(Mock()))
  75. self.assertFalse(x.acquire(Mock()))
  76. self.assertEqual(x.value, 0)
  77. for i in range(100):
  78. x.release()
  79. self.assertEqual(x.value, x.initial_value)
  80. def test_clear(self):
  81. x = LaxBoundedSemaphore(10)
  82. for i in range(11):
  83. x.acquire(Mock())
  84. self.assertTrue(x._waiting)
  85. self.assertEqual(x.value, 0)
  86. x.clear()
  87. self.assertFalse(x._waiting)
  88. self.assertEqual(x.value, x.initial_value)
  89. class test_Hub(Case):
  90. def test_repr_flag(self):
  91. self.assertEqual(repr_flag(READ), 'R')
  92. self.assertEqual(repr_flag(WRITE), 'W')
  93. self.assertEqual(repr_flag(ERR), '!')
  94. self.assertEqual(repr_flag(READ | WRITE), 'RW')
  95. self.assertEqual(repr_flag(READ | ERR), 'R!')
  96. self.assertEqual(repr_flag(WRITE | ERR), 'W!')
  97. self.assertEqual(repr_flag(READ | WRITE | ERR), 'RW!')
  98. def test_repr_callback_rcb(self):
  99. def f():
  100. pass
  101. self.assertEqual(_rcb(f), f.__name__)
  102. self.assertEqual(_rcb('foo'), 'foo')
  103. @patch('kombu.async.hub.poll')
  104. def test_start_stop(self, poll):
  105. hub = Hub()
  106. poll.assert_called_with()
  107. poller = hub.poller
  108. hub.stop()
  109. hub.close()
  110. poller.close.assert_called_with()
  111. def test_fire_timers(self):
  112. hub = Hub()
  113. hub.timer = Mock()
  114. hub.timer._queue = []
  115. self.assertEqual(hub.fire_timers(min_delay=42.324,
  116. max_delay=32.321), 32.321)
  117. hub.timer._queue = [1]
  118. hub.scheduler = iter([(3.743, None)])
  119. self.assertEqual(hub.fire_timers(), 3.743)
  120. e1, e2, e3 = Mock(), Mock(), Mock()
  121. entries = [e1, e2, e3]
  122. reset = lambda: [m.reset() for m in [e1, e2, e3]]
  123. def se():
  124. while 1:
  125. while entries:
  126. yield None, entries.pop()
  127. yield 3.982, None
  128. hub.scheduler = se()
  129. self.assertEqual(hub.fire_timers(max_timers=10), 3.982)
  130. for E in [e3, e2, e1]:
  131. E.assert_called_with()
  132. reset()
  133. entries[:] = [Mock() for _ in range(11)]
  134. keep = list(entries)
  135. self.assertEqual(hub.fire_timers(max_timers=10, min_delay=1.13), 1.13)
  136. for E in reversed(keep[1:]):
  137. E.assert_called_with()
  138. reset()
  139. self.assertEqual(hub.fire_timers(max_timers=10), 3.982)
  140. keep[0].assert_called_with()
  141. def test_fire_timers_raises(self):
  142. hub = Hub()
  143. eback = Mock()
  144. eback.side_effect = KeyError('foo')
  145. hub.timer = Mock()
  146. hub.scheduler = iter([(0, eback)])
  147. with self.assertRaises(KeyError):
  148. hub.fire_timers(propagate=(KeyError, ))
  149. eback.side_effect = ValueError('foo')
  150. hub.scheduler = iter([(0, eback)])
  151. with patch('kombu.async.hub.logger') as logger:
  152. with self.assertRaises(StopIteration):
  153. hub.fire_timers()
  154. self.assertTrue(logger.error.called)
  155. def test_add_raises_ValueError(self):
  156. hub = Hub()
  157. hub.poller = Mock(name='hub.poller')
  158. hub.poller.register.side_effect = ValueError()
  159. hub._discard = Mock(name='hub.discard')
  160. hub.add(2, Mock(), READ)
  161. hub._discard.assert_called_with(2)
  162. def test_repr_active(self):
  163. hub = Hub()
  164. hub.readers = {1: Mock(), 2: Mock()}
  165. hub.writers = {3: Mock(), 4: Mock()}
  166. for value in list(hub.readers.values()) + list(hub.writers.values()):
  167. value.__name__ = 'mock'
  168. self.assertTrue(hub.repr_active())
  169. def test_repr_events(self):
  170. hub = Hub()
  171. hub.readers = {6: Mock(), 7: Mock(), 8: Mock()}
  172. hub.writers = {9: Mock()}
  173. for value in list(hub.readers.values()) + list(hub.writers.values()):
  174. value.__name__ = 'mock'
  175. self.assertTrue(hub.repr_events([
  176. (6, READ),
  177. (7, ERR),
  178. (8, READ | ERR),
  179. (9, WRITE),
  180. (10, 13213),
  181. ]))
  182. def test_callback_for(self):
  183. hub = Hub()
  184. reader, writer = Mock(), Mock()
  185. hub.readers = {6: reader}
  186. hub.writers = {7: writer}
  187. self.assertEqual(hub._callback_for(6, READ), reader)
  188. self.assertEqual(hub._callback_for(7, WRITE), writer)
  189. with self.assertRaises(KeyError):
  190. hub._callback_for(6, WRITE)
  191. self.assertEqual(hub._callback_for(6, WRITE, 'foo'), 'foo')
  192. def test_add_remove_readers(self):
  193. hub = Hub()
  194. P = hub.poller = Mock()
  195. read_A = Mock()
  196. read_B = Mock()
  197. hub.add_reader(10, read_A, 10)
  198. hub.add_reader(File(11), read_B, 11)
  199. P.register.assert_has_calls([
  200. call(10, hub.READ | hub.ERR),
  201. call(File(11), hub.READ | hub.ERR),
  202. ], any_order=True)
  203. self.assertEqual(hub.readers[10], (read_A, (10, )))
  204. self.assertEqual(hub.readers[11], (read_B, (11, )))
  205. hub.remove(10)
  206. self.assertNotIn(10, hub.readers)
  207. hub.remove(File(11))
  208. self.assertNotIn(11, hub.readers)
  209. P.unregister.assert_has_calls([
  210. call(10), call(11),
  211. ])
  212. def test_can_remove_unknown_fds(self):
  213. hub = Hub()
  214. hub.poller = Mock()
  215. hub.remove(30)
  216. hub.remove(File(301))
  217. def test_remove__unregister_raises(self):
  218. hub = Hub()
  219. hub.poller = Mock()
  220. hub.poller.unregister.side_effect = OSError()
  221. hub.remove(313)
  222. def test_add_writers(self):
  223. hub = Hub()
  224. P = hub.poller = Mock()
  225. write_A = Mock()
  226. write_B = Mock()
  227. hub.add_writer(20, write_A)
  228. hub.add_writer(File(21), write_B)
  229. P.register.assert_has_calls([
  230. call(20, hub.WRITE),
  231. call(File(21), hub.WRITE),
  232. ], any_order=True)
  233. self.assertEqual(hub.writers[20], (write_A, ()))
  234. self.assertEqual(hub.writers[21], (write_B, ()))
  235. hub.remove(20)
  236. self.assertNotIn(20, hub.writers)
  237. hub.remove(File(21))
  238. self.assertNotIn(21, hub.writers)
  239. P.unregister.assert_has_calls([
  240. call(20), call(21),
  241. ])
  242. def test_enter__exit(self):
  243. hub = Hub()
  244. P = hub.poller = Mock()
  245. on_close = Mock()
  246. hub.on_close.add(on_close)
  247. try:
  248. read_A = Mock()
  249. read_B = Mock()
  250. hub.add_reader(10, read_A)
  251. hub.add_reader(File(11), read_B)
  252. write_A = Mock()
  253. write_B = Mock()
  254. hub.add_writer(20, write_A)
  255. hub.add_writer(File(21), write_B)
  256. self.assertTrue(hub.readers)
  257. self.assertTrue(hub.writers)
  258. finally:
  259. hub.close()
  260. self.assertFalse(hub.readers)
  261. self.assertFalse(hub.writers)
  262. P.unregister.assert_has_calls([
  263. call(10), call(11), call(20), call(21),
  264. ], any_order=True)
  265. on_close.assert_called_with(hub)
  266. def test_scheduler_property(self):
  267. hub = Hub(timer=[1, 2, 3])
  268. self.assertEqual(list(hub.scheduler), [1, 2, 3])