test_event_system.py 17 KB

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