test_event_system.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. import unittest
  2. from cloudbridge.cloud.base.events import SimpleEventDispatcher
  3. from cloudbridge.cloud.interfaces.events import EventHandler
  4. from cloudbridge.cloud.interfaces.exceptions import HandlerException
  5. class EventSystemTestCase(unittest.TestCase):
  6. def test_emit_event_no_handlers(self):
  7. dispatcher = SimpleEventDispatcher()
  8. result = dispatcher.emit(self, "event.hello.world")
  9. self.assertIsNone(result, "Result should be none as there are no"
  10. "registered handlers")
  11. def test_emit_event_observing_handler(self):
  12. EVENT_NAME = "event.hello.world"
  13. callback_tracker = ['']
  14. def my_callback(**kwargs):
  15. self.assertDictEqual(kwargs,
  16. {'sender': self,
  17. 'event_name': EVENT_NAME})
  18. callback_tracker[0] += 'obs'
  19. return "hello"
  20. dispatcher = SimpleEventDispatcher()
  21. handler = dispatcher.observe(EVENT_NAME, 1000, my_callback)
  22. self.assertIsInstance(handler, EventHandler)
  23. result = dispatcher.emit(self, EVENT_NAME)
  24. self.assertEqual(
  25. callback_tracker[0], "obs", "callback should have been invoked"
  26. "once and contain value `obs` but tracker value is {0}".format(
  27. callback_tracker[0]))
  28. self.assertIsNone(result, "Result should be none as this is an"
  29. " observing handler")
  30. def test_emit_event_intercepting_handler(self):
  31. EVENT_NAME = "event.hello.world"
  32. callback_tracker = ['']
  33. def my_callback(**kwargs):
  34. self.assertDictEqual(kwargs,
  35. {'sender': self,
  36. 'event_name': EVENT_NAME,
  37. 'next_handler': None})
  38. callback_tracker[0] += "intcpt"
  39. return "world"
  40. dispatcher = SimpleEventDispatcher()
  41. handler = dispatcher.intercept(EVENT_NAME, 1000, my_callback)
  42. self.assertIsInstance(handler, EventHandler)
  43. result = dispatcher.emit(self, EVENT_NAME)
  44. self.assertEqual(
  45. callback_tracker[0], "intcpt", "callback should have been invoked"
  46. "once and contain value `intcpt` but tracker value is {0}".format(
  47. callback_tracker[0]))
  48. self.assertEqual(result, "world", "Result should be `world` as this"
  49. " is an intercepting handler")
  50. def test_emit_event_observe_precedes_intercept(self):
  51. EVENT_NAME = "event.hello.world"
  52. callback_tracker = ['']
  53. def my_callback_obs(**kwargs):
  54. self.assertDictEqual(kwargs,
  55. {'sender': self,
  56. 'event_name': EVENT_NAME})
  57. callback_tracker[0] += "obs_"
  58. return "hello"
  59. def my_callback_intcpt(**kwargs):
  60. self.assertDictEqual(kwargs,
  61. {'sender': self,
  62. 'event_name': EVENT_NAME,
  63. 'next_handler': None})
  64. callback_tracker[0] += "intcpt_"
  65. return "world"
  66. dispatcher = SimpleEventDispatcher()
  67. dispatcher.observe(EVENT_NAME, 1000, my_callback_obs)
  68. dispatcher.intercept(EVENT_NAME, 1001, my_callback_intcpt)
  69. result = dispatcher.emit(self, EVENT_NAME)
  70. self.assertEqual(
  71. callback_tracker[0], "obs_intcpt_", "callback was not invoked in "
  72. "expected order. Should have been obs_intcpt_ but is {0}".format(
  73. callback_tracker[0]))
  74. self.assertEqual(result, "world", "Result should be `world` as this"
  75. " is the return value of the intercepting handler")
  76. def test_emit_event_observe_follows_intercept(self):
  77. EVENT_NAME = "event.hello.world"
  78. callback_tracker = ['']
  79. def my_callback_intcpt(**kwargs):
  80. self.assertEqual(kwargs.get('sender'), self)
  81. self.assertEqual(kwargs.get('next_handler').priority, 1001)
  82. self.assertEqual(kwargs.get('next_handler').callback.__name__,
  83. "my_callback_obs")
  84. callback_tracker[0] += "intcpt_"
  85. # invoke next handler
  86. retval = kwargs.get('next_handler').invoke(**kwargs)
  87. self.assertIsNone(retval, "Return values of observable handlers"
  88. " should not be propagated.")
  89. return "world"
  90. def my_callback_obs(**kwargs):
  91. self.assertDictEqual(kwargs,
  92. {'sender': self,
  93. 'event_name': EVENT_NAME})
  94. callback_tracker[0] += "obs_"
  95. return "hello"
  96. dispatcher = SimpleEventDispatcher()
  97. # register priorities out of order to test that too
  98. dispatcher.observe(EVENT_NAME, 1001, my_callback_obs)
  99. dispatcher.intercept(EVENT_NAME, 1000, my_callback_intcpt)
  100. result = dispatcher.emit(self, EVENT_NAME)
  101. self.assertEqual(
  102. callback_tracker[0], "intcpt_obs_", "callback was not invoked in "
  103. "expected order. Should have been intcpt_obs_ but is {0}".format(
  104. callback_tracker[0]))
  105. self.assertEqual(result, "world", "Result should be `world` as this"
  106. " is the return value of the intercepting handler")
  107. def test_emit_event_intercept_follows_intercept(self):
  108. EVENT_NAME = "event.hello.world"
  109. callback_tracker = ['']
  110. def my_callback_intcpt1(**kwargs):
  111. self.assertEqual(kwargs.get('sender'), self)
  112. self.assertEqual(kwargs.get('next_handler').priority, 2020)
  113. self.assertEqual(kwargs.get('next_handler').callback.__name__,
  114. "my_callback_intcpt2")
  115. callback_tracker[0] += "intcpt1_"
  116. # invoke next handler but ignore return value
  117. return "hello" + kwargs.get('next_handler').invoke(**kwargs)
  118. def my_callback_intcpt2(**kwargs):
  119. self.assertDictEqual(kwargs,
  120. {'sender': self,
  121. 'event_name': EVENT_NAME,
  122. 'next_handler': None})
  123. callback_tracker[0] += "intcpt2_"
  124. return "world"
  125. dispatcher = SimpleEventDispatcher()
  126. dispatcher.intercept(EVENT_NAME, 2000, my_callback_intcpt1)
  127. dispatcher.intercept(EVENT_NAME, 2020, my_callback_intcpt2)
  128. result = dispatcher.emit(self, EVENT_NAME)
  129. self.assertEqual(
  130. callback_tracker[0], "intcpt1_intcpt2_", "callback was not invoked"
  131. " in expected order. Should have been intcpt1_intcpt2_ but is"
  132. " {0}".format(callback_tracker[0]))
  133. self.assertEqual(result, "helloworld", "Result should be `helloworld` "
  134. "as this is the expected return value from the chain")
  135. def test_subscribe_event_duplicate_priority(self):
  136. def my_callback(**kwargs):
  137. pass
  138. dispatcher = SimpleEventDispatcher()
  139. dispatcher.intercept("event.hello.world", 1000, my_callback)
  140. dispatcher.intercept("event.hello.world", 1000, my_callback)
  141. with self.assertRaises(HandlerException):
  142. dispatcher.emit(self, "event.hello.world")
  143. def test_subscribe_event_duplicate_wildcard_priority(self):
  144. def my_callback(**kwargs):
  145. pass
  146. dispatcher = SimpleEventDispatcher()
  147. dispatcher.intercept("event.hello.world", 1000, my_callback)
  148. dispatcher.intercept("event.hello.*", 1000, my_callback)
  149. with self.assertRaises(HandlerException):
  150. dispatcher.emit(self, "event.hello.world")
  151. def test_subscribe_event_duplicate_wildcard_priority_allowed(self):
  152. # duplicate priorities for different wildcard namespaces allowed
  153. def my_callback(**kwargs):
  154. pass
  155. dispatcher = SimpleEventDispatcher()
  156. dispatcher.intercept("event.hello.world", 1000, my_callback)
  157. dispatcher.intercept("someevent.hello.*", 1000, my_callback)
  158. # emit should work fine in this case with no exceptions
  159. dispatcher.emit(self, "event.hello.world")
  160. def test_subscribe_multiple_events(self):
  161. EVENT_NAME = "event.hello.world"
  162. callback_tracker = ['']
  163. def my_callback1(**kwargs):
  164. self.assertDictEqual(kwargs, {'sender': self,
  165. 'event_name': EVENT_NAME})
  166. callback_tracker[0] += "event1_"
  167. return "hello"
  168. def my_callback2(**kwargs):
  169. self.assertDictEqual(kwargs,
  170. {'sender': self,
  171. 'event_name': "event.hello.anotherworld"})
  172. callback_tracker[0] += "event2_"
  173. return "another"
  174. def my_callback3(**kwargs):
  175. self.assertDictEqual(kwargs,
  176. {'sender': self,
  177. 'event_name': "event.hello.anotherworld",
  178. 'next_handler': None})
  179. callback_tracker[0] += "event3_"
  180. return "world"
  181. dispatcher = SimpleEventDispatcher()
  182. dispatcher.observe(EVENT_NAME, 2000, my_callback1)
  183. # register to a different event with the same priority
  184. dispatcher.observe("event.hello.anotherworld", 2000, my_callback2)
  185. dispatcher.intercept("event.hello.anotherworld", 2020, my_callback3)
  186. result = dispatcher.emit(self, EVENT_NAME)
  187. self.assertEqual(
  188. callback_tracker[0], "event1_", "only `event.hello.world` handlers"
  189. " should have been triggered but received {0}".format(
  190. callback_tracker[0]))
  191. self.assertEqual(result, None, "Result should be `helloworld` "
  192. "as this is the expected return value from the chain")
  193. result = dispatcher.emit(self, "event.hello.anotherworld")
  194. self.assertEqual(
  195. callback_tracker[0], "event1_event2_event3_", "only handlers for"
  196. " event `event.hello.anotherworld` should have been triggered"
  197. " but received {0}".format(callback_tracker[0]))
  198. self.assertEqual(result, "world", "Result should be `world` "
  199. "as this is the expected return value from the chain")
  200. def test_subscribe_wildcard(self):
  201. callback_tracker = ['']
  202. def my_callback1(**kwargs):
  203. callback_tracker[0] += "event1_"
  204. return "hello" + kwargs.get('next_handler').invoke(**kwargs)
  205. def my_callback2(**kwargs):
  206. callback_tracker[0] += "event2_"
  207. return "some" + kwargs.get('next_handler').invoke(**kwargs)
  208. def my_callback3(**kwargs):
  209. callback_tracker[0] += "event3_"
  210. return "other" + kwargs.get('next_handler').invoke(**kwargs)
  211. def my_callback4(**kwargs):
  212. callback_tracker[0] += "event4_"
  213. return "world"
  214. dispatcher = SimpleEventDispatcher()
  215. dispatcher.intercept("event.*", 2000, my_callback1)
  216. # register to a different event with the same priority
  217. dispatcher.intercept("event.hello.*", 2010, my_callback2)
  218. dispatcher.intercept("event.hello.there", 2030, my_callback4)
  219. dispatcher.intercept("event.*.there", 2020, my_callback3)
  220. dispatcher.intercept("event.*.world", 2020, my_callback4)
  221. dispatcher.intercept("someevent.hello.there", 2030, my_callback3)
  222. # emit a series of events
  223. result = dispatcher.emit(self, "event.hello.there")
  224. self.assertEqual(
  225. callback_tracker[0], "event1_event2_event3_event4_",
  226. "Event handlers executed in unexpected order {0}".format(
  227. callback_tracker[0]))
  228. self.assertEqual(result, "hellosomeotherworld")
  229. result = dispatcher.emit(self, "event.test.hello.world")
  230. self.assertEqual(
  231. callback_tracker[0], "event1_event2_event3_event4_event1_event4_",
  232. "Event handlers executed in unexpected order {0}".format(
  233. callback_tracker[0]))
  234. self.assertEqual(result, "helloworld")
  235. # make sure cache gets invalidated when subscribing after emit
  236. def test_subscribe_after_emit(self):
  237. callback_tracker = ['']
  238. def my_callback1(**kwargs):
  239. callback_tracker[0] += "event1_"
  240. if kwargs.get('next_handler'):
  241. return "hello" + kwargs.get('next_handler').invoke(**kwargs)
  242. else:
  243. return "hello"
  244. def my_callback2(**kwargs):
  245. callback_tracker[0] += "event2_"
  246. return "some"
  247. dispatcher = SimpleEventDispatcher()
  248. dispatcher.intercept("event.hello.world", 1000, my_callback1)
  249. dispatcher.emit(self, "event.hello.world")
  250. dispatcher.intercept("event.hello.*", 1001, my_callback2)
  251. result = dispatcher.emit(self, "event.hello.world")
  252. self.assertEqual(
  253. callback_tracker[0], "event1_event1_event2_",
  254. "Event handlers executed in unexpected order {0}".format(
  255. callback_tracker[0]))
  256. self.assertEqual(result, "hellosome")
  257. def test_unubscribe(self):
  258. callback_tracker = ['']
  259. def my_callback1(**kwargs):
  260. callback_tracker[0] += "event1_"
  261. if kwargs.get('next_handler'):
  262. return "hello" + kwargs.get('next_handler').invoke(**kwargs)
  263. else:
  264. return "hello"
  265. def my_callback2(**kwargs):
  266. callback_tracker[0] += "event2_"
  267. return "some"
  268. dispatcher = SimpleEventDispatcher()
  269. hndlr1 = dispatcher.intercept("event.hello.world", 1000, my_callback1)
  270. dispatcher.emit(self, "event.hello.world")
  271. hndlr2 = dispatcher.intercept("event.hello.*", 1001, my_callback2)
  272. hndlr1.unsubscribe()
  273. result = dispatcher.emit(self, "event.hello.world")
  274. self.assertEqual(
  275. callback_tracker[0], "event1_event2_",
  276. "Event handlers executed in unexpected order {0}".format(
  277. callback_tracker[0]))
  278. self.assertEqual(result, "some")
  279. hndlr2.unsubscribe()
  280. result = dispatcher.emit(self, "event.hello.world")
  281. self.assertEqual(result, None)