test_event_system.py 15 KB

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