test_mongodb.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. from __future__ import absolute_import
  2. import datetime
  3. import uuid
  4. from pickle import loads, dumps
  5. from celery import states
  6. from celery.backends import mongodb as module
  7. from celery.backends.mongodb import MongoBackend, Bunch, pymongo
  8. from celery.exceptions import ImproperlyConfigured
  9. from celery.tests.case import (
  10. AppCase, MagicMock, Mock, SkipTest, ANY,
  11. depends_on_current_app, patch, sentinel,
  12. )
  13. COLLECTION = 'taskmeta_celery'
  14. TASK_ID = str(uuid.uuid1())
  15. MONGODB_HOST = 'localhost'
  16. MONGODB_PORT = 27017
  17. MONGODB_USER = 'mongo'
  18. MONGODB_PASSWORD = '1234'
  19. MONGODB_DATABASE = 'testing'
  20. MONGODB_COLLECTION = 'collection1'
  21. class test_MongoBackend(AppCase):
  22. def setup(self):
  23. if pymongo is None:
  24. raise SkipTest('pymongo is not installed.')
  25. R = self._reset = {}
  26. R['encode'], MongoBackend.encode = MongoBackend.encode, Mock()
  27. R['decode'], MongoBackend.decode = MongoBackend.decode, Mock()
  28. R['Binary'], module.Binary = module.Binary, Mock()
  29. R['datetime'], datetime.datetime = datetime.datetime, Mock()
  30. self.backend = MongoBackend(app=self.app)
  31. def teardown(self):
  32. MongoBackend.encode = self._reset['encode']
  33. MongoBackend.decode = self._reset['decode']
  34. module.Binary = self._reset['Binary']
  35. datetime.datetime = self._reset['datetime']
  36. def test_Bunch(self):
  37. x = Bunch(foo='foo', bar=2)
  38. self.assertEqual(x.foo, 'foo')
  39. self.assertEqual(x.bar, 2)
  40. def test_init_no_mongodb(self):
  41. prev, module.pymongo = module.pymongo, None
  42. try:
  43. with self.assertRaises(ImproperlyConfigured):
  44. MongoBackend(app=self.app)
  45. finally:
  46. module.pymongo = prev
  47. def test_init_no_settings(self):
  48. self.app.conf.CELERY_MONGODB_BACKEND_SETTINGS = []
  49. with self.assertRaises(ImproperlyConfigured):
  50. MongoBackend(app=self.app)
  51. def test_init_settings_is_None(self):
  52. self.app.conf.CELERY_MONGODB_BACKEND_SETTINGS = None
  53. MongoBackend(app=self.app)
  54. def test_restore_group_no_entry(self):
  55. x = MongoBackend(app=self.app)
  56. x.collection = Mock()
  57. fo = x.collection.find_one = Mock()
  58. fo.return_value = None
  59. self.assertIsNone(x._restore_group('1f3fab'))
  60. @depends_on_current_app
  61. def test_reduce(self):
  62. x = MongoBackend(app=self.app)
  63. self.assertTrue(loads(dumps(x)))
  64. def test_get_connection_connection_exists(self):
  65. with patch('pymongo.MongoClient') as mock_Connection:
  66. self.backend._connection = sentinel._connection
  67. connection = self.backend._get_connection()
  68. self.assertEqual(sentinel._connection, connection)
  69. self.assertFalse(mock_Connection.called)
  70. def test_get_connection_no_connection_host(self):
  71. with patch('pymongo.MongoClient') as mock_Connection:
  72. self.backend._connection = None
  73. self.backend.host = MONGODB_HOST
  74. self.backend.port = MONGODB_PORT
  75. mock_Connection.return_value = sentinel.connection
  76. connection = self.backend._get_connection()
  77. mock_Connection.assert_called_once_with(
  78. host='mongodb://localhost:27017', ssl=False, max_pool_size=10,
  79. auto_start_request=False)
  80. self.assertEqual(sentinel.connection, connection)
  81. def test_get_connection_no_connection_mongodb_uri(self):
  82. with patch('pymongo.MongoClient') as mock_Connection:
  83. mongodb_uri = 'mongodb://%s:%d' % (MONGODB_HOST, MONGODB_PORT)
  84. self.backend._connection = None
  85. self.backend.host = mongodb_uri
  86. mock_Connection.return_value = sentinel.connection
  87. connection = self.backend._get_connection()
  88. mock_Connection.assert_called_once_with(
  89. host=mongodb_uri, ssl=False, max_pool_size=10,
  90. auto_start_request=False)
  91. self.assertEqual(sentinel.connection, connection)
  92. @patch('celery.backends.mongodb.MongoBackend._get_connection')
  93. def test_get_database_no_existing(self, mock_get_connection):
  94. # Should really check for combinations of these two, to be complete.
  95. self.backend.user = MONGODB_USER
  96. self.backend.password = MONGODB_PASSWORD
  97. mock_database = Mock()
  98. mock_connection = MagicMock(spec=['__getitem__'])
  99. mock_connection.__getitem__.return_value = mock_database
  100. mock_get_connection.return_value = mock_connection
  101. database = self.backend.database
  102. self.assertTrue(database is mock_database)
  103. self.assertTrue(self.backend.__dict__['database'] is mock_database)
  104. mock_database.authenticate.assert_called_once_with(
  105. MONGODB_USER, MONGODB_PASSWORD)
  106. @patch('celery.backends.mongodb.MongoBackend._get_connection')
  107. def test_get_database_no_existing_no_auth(self, mock_get_connection):
  108. # Should really check for combinations of these two, to be complete.
  109. self.backend.user = None
  110. self.backend.password = None
  111. mock_database = Mock()
  112. mock_connection = MagicMock(spec=['__getitem__'])
  113. mock_connection.__getitem__.return_value = mock_database
  114. mock_get_connection.return_value = mock_connection
  115. database = self.backend.database
  116. self.assertTrue(database is mock_database)
  117. self.assertFalse(mock_database.authenticate.called)
  118. self.assertTrue(self.backend.__dict__['database'] is mock_database)
  119. def test_process_cleanup(self):
  120. self.backend._connection = None
  121. self.backend.process_cleanup()
  122. self.assertEqual(self.backend._connection, None)
  123. self.backend._connection = 'not none'
  124. self.backend.process_cleanup()
  125. self.assertEqual(self.backend._connection, None)
  126. @patch('celery.backends.mongodb.MongoBackend._get_database')
  127. def test_store_result(self, mock_get_database):
  128. self.backend.taskmeta_collection = MONGODB_COLLECTION
  129. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  130. mock_collection = Mock()
  131. mock_get_database.return_value = mock_database
  132. mock_database.__getitem__.return_value = mock_collection
  133. ret_val = self.backend._store_result(
  134. sentinel.task_id, sentinel.result, sentinel.status)
  135. mock_get_database.assert_called_once_with()
  136. mock_database.__getitem__.assert_called_once_with(MONGODB_COLLECTION)
  137. mock_collection.save.assert_called_once_with(ANY)
  138. self.assertEqual(sentinel.result, ret_val)
  139. @patch('celery.backends.mongodb.MongoBackend._get_database')
  140. def test_get_task_meta_for(self, mock_get_database):
  141. datetime.datetime = self._reset['datetime']
  142. self.backend.taskmeta_collection = MONGODB_COLLECTION
  143. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  144. mock_collection = Mock()
  145. mock_collection.find_one.return_value = MagicMock()
  146. mock_get_database.return_value = mock_database
  147. mock_database.__getitem__.return_value = mock_collection
  148. ret_val = self.backend._get_task_meta_for(sentinel.task_id)
  149. mock_get_database.assert_called_once_with()
  150. mock_database.__getitem__.assert_called_once_with(MONGODB_COLLECTION)
  151. self.assertEqual(
  152. ['status', 'task_id', 'date_done', 'traceback', 'result',
  153. 'children'],
  154. list(ret_val.keys()))
  155. @patch('celery.backends.mongodb.MongoBackend._get_database')
  156. def test_get_task_meta_for_no_result(self, mock_get_database):
  157. self.backend.taskmeta_collection = MONGODB_COLLECTION
  158. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  159. mock_collection = Mock()
  160. mock_collection.find_one.return_value = None
  161. mock_get_database.return_value = mock_database
  162. mock_database.__getitem__.return_value = mock_collection
  163. ret_val = self.backend._get_task_meta_for(sentinel.task_id)
  164. mock_get_database.assert_called_once_with()
  165. mock_database.__getitem__.assert_called_once_with(MONGODB_COLLECTION)
  166. self.assertEqual({'status': states.PENDING, 'result': None}, ret_val)
  167. @patch('celery.backends.mongodb.MongoBackend._get_database')
  168. def test_save_group(self, mock_get_database):
  169. self.backend.taskmeta_collection = MONGODB_COLLECTION
  170. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  171. mock_collection = Mock()
  172. mock_get_database.return_value = mock_database
  173. mock_database.__getitem__.return_value = mock_collection
  174. ret_val = self.backend._save_group(
  175. sentinel.taskset_id, sentinel.result)
  176. mock_get_database.assert_called_once_with()
  177. mock_database.__getitem__.assert_called_once_with(MONGODB_COLLECTION)
  178. mock_collection.save.assert_called_once_with(ANY)
  179. self.assertEqual(sentinel.result, ret_val)
  180. @patch('celery.backends.mongodb.MongoBackend._get_database')
  181. def test_restore_group(self, mock_get_database):
  182. self.backend.taskmeta_collection = MONGODB_COLLECTION
  183. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  184. mock_collection = Mock()
  185. mock_collection.find_one.return_value = MagicMock()
  186. mock_get_database.return_value = mock_database
  187. mock_database.__getitem__.return_value = mock_collection
  188. ret_val = self.backend._restore_group(sentinel.taskset_id)
  189. mock_get_database.assert_called_once_with()
  190. mock_database.__getitem__.assert_called_once_with(MONGODB_COLLECTION)
  191. mock_collection.find_one.assert_called_once_with(
  192. {'_id': sentinel.taskset_id})
  193. self.assertEqual(
  194. ['date_done', 'result', 'task_id'],
  195. list(ret_val.keys()),
  196. )
  197. @patch('celery.backends.mongodb.MongoBackend._get_database')
  198. def test_delete_group(self, mock_get_database):
  199. self.backend.taskmeta_collection = MONGODB_COLLECTION
  200. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  201. mock_collection = Mock()
  202. mock_get_database.return_value = mock_database
  203. mock_database.__getitem__.return_value = mock_collection
  204. self.backend._delete_group(sentinel.taskset_id)
  205. mock_get_database.assert_called_once_with()
  206. mock_database.__getitem__.assert_called_once_with(MONGODB_COLLECTION)
  207. mock_collection.remove.assert_called_once_with(
  208. {'_id': sentinel.taskset_id})
  209. @patch('celery.backends.mongodb.MongoBackend._get_database')
  210. def test_forget(self, mock_get_database):
  211. self.backend.taskmeta_collection = MONGODB_COLLECTION
  212. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  213. mock_collection = Mock()
  214. mock_get_database.return_value = mock_database
  215. mock_database.__getitem__.return_value = mock_collection
  216. self.backend._forget(sentinel.task_id)
  217. mock_get_database.assert_called_once_with()
  218. mock_database.__getitem__.assert_called_once_with(
  219. MONGODB_COLLECTION)
  220. mock_collection.remove.assert_called_once_with(
  221. {'_id': sentinel.task_id})
  222. @patch('celery.backends.mongodb.MongoBackend._get_database')
  223. def test_cleanup(self, mock_get_database):
  224. datetime.datetime = self._reset['datetime']
  225. self.backend.taskmeta_collection = MONGODB_COLLECTION
  226. mock_database = MagicMock(spec=['__getitem__', '__setitem__'])
  227. mock_collection = Mock()
  228. mock_get_database.return_value = mock_database
  229. mock_database.__getitem__.return_value = mock_collection
  230. self.backend.app.now = datetime.datetime.utcnow
  231. self.backend.cleanup()
  232. mock_get_database.assert_called_once_with()
  233. mock_database.__getitem__.assert_called_once_with(
  234. MONGODB_COLLECTION)
  235. mock_collection.assert_called_once_with()
  236. def test_get_database_authfailure(self):
  237. x = MongoBackend(app=self.app)
  238. x._get_connection = Mock()
  239. conn = x._get_connection.return_value = {}
  240. db = conn[x.database_name] = Mock()
  241. db.authenticate.return_value = False
  242. x.user = 'jerry'
  243. x.password = 'cere4l'
  244. with self.assertRaises(ImproperlyConfigured):
  245. x._get_database()
  246. db.authenticate.assert_called_with('jerry', 'cere4l')