test_platforms.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. from __future__ import absolute_import
  2. import errno
  3. import os
  4. import sys
  5. import signal
  6. from celery import _find_option_with_arg
  7. from celery import platforms
  8. from celery.five import open_fqdn
  9. from celery.platforms import (
  10. get_fdmax,
  11. ignore_errno,
  12. set_process_title,
  13. signals,
  14. maybe_drop_privileges,
  15. setuid,
  16. setgid,
  17. initgroups,
  18. parse_uid,
  19. parse_gid,
  20. detached,
  21. DaemonContext,
  22. create_pidlock,
  23. Pidfile,
  24. LockFailed,
  25. setgroups,
  26. _setgroups_hack,
  27. close_open_fds,
  28. )
  29. try:
  30. import resource
  31. except ImportError: # pragma: no cover
  32. resource = None # noqa
  33. from celery.tests.case import (
  34. Case, WhateverIO, Mock, SkipTest,
  35. call, override_stdouts, mock_open, patch,
  36. )
  37. class test_find_option_with_arg(Case):
  38. def test_long_opt(self):
  39. self.assertEqual(
  40. _find_option_with_arg(['--foo=bar'], long_opts=['--foo']),
  41. 'bar'
  42. )
  43. def test_short_opt(self):
  44. self.assertEqual(
  45. _find_option_with_arg(['-f', 'bar'], short_opts=['-f']),
  46. 'bar'
  47. )
  48. class test_close_open_fds(Case):
  49. def test_closes(self):
  50. with patch('os.close') as _close:
  51. with patch('os.closerange', create=True) as closerange:
  52. with patch('celery.platforms.get_fdmax') as fdmax:
  53. fdmax.return_value = 3
  54. close_open_fds()
  55. if not closerange.called:
  56. _close.assert_has_calls([call(2), call(1), call(0)])
  57. _close.side_effect = OSError()
  58. _close.side_effect.errno = errno.EBADF
  59. close_open_fds()
  60. class test_ignore_errno(Case):
  61. def test_raises_EBADF(self):
  62. with ignore_errno('EBADF'):
  63. exc = OSError()
  64. exc.errno = errno.EBADF
  65. raise exc
  66. def test_otherwise(self):
  67. with self.assertRaises(OSError):
  68. with ignore_errno('EBADF'):
  69. exc = OSError()
  70. exc.errno = errno.ENOENT
  71. raise exc
  72. class test_set_process_title(Case):
  73. def when_no_setps(self):
  74. prev = platforms._setproctitle = platforms._setproctitle, None
  75. try:
  76. set_process_title('foo')
  77. finally:
  78. platforms._setproctitle = prev
  79. class test_Signals(Case):
  80. @patch('signal.getsignal')
  81. def test_getitem(self, getsignal):
  82. signals['SIGINT']
  83. getsignal.assert_called_with(signal.SIGINT)
  84. def test_supported(self):
  85. self.assertTrue(signals.supported('INT'))
  86. self.assertFalse(signals.supported('SIGIMAGINARY'))
  87. def test_reset_alarm(self):
  88. if sys.platform == 'win32':
  89. raise SkipTest('signal.alarm not available on Windows')
  90. with patch('signal.alarm') as _alarm:
  91. signals.reset_alarm()
  92. _alarm.assert_called_with(0)
  93. def test_arm_alarm(self):
  94. if hasattr(signal, 'setitimer'):
  95. with patch('signal.setitimer', create=True) as seti:
  96. signals.arm_alarm(30)
  97. self.assertTrue(seti.called)
  98. def test_signum(self):
  99. self.assertEqual(signals.signum(13), 13)
  100. self.assertEqual(signals.signum('INT'), signal.SIGINT)
  101. self.assertEqual(signals.signum('SIGINT'), signal.SIGINT)
  102. with self.assertRaises(TypeError):
  103. signals.signum('int')
  104. signals.signum(object())
  105. @patch('signal.signal')
  106. def test_ignore(self, set):
  107. signals.ignore('SIGINT')
  108. set.assert_called_with(signals.signum('INT'), signals.ignored)
  109. signals.ignore('SIGTERM')
  110. set.assert_called_with(signals.signum('TERM'), signals.ignored)
  111. @patch('signal.signal')
  112. def test_setitem(self, set):
  113. def handle(*args):
  114. return args
  115. signals['INT'] = handle
  116. set.assert_called_with(signal.SIGINT, handle)
  117. @patch('signal.signal')
  118. def test_setitem_raises(self, set):
  119. set.side_effect = ValueError()
  120. signals['INT'] = lambda *a: a
  121. if not platforms.IS_WINDOWS:
  122. class test_get_fdmax(Case):
  123. @patch('resource.getrlimit')
  124. def test_when_infinity(self, getrlimit):
  125. with patch('os.sysconf') as sysconfig:
  126. sysconfig.side_effect = KeyError()
  127. getrlimit.return_value = [None, resource.RLIM_INFINITY]
  128. default = object()
  129. self.assertIs(get_fdmax(default), default)
  130. @patch('resource.getrlimit')
  131. def test_when_actual(self, getrlimit):
  132. with patch('os.sysconf') as sysconfig:
  133. sysconfig.side_effect = KeyError()
  134. getrlimit.return_value = [None, 13]
  135. self.assertEqual(get_fdmax(None), 13)
  136. class test_maybe_drop_privileges(Case):
  137. @patch('celery.platforms.parse_uid')
  138. @patch('pwd.getpwuid')
  139. @patch('celery.platforms.setgid')
  140. @patch('celery.platforms.setuid')
  141. @patch('celery.platforms.initgroups')
  142. def test_with_uid(self, initgroups, setuid, setgid,
  143. getpwuid, parse_uid):
  144. class pw_struct(object):
  145. pw_gid = 50001
  146. def raise_on_second_call(*args, **kwargs):
  147. setuid.side_effect = OSError()
  148. setuid.side_effect.errno = errno.EPERM
  149. setuid.side_effect = raise_on_second_call
  150. getpwuid.return_value = pw_struct()
  151. parse_uid.return_value = 5001
  152. maybe_drop_privileges(uid='user')
  153. parse_uid.assert_called_with('user')
  154. getpwuid.assert_called_with(5001)
  155. setgid.assert_called_with(50001)
  156. initgroups.assert_called_with(5001, 50001)
  157. setuid.assert_has_calls([call(5001), call(0)])
  158. @patch('celery.platforms.parse_uid')
  159. @patch('celery.platforms.parse_gid')
  160. @patch('celery.platforms.setgid')
  161. @patch('celery.platforms.setuid')
  162. @patch('celery.platforms.initgroups')
  163. def test_with_guid(self, initgroups, setuid, setgid,
  164. parse_gid, parse_uid):
  165. def raise_on_second_call(*args, **kwargs):
  166. setuid.side_effect = OSError()
  167. setuid.side_effect.errno = errno.EPERM
  168. setuid.side_effect = raise_on_second_call
  169. parse_uid.return_value = 5001
  170. parse_gid.return_value = 50001
  171. maybe_drop_privileges(uid='user', gid='group')
  172. parse_uid.assert_called_with('user')
  173. parse_gid.assert_called_with('group')
  174. setgid.assert_called_with(50001)
  175. initgroups.assert_called_with(5001, 50001)
  176. setuid.assert_has_calls([call(5001), call(0)])
  177. setuid.side_effect = None
  178. with self.assertRaises(RuntimeError):
  179. maybe_drop_privileges(uid='user', gid='group')
  180. setuid.side_effect = OSError()
  181. setuid.side_effect.errno = errno.EINVAL
  182. with self.assertRaises(OSError):
  183. maybe_drop_privileges(uid='user', gid='group')
  184. @patch('celery.platforms.setuid')
  185. @patch('celery.platforms.setgid')
  186. @patch('celery.platforms.parse_gid')
  187. def test_only_gid(self, parse_gid, setgid, setuid):
  188. parse_gid.return_value = 50001
  189. maybe_drop_privileges(gid='group')
  190. parse_gid.assert_called_with('group')
  191. setgid.assert_called_with(50001)
  192. self.assertFalse(setuid.called)
  193. class test_setget_uid_gid(Case):
  194. @patch('celery.platforms.parse_uid')
  195. @patch('os.setuid')
  196. def test_setuid(self, _setuid, parse_uid):
  197. parse_uid.return_value = 5001
  198. setuid('user')
  199. parse_uid.assert_called_with('user')
  200. _setuid.assert_called_with(5001)
  201. @patch('celery.platforms.parse_gid')
  202. @patch('os.setgid')
  203. def test_setgid(self, _setgid, parse_gid):
  204. parse_gid.return_value = 50001
  205. setgid('group')
  206. parse_gid.assert_called_with('group')
  207. _setgid.assert_called_with(50001)
  208. def test_parse_uid_when_int(self):
  209. self.assertEqual(parse_uid(5001), 5001)
  210. @patch('pwd.getpwnam')
  211. def test_parse_uid_when_existing_name(self, getpwnam):
  212. class pwent(object):
  213. pw_uid = 5001
  214. getpwnam.return_value = pwent()
  215. self.assertEqual(parse_uid('user'), 5001)
  216. @patch('pwd.getpwnam')
  217. def test_parse_uid_when_nonexisting_name(self, getpwnam):
  218. getpwnam.side_effect = KeyError('user')
  219. with self.assertRaises(KeyError):
  220. parse_uid('user')
  221. def test_parse_gid_when_int(self):
  222. self.assertEqual(parse_gid(50001), 50001)
  223. @patch('grp.getgrnam')
  224. def test_parse_gid_when_existing_name(self, getgrnam):
  225. class grent(object):
  226. gr_gid = 50001
  227. getgrnam.return_value = grent()
  228. self.assertEqual(parse_gid('group'), 50001)
  229. @patch('grp.getgrnam')
  230. def test_parse_gid_when_nonexisting_name(self, getgrnam):
  231. getgrnam.side_effect = KeyError('group')
  232. with self.assertRaises(KeyError):
  233. parse_gid('group')
  234. class test_initgroups(Case):
  235. @patch('pwd.getpwuid')
  236. @patch('os.initgroups', create=True)
  237. def test_with_initgroups(self, initgroups_, getpwuid):
  238. getpwuid.return_value = ['user']
  239. initgroups(5001, 50001)
  240. initgroups_.assert_called_with('user', 50001)
  241. @patch('celery.platforms.setgroups')
  242. @patch('grp.getgrall')
  243. @patch('pwd.getpwuid')
  244. def test_without_initgroups(self, getpwuid, getgrall, setgroups):
  245. prev = getattr(os, 'initgroups', None)
  246. try:
  247. delattr(os, 'initgroups')
  248. except AttributeError:
  249. pass
  250. try:
  251. getpwuid.return_value = ['user']
  252. class grent(object):
  253. gr_mem = ['user']
  254. def __init__(self, gid):
  255. self.gr_gid = gid
  256. getgrall.return_value = [grent(1), grent(2), grent(3)]
  257. initgroups(5001, 50001)
  258. setgroups.assert_called_with([1, 2, 3])
  259. finally:
  260. if prev:
  261. os.initgroups = prev
  262. class test_detached(Case):
  263. def test_without_resource(self):
  264. prev, platforms.resource = platforms.resource, None
  265. try:
  266. with self.assertRaises(RuntimeError):
  267. detached()
  268. finally:
  269. platforms.resource = prev
  270. @patch('celery.platforms._create_pidlock')
  271. @patch('celery.platforms.signals')
  272. @patch('celery.platforms.maybe_drop_privileges')
  273. @patch('os.geteuid')
  274. @patch(open_fqdn)
  275. def test_default(self, open, geteuid, maybe_drop,
  276. signals, pidlock):
  277. geteuid.return_value = 0
  278. context = detached(uid='user', gid='group')
  279. self.assertIsInstance(context, DaemonContext)
  280. signals.reset.assert_called_with('SIGCLD')
  281. maybe_drop.assert_called_with(uid='user', gid='group')
  282. open.return_value = Mock()
  283. geteuid.return_value = 5001
  284. context = detached(uid='user', gid='group', logfile='/foo/bar')
  285. self.assertIsInstance(context, DaemonContext)
  286. self.assertTrue(context.after_chdir)
  287. context.after_chdir()
  288. open.assert_called_with('/foo/bar', 'a')
  289. open.return_value.close.assert_called_with()
  290. context = detached(pidfile='/foo/bar/pid')
  291. self.assertIsInstance(context, DaemonContext)
  292. self.assertTrue(context.after_chdir)
  293. context.after_chdir()
  294. pidlock.assert_called_with('/foo/bar/pid')
  295. class test_DaemonContext(Case):
  296. @patch('os.fork')
  297. @patch('os.setsid')
  298. @patch('os._exit')
  299. @patch('os.chdir')
  300. @patch('os.umask')
  301. @patch('os.close')
  302. @patch('os.closerange')
  303. @patch('os.open')
  304. @patch('os.dup2')
  305. def test_open(self, dup2, open, close, closer, umask, chdir,
  306. _exit, setsid, fork):
  307. x = DaemonContext(workdir='/opt/workdir', umask=0o22)
  308. x.stdfds = [0, 1, 2]
  309. fork.return_value = 0
  310. with x:
  311. self.assertTrue(x._is_open)
  312. with x:
  313. pass
  314. self.assertEqual(fork.call_count, 2)
  315. setsid.assert_called_with()
  316. self.assertFalse(_exit.called)
  317. chdir.assert_called_with(x.workdir)
  318. umask.assert_called_with(0o22)
  319. self.assertTrue(dup2.called)
  320. fork.reset_mock()
  321. fork.return_value = 1
  322. x = DaemonContext(workdir='/opt/workdir')
  323. x.stdfds = [0, 1, 2]
  324. with x:
  325. pass
  326. self.assertEqual(fork.call_count, 1)
  327. _exit.assert_called_with(0)
  328. x = DaemonContext(workdir='/opt/workdir', fake=True)
  329. x.stdfds = [0, 1, 2]
  330. x._detach = Mock()
  331. with x:
  332. pass
  333. self.assertFalse(x._detach.called)
  334. x.after_chdir = Mock()
  335. with x:
  336. pass
  337. x.after_chdir.assert_called_with()
  338. class test_Pidfile(Case):
  339. @patch('celery.platforms.Pidfile')
  340. def test_create_pidlock(self, Pidfile):
  341. p = Pidfile.return_value = Mock()
  342. p.is_locked.return_value = True
  343. p.remove_if_stale.return_value = False
  344. with override_stdouts() as (_, err):
  345. with self.assertRaises(SystemExit):
  346. create_pidlock('/var/pid')
  347. self.assertIn('already exists', err.getvalue())
  348. p.remove_if_stale.return_value = True
  349. ret = create_pidlock('/var/pid')
  350. self.assertIs(ret, p)
  351. def test_context(self):
  352. p = Pidfile('/var/pid')
  353. p.write_pid = Mock()
  354. p.remove = Mock()
  355. with p as _p:
  356. self.assertIs(_p, p)
  357. p.write_pid.assert_called_with()
  358. p.remove.assert_called_with()
  359. def test_acquire_raises_LockFailed(self):
  360. p = Pidfile('/var/pid')
  361. p.write_pid = Mock()
  362. p.write_pid.side_effect = OSError()
  363. with self.assertRaises(LockFailed):
  364. with p:
  365. pass
  366. @patch('os.path.exists')
  367. def test_is_locked(self, exists):
  368. p = Pidfile('/var/pid')
  369. exists.return_value = True
  370. self.assertTrue(p.is_locked())
  371. exists.return_value = False
  372. self.assertFalse(p.is_locked())
  373. def test_read_pid(self):
  374. with mock_open() as s:
  375. s.write('1816\n')
  376. s.seek(0)
  377. p = Pidfile('/var/pid')
  378. self.assertEqual(p.read_pid(), 1816)
  379. def test_read_pid_partially_written(self):
  380. with mock_open() as s:
  381. s.write('1816')
  382. s.seek(0)
  383. p = Pidfile('/var/pid')
  384. with self.assertRaises(ValueError):
  385. p.read_pid()
  386. def test_read_pid_raises_ENOENT(self):
  387. exc = IOError()
  388. exc.errno = errno.ENOENT
  389. with mock_open(side_effect=exc):
  390. p = Pidfile('/var/pid')
  391. self.assertIsNone(p.read_pid())
  392. def test_read_pid_raises_IOError(self):
  393. exc = IOError()
  394. exc.errno = errno.EAGAIN
  395. with mock_open(side_effect=exc):
  396. p = Pidfile('/var/pid')
  397. with self.assertRaises(IOError):
  398. p.read_pid()
  399. def test_read_pid_bogus_pidfile(self):
  400. with mock_open() as s:
  401. s.write('eighteensixteen\n')
  402. s.seek(0)
  403. p = Pidfile('/var/pid')
  404. with self.assertRaises(ValueError):
  405. p.read_pid()
  406. @patch('os.unlink')
  407. def test_remove(self, unlink):
  408. unlink.return_value = True
  409. p = Pidfile('/var/pid')
  410. p.remove()
  411. unlink.assert_called_with(p.path)
  412. @patch('os.unlink')
  413. def test_remove_ENOENT(self, unlink):
  414. exc = OSError()
  415. exc.errno = errno.ENOENT
  416. unlink.side_effect = exc
  417. p = Pidfile('/var/pid')
  418. p.remove()
  419. unlink.assert_called_with(p.path)
  420. @patch('os.unlink')
  421. def test_remove_EACCES(self, unlink):
  422. exc = OSError()
  423. exc.errno = errno.EACCES
  424. unlink.side_effect = exc
  425. p = Pidfile('/var/pid')
  426. p.remove()
  427. unlink.assert_called_with(p.path)
  428. @patch('os.unlink')
  429. def test_remove_OSError(self, unlink):
  430. exc = OSError()
  431. exc.errno = errno.EAGAIN
  432. unlink.side_effect = exc
  433. p = Pidfile('/var/pid')
  434. with self.assertRaises(OSError):
  435. p.remove()
  436. unlink.assert_called_with(p.path)
  437. @patch('os.kill')
  438. def test_remove_if_stale_process_alive(self, kill):
  439. p = Pidfile('/var/pid')
  440. p.read_pid = Mock()
  441. p.read_pid.return_value = 1816
  442. kill.return_value = 0
  443. self.assertFalse(p.remove_if_stale())
  444. kill.assert_called_with(1816, 0)
  445. p.read_pid.assert_called_with()
  446. kill.side_effect = OSError()
  447. kill.side_effect.errno = errno.ENOENT
  448. self.assertFalse(p.remove_if_stale())
  449. @patch('os.kill')
  450. def test_remove_if_stale_process_dead(self, kill):
  451. with override_stdouts():
  452. p = Pidfile('/var/pid')
  453. p.read_pid = Mock()
  454. p.read_pid.return_value = 1816
  455. p.remove = Mock()
  456. exc = OSError()
  457. exc.errno = errno.ESRCH
  458. kill.side_effect = exc
  459. self.assertTrue(p.remove_if_stale())
  460. kill.assert_called_with(1816, 0)
  461. p.remove.assert_called_with()
  462. def test_remove_if_stale_broken_pid(self):
  463. with override_stdouts():
  464. p = Pidfile('/var/pid')
  465. p.read_pid = Mock()
  466. p.read_pid.side_effect = ValueError()
  467. p.remove = Mock()
  468. self.assertTrue(p.remove_if_stale())
  469. p.remove.assert_called_with()
  470. def test_remove_if_stale_no_pidfile(self):
  471. p = Pidfile('/var/pid')
  472. p.read_pid = Mock()
  473. p.read_pid.return_value = None
  474. p.remove = Mock()
  475. self.assertTrue(p.remove_if_stale())
  476. p.remove.assert_called_with()
  477. @patch('os.fsync')
  478. @patch('os.getpid')
  479. @patch('os.open')
  480. @patch('os.fdopen')
  481. @patch(open_fqdn)
  482. def test_write_pid(self, open_, fdopen, osopen, getpid, fsync):
  483. getpid.return_value = 1816
  484. osopen.return_value = 13
  485. w = fdopen.return_value = WhateverIO()
  486. w.close = Mock()
  487. r = open_.return_value = WhateverIO()
  488. r.write('1816\n')
  489. r.seek(0)
  490. p = Pidfile('/var/pid')
  491. p.write_pid()
  492. w.seek(0)
  493. self.assertEqual(w.readline(), '1816\n')
  494. self.assertTrue(w.close.called)
  495. getpid.assert_called_with()
  496. osopen.assert_called_with(p.path, platforms.PIDFILE_FLAGS,
  497. platforms.PIDFILE_MODE)
  498. fdopen.assert_called_with(13, 'w')
  499. fsync.assert_called_with(13)
  500. open_.assert_called_with(p.path)
  501. @patch('os.fsync')
  502. @patch('os.getpid')
  503. @patch('os.open')
  504. @patch('os.fdopen')
  505. @patch(open_fqdn)
  506. def test_write_reread_fails(self, open_, fdopen,
  507. osopen, getpid, fsync):
  508. getpid.return_value = 1816
  509. osopen.return_value = 13
  510. w = fdopen.return_value = WhateverIO()
  511. w.close = Mock()
  512. r = open_.return_value = WhateverIO()
  513. r.write('11816\n')
  514. r.seek(0)
  515. p = Pidfile('/var/pid')
  516. with self.assertRaises(LockFailed):
  517. p.write_pid()
  518. class test_setgroups(Case):
  519. @patch('os.setgroups', create=True)
  520. def test_setgroups_hack_ValueError(self, setgroups):
  521. def on_setgroups(groups):
  522. if len(groups) <= 200:
  523. setgroups.return_value = True
  524. return
  525. raise ValueError()
  526. setgroups.side_effect = on_setgroups
  527. _setgroups_hack(list(range(400)))
  528. setgroups.side_effect = ValueError()
  529. with self.assertRaises(ValueError):
  530. _setgroups_hack(list(range(400)))
  531. @patch('os.setgroups', create=True)
  532. def test_setgroups_hack_OSError(self, setgroups):
  533. exc = OSError()
  534. exc.errno = errno.EINVAL
  535. def on_setgroups(groups):
  536. if len(groups) <= 200:
  537. setgroups.return_value = True
  538. return
  539. raise exc
  540. setgroups.side_effect = on_setgroups
  541. _setgroups_hack(list(range(400)))
  542. setgroups.side_effect = exc
  543. with self.assertRaises(OSError):
  544. _setgroups_hack(list(range(400)))
  545. exc2 = OSError()
  546. exc.errno = errno.ESRCH
  547. setgroups.side_effect = exc2
  548. with self.assertRaises(OSError):
  549. _setgroups_hack(list(range(400)))
  550. @patch('os.sysconf')
  551. @patch('celery.platforms._setgroups_hack')
  552. def test_setgroups(self, hack, sysconf):
  553. sysconf.return_value = 100
  554. setgroups(list(range(400)))
  555. hack.assert_called_with(list(range(100)))
  556. @patch('os.sysconf')
  557. @patch('celery.platforms._setgroups_hack')
  558. def test_setgroups_sysconf_raises(self, hack, sysconf):
  559. sysconf.side_effect = ValueError()
  560. setgroups(list(range(400)))
  561. hack.assert_called_with(list(range(400)))
  562. @patch('os.getgroups')
  563. @patch('os.sysconf')
  564. @patch('celery.platforms._setgroups_hack')
  565. def test_setgroups_raises_ESRCH(self, hack, sysconf, getgroups):
  566. sysconf.side_effect = ValueError()
  567. esrch = OSError()
  568. esrch.errno = errno.ESRCH
  569. hack.side_effect = esrch
  570. with self.assertRaises(OSError):
  571. setgroups(list(range(400)))
  572. @patch('os.getgroups')
  573. @patch('os.sysconf')
  574. @patch('celery.platforms._setgroups_hack')
  575. def test_setgroups_raises_EPERM(self, hack, sysconf, getgroups):
  576. sysconf.side_effect = ValueError()
  577. eperm = OSError()
  578. eperm.errno = errno.EPERM
  579. hack.side_effect = eperm
  580. getgroups.return_value = list(range(400))
  581. setgroups(list(range(400)))
  582. getgroups.assert_called_with()
  583. getgroups.return_value = [1000]
  584. with self.assertRaises(OSError):
  585. setgroups(list(range(400)))
  586. getgroups.assert_called_with()