test_events.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. import sys
  2. import unittest
  3. from supervisor.tests.base import DummyOptions
  4. from supervisor.tests.base import DummyPConfig
  5. from supervisor.tests.base import DummyProcess
  6. from supervisor.tests.base import DummyEvent
  7. class EventSubscriptionNotificationTests(unittest.TestCase):
  8. def setUp(self):
  9. from supervisor import events
  10. events.callbacks[:] = []
  11. def tearDown(self):
  12. from supervisor import events
  13. events.callbacks[:] = []
  14. def test_subscribe(self):
  15. from supervisor import events
  16. events.subscribe(None, None)
  17. self.assertEqual(events.callbacks, [(None, None)])
  18. def test_clear(self):
  19. from supervisor import events
  20. events.callbacks[:] = [(None, None)]
  21. events.clear()
  22. self.assertEqual(events.callbacks, [])
  23. def test_notify_true(self):
  24. from supervisor import events
  25. L = []
  26. def callback(event):
  27. L.append(1)
  28. events.callbacks[:] = [(DummyEvent, callback)]
  29. events.notify(DummyEvent())
  30. self.assertEqual(L, [1])
  31. def test_notify_false(self):
  32. from supervisor import events
  33. L = []
  34. def callback(event):
  35. L.append(1)
  36. class AnotherEvent:
  37. pass
  38. events.callbacks[:] = [(AnotherEvent, callback)]
  39. events.notify(DummyEvent())
  40. self.assertEqual(L, [])
  41. def test_notify_via_subclass(self):
  42. from supervisor import events
  43. L = []
  44. def callback(event):
  45. L.append(1)
  46. class ASubclassEvent(DummyEvent):
  47. pass
  48. events.callbacks[:] = [(DummyEvent, callback)]
  49. events.notify(ASubclassEvent())
  50. self.assertEqual(L, [1])
  51. class TestEventTypes(unittest.TestCase):
  52. def test_ProcessLogEvent_attributes(self):
  53. from supervisor.events import ProcessLogEvent
  54. inst = ProcessLogEvent(1, 2, 3)
  55. self.assertEqual(inst.process, 1)
  56. self.assertEqual(inst.pid, 2)
  57. self.assertEqual(inst.data, 3)
  58. def test_ProcessLogEvent_inheritence(self):
  59. from supervisor.events import ProcessLogEvent
  60. from supervisor.events import Event
  61. self.assertTrue(
  62. issubclass(ProcessLogEvent, Event)
  63. )
  64. def test_ProcessLogStdoutEvent_attributes(self):
  65. from supervisor.events import ProcessLogStdoutEvent
  66. inst = ProcessLogStdoutEvent(1, 2, 3)
  67. self.assertEqual(inst.process, 1)
  68. self.assertEqual(inst.pid, 2)
  69. self.assertEqual(inst.data, 3)
  70. self.assertEqual(inst.channel, 'stdout')
  71. def test_ProcessLogStdoutEvent_inheritence(self):
  72. from supervisor.events import ProcessLogStdoutEvent
  73. from supervisor.events import ProcessLogEvent
  74. self.assertTrue(
  75. issubclass(ProcessLogStdoutEvent, ProcessLogEvent)
  76. )
  77. def test_ProcessLogStderrEvent_attributes(self):
  78. from supervisor.events import ProcessLogStderrEvent
  79. inst = ProcessLogStderrEvent(1, 2, 3)
  80. self.assertEqual(inst.process, 1)
  81. self.assertEqual(inst.pid, 2)
  82. self.assertEqual(inst.data, 3)
  83. self.assertEqual(inst.channel, 'stderr')
  84. def test_ProcessLogStderrEvent_inheritence(self):
  85. from supervisor.events import ProcessLogStderrEvent
  86. from supervisor.events import ProcessLogEvent
  87. self.assertTrue(
  88. issubclass(ProcessLogStderrEvent, ProcessLogEvent)
  89. )
  90. def test_ProcessCommunicationEvent_attributes(self):
  91. from supervisor.events import ProcessCommunicationEvent
  92. inst = ProcessCommunicationEvent(1, 2, 3)
  93. self.assertEqual(inst.process, 1)
  94. self.assertEqual(inst.pid, 2)
  95. self.assertEqual(inst.data, 3)
  96. def test_ProcessCommunicationEvent_inheritence(self):
  97. from supervisor.events import ProcessCommunicationEvent
  98. from supervisor.events import Event
  99. self.assertTrue(
  100. issubclass(ProcessCommunicationEvent, Event)
  101. )
  102. def test_ProcessCommunicationStdoutEvent_attributes(self):
  103. from supervisor.events import ProcessCommunicationStdoutEvent
  104. inst = ProcessCommunicationStdoutEvent(1, 2, 3)
  105. self.assertEqual(inst.process, 1)
  106. self.assertEqual(inst.pid, 2)
  107. self.assertEqual(inst.data, 3)
  108. self.assertEqual(inst.channel, 'stdout')
  109. def test_ProcessCommunicationStdoutEvent_inheritence(self):
  110. from supervisor.events import ProcessCommunicationStdoutEvent
  111. from supervisor.events import ProcessCommunicationEvent
  112. self.assertTrue(
  113. issubclass(ProcessCommunicationStdoutEvent,
  114. ProcessCommunicationEvent)
  115. )
  116. def test_ProcessCommunicationStderrEvent_attributes(self):
  117. from supervisor.events import ProcessCommunicationStderrEvent
  118. inst = ProcessCommunicationStderrEvent(1, 2, 3)
  119. self.assertEqual(inst.process, 1)
  120. self.assertEqual(inst.pid, 2)
  121. self.assertEqual(inst.data, 3)
  122. self.assertEqual(inst.channel, 'stderr')
  123. def test_ProcessCommunicationStderrEvent_inheritence(self):
  124. from supervisor.events import ProcessCommunicationStderrEvent
  125. from supervisor.events import ProcessCommunicationEvent
  126. self.assertTrue(
  127. issubclass(ProcessCommunicationStderrEvent,
  128. ProcessCommunicationEvent)
  129. )
  130. def test_RemoteCommunicationEvent_attributes(self):
  131. from supervisor.events import RemoteCommunicationEvent
  132. inst = RemoteCommunicationEvent(1, 2)
  133. self.assertEqual(inst.type, 1)
  134. self.assertEqual(inst.data, 2)
  135. def test_RemoteCommunicationEvent_inheritence(self):
  136. from supervisor.events import RemoteCommunicationEvent
  137. from supervisor.events import Event
  138. self.assertTrue(
  139. issubclass(RemoteCommunicationEvent, Event)
  140. )
  141. def test_EventRejectedEvent_attributes(self):
  142. from supervisor.events import EventRejectedEvent
  143. options = DummyOptions()
  144. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  145. process = DummyProcess(pconfig1)
  146. rejected_event = DummyEvent()
  147. event = EventRejectedEvent(process, rejected_event)
  148. self.assertEqual(event.process, process)
  149. self.assertEqual(event.event, rejected_event)
  150. def test_EventRejectedEvent_does_not_inherit_from_event(self):
  151. from supervisor.events import EventRejectedEvent
  152. from supervisor.events import Event
  153. self.assertFalse(
  154. issubclass(EventRejectedEvent, Event)
  155. )
  156. def test_all_SupervisorStateChangeEvents(self):
  157. from supervisor import events
  158. for klass in (
  159. events.SupervisorStateChangeEvent,
  160. events.SupervisorRunningEvent,
  161. events.SupervisorStoppingEvent
  162. ):
  163. self._test_one_SupervisorStateChangeEvent(klass)
  164. def _test_one_SupervisorStateChangeEvent(self, klass):
  165. from supervisor.events import SupervisorStateChangeEvent
  166. self.assertTrue(issubclass(klass, SupervisorStateChangeEvent))
  167. def test_all_ProcessStateEvents(self):
  168. from supervisor import events
  169. for klass in (
  170. events.ProcessStateEvent,
  171. events.ProcessStateStoppedEvent,
  172. events.ProcessStateExitedEvent,
  173. events.ProcessStateFatalEvent,
  174. events.ProcessStateBackoffEvent,
  175. events.ProcessStateRunningEvent,
  176. events.ProcessStateUnknownEvent,
  177. events.ProcessStateStoppingEvent,
  178. events.ProcessStateStartingEvent,
  179. ):
  180. self._test_one_ProcessStateEvent(klass)
  181. def _test_one_ProcessStateEvent(self, klass):
  182. from supervisor.states import ProcessStates
  183. from supervisor.events import ProcessStateEvent
  184. self.assertTrue(issubclass(klass, ProcessStateEvent))
  185. options = DummyOptions()
  186. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  187. process = DummyProcess(pconfig1)
  188. inst = klass(process, ProcessStates.STARTING)
  189. self.assertEqual(inst.process, process)
  190. self.assertEqual(inst.from_state, ProcessStates.STARTING)
  191. self.assertEqual(inst.expected, True)
  192. def test_all_TickEvents(self):
  193. from supervisor import events
  194. for klass in (
  195. events.TickEvent,
  196. events.Tick5Event,
  197. events.Tick60Event,
  198. events.Tick3600Event
  199. ):
  200. self._test_one_TickEvent(klass)
  201. def _test_one_TickEvent(self, klass):
  202. from supervisor.events import TickEvent
  203. self.assertTrue(issubclass(klass, TickEvent))
  204. inst = klass(1, 2)
  205. self.assertEqual(inst.when, 1)
  206. self.assertEqual(inst.supervisord, 2)
  207. def test_ProcessGroupAddedEvent_attributes(self):
  208. from supervisor.events import ProcessGroupAddedEvent
  209. inst = ProcessGroupAddedEvent('myprocess')
  210. self.assertEqual(inst.group, 'myprocess')
  211. def test_ProcessGroupRemovedEvent_attributes(self):
  212. from supervisor.events import ProcessGroupRemovedEvent
  213. inst = ProcessGroupRemovedEvent('myprocess')
  214. self.assertEqual(inst.group, 'myprocess')
  215. class TestSerializations(unittest.TestCase):
  216. def _deserialize(self, serialization):
  217. data = serialization.split('\n')
  218. headerdata = data[0]
  219. payload = ''
  220. headers = {}
  221. if len(data) > 1:
  222. payload = data[1]
  223. if headerdata:
  224. try:
  225. headers = dict( [ x.split(':',1) for x in
  226. headerdata.split()] )
  227. except ValueError:
  228. raise AssertionError('headerdata %r could not be deserialized' %
  229. headerdata)
  230. return headers, payload
  231. def test_plog_stdout_event(self):
  232. options = DummyOptions()
  233. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  234. process1 = DummyProcess(pconfig1)
  235. from supervisor.events import ProcessLogStdoutEvent
  236. class DummyGroup:
  237. config = pconfig1
  238. process1.group = DummyGroup
  239. event = ProcessLogStdoutEvent(process1, 1, 'yo')
  240. headers, payload = self._deserialize(str(event))
  241. self.assertEqual(headers['processname'], 'process1', headers)
  242. self.assertEqual(headers['groupname'], 'process1', headers)
  243. self.assertEqual(headers['pid'], '1', headers)
  244. self.assertEqual(payload, 'yo')
  245. def test_plog_stderr_event(self):
  246. options = DummyOptions()
  247. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  248. process1 = DummyProcess(pconfig1)
  249. from supervisor.events import ProcessLogStderrEvent
  250. class DummyGroup:
  251. config = pconfig1
  252. process1.group = DummyGroup
  253. event = ProcessLogStderrEvent(process1, 1, 'yo')
  254. headers, payload = self._deserialize(str(event))
  255. self.assertEqual(headers['processname'], 'process1', headers)
  256. self.assertEqual(headers['groupname'], 'process1', headers)
  257. self.assertEqual(headers['pid'], '1', headers)
  258. self.assertEqual(payload, 'yo')
  259. def test_pcomm_stdout_event(self):
  260. options = DummyOptions()
  261. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  262. process1 = DummyProcess(pconfig1)
  263. from supervisor.events import ProcessCommunicationStdoutEvent
  264. class DummyGroup:
  265. config = pconfig1
  266. process1.group = DummyGroup
  267. event = ProcessCommunicationStdoutEvent(process1, 1, 'yo')
  268. headers, payload = self._deserialize(str(event))
  269. self.assertEqual(headers['processname'], 'process1', headers)
  270. self.assertEqual(headers['groupname'], 'process1', headers)
  271. self.assertEqual(headers['pid'], '1', headers)
  272. self.assertEqual(payload, 'yo')
  273. def test_pcomm_stderr_event(self):
  274. options = DummyOptions()
  275. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  276. process1 = DummyProcess(pconfig1)
  277. class DummyGroup:
  278. config = pconfig1
  279. process1.group = DummyGroup
  280. from supervisor.events import ProcessCommunicationStderrEvent
  281. event = ProcessCommunicationStderrEvent(process1, 1, 'yo')
  282. headers, payload = self._deserialize(str(event))
  283. self.assertEqual(headers['processname'], 'process1', headers)
  284. self.assertEqual(headers['groupname'], 'process1', headers)
  285. self.assertEqual(headers['pid'], '1', headers)
  286. self.assertEqual(payload, 'yo')
  287. def test_remote_comm_event(self):
  288. from supervisor.events import RemoteCommunicationEvent
  289. event = RemoteCommunicationEvent('foo', 'bar')
  290. headers, payload = self._deserialize(str(event))
  291. self.assertEqual(headers['type'], 'foo', headers)
  292. self.assertEqual(payload, 'bar')
  293. def test_process_group_added_event(self):
  294. from supervisor.events import ProcessGroupAddedEvent
  295. event = ProcessGroupAddedEvent('foo')
  296. headers, payload = self._deserialize(str(event))
  297. self.assertEqual(headers['groupname'], 'foo')
  298. self.assertEqual(payload, '')
  299. def test_process_group_removed_event(self):
  300. from supervisor.events import ProcessGroupRemovedEvent
  301. event = ProcessGroupRemovedEvent('foo')
  302. headers, payload = self._deserialize(str(event))
  303. self.assertEqual(headers['groupname'], 'foo')
  304. self.assertEqual(payload, '')
  305. def test_process_state_events_without_extra_values(self):
  306. from supervisor.states import ProcessStates
  307. from supervisor import events
  308. for klass in (
  309. events.ProcessStateFatalEvent,
  310. events.ProcessStateUnknownEvent,
  311. ):
  312. options = DummyOptions()
  313. pconfig1 = DummyPConfig(options, 'process1', 'process1',
  314. '/bin/process1')
  315. class DummyGroup:
  316. config = pconfig1
  317. process1 = DummyProcess(pconfig1)
  318. process1.group = DummyGroup
  319. event = klass(process1, ProcessStates.STARTING)
  320. headers, payload = self._deserialize(str(event))
  321. self.assertEqual(len(headers), 3)
  322. self.assertEqual(headers['processname'], 'process1')
  323. self.assertEqual(headers['groupname'], 'process1')
  324. self.assertEqual(headers['from_state'], 'STARTING')
  325. self.assertEqual(payload, '')
  326. def test_process_state_events_with_pid(self):
  327. from supervisor.states import ProcessStates
  328. from supervisor import events
  329. for klass in (
  330. events.ProcessStateRunningEvent,
  331. events.ProcessStateStoppedEvent,
  332. events.ProcessStateStoppingEvent,
  333. ):
  334. options = DummyOptions()
  335. pconfig1 = DummyPConfig(options, 'process1', 'process1',
  336. '/bin/process1')
  337. class DummyGroup:
  338. config = pconfig1
  339. process1 = DummyProcess(pconfig1)
  340. process1.group = DummyGroup
  341. process1.pid = 1
  342. event = klass(process1, ProcessStates.STARTING)
  343. headers, payload = self._deserialize(str(event))
  344. self.assertEqual(len(headers), 4)
  345. self.assertEqual(headers['processname'], 'process1')
  346. self.assertEqual(headers['groupname'], 'process1')
  347. self.assertEqual(headers['from_state'], 'STARTING')
  348. self.assertEqual(headers['pid'], '1')
  349. self.assertEqual(payload, '')
  350. def test_process_state_events_starting_and_backoff(self):
  351. from supervisor.states import ProcessStates
  352. from supervisor import events
  353. for klass in (
  354. events.ProcessStateStartingEvent,
  355. events.ProcessStateBackoffEvent,
  356. ):
  357. options = DummyOptions()
  358. pconfig1 = DummyPConfig(options, 'process1', 'process1',
  359. '/bin/process1')
  360. class DummyGroup:
  361. config = pconfig1
  362. process1 = DummyProcess(pconfig1)
  363. process1.group = DummyGroup
  364. event = klass(process1, ProcessStates.STARTING)
  365. headers, payload = self._deserialize(str(event))
  366. self.assertEqual(len(headers), 4)
  367. self.assertEqual(headers['processname'], 'process1')
  368. self.assertEqual(headers['groupname'], 'process1')
  369. self.assertEqual(headers['from_state'], 'STARTING')
  370. self.assertEqual(headers['tries'], '0')
  371. self.assertEqual(payload, '')
  372. process1.backoff = 1
  373. event = klass(process1, ProcessStates.STARTING)
  374. headers, payload = self._deserialize(str(event))
  375. self.assertEqual(headers['tries'], '1')
  376. process1.backoff = 2
  377. event = klass(process1, ProcessStates.STARTING)
  378. headers, payload = self._deserialize(str(event))
  379. self.assertEqual(headers['tries'], '2')
  380. def test_process_state_exited_event_expected(self):
  381. from supervisor import events
  382. from supervisor.states import ProcessStates
  383. options = DummyOptions()
  384. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  385. process1 = DummyProcess(pconfig1)
  386. class DummyGroup:
  387. config = pconfig1
  388. process1.group = DummyGroup
  389. process1.pid = 1
  390. event = events.ProcessStateExitedEvent(process1,
  391. ProcessStates.STARTING,
  392. expected=True)
  393. headers, payload = self._deserialize(str(event))
  394. self.assertEqual(len(headers), 5)
  395. self.assertEqual(headers['processname'], 'process1')
  396. self.assertEqual(headers['groupname'], 'process1')
  397. self.assertEqual(headers['pid'], '1')
  398. self.assertEqual(headers['from_state'], 'STARTING')
  399. self.assertEqual(headers['expected'], '1')
  400. self.assertEqual(payload, '')
  401. def test_process_state_exited_event_unexpected(self):
  402. from supervisor import events
  403. from supervisor.states import ProcessStates
  404. options = DummyOptions()
  405. pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1')
  406. process1 = DummyProcess(pconfig1)
  407. class DummyGroup:
  408. config = pconfig1
  409. process1.group = DummyGroup
  410. process1.pid = 1
  411. event = events.ProcessStateExitedEvent(process1,
  412. ProcessStates.STARTING,
  413. expected=False)
  414. headers, payload = self._deserialize(str(event))
  415. self.assertEqual(len(headers), 5)
  416. self.assertEqual(headers['processname'], 'process1')
  417. self.assertEqual(headers['groupname'], 'process1')
  418. self.assertEqual(headers['pid'], '1')
  419. self.assertEqual(headers['from_state'], 'STARTING')
  420. self.assertEqual(headers['expected'], '0')
  421. self.assertEqual(payload, '')
  422. def test_supervisor_sc_event(self):
  423. from supervisor import events
  424. event = events.SupervisorRunningEvent()
  425. headers, payload = self._deserialize(str(event))
  426. self.assertEqual(headers, {})
  427. self.assertEqual(payload, '')
  428. def test_tick_events(self):
  429. from supervisor import events
  430. for klass in (
  431. events.Tick5Event,
  432. events.Tick60Event,
  433. events.Tick3600Event,
  434. ):
  435. event = klass(1, 2)
  436. headers, payload = self._deserialize(str(event))
  437. self.assertEqual(headers, {'when':'1'})
  438. self.assertEqual(payload, '')
  439. class TestUtilityFunctions(unittest.TestCase):
  440. def test_getEventNameByType(self):
  441. from supervisor import events
  442. for name, value in events.EventTypes.__dict__.items():
  443. self.assertEqual(events.getEventNameByType(value), name)
  444. def test_register(self):
  445. from supervisor import events
  446. self.assertFalse(hasattr(events.EventTypes, 'FOO'))
  447. class FooEvent(events.Event):
  448. pass
  449. try:
  450. events.register('FOO', FooEvent)
  451. self.assertTrue(events.EventTypes.FOO is FooEvent)
  452. finally:
  453. del events.EventTypes.FOO
  454. def test_suite():
  455. return unittest.findTestCases(sys.modules[__name__])
  456. if __name__ == '__main__':
  457. unittest.main(defaultTest='test_suite')