Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_SQS.py 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. """Testing module for the kombu.transport.SQS package.
  2. NOTE: The SQSQueueMock and SQSConnectionMock classes originally come from
  3. http://github.com/pcsforeducation/sqs-mock-python. They have been patched
  4. slightly.
  5. """
  6. from __future__ import absolute_import
  7. import sys
  8. from kombu import Connection
  9. from kombu import messaging
  10. from kombu import five
  11. from kombu.tests.case import Case, SkipTest
  12. import kombu
  13. if sys.version_info[0] >= 3:
  14. SQS, skip_reason = None, 'boto does not support Python 3' # noqa
  15. else:
  16. try:
  17. from kombu.transport import SQS
  18. except ImportError:
  19. # Boto must not be installed if the SQS transport fails to import,
  20. # so we skip all unit tests. Set SQS to None here, and it will be
  21. # checked during the setUp() phase later.
  22. SQS, skip_reason = None, 'boto not installed' # noqa
  23. class SQSQueueMock(object):
  24. def __init__(self, name):
  25. self.name = name
  26. self.messages = []
  27. self._get_message_calls = 0
  28. def clear(self, page_size=10, vtimeout=10):
  29. empty, self.messages[:] = not self.messages, []
  30. return not empty
  31. def count(self, page_size=10, vtimeout=10):
  32. return len(self.messages)
  33. count_slow = count
  34. def delete(self):
  35. self.messages[:] = []
  36. return True
  37. def delete_message(self, message):
  38. try:
  39. self.messages.remove(message)
  40. except ValueError:
  41. return False
  42. return True
  43. def get_messages(self, num_messages=1, visibility_timeout=None,
  44. attributes=None, *args, **kwargs):
  45. self._get_message_calls += 1
  46. return self.messages[:num_messages]
  47. def read(self, visibility_timeout=None):
  48. return self.messages.pop(0)
  49. def write(self, message):
  50. self.messages.append(message)
  51. return True
  52. class SQSConnectionMock(object):
  53. def __init__(self):
  54. self.queues = {}
  55. def get_queue(self, queue):
  56. return self.queues.get(queue)
  57. def get_all_queues(self, prefix=""):
  58. return self.queues.values()
  59. def delete_queue(self, queue, force_deletion=False):
  60. q = self.get_queue(queue)
  61. if q:
  62. if q.count():
  63. return False
  64. q.clear()
  65. self.queues.pop(queue, None)
  66. def delete_message(self, queue, message):
  67. return queue.delete_message(message)
  68. def create_queue(self, name, *args, **kwargs):
  69. q = self.queues[name] = SQSQueueMock(name)
  70. return q
  71. class test_Channel(Case):
  72. def handleMessageCallback(self, message):
  73. self.callback_message = message
  74. def setUp(self):
  75. """Mock the back-end SQS classes"""
  76. # Sanity check... if SQS is None, then it did not import and we
  77. # cannot execute our tests.
  78. if SQS is None:
  79. raise SkipTest(skip_reason)
  80. SQS.Channel._queue_cache.clear()
  81. # Common variables used in the unit tests
  82. self.queue_name = 'unittest'
  83. # Mock the sqs() method that returns an SQSConnection object and
  84. # instead return an SQSConnectionMock() object.
  85. self.sqs_conn_mock = SQSConnectionMock()
  86. def mock_sqs():
  87. return self.sqs_conn_mock
  88. SQS.Channel.sqs = mock_sqs()
  89. # Set up a task exchange for passing tasks through the queue
  90. self.exchange = kombu.Exchange('test_SQS', type='direct')
  91. self.queue = kombu.Queue(self.queue_name,
  92. self.exchange,
  93. self.queue_name)
  94. # Mock up a test SQS Queue with the SQSQueueMock class (and always
  95. # make sure its a clean empty queue)
  96. self.sqs_queue_mock = SQSQueueMock(self.queue_name)
  97. # Now, create our Connection object with the SQS Transport and store
  98. # the connection/channel objects as references for use in these tests.
  99. self.connection = Connection(transport=SQS.Transport)
  100. self.channel = self.connection.channel()
  101. self.queue(self.channel).declare()
  102. self.producer = messaging.Producer(self.channel,
  103. self.exchange,
  104. routing_key=self.queue_name)
  105. # Lastly, make sure that we're set up to 'consume' this queue.
  106. self.channel.basic_consume(self.queue_name,
  107. no_ack=True,
  108. callback=self.handleMessageCallback,
  109. consumer_tag='unittest')
  110. def test_init(self):
  111. """kombu.SQS.Channel instantiates correctly with mocked queues"""
  112. self.assertIn(self.queue_name, self.channel._queue_cache)
  113. def test_new_queue(self):
  114. queue_name = 'new_unittest_queue'
  115. self.channel._new_queue(queue_name)
  116. self.assertIn(queue_name, self.sqs_conn_mock.queues)
  117. # For cleanup purposes, delete the queue and the queue file
  118. self.channel._delete(queue_name)
  119. def test_delete(self):
  120. queue_name = 'new_unittest_queue'
  121. self.channel._new_queue(queue_name)
  122. self.channel._delete(queue_name)
  123. self.assertNotIn(queue_name, self.channel._queue_cache)
  124. def test_get_from_sqs(self):
  125. # Test getting a single message
  126. message = 'my test message'
  127. self.producer.publish(message)
  128. results = self.channel._get_from_sqs(self.queue_name)
  129. self.assertEqual(len(results), 1)
  130. # Now test getting many messages
  131. for i in range(3):
  132. message = 'message: {0}'.format(i)
  133. self.producer.publish(message)
  134. results = self.channel._get_from_sqs(self.queue_name, count=3)
  135. self.assertEqual(len(results), 3)
  136. def test_get_with_empty_list(self):
  137. with self.assertRaises(five.Empty):
  138. self.channel._get(self.queue_name)
  139. def test_get_bulk_raises_empty(self):
  140. with self.assertRaises(five.Empty):
  141. self.channel._get_bulk(self.queue_name)
  142. def test_messages_to_python(self):
  143. message_count = 3
  144. # Create several test messages and publish them
  145. for i in range(message_count):
  146. message = 'message: %s' % i
  147. self.producer.publish(message)
  148. # Get the messages now
  149. messages = self.channel._get_from_sqs(
  150. self.queue_name, count=message_count,
  151. )
  152. # Now convert them to payloads
  153. payloads = self.channel._messages_to_python(
  154. messages, self.queue_name,
  155. )
  156. # We got the same number of payloads back, right?
  157. self.assertEqual(len(payloads), message_count)
  158. # Make sure they're payload-style objects
  159. for p in payloads:
  160. self.assertTrue('properties' in p)
  161. def test_put_and_get(self):
  162. message = 'my test message'
  163. self.producer.publish(message)
  164. results = self.queue(self.channel).get().payload
  165. self.assertEqual(message, results)
  166. def test_puts_and_gets(self):
  167. for i in range(3):
  168. message = 'message: %s' % i
  169. self.producer.publish(message)
  170. for i in range(3):
  171. self.assertEqual('message: %s' % i,
  172. self.queue(self.channel).get().payload)
  173. def test_put_and_get_bulk(self):
  174. # With QoS.prefetch_count = 0
  175. message = 'my test message'
  176. self.producer.publish(message)
  177. results = self.channel._get_bulk(self.queue_name)
  178. self.assertEqual(1, len(results))
  179. def test_puts_and_get_bulk(self):
  180. # Generate 8 messages
  181. message_count = 8
  182. # Set the prefetch_count to 5
  183. self.channel.qos.prefetch_count = 5
  184. # Now, generate all the messages
  185. for i in range(message_count):
  186. message = 'message: %s' % i
  187. self.producer.publish(message)
  188. # Count how many messages are retrieved the first time. Should
  189. # be 5 (message_count).
  190. results = self.channel._get_bulk(self.queue_name)
  191. self.assertEqual(5, len(results))
  192. # Now, do the get again, the number of messages returned should be 3.
  193. results = self.channel._get_bulk(self.queue_name)
  194. self.assertEqual(3, len(results))
  195. def test_drain_events_with_empty_list(self):
  196. def mock_can_consume():
  197. return False
  198. self.channel.qos.can_consume = mock_can_consume
  199. with self.assertRaises(five.Empty):
  200. self.channel.drain_events()
  201. def test_drain_events_with_prefetch_5(self):
  202. # Generate 20 messages
  203. message_count = 20
  204. expected_get_message_count = 4
  205. # Set the prefetch_count to 5
  206. self.channel.qos.prefetch_count = 5
  207. # Now, generate all the messages
  208. for i in range(message_count):
  209. self.producer.publish('message: %s' % i)
  210. # Now drain all the events
  211. for i in range(message_count):
  212. self.channel.drain_events()
  213. # How many times was the SQSConnectionMock get_message method called?
  214. self.assertEqual(
  215. expected_get_message_count,
  216. self.channel._queue_cache[self.queue_name]._get_message_calls)
  217. def test_drain_events_with_prefetch_none(self):
  218. # Generate 20 messages
  219. message_count = 20
  220. expected_get_message_count = 2
  221. # Set the prefetch_count to None
  222. self.channel.qos.prefetch_count = None
  223. # Now, generate all the messages
  224. for i in range(message_count):
  225. self.producer.publish('message: %s' % i)
  226. # Now drain all the events
  227. for i in range(message_count):
  228. self.channel.drain_events()
  229. # How many times was the SQSConnectionMock get_message method called?
  230. self.assertEqual(
  231. expected_get_message_count,
  232. self.channel._queue_cache[self.queue_name]._get_message_calls)