test_rpcinterfaces.py 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995
  1. import unittest
  2. import sys
  3. import os
  4. import time
  5. import errno
  6. from supervisor.tests.base import DummyOptions
  7. from supervisor.tests.base import DummySupervisor
  8. from supervisor.tests.base import DummyProcess
  9. from supervisor.tests.base import DummyPConfig
  10. from supervisor.tests.base import DummyPGroupConfig
  11. from supervisor.tests.base import DummyProcessGroup
  12. from supervisor.tests.base import PopulatedDummySupervisor
  13. from supervisor.tests.base import _NOW
  14. from supervisor.tests.base import _TIMEFORMAT
  15. class TestBase(unittest.TestCase):
  16. def setUp(self):
  17. pass
  18. def tearDown(self):
  19. pass
  20. def _assertRPCError(self, code, callable, *args, **kw):
  21. from supervisor import xmlrpc
  22. try:
  23. callable(*args, **kw)
  24. except xmlrpc.RPCError, inst:
  25. self.assertEqual(inst.code, code)
  26. else:
  27. raise AssertionError("Didnt raise")
  28. class MainXMLRPCInterfaceTests(TestBase):
  29. def _getTargetClass(self):
  30. from supervisor import xmlrpc
  31. return xmlrpc.RootRPCInterface
  32. def _makeOne(self, *args, **kw):
  33. return self._getTargetClass()(*args, **kw)
  34. def test_ctor(self):
  35. interface = self._makeOne([('supervisor', None)])
  36. self.assertEqual(interface.supervisor, None)
  37. def test_traverse(self):
  38. dummy = DummyRPCInterface()
  39. interface = self._makeOne([('dummy', dummy)])
  40. from supervisor import xmlrpc
  41. self._assertRPCError(xmlrpc.Faults.UNKNOWN_METHOD,
  42. xmlrpc.traverse, interface, 'notthere.hello', [])
  43. self._assertRPCError(xmlrpc.Faults.UNKNOWN_METHOD,
  44. xmlrpc.traverse, interface,
  45. 'supervisor._readFile', [])
  46. self._assertRPCError(xmlrpc.Faults.INCORRECT_PARAMETERS,
  47. xmlrpc.traverse, interface,
  48. 'dummy.hello', [1])
  49. self.assertEqual(xmlrpc.traverse(
  50. interface, 'dummy.hello', []), 'Hello!')
  51. class SupervisorNamespaceXMLRPCInterfaceTests(TestBase):
  52. def _getTargetClass(self):
  53. from supervisor import rpcinterface
  54. return rpcinterface.SupervisorNamespaceRPCInterface
  55. def _makeOne(self, *args, **kw):
  56. return self._getTargetClass()(*args, **kw)
  57. def test_update(self):
  58. from supervisor import xmlrpc
  59. from supervisor.supervisord import SupervisorStates
  60. supervisord = DummySupervisor()
  61. interface = self._makeOne(supervisord)
  62. interface._update('foo')
  63. self.assertEqual(interface.update_text, 'foo')
  64. supervisord.options.mood = SupervisorStates.SHUTDOWN
  65. self._assertRPCError(xmlrpc.Faults.SHUTDOWN_STATE, interface._update,
  66. 'foo')
  67. def test_getAPIVersion(self):
  68. from supervisor import rpcinterface
  69. supervisord = DummySupervisor()
  70. interface = self._makeOne(supervisord)
  71. version = interface.getAPIVersion()
  72. self.assertEqual(version, rpcinterface.API_VERSION)
  73. self.assertEqual(interface.update_text, 'getAPIVersion')
  74. def test_getAPIVersion_aliased_to_deprecated_getVersion(self):
  75. supervisord = DummySupervisor()
  76. interface = self._makeOne(supervisord)
  77. self.assertEqual(interface.getAPIVersion, interface.getVersion)
  78. def test_getSupervisorVersion(self):
  79. supervisord = DummySupervisor()
  80. interface = self._makeOne(supervisord)
  81. version = interface.getSupervisorVersion()
  82. from supervisor import options
  83. self.assertEqual(version, options.VERSION)
  84. self.assertEqual(interface.update_text, 'getSupervisorVersion')
  85. def test_getIdentification(self):
  86. supervisord = DummySupervisor()
  87. interface = self._makeOne(supervisord)
  88. identifier = interface.getIdentification()
  89. self.assertEqual(identifier, supervisord.options.identifier)
  90. self.assertEqual(interface.update_text, 'getIdentification')
  91. def test_getState(self):
  92. from supervisor.states import getSupervisorStateDescription
  93. supervisord = DummySupervisor()
  94. interface = self._makeOne(supervisord)
  95. stateinfo = interface.getState()
  96. statecode = supervisord.options.mood
  97. statename = getSupervisorStateDescription(statecode)
  98. self.assertEqual(stateinfo['statecode'], statecode)
  99. self.assertEqual(stateinfo['statename'], statename)
  100. self.assertEqual(interface.update_text, 'getState')
  101. def test_getPID(self):
  102. options = DummyOptions()
  103. supervisord = DummySupervisor(options)
  104. interface = self._makeOne(supervisord)
  105. self.assertEqual(interface.getPID(), options.get_pid())
  106. self.assertEqual(interface.update_text, 'getPID')
  107. def test_readLog_aliased_to_deprecated_readMainLog(self):
  108. supervisord = DummySupervisor()
  109. interface = self._makeOne(supervisord)
  110. self.assertEqual(interface.readMainLog, interface.readLog)
  111. def test_readLog_unreadable(self):
  112. from supervisor import xmlrpc
  113. supervisord = DummySupervisor()
  114. interface = self._makeOne(supervisord)
  115. self._assertRPCError(xmlrpc.Faults.NO_FILE, interface.readLog,
  116. offset=0, length=1)
  117. def test_readLog_badargs(self):
  118. from supervisor import xmlrpc
  119. supervisord = DummySupervisor()
  120. interface = self._makeOne(supervisord)
  121. try:
  122. logfile = supervisord.options.logfile
  123. f = open(logfile, 'w+')
  124. f.write('x' * 2048)
  125. f.close()
  126. self._assertRPCError(xmlrpc.Faults.BAD_ARGUMENTS,
  127. interface.readLog, offset=-1, length=1)
  128. self._assertRPCError(xmlrpc.Faults.BAD_ARGUMENTS,
  129. interface.readLog, offset=-1,
  130. length=-1)
  131. finally:
  132. os.remove(logfile)
  133. def test_readLog(self):
  134. supervisord = DummySupervisor()
  135. interface = self._makeOne(supervisord)
  136. logfile = supervisord.options.logfile
  137. try:
  138. f = open(logfile, 'w+')
  139. f.write('x' * 2048)
  140. f.write('y' * 2048)
  141. f.close()
  142. data = interface.readLog(offset=0, length=0)
  143. self.assertEqual(interface.update_text, 'readLog')
  144. self.assertEqual(data, ('x' * 2048) + ('y' * 2048))
  145. data = interface.readLog(offset=2048, length=0)
  146. self.assertEqual(data, 'y' * 2048)
  147. data = interface.readLog(offset=0, length=2048)
  148. self.assertEqual(data, 'x' * 2048)
  149. data = interface.readLog(offset=-4, length=0)
  150. self.assertEqual(data, 'y' * 4)
  151. finally:
  152. os.remove(logfile)
  153. def test_clearLog_unreadable(self):
  154. from supervisor import xmlrpc
  155. supervisord = DummySupervisor()
  156. interface = self._makeOne(supervisord)
  157. self._assertRPCError(xmlrpc.Faults.NO_FILE, interface.clearLog)
  158. def test_clearLog_unremoveable(self):
  159. from supervisor import xmlrpc
  160. options = DummyOptions()
  161. options.existing = [options.logfile]
  162. options.remove_error = 1
  163. supervisord = DummySupervisor(options)
  164. interface = self._makeOne(supervisord)
  165. self.assertRaises(xmlrpc.RPCError, interface.clearLog)
  166. self.assertEqual(interface.update_text, 'clearLog')
  167. def test_clearLog(self):
  168. options = DummyOptions()
  169. options.existing = [options.logfile]
  170. supervisord = DummySupervisor(options)
  171. interface = self._makeOne(supervisord)
  172. result = interface.clearLog()
  173. self.assertEqual(interface.update_text, 'clearLog')
  174. self.assertEqual(result, True)
  175. self.assertEqual(options.removed[0], options.logfile)
  176. for handler in supervisord.options.logger.handlers:
  177. self.assertEqual(handler.reopened, True)
  178. def test_shutdown(self):
  179. supervisord = DummySupervisor()
  180. interface = self._makeOne(supervisord)
  181. value = interface.shutdown()
  182. self.assertEqual(value, True)
  183. self.assertEqual(supervisord.options.mood, -1)
  184. def test_restart(self):
  185. supervisord = DummySupervisor()
  186. interface = self._makeOne(supervisord)
  187. value = interface.restart()
  188. self.assertEqual(value, True)
  189. self.assertEqual(supervisord.options.mood, 0)
  190. def test_reloadConfig(self):
  191. options = DummyOptions()
  192. supervisord = DummySupervisor(options)
  193. interface = self._makeOne(supervisord)
  194. changes = [ [DummyPGroupConfig(options, 'added')],
  195. [DummyPGroupConfig(options, 'changed')],
  196. [DummyPGroupConfig(options, 'dropped')] ]
  197. supervisord.diff_to_active = lambda : changes
  198. value = interface.reloadConfig()
  199. self.assertEqual(value, [[['added'], ['changed'], ['dropped']]])
  200. def test_reloadConfig_process_config_raises_ValueError(self):
  201. from supervisor import xmlrpc
  202. options = DummyOptions()
  203. def raise_exc(*arg, **kw):
  204. raise ValueError('foo')
  205. options.process_config = raise_exc
  206. supervisord = DummySupervisor(options)
  207. interface = self._makeOne(supervisord)
  208. self._assertRPCError(xmlrpc.Faults.CANT_REREAD, interface.reloadConfig)
  209. def test_addProcessGroup(self):
  210. from supervisor.supervisord import Supervisor
  211. from supervisor import xmlrpc
  212. options = DummyOptions()
  213. supervisord = Supervisor(options)
  214. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  215. gconfig = DummyPGroupConfig(options, 'group1', pconfigs=[pconfig])
  216. supervisord.options.process_group_configs = [gconfig]
  217. interface = self._makeOne(supervisord)
  218. result = interface.addProcessGroup('group1')
  219. self.assertTrue(result)
  220. self.assertEqual(supervisord.process_groups.keys(), ['group1'])
  221. self._assertRPCError(xmlrpc.Faults.ALREADY_ADDED,
  222. interface.addProcessGroup, 'group1')
  223. self.assertEqual(supervisord.process_groups.keys(), ['group1'])
  224. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  225. interface.addProcessGroup, 'asdf')
  226. self.assertEqual(supervisord.process_groups.keys(), ['group1'])
  227. def test_removeProcessGroup(self):
  228. from supervisor.supervisord import Supervisor
  229. options = DummyOptions()
  230. supervisord = Supervisor(options)
  231. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  232. gconfig = DummyPGroupConfig(options, 'group1', pconfigs=[pconfig])
  233. supervisord.options.process_group_configs = [gconfig]
  234. interface = self._makeOne(supervisord)
  235. interface.addProcessGroup('group1')
  236. result = interface.removeProcessGroup('group1')
  237. self.assertTrue(result)
  238. self.assertEqual(supervisord.process_groups.keys(), [])
  239. def test_removeProcessGroup_bad_name(self):
  240. from supervisor.supervisord import Supervisor
  241. from supervisor import xmlrpc
  242. options = DummyOptions()
  243. supervisord = Supervisor(options)
  244. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  245. gconfig = DummyPGroupConfig(options, 'group1', pconfigs=[pconfig])
  246. supervisord.options.process_group_configs = [gconfig]
  247. interface = self._makeOne(supervisord)
  248. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  249. interface.removeProcessGroup, 'asdf')
  250. def test_removeProcessGroup_still_running(self):
  251. from supervisor.supervisord import Supervisor
  252. from supervisor import xmlrpc
  253. options = DummyOptions()
  254. supervisord = Supervisor(options)
  255. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  256. gconfig = DummyPGroupConfig(options, 'group1', pconfigs=[pconfig])
  257. supervisord.options.process_group_configs = [gconfig]
  258. process = DummyProcessGroup(gconfig)
  259. process.unstopped_processes = [123]
  260. supervisord.process_groups = {'group1':process}
  261. interface = self._makeOne(supervisord)
  262. self._assertRPCError(xmlrpc.Faults.STILL_RUNNING,
  263. interface.removeProcessGroup, 'group1')
  264. def test_startProcess_already_started(self):
  265. from supervisor import xmlrpc
  266. options = DummyOptions()
  267. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  268. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  269. supervisord.set_procattr('foo', 'pid', 10)
  270. interface = self._makeOne(supervisord)
  271. self._assertRPCError(
  272. xmlrpc.Faults.ALREADY_STARTED,
  273. interface.startProcess, 'foo'
  274. )
  275. def test_startProcess_bad_group_name(self):
  276. options = DummyOptions()
  277. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  278. supervisord = PopulatedDummySupervisor(options, 'group1', pconfig)
  279. interface = self._makeOne(supervisord)
  280. from supervisor import xmlrpc
  281. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  282. interface.startProcess, 'group2:foo')
  283. def test_startProcess_bad_process_name(self):
  284. options = DummyOptions()
  285. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  286. supervisord = PopulatedDummySupervisor(options, 'group1', pconfig)
  287. interface = self._makeOne(supervisord)
  288. from supervisor import xmlrpc
  289. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  290. interface.startProcess, 'group1:bar')
  291. def test_startProcess_file_not_found(self):
  292. options = DummyOptions()
  293. pconfig = DummyPConfig(options, 'foo', '/foo/bar', autostart=False)
  294. from supervisor.options import NotFound
  295. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  296. process = supervisord.process_groups['foo'].processes['foo']
  297. process.execv_arg_exception = NotFound
  298. interface = self._makeOne(supervisord)
  299. from supervisor import xmlrpc
  300. self._assertRPCError(xmlrpc.Faults.NO_FILE,
  301. interface.startProcess, 'foo')
  302. def test_startProcess_file_not_executable(self):
  303. options = DummyOptions()
  304. pconfig = DummyPConfig(options, 'foo', '/foo/bar', autostart=False)
  305. from supervisor.options import NotExecutable
  306. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  307. process = supervisord.process_groups['foo'].processes['foo']
  308. process.execv_arg_exception = NotExecutable
  309. interface = self._makeOne(supervisord)
  310. from supervisor import xmlrpc
  311. self._assertRPCError(xmlrpc.Faults.NOT_EXECUTABLE,
  312. interface.startProcess, 'foo')
  313. def test_startProcess_spawnerr(self):
  314. from supervisor import xmlrpc
  315. options = DummyOptions()
  316. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  317. from supervisor.process import ProcessStates
  318. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  319. supervisord.set_procattr('foo', 'state', ProcessStates.STOPPED)
  320. process = supervisord.process_groups['foo'].processes['foo']
  321. process.spawnerr = 'abc'
  322. interface = self._makeOne(supervisord)
  323. self._assertRPCError(
  324. xmlrpc.Faults.SPAWN_ERROR,
  325. interface.startProcess,
  326. 'foo'
  327. )
  328. def test_startProcess(self):
  329. options = DummyOptions()
  330. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False,
  331. startsecs=.01)
  332. from supervisor.process import ProcessStates
  333. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  334. supervisord.set_procattr('foo', 'state', ProcessStates.STOPPED)
  335. interface = self._makeOne(supervisord)
  336. result = interface.startProcess('foo')
  337. process = supervisord.process_groups['foo'].processes['foo']
  338. self.assertEqual(process.spawned, True)
  339. self.assertEqual(interface.update_text, 'startProcess')
  340. process.state = ProcessStates.RUNNING
  341. self.assertEqual(result, True)
  342. def test_startProcess_spawnerr_in_onwait(self):
  343. from supervisor import xmlrpc
  344. options = DummyOptions()
  345. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  346. from supervisor.process import ProcessStates
  347. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  348. supervisord.set_procattr('foo', 'state', ProcessStates.STOPPED)
  349. process = supervisord.process_groups['foo'].processes['foo']
  350. def spawn():
  351. process.spawned = True
  352. process.state = ProcessStates.STARTING
  353. def transition():
  354. process.spawnerr = 'abc'
  355. process.spawn = spawn
  356. process.transition = transition
  357. interface = self._makeOne(supervisord)
  358. callback = interface.startProcess('foo')
  359. self._assertRPCError(xmlrpc.Faults.SPAWN_ERROR, callback)
  360. def test_startProcess_success_in_onwait(self):
  361. options = DummyOptions()
  362. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  363. from supervisor.process import ProcessStates
  364. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  365. supervisord.set_procattr('foo', 'state', ProcessStates.STOPPED)
  366. process = supervisord.process_groups['foo'].processes['foo']
  367. def spawn():
  368. process.spawned = True
  369. process.state = ProcessStates.STARTING
  370. process.spawn = spawn
  371. interface = self._makeOne(supervisord)
  372. callback = interface.startProcess('foo')
  373. process.state = ProcessStates.RUNNING
  374. self.assertEqual(callback(), True)
  375. def test_startProcess_nowait(self):
  376. options = DummyOptions()
  377. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  378. from supervisor.process import ProcessStates
  379. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  380. supervisord.set_procattr('foo', 'state', ProcessStates.STOPPED)
  381. interface = self._makeOne(supervisord)
  382. result = interface.startProcess('foo', wait=False)
  383. self.assertEqual(result, True)
  384. process = supervisord.process_groups['foo'].processes['foo']
  385. self.assertEqual(process.spawned, True)
  386. self.assertEqual(interface.update_text, 'startProcess')
  387. def test_startProcess_abnormal_term_process_not_running(self):
  388. options = DummyOptions()
  389. pconfig = DummyPConfig(options, 'foo', __file__, autostart=False)
  390. from supervisor.process import ProcessStates
  391. from supervisor import http
  392. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  393. supervisord.set_procattr('foo', 'state', ProcessStates.STOPPED)
  394. interface = self._makeOne(supervisord)
  395. process = supervisord.process_groups['foo'].processes['foo']
  396. def spawn():
  397. process.spawned = True
  398. process.state = ProcessStates.STARTING
  399. process.spawn = spawn
  400. callback = interface.startProcess('foo', 100) # milliseconds
  401. result = callback()
  402. self.assertEqual(result, http.NOT_DONE_YET)
  403. self.assertEqual(process.spawned, True)
  404. self.assertEqual(interface.update_text, 'startProcess')
  405. process.state = ProcessStates.BACKOFF
  406. from supervisor import xmlrpc
  407. self._assertRPCError(xmlrpc.Faults.ABNORMAL_TERMINATION, callback)
  408. def test_startProcess_splat_calls_startProcessGroup(self):
  409. options = DummyOptions()
  410. pconfig1 = DummyPConfig(options, 'process1', __file__, autostart=False,
  411. startsecs=.01)
  412. pconfig2 = DummyPConfig(options, 'process2', __file__, priority=2,
  413. startsecs=.01)
  414. supervisord = PopulatedDummySupervisor(options, 'foo',
  415. pconfig1, pconfig2)
  416. from supervisor.process import ProcessStates
  417. supervisord.set_procattr('process1', 'state', ProcessStates.STOPPED)
  418. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  419. interface = self._makeOne(supervisord)
  420. interface.startProcess('foo:*')
  421. self.assertEqual(interface.update_text, 'startProcessGroup')
  422. def test_startProcessGroup(self):
  423. options = DummyOptions()
  424. pconfig1 = DummyPConfig(options, 'process1', __file__, priority=1,
  425. startsecs=.01)
  426. pconfig2 = DummyPConfig(options, 'process2', __file__, priority=2,
  427. startsecs=.01)
  428. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  429. pconfig2)
  430. from supervisor.process import ProcessStates
  431. from supervisor.xmlrpc import Faults
  432. supervisord.set_procattr('process1', 'state', ProcessStates.STOPPED)
  433. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  434. interface = self._makeOne(supervisord)
  435. callback = interface.startProcessGroup('foo')
  436. self.assertEqual(
  437. callback(),
  438. [{'group': 'foo',
  439. 'status': Faults.SUCCESS,
  440. 'description': 'OK',
  441. 'name': 'process1'},
  442. {'group': 'foo',
  443. 'status': Faults.SUCCESS,
  444. 'description': 'OK',
  445. 'name': 'process2'}
  446. ]
  447. )
  448. self.assertEqual(interface.update_text, 'startProcess')
  449. process1 = supervisord.process_groups['foo'].processes['process1']
  450. self.assertEqual(process1.spawned, True)
  451. process2 = supervisord.process_groups['foo'].processes['process2']
  452. self.assertEqual(process2.spawned, True)
  453. def test_startProcessGroup_nowait(self):
  454. options = DummyOptions()
  455. pconfig1 = DummyPConfig(options, 'process1', __file__, priority=1,
  456. startsecs=.01)
  457. pconfig2 = DummyPConfig(options, 'process2', __file__, priority=2,
  458. startsecs=.01)
  459. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  460. pconfig2)
  461. from supervisor.process import ProcessStates
  462. supervisord.set_procattr('process1', 'state', ProcessStates.STOPPED)
  463. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  464. interface = self._makeOne(supervisord)
  465. callback = interface.startProcessGroup('foo', wait=False)
  466. from supervisor.xmlrpc import Faults
  467. self.assertEqual(
  468. callback(),
  469. [{'group': 'foo',
  470. 'status': Faults.SUCCESS,
  471. 'description': 'OK',
  472. 'name': 'process1'},
  473. {'group': 'foo',
  474. 'status': Faults.SUCCESS,
  475. 'description': 'OK',
  476. 'name': 'process2'}
  477. ]
  478. )
  479. def test_startProcessGroup_badname(self):
  480. from supervisor import xmlrpc
  481. supervisord = DummySupervisor()
  482. interface = self._makeOne(supervisord)
  483. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  484. interface.startProcessGroup, 'foo')
  485. def test_startAllProcesses(self):
  486. options = DummyOptions()
  487. pconfig1 = DummyPConfig(options, 'process1', __file__, priority=1,
  488. startsecs=.01)
  489. pconfig2 = DummyPConfig(options, 'process2', __file__, priority=2,
  490. startsecs=.01)
  491. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  492. pconfig2)
  493. from supervisor.process import ProcessStates
  494. supervisord.set_procattr('process1', 'state', ProcessStates.STOPPED)
  495. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  496. interface = self._makeOne(supervisord)
  497. callback = interface.startAllProcesses()
  498. from supervisor.xmlrpc import Faults
  499. self.assertEqual(
  500. callback(),
  501. [{'group': 'foo',
  502. 'status': Faults.SUCCESS,
  503. 'description': 'OK',
  504. 'name': 'process1'},
  505. {'group': 'foo',
  506. 'status': Faults.SUCCESS,
  507. 'description': 'OK',
  508. 'name': 'process2'}
  509. ]
  510. )
  511. self.assertEqual(interface.update_text, 'startProcess')
  512. process1 = supervisord.process_groups['foo'].processes['process1']
  513. self.assertEqual(process1.spawned, True)
  514. process2 = supervisord.process_groups['foo'].processes['process2']
  515. self.assertEqual(process2.spawned, True)
  516. def test_startAllProcesses_nowait(self):
  517. options = DummyOptions()
  518. pconfig1 = DummyPConfig(options, 'process1', __file__, priority=1,
  519. startsecs=.01)
  520. pconfig2 = DummyPConfig(options, 'process2', __file__, priority=2,
  521. startsecs=.01)
  522. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  523. pconfig2)
  524. from supervisor.process import ProcessStates
  525. supervisord.set_procattr('process1', 'state', ProcessStates.STOPPED)
  526. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  527. interface = self._makeOne(supervisord)
  528. callback = interface.startAllProcesses(wait=False)
  529. from supervisor.xmlrpc import Faults
  530. self.assertEqual(
  531. callback(),
  532. [{'group': 'foo',
  533. 'status': Faults.SUCCESS,
  534. 'description': 'OK',
  535. 'name': 'process1'},
  536. {'group': 'foo',
  537. 'status': Faults.SUCCESS,
  538. 'description': 'OK',
  539. 'name': 'process2'}
  540. ]
  541. )
  542. def test_stopProcess(self):
  543. options = DummyOptions()
  544. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  545. from supervisor.process import ProcessStates
  546. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  547. supervisord.set_procattr('foo', 'state', ProcessStates.RUNNING)
  548. interface = self._makeOne(supervisord)
  549. result = interface.stopProcess('foo')
  550. self.assertTrue(result)
  551. self.assertEqual(interface.update_text, 'stopProcess')
  552. process = supervisord.process_groups['foo'].processes['foo']
  553. self.assertEqual(process.backoff, 0)
  554. self.assertEqual(process.delay, 0)
  555. self.assertEqual(process.killing, 0)
  556. self.assertEqual(process.state, ProcessStates.STOPPED)
  557. self.assertTrue(process.stop_report_called)
  558. self.assertEqual(len(supervisord.process_groups['foo'].processes), 1)
  559. self.assertEqual(interface.update_text, 'stopProcess')
  560. def test_stopProcess_nowait(self):
  561. options = DummyOptions()
  562. pconfig = DummyPConfig(options, 'foo', __file__)
  563. from supervisor.process import ProcessStates
  564. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  565. supervisord.set_procattr('foo', 'state', ProcessStates.RUNNING)
  566. interface = self._makeOne(supervisord)
  567. result = interface.stopProcess('foo', wait=False)
  568. self.assertEqual(result, True)
  569. process = supervisord.process_groups['foo'].processes['foo']
  570. self.assertEqual(process.stop_called, True)
  571. self.assertTrue(process.stop_report_called)
  572. self.assertEqual(interface.update_text, 'stopProcess')
  573. def test_stopProcess_success_in_onwait(self):
  574. options = DummyOptions()
  575. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  576. from supervisor.process import ProcessStates
  577. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  578. process = supervisord.process_groups['foo'].processes['foo']
  579. L = [ ProcessStates.RUNNING,
  580. ProcessStates.STOPPING,
  581. ProcessStates.STOPPED ]
  582. def get_state():
  583. return L.pop(0)
  584. process.get_state = get_state
  585. interface = self._makeOne(supervisord)
  586. callback = interface.stopProcess('foo')
  587. self.assertEqual(interface.update_text, 'stopProcess')
  588. self.assertTrue(callback())
  589. def test_stopProcess_NDY_in_onwait(self):
  590. from supervisor.http import NOT_DONE_YET
  591. options = DummyOptions()
  592. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  593. from supervisor.process import ProcessStates
  594. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  595. process = supervisord.process_groups['foo'].processes['foo']
  596. L = [ ProcessStates.RUNNING,
  597. ProcessStates.STOPPING,
  598. ProcessStates.STOPPING ]
  599. def get_state():
  600. return L.pop(0)
  601. process.get_state = get_state
  602. interface = self._makeOne(supervisord)
  603. callback = interface.stopProcess('foo')
  604. self.assertEqual(callback(), NOT_DONE_YET)
  605. self.assertEqual(interface.update_text, 'stopProcess')
  606. def test_stopProcess_bad_name(self):
  607. from supervisor.xmlrpc import Faults
  608. supervisord = DummySupervisor()
  609. interface = self._makeOne(supervisord)
  610. self._assertRPCError(Faults.BAD_NAME,
  611. interface.stopProcess, 'foo')
  612. def test_stopProcess_not_running(self):
  613. from supervisor.states import ProcessStates
  614. from supervisor.xmlrpc import Faults
  615. options = DummyOptions()
  616. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  617. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  618. supervisord.set_procattr('foo', 'state', ProcessStates.EXITED)
  619. interface = self._makeOne(supervisord)
  620. self._assertRPCError(Faults.NOT_RUNNING, interface.stopProcess, 'foo')
  621. def test_stopProcess_failed(self):
  622. from supervisor.xmlrpc import Faults
  623. options = DummyOptions()
  624. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  625. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  626. supervisord.set_procattr('foo', 'stop', lambda: 'unstoppable')
  627. interface = self._makeOne(supervisord)
  628. self._assertRPCError(Faults.FAILED, interface.stopProcess, 'foo')
  629. def test_stopProcessGroup(self):
  630. options = DummyOptions()
  631. pconfig1 = DummyPConfig(options, 'process1', '/bin/foo')
  632. pconfig2 = DummyPConfig(options, 'process2', '/bin/foo2')
  633. from supervisor.process import ProcessStates
  634. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  635. pconfig2)
  636. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  637. supervisord.set_procattr('process2', 'state', ProcessStates.RUNNING)
  638. interface = self._makeOne(supervisord)
  639. callback = interface.stopProcessGroup('foo')
  640. self.assertEqual(interface.update_text, 'stopProcessGroup')
  641. from supervisor import http
  642. value = http.NOT_DONE_YET
  643. while 1:
  644. value = callback()
  645. if value is not http.NOT_DONE_YET:
  646. break
  647. self.assertEqual(value, [
  648. {'status':80,'group':'foo','name': 'process1','description': 'OK'},
  649. {'status':80,'group':'foo','name': 'process2','description': 'OK'},
  650. ] )
  651. process1 = supervisord.process_groups['foo'].processes['process1']
  652. self.assertEqual(process1.stop_called, True)
  653. process2 = supervisord.process_groups['foo'].processes['process2']
  654. self.assertEqual(process2.stop_called, True)
  655. def test_stopProcessGroup_nowait(self):
  656. options = DummyOptions()
  657. pconfig1 = DummyPConfig(options, 'process1', __file__)
  658. pconfig2 = DummyPConfig(options, 'process2', __file__)
  659. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  660. pconfig2)
  661. from supervisor.process import ProcessStates
  662. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  663. supervisord.set_procattr('process2', 'state', ProcessStates.RUNNING)
  664. interface = self._makeOne(supervisord)
  665. callback = interface.stopProcessGroup('foo', wait=False)
  666. from supervisor.xmlrpc import Faults
  667. self.assertEqual(
  668. callback(),
  669. [
  670. {'name': 'process1',
  671. 'description': 'OK',
  672. 'group': 'foo',
  673. 'status': Faults.SUCCESS},
  674. {'name': 'process2',
  675. 'description': 'OK',
  676. 'group': 'foo',
  677. 'status': Faults.SUCCESS}
  678. ]
  679. )
  680. def test_stopProcessGroup_badname(self):
  681. from supervisor import xmlrpc
  682. supervisord = DummySupervisor()
  683. interface = self._makeOne(supervisord)
  684. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  685. interface.stopProcessGroup, 'foo')
  686. def test_stopProcess_splat_calls_stopProcessGroup(self):
  687. options = DummyOptions()
  688. pconfig1 = DummyPConfig(options, 'process1', __file__, autostart=False,
  689. startsecs=.01)
  690. pconfig2 = DummyPConfig(options, 'process2', __file__, priority=2,
  691. startsecs=.01)
  692. supervisord = PopulatedDummySupervisor(options, 'foo',
  693. pconfig1, pconfig2)
  694. from supervisor.process import ProcessStates
  695. supervisord.set_procattr('process1', 'state', ProcessStates.STOPPED)
  696. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  697. interface = self._makeOne(supervisord)
  698. interface.stopProcess('foo:*')
  699. self.assertEqual(interface.update_text, 'stopProcessGroup')
  700. def test_stopAllProcesses(self):
  701. options = DummyOptions()
  702. pconfig1 = DummyPConfig(options, 'process1', '/bin/foo')
  703. pconfig2 = DummyPConfig(options, 'process2', '/bin/foo2')
  704. from supervisor.process import ProcessStates
  705. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  706. pconfig2)
  707. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  708. supervisord.set_procattr('process2', 'state', ProcessStates.RUNNING)
  709. interface = self._makeOne(supervisord)
  710. callback = interface.stopAllProcesses()
  711. self.assertEqual(interface.update_text, 'stopAllProcesses')
  712. from supervisor import http
  713. value = http.NOT_DONE_YET
  714. while 1:
  715. value = callback()
  716. if value is not http.NOT_DONE_YET:
  717. break
  718. self.assertEqual(value, [
  719. {'status':80,'group':'foo','name': 'process1','description': 'OK'},
  720. {'status':80,'group':'foo','name': 'process2','description': 'OK'},
  721. ] )
  722. process1 = supervisord.process_groups['foo'].processes['process1']
  723. self.assertEqual(process1.stop_called, True)
  724. process2 = supervisord.process_groups['foo'].processes['process2']
  725. self.assertEqual(process2.stop_called, True)
  726. def test_stopAllProcesses_nowait(self):
  727. options = DummyOptions()
  728. pconfig1 = DummyPConfig(options, 'process1', __file__)
  729. pconfig2 = DummyPConfig(options, 'process2', __file__)
  730. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  731. pconfig2)
  732. from supervisor.process import ProcessStates
  733. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  734. supervisord.set_procattr('process2', 'state', ProcessStates.RUNNING)
  735. interface = self._makeOne(supervisord)
  736. callback = interface.stopAllProcesses(wait=False)
  737. from supervisor.xmlrpc import Faults
  738. self.assertEqual(
  739. callback(),
  740. [{'group': 'foo',
  741. 'status': Faults.SUCCESS,
  742. 'description': 'OK',
  743. 'name': 'process1'},
  744. {'group': 'foo',
  745. 'status': Faults.SUCCESS,
  746. 'description': 'OK',
  747. 'name': 'process2'}
  748. ]
  749. )
  750. def test_sendProcessSignal(self):
  751. options = DummyOptions()
  752. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  753. from supervisor.process import ProcessStates
  754. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  755. supervisord.set_procattr('foo', 'state', ProcessStates.RUNNING)
  756. interface = self._makeOne(supervisord)
  757. result = interface.sendProcessSignal('foo', 10)()
  758. self.assertEqual(interface.update_text, 'sendProcessSignal')
  759. self.assertEqual(result, True)
  760. p = supervisord.process_groups[supervisord.group_name].processes['foo']
  761. self.assertEqual(p.sent_signal, 10 )
  762. def test_sendGroupSignal(self):
  763. options = DummyOptions()
  764. pconfig1 = DummyPConfig(options, 'process1', '/bin/foo')
  765. pconfig2 = DummyPConfig(options, 'process2', '/bin/foo2')
  766. from supervisor.process import ProcessStates
  767. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  768. pconfig2)
  769. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  770. supervisord.set_procattr('process2', 'state', ProcessStates.RUNNING)
  771. interface = self._makeOne(supervisord)
  772. callback = interface.sendGroupSignal('foo', 10)
  773. self.assertEqual(interface.update_text, 'sendGroupSignal')
  774. from supervisor import http
  775. result = http.NOT_DONE_YET
  776. while result is http.NOT_DONE_YET:
  777. result = callback()
  778. self.assertEqual(result, [
  779. {'status':80,'group':'foo','name': 'process1','description': 'OK'},
  780. {'status':80,'group':'foo','name': 'process2','description': 'OK'},
  781. ] )
  782. process1 = supervisord.process_groups['foo'].processes['process1']
  783. self.assertEqual(process1.sent_signal, 10)
  784. process2 = supervisord.process_groups['foo'].processes['process2']
  785. self.assertEqual(process2.sent_signal, 10)
  786. def test_sendProcessGroupSignal(self):
  787. """ Test that sending foo:* works """
  788. options = DummyOptions()
  789. pconfig1 = DummyPConfig(options, 'process1', '/bin/foo')
  790. pconfig2 = DummyPConfig(options, 'process2', '/bin/foo2')
  791. from supervisor.process import ProcessStates
  792. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  793. pconfig2)
  794. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  795. supervisord.set_procattr('process2', 'state', ProcessStates.RUNNING)
  796. interface = self._makeOne(supervisord)
  797. callback = interface.sendProcessSignal('foo:*', 10)
  798. self.assertEqual(interface.update_text, 'sendGroupSignal')
  799. from supervisor import http
  800. result = http.NOT_DONE_YET
  801. while result is http.NOT_DONE_YET:
  802. result = callback()
  803. self.assertEqual(result, [
  804. {'status':80,'group':'foo','name': 'process1','description': 'OK'},
  805. {'status':80,'group':'foo','name': 'process2','description': 'OK'},
  806. ] )
  807. process1 = supervisord.process_groups['foo'].processes['process1']
  808. self.assertEqual(process1.sent_signal, 10)
  809. process2 = supervisord.process_groups['foo'].processes['process2']
  810. self.assertEqual(process2.sent_signal, 10)
  811. def test_getAllConfigInfo(self):
  812. options = DummyOptions()
  813. supervisord = DummySupervisor(options, 'foo')
  814. pconfig1 = DummyPConfig(options, 'process1', __file__)
  815. pconfig2 = DummyPConfig(options, 'process2', __file__)
  816. gconfig = DummyPGroupConfig(options, 'group1', pconfigs=[pconfig1, pconfig2])
  817. supervisord.process_groups = {'group1': DummyProcessGroup(gconfig)}
  818. supervisord.options.process_group_configs = [gconfig]
  819. interface = self._makeOne(supervisord)
  820. configs = interface.getAllConfigInfo()
  821. self.assertEqual(configs, [{ 'group': 'group1',
  822. 'name': 'process1',
  823. 'inuse': True,
  824. 'autostart': True,
  825. 'process_prio': 999,
  826. 'group_prio': 999 },
  827. { 'group': 'group1',
  828. 'name': 'process2',
  829. 'inuse': True,
  830. 'autostart': True,
  831. 'process_prio': 999,
  832. 'group_prio': 999 }])
  833. def test__interpretProcessInfo(self):
  834. supervisord = DummySupervisor()
  835. interface = self._makeOne(supervisord)
  836. start = _NOW -100
  837. stop = _NOW -1
  838. from supervisor.process import ProcessStates
  839. running = {'name':'running',
  840. 'pid':1,
  841. 'state':ProcessStates.RUNNING,
  842. 'start':start,
  843. 'stop':stop,
  844. 'now':_NOW}
  845. description = interface._interpretProcessInfo(running)
  846. self.assertEqual(description, 'pid 1, uptime 0:01:40')
  847. fatal = {'name':'fatal',
  848. 'pid':2,
  849. 'state':ProcessStates.FATAL,
  850. 'start':start,
  851. 'stop':stop,
  852. 'now':_NOW,
  853. 'spawnerr':'Hosed'}
  854. description = interface._interpretProcessInfo(fatal)
  855. self.assertEqual(description, 'Hosed')
  856. fatal2 = {'name':'fatal',
  857. 'pid':2,
  858. 'state':ProcessStates.FATAL,
  859. 'start':start,
  860. 'stop':stop,
  861. 'now':_NOW,
  862. 'spawnerr':'',}
  863. description = interface._interpretProcessInfo(fatal2)
  864. self.assertEqual(description, 'unknown error (try "tail fatal")')
  865. stopped = {'name':'stopped',
  866. 'pid':3,
  867. 'state':ProcessStates.STOPPED,
  868. 'start':start,
  869. 'stop':stop,
  870. 'now':_NOW,
  871. 'spawnerr':'',}
  872. description = interface._interpretProcessInfo(stopped)
  873. from datetime import datetime
  874. stoptime = datetime(*time.localtime(stop)[:7])
  875. self.assertEqual(description, stoptime.strftime(_TIMEFORMAT))
  876. stopped2 = {'name':'stopped',
  877. 'pid':3,
  878. 'state':ProcessStates.STOPPED,
  879. 'start':0,
  880. 'stop':stop,
  881. 'now':_NOW,
  882. 'spawnerr':'',}
  883. description = interface._interpretProcessInfo(stopped2)
  884. self.assertEqual(description, 'Not started')
  885. def test_getProcessInfo(self):
  886. from supervisor.process import ProcessStates
  887. options = DummyOptions()
  888. config = DummyPConfig(options, 'foo', '/bin/foo',
  889. stdout_logfile='/tmp/fleeb.bar')
  890. process = DummyProcess(config)
  891. process.pid = 111
  892. process.laststart = 10
  893. process.laststop = 11
  894. pgroup_config = DummyPGroupConfig(options, name='foo')
  895. pgroup = DummyProcessGroup(pgroup_config)
  896. pgroup.processes = {'foo':process}
  897. supervisord = DummySupervisor(process_groups={'foo':pgroup})
  898. interface = self._makeOne(supervisord)
  899. data = interface.getProcessInfo('foo')
  900. self.assertEqual(interface.update_text, 'getProcessInfo')
  901. self.assertEqual(data['logfile'], '/tmp/fleeb.bar')
  902. self.assertEqual(data['stdout_logfile'], '/tmp/fleeb.bar')
  903. self.assertEqual(data['stderr_logfile'], '')
  904. self.assertEqual(data['name'], 'foo')
  905. self.assertEqual(data['pid'], 111)
  906. self.assertEqual(data['start'], 10)
  907. self.assertEqual(data['stop'], 11)
  908. self.assertEqual(data['state'], ProcessStates.RUNNING)
  909. self.assertEqual(data['statename'], 'RUNNING')
  910. self.assertEqual(data['exitstatus'], 0)
  911. self.assertEqual(data['spawnerr'], '')
  912. self.assertTrue(data['description'].startswith('pid 111'))
  913. def test_getProcessInfo_logfile_NONE(self):
  914. options = DummyOptions()
  915. config = DummyPConfig(options, 'foo', '/bin/foo',
  916. stdout_logfile=None)
  917. process = DummyProcess(config)
  918. process.pid = 111
  919. process.laststart = 10
  920. process.laststop = 11
  921. pgroup_config = DummyPGroupConfig(options, name='foo')
  922. pgroup = DummyProcessGroup(pgroup_config)
  923. pgroup.processes = {'foo':process}
  924. supervisord = DummySupervisor(process_groups={'foo':pgroup})
  925. interface = self._makeOne(supervisord)
  926. data = interface.getProcessInfo('foo')
  927. self.assertEqual(data['logfile'], '')
  928. self.assertEqual(data['stdout_logfile'], '')
  929. def test_getProcessInfo_unknown_state(self):
  930. from supervisor.states import ProcessStates
  931. options = DummyOptions()
  932. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  933. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  934. supervisord.set_procattr('foo', 'state', ProcessStates.UNKNOWN)
  935. interface = self._makeOne(supervisord)
  936. data = interface.getProcessInfo('foo')
  937. self.assertEqual(data['statename'], 'UNKNOWN')
  938. self.assertEqual(data['description'], '')
  939. def test_getProcessInfo_bad_name_when_bad_process(self):
  940. from supervisor import xmlrpc
  941. supervisord = DummySupervisor()
  942. interface = self._makeOne(supervisord)
  943. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  944. interface.getProcessInfo, 'nonexistant')
  945. def test_getProcessInfo_bad_name_when_no_process(self):
  946. from supervisor import xmlrpc
  947. options = DummyOptions()
  948. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  949. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  950. interface = self._makeOne(supervisord)
  951. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  952. interface.getProcessInfo, 'foo:')
  953. def test_getAllProcessInfo(self):
  954. from supervisor.process import ProcessStates
  955. options = DummyOptions()
  956. p1config = DummyPConfig(options, 'process1', '/bin/process1',
  957. priority=1,
  958. stdout_logfile='/tmp/process1.log')
  959. p2config = DummyPConfig(options, 'process2', '/bin/process2',
  960. priority=2,
  961. stdout_logfile='/tmp/process2.log')
  962. supervisord = PopulatedDummySupervisor(options, 'gname', p1config,
  963. p2config)
  964. supervisord.set_procattr('process1', 'pid', 111)
  965. supervisord.set_procattr('process1', 'laststart', 10)
  966. supervisord.set_procattr('process1', 'laststop', 11)
  967. supervisord.set_procattr('process1', 'state', ProcessStates.RUNNING)
  968. supervisord.set_procattr('process2', 'pid', 0)
  969. supervisord.set_procattr('process2', 'laststart', 20)
  970. supervisord.set_procattr('process2', 'laststop', 11)
  971. supervisord.set_procattr('process2', 'state', ProcessStates.STOPPED)
  972. interface = self._makeOne(supervisord)
  973. info = interface.getAllProcessInfo()
  974. self.assertEqual(interface.update_text, 'getProcessInfo')
  975. self.assertEqual(len(info), 2)
  976. p1info = info[0]
  977. self.assertEqual(p1info['logfile'], '/tmp/process1.log')
  978. self.assertEqual(p1info['stdout_logfile'], '/tmp/process1.log')
  979. self.assertEqual(p1info['stderr_logfile'], '')
  980. self.assertEqual(p1info['name'], 'process1')
  981. self.assertEqual(p1info['pid'], 111)
  982. self.assertEqual(p1info['start'], 10)
  983. self.assertEqual(p1info['stop'], 11)
  984. self.assertEqual(p1info['state'], ProcessStates.RUNNING)
  985. self.assertEqual(p1info['statename'], 'RUNNING')
  986. self.assertEqual(p1info['exitstatus'], 0)
  987. self.assertEqual(p1info['spawnerr'], '')
  988. self.assertEqual(p1info['group'], 'gname')
  989. self.assertTrue(p1info['description'].startswith('pid 111'))
  990. p2info = info[1]
  991. process2 = supervisord.process_groups['gname'].processes['process2']
  992. self.assertEqual(p2info['logfile'], '/tmp/process2.log')
  993. self.assertEqual(p2info['stdout_logfile'], '/tmp/process2.log')
  994. self.assertEqual(p1info['stderr_logfile'], '')
  995. self.assertEqual(p2info['name'], 'process2')
  996. self.assertEqual(p2info['pid'], 0)
  997. self.assertEqual(p2info['start'], process2.laststart)
  998. self.assertEqual(p2info['stop'], 11)
  999. self.assertEqual(p2info['state'], ProcessStates.STOPPED)
  1000. self.assertEqual(p2info['statename'], 'STOPPED')
  1001. self.assertEqual(p2info['exitstatus'], 0)
  1002. self.assertEqual(p2info['spawnerr'], '')
  1003. self.assertEqual(p1info['group'], 'gname')
  1004. from datetime import datetime
  1005. starttime = datetime(*time.localtime(process2.laststart)[:7])
  1006. self.assertEqual(p2info['description'],
  1007. starttime.strftime(_TIMEFORMAT))
  1008. def test_readProcessStdoutLog_unreadable(self):
  1009. from supervisor import xmlrpc
  1010. options = DummyOptions()
  1011. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1012. stdout_logfile='/tmp/process1.log')
  1013. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig)
  1014. interface = self._makeOne(supervisord)
  1015. self._assertRPCError(xmlrpc.Faults.NO_FILE,
  1016. interface.readProcessStdoutLog,
  1017. 'process1', offset=0, length=1)
  1018. def test_readProcessStdoutLog_badargs(self):
  1019. from supervisor import xmlrpc
  1020. options = DummyOptions()
  1021. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1022. stdout_logfile='/tmp/process1.log')
  1023. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig)
  1024. interface = self._makeOne(supervisord)
  1025. process = supervisord.process_groups['process1'].processes['process1']
  1026. logfile = process.config.stdout_logfile
  1027. try:
  1028. f = open(logfile, 'w+')
  1029. f.write('x' * 2048)
  1030. f.close()
  1031. self._assertRPCError(xmlrpc.Faults.BAD_ARGUMENTS,
  1032. interface.readProcessStdoutLog,
  1033. 'process1', offset=-1, length=1)
  1034. self._assertRPCError(xmlrpc.Faults.BAD_ARGUMENTS,
  1035. interface.readProcessStdoutLog, 'process1',
  1036. offset=-1, length=-1)
  1037. finally:
  1038. os.remove(logfile)
  1039. def test_readProcessStdoutLog_bad_name_no_process(self):
  1040. from supervisor import xmlrpc
  1041. options = DummyOptions()
  1042. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1043. stdout_logfile='/tmp/process1.log')
  1044. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1045. interface = self._makeOne(supervisord)
  1046. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1047. interface.readProcessStdoutLog,
  1048. 'foo:*', offset=0, length=1)
  1049. def test_readProcessStdoutLog(self):
  1050. options = DummyOptions()
  1051. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1052. stdout_logfile='/tmp/fooooooo')
  1053. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1054. interface = self._makeOne(supervisord)
  1055. process = supervisord.process_groups['foo'].processes['foo']
  1056. logfile = process.config.stdout_logfile
  1057. try:
  1058. f = open(logfile, 'w+')
  1059. f.write('x' * 2048)
  1060. f.write('y' * 2048)
  1061. f.close()
  1062. data = interface.readProcessStdoutLog('foo', offset=0, length=0)
  1063. self.assertEqual(interface.update_text, 'readProcessStdoutLog')
  1064. self.assertEqual(data, ('x' * 2048) + ('y' * 2048))
  1065. data = interface.readProcessStdoutLog('foo', offset=2048, length=0)
  1066. self.assertEqual(data, 'y' * 2048)
  1067. data = interface.readProcessStdoutLog('foo', offset=0, length=2048)
  1068. self.assertEqual(data, 'x' * 2048)
  1069. data = interface.readProcessStdoutLog('foo', offset=-4, length=0)
  1070. self.assertEqual(data, 'y' * 4)
  1071. finally:
  1072. os.remove(logfile)
  1073. def test_readProcessLogAliasedTo_readProcessStdoutLog(self):
  1074. options = DummyOptions()
  1075. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  1076. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1077. interface = self._makeOne(supervisord)
  1078. self.assertEqual(interface.readProcessLog,
  1079. interface.readProcessStdoutLog)
  1080. def test_readProcessStderrLog_unreadable(self):
  1081. from supervisor import xmlrpc
  1082. options = DummyOptions()
  1083. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1084. stderr_logfile='/tmp/process1.log')
  1085. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig)
  1086. interface = self._makeOne(supervisord)
  1087. self._assertRPCError(xmlrpc.Faults.NO_FILE,
  1088. interface.readProcessStderrLog,
  1089. 'process1', offset=0, length=1)
  1090. def test_readProcessStderrLog_badargs(self):
  1091. from supervisor import xmlrpc
  1092. options = DummyOptions()
  1093. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1094. stderr_logfile='/tmp/process1.log')
  1095. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig)
  1096. interface = self._makeOne(supervisord)
  1097. process = supervisord.process_groups['process1'].processes['process1']
  1098. logfile = process.config.stderr_logfile
  1099. try:
  1100. f = open(logfile, 'w+')
  1101. f.write('x' * 2048)
  1102. f.close()
  1103. self._assertRPCError(xmlrpc.Faults.BAD_ARGUMENTS,
  1104. interface.readProcessStderrLog,
  1105. 'process1', offset=-1, length=1)
  1106. self._assertRPCError(xmlrpc.Faults.BAD_ARGUMENTS,
  1107. interface.readProcessStderrLog, 'process1',
  1108. offset=-1, length=-1)
  1109. finally:
  1110. os.remove(logfile)
  1111. def test_readProcessStderrLog_bad_name_no_process(self):
  1112. from supervisor import xmlrpc
  1113. options = DummyOptions()
  1114. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1115. stdout_logfile='/tmp/process1.log')
  1116. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1117. interface = self._makeOne(supervisord)
  1118. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1119. interface.readProcessStderrLog,
  1120. 'foo:*', offset=0, length=1)
  1121. def test_readProcessStderrLog(self):
  1122. options = DummyOptions()
  1123. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1124. stderr_logfile='/tmp/fooooooo')
  1125. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1126. interface = self._makeOne(supervisord)
  1127. process = supervisord.process_groups['foo'].processes['foo']
  1128. logfile = process.config.stderr_logfile
  1129. try:
  1130. f = open(logfile, 'w+')
  1131. f.write('x' * 2048)
  1132. f.write('y' * 2048)
  1133. f.close()
  1134. data = interface.readProcessStderrLog('foo', offset=0, length=0)
  1135. self.assertEqual(interface.update_text, 'readProcessStderrLog')
  1136. self.assertEqual(data, ('x' * 2048) + ('y' * 2048))
  1137. data = interface.readProcessStderrLog('foo', offset=2048, length=0)
  1138. self.assertEqual(data, 'y' * 2048)
  1139. data = interface.readProcessStderrLog('foo', offset=0, length=2048)
  1140. self.assertEqual(data, 'x' * 2048)
  1141. data = interface.readProcessStderrLog('foo', offset=-4, length=0)
  1142. self.assertEqual(data, 'y' * 4)
  1143. finally:
  1144. os.remove(logfile)
  1145. def test_tailProcessStdoutLog_bad_name(self):
  1146. from supervisor import xmlrpc
  1147. supervisord = DummySupervisor()
  1148. interface = self._makeOne(supervisord)
  1149. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1150. interface.tailProcessStdoutLog, 'BAD_NAME', 0, 10)
  1151. def test_tailProcessStdoutLog_bad_name_no_process(self):
  1152. from supervisor import xmlrpc
  1153. options = DummyOptions()
  1154. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1155. stdout_logfile='/tmp/process1.log')
  1156. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1157. interface = self._makeOne(supervisord)
  1158. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1159. interface.tailProcessStdoutLog, 'foo:*', 0, 10)
  1160. def test_tailProcessStdoutLog_all(self):
  1161. # test entire log is returned when offset==0 and logsize < length
  1162. from string import letters
  1163. options = DummyOptions()
  1164. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1165. stdout_logfile='/tmp/fooooooo')
  1166. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1167. interface = self._makeOne(supervisord)
  1168. process = supervisord.process_groups['foo'].processes['foo']
  1169. logfile = process.config.stdout_logfile
  1170. try:
  1171. f = open(logfile, 'w+')
  1172. f.write(letters)
  1173. f.close()
  1174. data, offset, overflow = interface.tailProcessStdoutLog('foo',
  1175. offset=0,
  1176. length=len(letters))
  1177. self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
  1178. self.assertEqual(overflow, False)
  1179. self.assertEqual(offset, len(letters))
  1180. self.assertEqual(data, letters)
  1181. finally:
  1182. os.remove(logfile)
  1183. def test_tailProcessStdoutLog_none(self):
  1184. # test nothing is returned when offset <= logsize
  1185. from string import letters
  1186. options = DummyOptions()
  1187. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1188. stdout_logfile='/tmp/fooooooo')
  1189. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1190. interface = self._makeOne(supervisord)
  1191. process = supervisord.process_groups['foo'].processes['foo']
  1192. logfile = process.config.stdout_logfile
  1193. try:
  1194. f = open(logfile, 'w+')
  1195. f.write(letters)
  1196. f.close()
  1197. # offset==logsize
  1198. data, offset, overflow = interface.tailProcessStdoutLog('foo',
  1199. offset=len(letters),
  1200. length=100)
  1201. self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
  1202. self.assertEqual(overflow, False)
  1203. self.assertEqual(offset, len(letters))
  1204. self.assertEqual(data, '')
  1205. # offset > logsize
  1206. data, offset, overflow = interface.tailProcessStdoutLog('foo',
  1207. offset=len(letters)+5,
  1208. length=100)
  1209. self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
  1210. self.assertEqual(overflow, False)
  1211. self.assertEqual(offset, len(letters))
  1212. self.assertEqual(data, '')
  1213. finally:
  1214. os.remove(logfile)
  1215. def test_tailProcessStdoutLog_overflow(self):
  1216. # test buffer overflow occurs when logsize > offset+length
  1217. from string import letters
  1218. options = DummyOptions()
  1219. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1220. stdout_logfile='/tmp/fooooooo')
  1221. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1222. interface = self._makeOne(supervisord)
  1223. process = supervisord.process_groups['foo'].processes['foo']
  1224. logfile = process.config.stdout_logfile
  1225. try:
  1226. f = open(logfile, 'w+')
  1227. f.write(letters)
  1228. f.close()
  1229. data, offset, overflow = interface.tailProcessStdoutLog('foo',
  1230. offset=0, length=5)
  1231. self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
  1232. self.assertEqual(overflow, True)
  1233. self.assertEqual(offset, len(letters))
  1234. self.assertEqual(data, letters[-5:])
  1235. finally:
  1236. os.remove(logfile)
  1237. def test_tailProcessStdoutLog_unreadable(self):
  1238. # test nothing is returned if the log doesn't exist yet
  1239. options = DummyOptions()
  1240. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1241. stdout_logfile='/tmp/fooooooo')
  1242. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1243. interface = self._makeOne(supervisord)
  1244. data, offset, overflow = interface.tailProcessStdoutLog('foo',
  1245. offset=0, length=100)
  1246. self.assertEqual(interface.update_text, 'tailProcessStdoutLog')
  1247. self.assertEqual(overflow, False)
  1248. self.assertEqual(offset, 0)
  1249. self.assertEqual(data, '')
  1250. def test_tailProcessLogAliasedTo_tailProcessStdoutLog(self):
  1251. options = DummyOptions()
  1252. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  1253. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1254. interface = self._makeOne(supervisord)
  1255. self.assertEqual(interface.tailProcessLog,
  1256. interface.tailProcessStdoutLog)
  1257. def test_tailProcessStderrLog_bad_name(self):
  1258. from supervisor import xmlrpc
  1259. supervisord = DummySupervisor()
  1260. interface = self._makeOne(supervisord)
  1261. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1262. interface.tailProcessStderrLog, 'BAD_NAME', 0, 10)
  1263. def test_tailProcessStderrLog_bad_name_no_process(self):
  1264. from supervisor import xmlrpc
  1265. options = DummyOptions()
  1266. pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1,
  1267. stdout_logfile='/tmp/process1.log')
  1268. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1269. interface = self._makeOne(supervisord)
  1270. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1271. interface.tailProcessStderrLog, 'foo:*', 0, 10)
  1272. def test_tailProcessStderrLog_all(self):
  1273. # test entire log is returned when offset==0 and logsize < length
  1274. from string import letters
  1275. options = DummyOptions()
  1276. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1277. stderr_logfile='/tmp/fooooooo')
  1278. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1279. interface = self._makeOne(supervisord)
  1280. process = supervisord.process_groups['foo'].processes['foo']
  1281. logfile = process.config.stderr_logfile
  1282. try:
  1283. f = open(logfile, 'w+')
  1284. f.write(letters)
  1285. f.close()
  1286. data, offset, overflow = interface.tailProcessStderrLog('foo',
  1287. offset=0,
  1288. length=len(letters))
  1289. self.assertEqual(interface.update_text, 'tailProcessStderrLog')
  1290. self.assertEqual(overflow, False)
  1291. self.assertEqual(offset, len(letters))
  1292. self.assertEqual(data, letters)
  1293. finally:
  1294. os.remove(logfile)
  1295. def test_tailProcessStderrLog_none(self):
  1296. # test nothing is returned when offset <= logsize
  1297. from string import letters
  1298. options = DummyOptions()
  1299. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1300. stderr_logfile='/tmp/fooooooo')
  1301. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1302. interface = self._makeOne(supervisord)
  1303. process = supervisord.process_groups['foo'].processes['foo']
  1304. logfile = process.config.stderr_logfile
  1305. try:
  1306. f = open(logfile, 'w+')
  1307. f.write(letters)
  1308. f.close()
  1309. # offset==logsize
  1310. data, offset, overflow = interface.tailProcessStderrLog('foo',
  1311. offset=len(letters),
  1312. length=100)
  1313. self.assertEqual(interface.update_text, 'tailProcessStderrLog')
  1314. self.assertEqual(overflow, False)
  1315. self.assertEqual(offset, len(letters))
  1316. self.assertEqual(data, '')
  1317. # offset > logsize
  1318. data, offset, overflow = interface.tailProcessStderrLog('foo',
  1319. offset=len(letters)+5,
  1320. length=100)
  1321. self.assertEqual(interface.update_text, 'tailProcessStderrLog')
  1322. self.assertEqual(overflow, False)
  1323. self.assertEqual(offset, len(letters))
  1324. self.assertEqual(data, '')
  1325. finally:
  1326. os.remove(logfile)
  1327. def test_tailProcessStderrLog_overflow(self):
  1328. # test buffer overflow occurs when logsize > offset+length
  1329. from string import letters
  1330. options = DummyOptions()
  1331. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1332. stderr_logfile='/tmp/fooooooo')
  1333. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1334. interface = self._makeOne(supervisord)
  1335. process = supervisord.process_groups['foo'].processes['foo']
  1336. logfile = process.config.stderr_logfile
  1337. try:
  1338. f = open(logfile, 'w+')
  1339. f.write(letters)
  1340. f.close()
  1341. data, offset, overflow = interface.tailProcessStderrLog('foo',
  1342. offset=0, length=5)
  1343. self.assertEqual(interface.update_text, 'tailProcessStderrLog')
  1344. self.assertEqual(overflow, True)
  1345. self.assertEqual(offset, len(letters))
  1346. self.assertEqual(data, letters[-5:])
  1347. finally:
  1348. os.remove(logfile)
  1349. def test_tailProcessStderrLog_unreadable(self):
  1350. # test nothing is returned if the log doesn't exist yet
  1351. options = DummyOptions()
  1352. pconfig = DummyPConfig(options, 'foo', '/bin/foo',
  1353. stderr_logfile='/tmp/fooooooo')
  1354. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1355. interface = self._makeOne(supervisord)
  1356. data, offset, overflow = interface.tailProcessStderrLog('foo',
  1357. offset=0, length=100)
  1358. self.assertEqual(interface.update_text, 'tailProcessStderrLog')
  1359. self.assertEqual(overflow, False)
  1360. self.assertEqual(offset, 0)
  1361. self.assertEqual(data, '')
  1362. def test_clearProcessLogs_bad_name_no_group(self):
  1363. from supervisor import xmlrpc
  1364. options = DummyOptions()
  1365. pconfig = DummyPConfig(options, 'foo', 'foo')
  1366. process = DummyProcess(pconfig)
  1367. pgroup = DummyProcessGroup(None)
  1368. pgroup.processes = {'foo': process}
  1369. supervisord = DummySupervisor(process_groups={'foo':pgroup})
  1370. interface = self._makeOne(supervisord)
  1371. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1372. interface.clearProcessLogs,
  1373. 'badgroup')
  1374. def test_clearProcessLogs_bad_name_no_process(self):
  1375. from supervisor import xmlrpc
  1376. options = DummyOptions()
  1377. pconfig = DummyPConfig(options, 'foo', 'foo')
  1378. process = DummyProcess(pconfig)
  1379. pgroup = DummyProcessGroup(None)
  1380. pgroup.processes = {'foo': process}
  1381. supervisord = DummySupervisor(process_groups={'foo':pgroup})
  1382. interface = self._makeOne(supervisord)
  1383. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1384. interface.clearProcessLogs,
  1385. 'foo:*')
  1386. def test_clearProcessLogs(self):
  1387. options = DummyOptions()
  1388. pconfig = DummyPConfig(options, 'foo', 'foo')
  1389. process = DummyProcess(pconfig)
  1390. pgroup = DummyProcessGroup(None)
  1391. pgroup.processes = {'foo': process}
  1392. supervisord = DummySupervisor(process_groups={'foo':pgroup})
  1393. interface = self._makeOne(supervisord)
  1394. interface.clearProcessLogs('foo')
  1395. self.assertEqual(process.logsremoved, True)
  1396. def test_clearProcessLogs_failed(self):
  1397. from supervisor import xmlrpc
  1398. options = DummyOptions()
  1399. pconfig = DummyPConfig(options, 'foo', 'foo')
  1400. process = DummyProcess(pconfig)
  1401. pgroup = DummyProcessGroup(None)
  1402. pgroup.processes = {'foo': process}
  1403. process.error_at_clear = True
  1404. supervisord = DummySupervisor(process_groups={'foo':pgroup})
  1405. interface = self._makeOne(supervisord)
  1406. self.assertRaises(xmlrpc.RPCError, interface.clearProcessLogs, 'foo')
  1407. def test_clearProcessLogAliasedTo_clearProcessLogs(self):
  1408. options = DummyOptions()
  1409. pconfig = DummyPConfig(options, 'foo', '/bin/foo')
  1410. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig)
  1411. interface = self._makeOne(supervisord)
  1412. self.assertEqual(interface.clearProcessLog,
  1413. interface.clearProcessLogs)
  1414. def test_clearAllProcessLogs(self):
  1415. options = DummyOptions()
  1416. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1417. pconfig2 = DummyPConfig(options, 'process2', 'bar')
  1418. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  1419. pconfig2)
  1420. interface = self._makeOne(supervisord)
  1421. callback = interface.clearAllProcessLogs()
  1422. callback()
  1423. results = callback()
  1424. from supervisor import xmlrpc
  1425. self.assertEqual(results[0],
  1426. {'name':'process1',
  1427. 'group':'foo',
  1428. 'status':xmlrpc.Faults.SUCCESS,
  1429. 'description':'OK'})
  1430. self.assertEqual(results[1],
  1431. {'name':'process2',
  1432. 'group':'foo',
  1433. 'status':xmlrpc.Faults.SUCCESS,
  1434. 'description':'OK'})
  1435. process1 = supervisord.process_groups['foo'].processes['process1']
  1436. self.assertEqual(process1.logsremoved, True)
  1437. process2 = supervisord.process_groups['foo'].processes['process2']
  1438. self.assertEqual(process2.logsremoved, True)
  1439. def test_clearAllProcessLogs_onefails(self):
  1440. options = DummyOptions()
  1441. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1442. pconfig2 = DummyPConfig(options, 'process2', 'bar')
  1443. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1,
  1444. pconfig2)
  1445. supervisord.set_procattr('process1', 'error_at_clear', True)
  1446. interface = self._makeOne(supervisord)
  1447. callback = interface.clearAllProcessLogs()
  1448. callback()
  1449. results = callback()
  1450. process1 = supervisord.process_groups['foo'].processes['process1']
  1451. self.assertEqual(process1.logsremoved, False)
  1452. process2 = supervisord.process_groups['foo'].processes['process2']
  1453. self.assertEqual(process2.logsremoved, True)
  1454. self.assertEqual(len(results), 2)
  1455. from supervisor import xmlrpc
  1456. self.assertEqual(results[0],
  1457. {'name':'process1',
  1458. 'group':'foo',
  1459. 'status':xmlrpc.Faults.FAILED,
  1460. 'description':'FAILED: foo:process1'})
  1461. self.assertEqual(results[1],
  1462. {'name':'process2',
  1463. 'group':'foo',
  1464. 'status':xmlrpc.Faults.SUCCESS,
  1465. 'description':'OK'})
  1466. def test_clearAllProcessLogs_no_processes(self):
  1467. supervisord = DummySupervisor()
  1468. self.assertEqual(supervisord.process_groups, {})
  1469. interface = self._makeOne(supervisord)
  1470. callback = interface.clearAllProcessLogs()
  1471. results = callback()
  1472. self.assertEqual(results, [])
  1473. def test_sendProcessStdin_raises_incorrect_params_when_not_chars(self):
  1474. options = DummyOptions()
  1475. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1476. supervisord = PopulatedDummySupervisor(options, 'foo', pconfig1)
  1477. interface = self._makeOne(supervisord)
  1478. thing_not_chars = 42
  1479. from supervisor import xmlrpc
  1480. self._assertRPCError(xmlrpc.Faults.INCORRECT_PARAMETERS,
  1481. interface.sendProcessStdin,
  1482. 'process1', thing_not_chars)
  1483. def test_sendProcessStdin_raises_bad_name_when_bad_process(self):
  1484. supervisord = DummySupervisor()
  1485. interface = self._makeOne(supervisord)
  1486. from supervisor import xmlrpc
  1487. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1488. interface.sendProcessStdin,
  1489. 'nonexistant', 'chars for stdin')
  1490. def test_sendProcessStdin_raises_bad_name_when_no_process(self):
  1491. options = DummyOptions()
  1492. supervisord = PopulatedDummySupervisor(options, 'foo')
  1493. interface = self._makeOne(supervisord)
  1494. from supervisor import xmlrpc
  1495. self._assertRPCError(xmlrpc.Faults.BAD_NAME,
  1496. interface.sendProcessStdin,
  1497. 'foo:*', 'chars for stdin')
  1498. def test_sendProcessStdin_raises_not_running_when_not_process_pid(self):
  1499. options = DummyOptions()
  1500. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1501. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig1)
  1502. supervisord.set_procattr('process1', 'pid', 0)
  1503. interface = self._makeOne(supervisord)
  1504. from supervisor import xmlrpc
  1505. self._assertRPCError(xmlrpc.Faults.NOT_RUNNING,
  1506. interface.sendProcessStdin,
  1507. 'process1', 'chars for stdin')
  1508. def test_sendProcessStdin_raises_not_running_when_killing(self):
  1509. options = DummyOptions()
  1510. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1511. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig1)
  1512. supervisord.set_procattr('process1', 'pid', 42)
  1513. supervisord.set_procattr('process1', 'killing',True)
  1514. interface = self._makeOne(supervisord)
  1515. from supervisor import xmlrpc
  1516. self._assertRPCError(xmlrpc.Faults.NOT_RUNNING,
  1517. interface.sendProcessStdin,
  1518. 'process1', 'chars for stdin')
  1519. def test_sendProcessStdin_raises_no_file_when_write_raises_epipe(self):
  1520. options = DummyOptions()
  1521. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1522. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig1)
  1523. supervisord.set_procattr('process1', 'pid', 42)
  1524. supervisord.set_procattr('process1', 'killing', False)
  1525. supervisord.set_procattr('process1', 'write_error', errno.EPIPE)
  1526. interface = self._makeOne(supervisord)
  1527. from supervisor import xmlrpc
  1528. self._assertRPCError(xmlrpc.Faults.NO_FILE,
  1529. interface.sendProcessStdin,
  1530. 'process1', 'chars for stdin')
  1531. def test_sendProcessStdin_reraises_other_oserrors(self):
  1532. options = DummyOptions()
  1533. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1534. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig1)
  1535. supervisord.set_procattr('process1', 'pid', 42)
  1536. supervisord.set_procattr('process1', 'killing', False)
  1537. supervisord.set_procattr('process1', 'write_error', errno.EINTR)
  1538. interface = self._makeOne(supervisord)
  1539. self.assertRaises(OSError,
  1540. interface.sendProcessStdin,
  1541. 'process1', 'chars for stdin')
  1542. def test_sendProcessStdin_writes_chars_and_returns_true(self):
  1543. options = DummyOptions()
  1544. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1545. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig1)
  1546. supervisord.set_procattr('process1', 'pid', 42)
  1547. interface = self._makeOne(supervisord)
  1548. chars = 'chars for stdin'
  1549. self.assertTrue(interface.sendProcessStdin('process1', chars))
  1550. self.assertEqual('sendProcessStdin', interface.update_text)
  1551. process1 = supervisord.process_groups['process1'].processes['process1']
  1552. self.assertEqual(process1.stdin_buffer, chars)
  1553. def test_sendProcessStdin_unicode_encoded_to_utf8(self):
  1554. options = DummyOptions()
  1555. pconfig1 = DummyPConfig(options, 'process1', 'foo')
  1556. supervisord = PopulatedDummySupervisor(options, 'process1', pconfig1)
  1557. supervisord.set_procattr('process1', 'pid', 42)
  1558. interface = self._makeOne(supervisord)
  1559. interface.sendProcessStdin('process1', u'fi\xed')
  1560. process1 = supervisord.process_groups['process1'].processes['process1']
  1561. self.assertEqual(process1.stdin_buffer, 'fi\xc3\xad')
  1562. def test_sendRemoteCommEvent_notifies_subscribers(self):
  1563. options = DummyOptions()
  1564. supervisord = DummySupervisor(options)
  1565. interface = self._makeOne(supervisord)
  1566. from supervisor import events
  1567. L = []
  1568. def callback(event):
  1569. L.append(event)
  1570. try:
  1571. events.callbacks[:] = [(events.RemoteCommunicationEvent, callback)]
  1572. result = interface.sendRemoteCommEvent('foo', 'bar')
  1573. finally:
  1574. events.callbacks[:] = []
  1575. events.clear()
  1576. self.assertTrue(result)
  1577. self.assertEqual(len(L), 1)
  1578. event = L[0]
  1579. self.assertEqual(event.type, 'foo')
  1580. self.assertEqual(event.data, 'bar')
  1581. def test_sendRemoteCommEvent_unicode_encoded_to_utf8(self):
  1582. options = DummyOptions()
  1583. supervisord = DummySupervisor(options)
  1584. interface = self._makeOne(supervisord)
  1585. from supervisor import events
  1586. L = []
  1587. def callback(event):
  1588. L.append(event)
  1589. try:
  1590. events.callbacks[:] = [(events.RemoteCommunicationEvent, callback)]
  1591. result = interface.sendRemoteCommEvent(u'fi\xed once', u'fi\xed twice')
  1592. finally:
  1593. events.callbacks[:] = []
  1594. events.clear()
  1595. self.assertTrue(result)
  1596. self.assertEqual(len(L), 1)
  1597. event = L[0]
  1598. self.assertEqual(event.type, 'fi\xc3\xad once')
  1599. self.assertEqual(event.data, 'fi\xc3\xad twice')
  1600. class SystemNamespaceXMLRPCInterfaceTests(TestBase):
  1601. def _getTargetClass(self):
  1602. from supervisor import xmlrpc
  1603. return xmlrpc.SystemNamespaceRPCInterface
  1604. def _makeOne(self):
  1605. from supervisor import rpcinterface
  1606. supervisord = DummySupervisor()
  1607. supervisor = rpcinterface.SupervisorNamespaceRPCInterface(supervisord)
  1608. return self._getTargetClass()(
  1609. [('supervisor', supervisor),
  1610. ]
  1611. )
  1612. def test_ctor(self):
  1613. interface = self._makeOne()
  1614. self.assertTrue(interface.namespaces['supervisor'])
  1615. self.assertTrue(interface.namespaces['system'])
  1616. def test_listMethods(self):
  1617. interface = self._makeOne()
  1618. methods = interface.listMethods()
  1619. methods.sort()
  1620. keys = interface._listMethods().keys()
  1621. keys.sort()
  1622. self.assertEqual(methods, keys)
  1623. def test_methodSignature(self):
  1624. from supervisor import xmlrpc
  1625. interface = self._makeOne()
  1626. self._assertRPCError(xmlrpc.Faults.SIGNATURE_UNSUPPORTED,
  1627. interface.methodSignature,
  1628. ['foo.bar'])
  1629. result = interface.methodSignature('system.methodSignature')
  1630. self.assertEqual(result, ['array', 'string'])
  1631. def test_allMethodDocs(self):
  1632. from supervisor import xmlrpc
  1633. # belt-and-suspenders test for docstring-as-typing parsing correctness
  1634. # and documentation validity vs. implementation
  1635. _RPCTYPES = ['int', 'double', 'string', 'boolean', 'dateTime.iso8601',
  1636. 'base64', 'binary', 'array', 'struct']
  1637. interface = self._makeOne()
  1638. methods = interface._listMethods()
  1639. for k in methods.keys():
  1640. # if a method doesn't have a @return value, an RPCError is raised.
  1641. # Detect that here.
  1642. try:
  1643. interface.methodSignature(k)
  1644. except xmlrpc.RPCError:
  1645. raise AssertionError('methodSignature for %s raises '
  1646. 'RPCError (missing @return doc?)' % k)
  1647. # we want to test that the number of arguments implemented in
  1648. # the function is the same as the number of arguments implied by
  1649. # the doc @params, and that they show up in the same order.
  1650. ns_name, method_name = k.split('.', 1)
  1651. namespace = interface.namespaces[ns_name]
  1652. meth = getattr(namespace, method_name)
  1653. code = meth.func_code
  1654. argnames = code.co_varnames[1:code.co_argcount]
  1655. parsed = xmlrpc.gettags(str(meth.__doc__))
  1656. plines = []
  1657. ptypes = []
  1658. pnames = []
  1659. ptexts = []
  1660. rlines = []
  1661. rtypes = []
  1662. rnames = []
  1663. rtexts = []
  1664. for thing in parsed:
  1665. if thing[1] == 'param': # tag name
  1666. plines.append(thing[0]) # doc line number
  1667. ptypes.append(thing[2]) # data type
  1668. pnames.append(thing[3]) # function name
  1669. ptexts.append(thing[4]) # description
  1670. elif thing[1] == 'return': # tag name
  1671. rlines.append(thing[0]) # doc line number
  1672. rtypes.append(thing[2]) # data type
  1673. rnames.append(thing[3]) # function name
  1674. rtexts.append(thing[4]) # description
  1675. elif thing[1] is not None:
  1676. raise AssertionError(
  1677. 'unknown tag type %s for %s, parsed %s' % (thing[1],
  1678. k,
  1679. parsed))
  1680. # param tokens
  1681. if len(argnames) != len(pnames):
  1682. raise AssertionError('Incorrect documentation '
  1683. '(%s args, %s doc params) in %s'
  1684. % (len(argnames), len(pnames), k))
  1685. for docline in plines:
  1686. self.assertTrue(type(docline) == int, (docline,
  1687. type(docline),
  1688. k,
  1689. parsed))
  1690. for doctype in ptypes:
  1691. self.assertTrue(doctype in _RPCTYPES, doctype)
  1692. for x in range(len(pnames)):
  1693. if pnames[x] != argnames[x]:
  1694. msg = 'Name wrong: (%s vs. %s in %s)\n%s' % (pnames[x],
  1695. argnames[x],
  1696. k,
  1697. parsed)
  1698. raise AssertionError(msg)
  1699. for doctext in ptexts:
  1700. self.assertTrue(type(doctext) == type(''), doctext)
  1701. # result tokens
  1702. if len(rlines) > 1:
  1703. raise AssertionError(
  1704. 'Duplicate @return values in docs for %s' % k)
  1705. for docline in rlines:
  1706. self.assertTrue(type(docline) == int, (docline,
  1707. type(docline), k))
  1708. for doctype in rtypes:
  1709. self.assertTrue(doctype in _RPCTYPES, doctype)
  1710. for docname in rnames:
  1711. self.assertTrue(type(docname) == type(''), (docname,
  1712. type(docname),
  1713. k))
  1714. for doctext in rtexts:
  1715. self.assertTrue(type(doctext) == type(''), (doctext,
  1716. type(doctext), k))
  1717. def test_multicall_simplevals(self):
  1718. interface = self._makeOne()
  1719. callback = interface.multicall([
  1720. {'methodName':'system.methodHelp', 'params':['system.methodHelp']},
  1721. {'methodName':'system.listMethods', 'params':[]},
  1722. ])
  1723. from supervisor import http
  1724. result = http.NOT_DONE_YET
  1725. while result is http.NOT_DONE_YET:
  1726. result = callback()
  1727. self.assertEqual(result[0], interface.methodHelp('system.methodHelp'))
  1728. self.assertEqual(result[1], interface.listMethods())
  1729. def test_multicall_recursion_guard(self):
  1730. from supervisor import xmlrpc
  1731. interface = self._makeOne()
  1732. callback = interface.multicall([
  1733. {'methodName': 'system.multicall', 'params': []},
  1734. ])
  1735. from supervisor import http
  1736. result = http.NOT_DONE_YET
  1737. while result is http.NOT_DONE_YET:
  1738. result = callback()
  1739. code = xmlrpc.Faults.INCORRECT_PARAMETERS
  1740. desc = xmlrpc.getFaultDescription(code)
  1741. recursion_fault = {'faultCode': code, 'faultString': desc}
  1742. self.assertEqual(result, [recursion_fault])
  1743. def test_multicall_nested_callback(self):
  1744. interface = self._makeOne()
  1745. callback = interface.multicall([
  1746. {'methodName':'supervisor.stopAllProcesses'}])
  1747. from supervisor import http
  1748. result = http.NOT_DONE_YET
  1749. while result is http.NOT_DONE_YET:
  1750. result = callback()
  1751. self.assertEqual(result[0], [])
  1752. def test_methodHelp(self):
  1753. from supervisor import xmlrpc
  1754. interface = self._makeOne()
  1755. self._assertRPCError(xmlrpc.Faults.SIGNATURE_UNSUPPORTED,
  1756. interface.methodHelp,
  1757. ['foo.bar'])
  1758. help = interface.methodHelp('system.methodHelp')
  1759. self.assertEqual(help, interface.methodHelp.__doc__)
  1760. class Test_make_main_rpcinterface(unittest.TestCase):
  1761. def _callFUT(self, supervisord):
  1762. from supervisor.rpcinterface import make_main_rpcinterface
  1763. return make_main_rpcinterface(supervisord)
  1764. def test_it(self):
  1765. inst = self._callFUT(None)
  1766. self.assertEqual(
  1767. inst.__class__.__name__,
  1768. 'SupervisorNamespaceRPCInterface'
  1769. )
  1770. class DummyRPCInterface:
  1771. def hello(self):
  1772. return 'Hello!'
  1773. def test_suite():
  1774. return unittest.findTestCases(sys.modules[__name__])
  1775. if __name__ == '__main__':
  1776. unittest.main(defaultTest='test_suite')