test_app.py 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  1. from __future__ import absolute_import, unicode_literals
  2. import gc
  3. import os
  4. import itertools
  5. from copy import deepcopy
  6. from pickle import loads, dumps
  7. from vine import promise
  8. from celery import Celery
  9. from celery import shared_task, current_app
  10. from celery import app as _app
  11. from celery import _state
  12. from celery.app import base as _appbase
  13. from celery.app import defaults
  14. from celery.exceptions import ImproperlyConfigured
  15. from celery.five import keys
  16. from celery.loaders.base import BaseLoader, unconfigured
  17. from celery.platforms import pyimplementation
  18. from celery.utils.serialization import pickle
  19. from celery.utils.timeutils import timezone
  20. from celery.tests.case import (
  21. CELERY_TEST_CONFIG,
  22. AppCase,
  23. Mock,
  24. Case,
  25. ContextMock,
  26. depends_on_current_app,
  27. mock,
  28. patch,
  29. )
  30. from celery.utils import uuid
  31. from celery.utils.mail import ErrorMail
  32. from celery.utils.objects import Bunch
  33. THIS_IS_A_KEY = 'this is a value'
  34. class ObjectConfig(object):
  35. FOO = 1
  36. BAR = 2
  37. object_config = ObjectConfig()
  38. dict_config = dict(FOO=10, BAR=20)
  39. class ObjectConfig2(object):
  40. LEAVE_FOR_WORK = True
  41. MOMENT_TO_STOP = True
  42. CALL_ME_BACK = 123456789
  43. WANT_ME_TO = False
  44. UNDERSTAND_ME = True
  45. def _get_test_config():
  46. return deepcopy(CELERY_TEST_CONFIG)
  47. test_config = _get_test_config()
  48. class test_module(AppCase):
  49. def test_default_app(self):
  50. self.assertEqual(_app.default_app, _state.default_app)
  51. def test_bugreport(self):
  52. self.assertTrue(_app.bugreport(app=self.app))
  53. class test_task_join_will_block(Case):
  54. def test_task_join_will_block(self):
  55. prev, _state._task_join_will_block = _state._task_join_will_block, 0
  56. try:
  57. self.assertEqual(_state._task_join_will_block, 0)
  58. _state._set_task_join_will_block(True)
  59. print(_state.task_join_will_block)
  60. self.assertTrue(_state.task_join_will_block())
  61. finally:
  62. _state._task_join_will_block = prev
  63. class test_App(AppCase):
  64. def setup(self):
  65. self.app.add_defaults(test_config)
  66. def test_task_autofinalize_disabled(self):
  67. with self.Celery('xyzibari', autofinalize=False) as app:
  68. @app.task
  69. def ttafd():
  70. return 42
  71. with self.assertRaises(RuntimeError):
  72. ttafd()
  73. with self.Celery('xyzibari', autofinalize=False) as app:
  74. @app.task
  75. def ttafd2():
  76. return 42
  77. app.finalize()
  78. self.assertEqual(ttafd2(), 42)
  79. def test_registry_autofinalize_disabled(self):
  80. with self.Celery('xyzibari', autofinalize=False) as app:
  81. with self.assertRaises(RuntimeError):
  82. app.tasks['celery.chain']
  83. app.finalize()
  84. self.assertTrue(app.tasks['celery.chain'])
  85. def test_task(self):
  86. with self.Celery('foozibari') as app:
  87. def fun():
  88. pass
  89. fun.__module__ = '__main__'
  90. task = app.task(fun)
  91. self.assertEqual(task.name, app.main + '.fun')
  92. def test_task_too_many_args(self):
  93. with self.assertRaises(TypeError):
  94. self.app.task(Mock(name='fun'), True)
  95. with self.assertRaises(TypeError):
  96. self.app.task(Mock(name='fun'), True, 1, 2)
  97. def test_with_config_source(self):
  98. with self.Celery(config_source=ObjectConfig) as app:
  99. self.assertEqual(app.conf.FOO, 1)
  100. self.assertEqual(app.conf.BAR, 2)
  101. @depends_on_current_app
  102. def test_task_windows_execv(self):
  103. prev, _appbase.USING_EXECV = _appbase.USING_EXECV, True
  104. try:
  105. @self.app.task(shared=False)
  106. def foo():
  107. pass
  108. self.assertTrue(foo._get_current_object()) # is proxy
  109. finally:
  110. _appbase.USING_EXECV = prev
  111. assert not _appbase.USING_EXECV
  112. def test_task_takes_no_args(self):
  113. with self.assertRaises(TypeError):
  114. @self.app.task(1)
  115. def foo():
  116. pass
  117. def test_add_defaults(self):
  118. self.assertFalse(self.app.configured)
  119. _conf = {'FOO': 300}
  120. def conf():
  121. return _conf
  122. self.app.add_defaults(conf)
  123. self.assertIn(conf, self.app._pending_defaults)
  124. self.assertFalse(self.app.configured)
  125. self.assertEqual(self.app.conf.FOO, 300)
  126. self.assertTrue(self.app.configured)
  127. self.assertFalse(self.app._pending_defaults)
  128. # defaults not pickled
  129. appr = loads(dumps(self.app))
  130. with self.assertRaises(AttributeError):
  131. appr.conf.FOO
  132. # add more defaults after configured
  133. conf2 = {'FOO': 'BAR'}
  134. self.app.add_defaults(conf2)
  135. self.assertEqual(self.app.conf.FOO, 'BAR')
  136. self.assertIn(_conf, self.app.conf.defaults)
  137. self.assertIn(conf2, self.app.conf.defaults)
  138. def test_connection_or_acquire(self):
  139. with self.app.connection_or_acquire(block=True):
  140. self.assertTrue(self.app.pool._dirty)
  141. with self.app.connection_or_acquire(pool=False):
  142. self.assertFalse(self.app.pool._dirty)
  143. def test_using_v1_reduce(self):
  144. self.app._using_v1_reduce = True
  145. self.assertTrue(loads(dumps(self.app)))
  146. def test_autodiscover_tasks_force(self):
  147. self.app.loader.autodiscover_tasks = Mock()
  148. self.app.autodiscover_tasks(['proj.A', 'proj.B'], force=True)
  149. self.app.loader.autodiscover_tasks.assert_called_with(
  150. ['proj.A', 'proj.B'], 'tasks',
  151. )
  152. self.app.loader.autodiscover_tasks = Mock()
  153. def lazy_list():
  154. return ['proj.A', 'proj.B']
  155. self.app.autodiscover_tasks(
  156. lazy_list,
  157. related_name='george',
  158. force=True,
  159. )
  160. self.app.loader.autodiscover_tasks.assert_called_with(
  161. ['proj.A', 'proj.B'], 'george',
  162. )
  163. def test_autodiscover_tasks_lazy(self):
  164. with patch('celery.signals.import_modules') as import_modules:
  165. def lazy_list():
  166. return [1, 2, 3]
  167. self.app.autodiscover_tasks(lazy_list)
  168. self.assertTrue(import_modules.connect.called)
  169. prom = import_modules.connect.call_args[0][0]
  170. self.assertIsInstance(prom, promise)
  171. self.assertEqual(prom.fun, self.app._autodiscover_tasks)
  172. self.assertEqual(prom.args[0](), [1, 2, 3])
  173. def test_autodiscover_tasks__no_packages(self):
  174. fixup1 = Mock(name='fixup')
  175. fixup2 = Mock(name='fixup')
  176. self.app._autodiscover_tasks_from_names = Mock(name='auto')
  177. self.app._fixups = [fixup1, fixup2]
  178. fixup1.autodiscover_tasks.return_value = ['A', 'B', 'C']
  179. fixup2.autodiscover_tasks.return_value = ['D', 'E', 'F']
  180. self.app.autodiscover_tasks(force=True)
  181. self.app._autodiscover_tasks_from_names.assert_called_with(
  182. ['A', 'B', 'C', 'D', 'E', 'F'], related_name='tasks',
  183. )
  184. @mock.environ('CELERY_BROKER_URL', '')
  185. def test_with_broker(self):
  186. with self.Celery(broker='foo://baribaz') as app:
  187. self.assertEqual(app.conf.broker_url, 'foo://baribaz')
  188. def test_pending_configuration__setattr(self):
  189. with self.Celery(broker='foo://bar') as app:
  190. app.conf.task_default_delivery_mode = 44
  191. app.conf.worker_agent = 'foo:Bar'
  192. self.assertFalse(app.configured)
  193. self.assertEqual(app.conf.worker_agent, 'foo:Bar')
  194. self.assertEqual(app.conf.broker_url, 'foo://bar')
  195. self.assertEqual(app._preconf['worker_agent'], 'foo:Bar')
  196. self.assertTrue(app.configured)
  197. reapp = pickle.loads(pickle.dumps(app))
  198. self.assertEqual(reapp._preconf['worker_agent'], 'foo:Bar')
  199. self.assertFalse(reapp.configured)
  200. self.assertEqual(reapp.conf.worker_agent, 'foo:Bar')
  201. self.assertTrue(reapp.configured)
  202. self.assertEqual(reapp.conf.broker_url, 'foo://bar')
  203. self.assertEqual(reapp._preconf['worker_agent'], 'foo:Bar')
  204. def test_pending_configuration__update(self):
  205. with self.Celery(broker='foo://bar') as app:
  206. app.conf.update(
  207. task_default_delivery_mode=44,
  208. worker_agent='foo:Bar',
  209. )
  210. self.assertFalse(app.configured)
  211. self.assertEqual(app.conf.worker_agent, 'foo:Bar')
  212. self.assertEqual(app.conf.broker_url, 'foo://bar')
  213. self.assertEqual(app._preconf['worker_agent'], 'foo:Bar')
  214. def test_pending_configuration__compat_settings(self):
  215. with self.Celery(broker='foo://bar', backend='foo') as app:
  216. app.conf.update(
  217. CELERY_ALWAYS_EAGER=4,
  218. CELERY_DEFAULT_DELIVERY_MODE=63,
  219. CELERYD_AGENT='foo:Barz',
  220. )
  221. self.assertEqual(app.conf.task_always_eager, 4)
  222. self.assertEqual(app.conf.task_default_delivery_mode, 63)
  223. self.assertEqual(app.conf.worker_agent, 'foo:Barz')
  224. self.assertEqual(app.conf.broker_url, 'foo://bar')
  225. self.assertEqual(app.conf.result_backend, 'foo')
  226. def test_pending_configuration__compat_settings_mixing(self):
  227. with self.Celery(broker='foo://bar', backend='foo') as app:
  228. app.conf.update(
  229. CELERY_ALWAYS_EAGER=4,
  230. CELERY_DEFAULT_DELIVERY_MODE=63,
  231. CELERYD_AGENT='foo:Barz',
  232. worker_consumer='foo:Fooz',
  233. )
  234. with self.assertRaises(ImproperlyConfigured):
  235. self.assertEqual(app.conf.task_always_eager, 4)
  236. def test_pending_configuration__compat_settings_mixing_new(self):
  237. with self.Celery(broker='foo://bar', backend='foo') as app:
  238. app.conf.update(
  239. task_always_eager=4,
  240. task_default_delivery_mode=63,
  241. worker_agent='foo:Barz',
  242. CELERYD_CONSUMER='foo:Fooz',
  243. CELERYD_AUTOSCALER='foo:Xuzzy',
  244. )
  245. with self.assertRaises(ImproperlyConfigured):
  246. self.assertEqual(app.conf.worker_consumer, 'foo:Fooz')
  247. def test_pending_configuration__compat_settings_mixing_alt(self):
  248. with self.Celery(broker='foo://bar', backend='foo') as app:
  249. app.conf.update(
  250. task_always_eager=4,
  251. task_default_delivery_mode=63,
  252. worker_agent='foo:Barz',
  253. CELERYD_CONSUMER='foo:Fooz',
  254. worker_consumer='foo:Fooz',
  255. CELERYD_AUTOSCALER='foo:Xuzzy',
  256. worker_autoscaler='foo:Xuzzy'
  257. )
  258. self.assertEqual(app.conf.task_always_eager, 4)
  259. self.assertEqual(app.conf.worker_autoscaler, 'foo:Xuzzy')
  260. def test_pending_configuration__setdefault(self):
  261. with self.Celery(broker='foo://bar') as app:
  262. app.conf.setdefault('worker_agent', 'foo:Bar')
  263. self.assertFalse(app.configured)
  264. def test_pending_configuration__iter(self):
  265. with self.Celery(broker='foo://bar') as app:
  266. app.conf.worker_agent = 'foo:Bar'
  267. self.assertFalse(app.configured)
  268. self.assertTrue(list(keys(app.conf)))
  269. self.assertFalse(app.configured)
  270. self.assertIn('worker_agent', app.conf)
  271. self.assertFalse(app.configured)
  272. self.assertTrue(dict(app.conf))
  273. self.assertTrue(app.configured)
  274. def test_pending_configuration__raises_ImproperlyConfigured(self):
  275. with self.Celery(set_as_current=False) as app:
  276. app.conf.worker_agent = 'foo://bar'
  277. app.conf.task_default_delivery_mode = 44
  278. app.conf.CELERY_ALWAYS_EAGER = 5
  279. with self.assertRaises(ImproperlyConfigured):
  280. app.finalize()
  281. with self.Celery() as app:
  282. self.assertFalse(self.app.conf.task_always_eager)
  283. def test_repr(self):
  284. self.assertTrue(repr(self.app))
  285. def test_custom_task_registry(self):
  286. with self.Celery(tasks=self.app.tasks) as app2:
  287. self.assertIs(app2.tasks, self.app.tasks)
  288. def test_include_argument(self):
  289. with self.Celery(include=('foo', 'bar.foo')) as app:
  290. self.assertEqual(app.conf.include, ('foo', 'bar.foo'))
  291. def test_set_as_current(self):
  292. current = _state._tls.current_app
  293. try:
  294. app = self.Celery(set_as_current=True)
  295. self.assertIs(_state._tls.current_app, app)
  296. finally:
  297. _state._tls.current_app = current
  298. def test_current_task(self):
  299. @self.app.task
  300. def foo(shared=False):
  301. pass
  302. _state._task_stack.push(foo)
  303. try:
  304. self.assertEqual(self.app.current_task.name, foo.name)
  305. finally:
  306. _state._task_stack.pop()
  307. def test_task_not_shared(self):
  308. with patch('celery.app.base.connect_on_app_finalize') as sh:
  309. @self.app.task(shared=False)
  310. def foo():
  311. pass
  312. self.assertFalse(sh.called)
  313. def test_task_compat_with_filter(self):
  314. with self.Celery() as app:
  315. check = Mock()
  316. def filter(task):
  317. check(task)
  318. return task
  319. @app.task(filter=filter, shared=False)
  320. def foo():
  321. pass
  322. check.assert_called_with(foo)
  323. def test_task_with_filter(self):
  324. with self.Celery() as app:
  325. check = Mock()
  326. def filter(task):
  327. check(task)
  328. return task
  329. assert not _appbase.USING_EXECV
  330. @app.task(filter=filter, shared=False)
  331. def foo():
  332. pass
  333. check.assert_called_with(foo)
  334. def test_task_sets_main_name_MP_MAIN_FILE(self):
  335. from celery import utils as _utils
  336. _utils.MP_MAIN_FILE = __file__
  337. try:
  338. with self.Celery('xuzzy') as app:
  339. @app.task
  340. def foo():
  341. pass
  342. self.assertEqual(foo.name, 'xuzzy.foo')
  343. finally:
  344. _utils.MP_MAIN_FILE = None
  345. def test_annotate_decorator(self):
  346. from celery.app.task import Task
  347. class adX(Task):
  348. abstract = True
  349. def run(self, y, z, x):
  350. return y, z, x
  351. check = Mock()
  352. def deco(fun):
  353. def _inner(*args, **kwargs):
  354. check(*args, **kwargs)
  355. return fun(*args, **kwargs)
  356. return _inner
  357. self.app.conf.task_annotations = {
  358. adX.name: {'@__call__': deco}
  359. }
  360. adX.bind(self.app)
  361. self.assertIs(adX.app, self.app)
  362. i = adX()
  363. i(2, 4, x=3)
  364. check.assert_called_with(i, 2, 4, x=3)
  365. i.annotate()
  366. i.annotate()
  367. def test_apply_async_has__self__(self):
  368. @self.app.task(__self__='hello', shared=False)
  369. def aawsX(x, y):
  370. pass
  371. with self.assertRaises(TypeError):
  372. aawsX.apply_async(())
  373. with self.assertRaises(TypeError):
  374. aawsX.apply_async((2,))
  375. with patch('celery.app.amqp.AMQP.create_task_message') as create:
  376. with patch('celery.app.amqp.AMQP.send_task_message') as send:
  377. create.return_value = Mock(), Mock(), Mock(), Mock()
  378. aawsX.apply_async((4, 5))
  379. args = create.call_args[0][2]
  380. self.assertEqual(args, ('hello', 4, 5))
  381. self.assertTrue(send.called)
  382. def test_apply_async_adds_children(self):
  383. from celery._state import _task_stack
  384. @self.app.task(bind=True, shared=False)
  385. def a3cX1(self):
  386. pass
  387. @self.app.task(bind=True, shared=False)
  388. def a3cX2(self):
  389. pass
  390. _task_stack.push(a3cX1)
  391. try:
  392. a3cX1.push_request(called_directly=False)
  393. try:
  394. res = a3cX2.apply_async(add_to_parent=True)
  395. self.assertIn(res, a3cX1.request.children)
  396. finally:
  397. a3cX1.pop_request()
  398. finally:
  399. _task_stack.pop()
  400. def test_pickle_app(self):
  401. changes = dict(THE_FOO_BAR='bars',
  402. THE_MII_MAR='jars')
  403. self.app.conf.update(changes)
  404. saved = pickle.dumps(self.app)
  405. self.assertLess(len(saved), 2048)
  406. restored = pickle.loads(saved)
  407. self.assertDictContainsSubset(changes, restored.conf)
  408. def test_worker_main(self):
  409. from celery.bin import worker as worker_bin
  410. class worker(worker_bin.worker):
  411. def execute_from_commandline(self, argv):
  412. return argv
  413. prev, worker_bin.worker = worker_bin.worker, worker
  414. try:
  415. ret = self.app.worker_main(argv=['--version'])
  416. self.assertListEqual(ret, ['--version'])
  417. finally:
  418. worker_bin.worker = prev
  419. def test_config_from_envvar(self):
  420. os.environ['CELERYTEST_CONFIG_OBJECT'] = 'celery.tests.app.test_app'
  421. self.app.config_from_envvar('CELERYTEST_CONFIG_OBJECT')
  422. self.assertEqual(self.app.conf.THIS_IS_A_KEY, 'this is a value')
  423. def assert_config2(self):
  424. self.assertTrue(self.app.conf.LEAVE_FOR_WORK)
  425. self.assertTrue(self.app.conf.MOMENT_TO_STOP)
  426. self.assertEqual(self.app.conf.CALL_ME_BACK, 123456789)
  427. self.assertFalse(self.app.conf.WANT_ME_TO)
  428. self.assertTrue(self.app.conf.UNDERSTAND_ME)
  429. def test_config_from_object__lazy(self):
  430. conf = ObjectConfig2()
  431. self.app.config_from_object(conf)
  432. self.assertIs(self.app.loader._conf, unconfigured)
  433. self.assertIs(self.app._config_source, conf)
  434. self.assert_config2()
  435. def test_config_from_object__force(self):
  436. self.app.config_from_object(ObjectConfig2(), force=True)
  437. self.assertTrue(self.app.loader._conf)
  438. self.assert_config2()
  439. def test_config_from_object__compat(self):
  440. class Config(object):
  441. CELERY_ALWAYS_EAGER = 44
  442. CELERY_DEFAULT_DELIVERY_MODE = 30
  443. CELERY_TASK_PUBLISH_RETRY = False
  444. self.app.config_from_object(Config)
  445. self.assertEqual(self.app.conf.task_always_eager, 44)
  446. self.assertEqual(self.app.conf.CELERY_ALWAYS_EAGER, 44)
  447. self.assertFalse(self.app.conf.task_publish_retry)
  448. self.assertEqual(self.app.conf.task_default_routing_key, 'celery')
  449. def test_config_from_object__supports_old_names(self):
  450. class Config(object):
  451. task_always_eager = 45
  452. task_default_delivery_mode = 301
  453. self.app.config_from_object(Config())
  454. self.assertEqual(self.app.conf.CELERY_ALWAYS_EAGER, 45)
  455. self.assertEqual(self.app.conf.task_always_eager, 45)
  456. self.assertEqual(self.app.conf.CELERY_DEFAULT_DELIVERY_MODE, 301)
  457. self.assertEqual(self.app.conf.task_default_delivery_mode, 301)
  458. self.assertEqual(self.app.conf.task_default_routing_key, 'testcelery')
  459. def test_config_from_object__namespace_uppercase(self):
  460. class Config(object):
  461. CELERY_TASK_ALWAYS_EAGER = 44
  462. CELERY_TASK_DEFAULT_DELIVERY_MODE = 301
  463. self.app.config_from_object(Config(), namespace='CELERY')
  464. self.assertEqual(self.app.conf.task_always_eager, 44)
  465. def test_config_from_object__namespace_lowercase(self):
  466. class Config(object):
  467. celery_task_always_eager = 44
  468. celery_task_default_delivery_mode = 301
  469. self.app.config_from_object(Config(), namespace='celery')
  470. self.assertEqual(self.app.conf.task_always_eager, 44)
  471. def test_config_from_object__mixing_new_and_old(self):
  472. class Config(object):
  473. task_always_eager = 44
  474. worker_agent = 'foo:Agent'
  475. worker_consumer = 'foo:Consumer'
  476. beat_schedule = '/foo/schedule'
  477. CELERY_DEFAULT_DELIVERY_MODE = 301
  478. with self.assertRaises(ImproperlyConfigured) as exc:
  479. self.app.config_from_object(Config(), force=True)
  480. self.assertTrue(
  481. exc.args[0].startswith('CELERY_DEFAULT_DELIVERY_MODE'))
  482. self.assertIn('task_default_delivery_mode', exc.args[0])
  483. def test_config_from_object__mixing_old_and_new(self):
  484. class Config(object):
  485. CELERY_ALWAYS_EAGER = 46
  486. CELERYD_AGENT = 'foo:Agent'
  487. CELERYD_CONSUMER = 'foo:Consumer'
  488. CELERYBEAT_SCHEDULE = '/foo/schedule'
  489. task_default_delivery_mode = 301
  490. with self.assertRaises(ImproperlyConfigured) as exc:
  491. self.app.config_from_object(Config(), force=True)
  492. self.assertTrue(
  493. exc.args[0].startswith('task_default_delivery_mode'))
  494. self.assertIn('CELERY_DEFAULT_DELIVERY_MODE', exc.args[0])
  495. def test_config_from_cmdline(self):
  496. cmdline = ['task_always_eager=no',
  497. 'result_backend=/dev/null',
  498. 'worker_prefetch_multiplier=368',
  499. '.foobarstring=(string)300',
  500. '.foobarint=(int)300',
  501. 'sqlalchemy_engine_options=(dict){"foo": "bar"}']
  502. self.app.config_from_cmdline(cmdline, namespace='worker')
  503. self.assertFalse(self.app.conf.task_always_eager)
  504. self.assertEqual(self.app.conf.result_backend, '/dev/null')
  505. self.assertEqual(self.app.conf.worker_prefetch_multiplier, 368)
  506. self.assertEqual(self.app.conf.worker_foobarstring, '300')
  507. self.assertEqual(self.app.conf.worker_foobarint, 300)
  508. self.assertDictEqual(self.app.conf.sqlalchemy_engine_options,
  509. {'foo': 'bar'})
  510. def test_setting__broker_transport_options(self):
  511. _args = {'foo': 'bar', 'spam': 'baz'}
  512. self.app.config_from_object(Bunch())
  513. self.assertEqual(self.app.conf.broker_transport_options, {})
  514. self.app.config_from_object(Bunch(broker_transport_options=_args))
  515. self.assertEqual(self.app.conf.broker_transport_options, _args)
  516. def test_Windows_log_color_disabled(self):
  517. self.app.IS_WINDOWS = True
  518. self.assertFalse(self.app.log.supports_color(True))
  519. def test_WorkController(self):
  520. x = self.app.WorkController
  521. self.assertIs(x.app, self.app)
  522. def test_Worker(self):
  523. x = self.app.Worker
  524. self.assertIs(x.app, self.app)
  525. @depends_on_current_app
  526. def test_AsyncResult(self):
  527. x = self.app.AsyncResult('1')
  528. self.assertIs(x.app, self.app)
  529. r = loads(dumps(x))
  530. # not set as current, so ends up as default app after reduce
  531. self.assertIs(r.app, current_app._get_current_object())
  532. def test_get_active_apps(self):
  533. self.assertTrue(list(_state._get_active_apps()))
  534. app1 = self.Celery()
  535. appid = id(app1)
  536. self.assertIn(app1, _state._get_active_apps())
  537. app1.close()
  538. del(app1)
  539. gc.collect()
  540. # weakref removed from list when app goes out of scope.
  541. with self.assertRaises(StopIteration):
  542. next(app for app in _state._get_active_apps() if id(app) == appid)
  543. def test_config_from_envvar_more(self, key='CELERY_HARNESS_CFG1'):
  544. self.assertFalse(
  545. self.app.config_from_envvar(
  546. 'HDSAJIHWIQHEWQU', force=True, silent=True),
  547. )
  548. with self.assertRaises(ImproperlyConfigured):
  549. self.app.config_from_envvar(
  550. 'HDSAJIHWIQHEWQU', force=True, silent=False,
  551. )
  552. os.environ[key] = __name__ + '.object_config'
  553. self.assertTrue(self.app.config_from_envvar(key, force=True))
  554. self.assertEqual(self.app.conf['FOO'], 1)
  555. self.assertEqual(self.app.conf['BAR'], 2)
  556. os.environ[key] = 'unknown_asdwqe.asdwqewqe'
  557. with self.assertRaises(ImportError):
  558. self.app.config_from_envvar(key, silent=False)
  559. self.assertFalse(
  560. self.app.config_from_envvar(key, force=True, silent=True),
  561. )
  562. os.environ[key] = __name__ + '.dict_config'
  563. self.assertTrue(self.app.config_from_envvar(key, force=True))
  564. self.assertEqual(self.app.conf['FOO'], 10)
  565. self.assertEqual(self.app.conf['BAR'], 20)
  566. @patch('celery.bin.celery.CeleryCommand.execute_from_commandline')
  567. def test_start(self, execute):
  568. self.app.start()
  569. self.assertTrue(execute.called)
  570. def test_mail_admins(self):
  571. class Loader(BaseLoader):
  572. def mail_admins(*args, **kwargs):
  573. return args, kwargs
  574. self.app.loader = Loader(app=self.app)
  575. self.app.conf.admins = None
  576. self.assertFalse(self.app.mail_admins('Subject', 'Body'))
  577. self.app.conf.admins = [('George Costanza', 'george@vandelay.com')]
  578. self.assertTrue(self.app.mail_admins('Subject', 'Body'))
  579. def test_amqp_get_broker_info(self):
  580. self.assertDictContainsSubset(
  581. {'hostname': 'localhost',
  582. 'userid': 'guest',
  583. 'password': 'guest',
  584. 'virtual_host': '/'},
  585. self.app.connection('pyamqp://').info(),
  586. )
  587. self.app.conf.broker_port = 1978
  588. self.app.conf.broker_vhost = 'foo'
  589. self.assertDictContainsSubset(
  590. {'port': 1978, 'virtual_host': 'foo'},
  591. self.app.connection('pyamqp://:1978/foo').info(),
  592. )
  593. conn = self.app.connection('pyamqp:////value')
  594. self.assertDictContainsSubset({'virtual_host': '/value'},
  595. conn.info())
  596. def test_amqp_failover_strategy_selection(self):
  597. # Test passing in a string and make sure the string
  598. # gets there untouched
  599. self.app.conf.broker_failover_strategy = 'foo-bar'
  600. self.assertEqual(
  601. self.app.connection('amqp:////value').failover_strategy,
  602. 'foo-bar',
  603. )
  604. # Try passing in None
  605. self.app.conf.broker_failover_strategy = None
  606. self.assertEqual(
  607. self.app.connection('amqp:////value').failover_strategy,
  608. itertools.cycle,
  609. )
  610. # Test passing in a method
  611. def my_failover_strategy(it):
  612. yield True
  613. self.app.conf.broker_failover_strategy = my_failover_strategy
  614. self.assertEqual(
  615. self.app.connection('amqp:////value').failover_strategy,
  616. my_failover_strategy,
  617. )
  618. def test_after_fork(self):
  619. self.app._pool = Mock()
  620. self.app.on_after_fork = Mock(name='on_after_fork')
  621. self.app._after_fork()
  622. self.assertIsNone(self.app._pool)
  623. self.app.on_after_fork.send.assert_called_with(sender=self.app)
  624. self.app._after_fork()
  625. def test_global_after_fork(self):
  626. self.app._after_fork = Mock(name='_after_fork')
  627. _appbase._after_fork_cleanup_app(self.app)
  628. self.app._after_fork.assert_called_with()
  629. @patch('celery.app.base.logger')
  630. def test_after_fork_cleanup_app__raises(self, logger):
  631. self.app._after_fork = Mock(name='_after_fork')
  632. exc = self.app._after_fork.side_effect = KeyError()
  633. _appbase._after_fork_cleanup_app(self.app)
  634. logger.info.assert_called_with(
  635. 'after forker raised exception: %r', exc, exc_info=1)
  636. def test_ensure_after_fork__no_multiprocessing(self):
  637. prev, _appbase.register_after_fork = (
  638. _appbase.register_after_fork, None)
  639. try:
  640. self.app._after_fork_registered = False
  641. self.app._ensure_after_fork()
  642. self.assertTrue(self.app._after_fork_registered)
  643. finally:
  644. _appbase.register_after_fork = prev
  645. def test_canvas(self):
  646. self.assertTrue(self.app.canvas.Signature)
  647. def test_signature(self):
  648. sig = self.app.signature('foo', (1, 2))
  649. self.assertIs(sig.app, self.app)
  650. def test_timezone__none_set(self):
  651. self.app.conf.timezone = None
  652. tz = self.app.timezone
  653. self.assertEqual(tz, timezone.get_timezone('UTC'))
  654. def test_compat_on_configure(self):
  655. _on_configure = Mock(name='on_configure')
  656. class CompatApp(Celery):
  657. def on_configure(self, *args, **kwargs):
  658. # on pypy3 if named on_configure the class function
  659. # will be called, instead of the mock defined above,
  660. # so we add the underscore.
  661. _on_configure(*args, **kwargs)
  662. with CompatApp(set_as_current=False) as app:
  663. app.loader = Mock()
  664. app.loader.conf = {}
  665. app._load_config()
  666. _on_configure.assert_called_with()
  667. def test_add_periodic_task(self):
  668. @self.app.task
  669. def add(x, y):
  670. pass
  671. assert not self.app.configured
  672. self.app.add_periodic_task(
  673. 10, self.app.signature('add', (2, 2)),
  674. name='add1', expires=3,
  675. )
  676. self.assertTrue(self.app._pending_periodic_tasks)
  677. assert not self.app.configured
  678. sig2 = add.s(4, 4)
  679. self.assertTrue(self.app.configured)
  680. self.app.add_periodic_task(20, sig2, name='add2', expires=4)
  681. self.assertIn('add1', self.app.conf.beat_schedule)
  682. self.assertIn('add2', self.app.conf.beat_schedule)
  683. def test_pool_no_multiprocessing(self):
  684. with mock.mask_modules('multiprocessing.util'):
  685. pool = self.app.pool
  686. self.assertIs(pool, self.app._pool)
  687. def test_bugreport(self):
  688. self.assertTrue(self.app.bugreport())
  689. def test_send_task__connection_provided(self):
  690. connection = Mock(name='connection')
  691. router = Mock(name='router')
  692. router.route.return_value = {}
  693. self.app.amqp = Mock(name='amqp')
  694. self.app.amqp.Producer.attach_mock(ContextMock(), 'return_value')
  695. self.app.send_task('foo', (1, 2), connection=connection, router=router)
  696. self.app.amqp.Producer.assert_called_with(connection)
  697. self.app.amqp.send_task_message.assert_called_with(
  698. self.app.amqp.Producer(), 'foo',
  699. self.app.amqp.create_task_message())
  700. def test_send_task_sent_event(self):
  701. class Dispatcher(object):
  702. sent = []
  703. def publish(self, type, fields, *args, **kwargs):
  704. self.sent.append((type, fields))
  705. conn = self.app.connection()
  706. chan = conn.channel()
  707. try:
  708. for e in ('foo_exchange', 'moo_exchange', 'bar_exchange'):
  709. chan.exchange_declare(e, 'direct', durable=True)
  710. chan.queue_declare(e, durable=True)
  711. chan.queue_bind(e, e, e)
  712. finally:
  713. chan.close()
  714. assert conn.transport_cls == 'memory'
  715. message = self.app.amqp.create_task_message(
  716. 'id', 'footask', (), {}, create_sent_event=True,
  717. )
  718. prod = self.app.amqp.Producer(conn)
  719. dispatcher = Dispatcher()
  720. self.app.amqp.send_task_message(
  721. prod, 'footask', message,
  722. exchange='moo_exchange', routing_key='moo_exchange',
  723. event_dispatcher=dispatcher,
  724. )
  725. self.assertTrue(dispatcher.sent)
  726. self.assertEqual(dispatcher.sent[0][0], 'task-sent')
  727. self.app.amqp.send_task_message(
  728. prod, 'footask', message, event_dispatcher=dispatcher,
  729. exchange='bar_exchange', routing_key='bar_exchange',
  730. )
  731. def test_error_mail_sender(self):
  732. x = ErrorMail.subject % {'name': 'task_name',
  733. 'id': uuid(),
  734. 'exc': 'FOOBARBAZ',
  735. 'hostname': 'lana'}
  736. self.assertTrue(x)
  737. def test_error_mail_disabled(self):
  738. task = Mock()
  739. x = ErrorMail(task)
  740. x.should_send = Mock()
  741. x.should_send.return_value = False
  742. x.send(Mock(), Mock())
  743. self.assertFalse(task.app.mail_admins.called)
  744. def test_select_queues(self):
  745. self.app.amqp = Mock(name='amqp')
  746. self.app.select_queues({'foo', 'bar'})
  747. self.app.amqp.queues.select.assert_called_with({'foo', 'bar'})
  748. class test_defaults(AppCase):
  749. def test_strtobool(self):
  750. for s in ('false', 'no', '0'):
  751. self.assertFalse(defaults.strtobool(s))
  752. for s in ('true', 'yes', '1'):
  753. self.assertTrue(defaults.strtobool(s))
  754. with self.assertRaises(TypeError):
  755. defaults.strtobool('unsure')
  756. class test_debugging_utils(AppCase):
  757. def test_enable_disable_trace(self):
  758. try:
  759. _app.enable_trace()
  760. self.assertEqual(_app.app_or_default, _app._app_or_default_trace)
  761. _app.disable_trace()
  762. self.assertEqual(_app.app_or_default, _app._app_or_default)
  763. finally:
  764. _app.disable_trace()
  765. class test_pyimplementation(AppCase):
  766. def test_platform_python_implementation(self):
  767. with mock.platform_pyimp(lambda: 'Xython'):
  768. self.assertEqual(pyimplementation(), 'Xython')
  769. def test_platform_jython(self):
  770. with mock.platform_pyimp():
  771. with mock.sys_platform('java 1.6.51'):
  772. self.assertIn('Jython', pyimplementation())
  773. def test_platform_pypy(self):
  774. with mock.platform_pyimp():
  775. with mock.sys_platform('darwin'):
  776. with mock.pypy_version((1, 4, 3)):
  777. self.assertIn('PyPy', pyimplementation())
  778. with mock.pypy_version((1, 4, 3, 'a4')):
  779. self.assertIn('PyPy', pyimplementation())
  780. def test_platform_fallback(self):
  781. with mock.platform_pyimp():
  782. with mock.sys_platform('darwin'):
  783. with mock.pypy_version():
  784. self.assertEqual('CPython', pyimplementation())
  785. class test_shared_task(AppCase):
  786. def test_registers_to_all_apps(self):
  787. with self.Celery('xproj', set_as_current=True) as xproj:
  788. xproj.finalize()
  789. @shared_task
  790. def foo():
  791. return 42
  792. @shared_task()
  793. def bar():
  794. return 84
  795. self.assertIs(foo.app, xproj)
  796. self.assertIs(bar.app, xproj)
  797. self.assertTrue(foo._get_current_object())
  798. with self.Celery('yproj', set_as_current=True) as yproj:
  799. self.assertIs(foo.app, yproj)
  800. self.assertIs(bar.app, yproj)
  801. @shared_task()
  802. def baz():
  803. return 168
  804. self.assertIs(baz.app, yproj)