from collections import deque import datetime import os import sys import tempfile import unittest from huey.api import Huey from huey.backends.dummy import DummyDataStore from huey.backends.dummy import DummyEventEmitter from huey.backends.dummy import DummyQueue from huey.backends.dummy import DummySchedule from huey.utils import EmptyData from huey.backends.sqlite_backend import SqliteDataStore from huey.backends.sqlite_backend import SqliteQueue from huey.backends.sqlite_backend import SqliteSchedule try: from huey.backends.redis_backend import RedisDataStore from huey.backends.redis_backend import RedisEventEmitter from huey.backends.redis_backend import RedisQueue from huey.backends.redis_backend import RedisSchedule except ImportError: RedisQueue = RedisDataStore = RedisSchedule = RedisEventEmitter = None try: from huey.backends.rabbitmq_backend import RabbitQueue, RabbitEventEmitter except ImportError: RabbitQueue = RabbitEventEmitter = None if sys.version_info[0] == 2: redis_kwargs = {} else: redis_kwargs = {'decode_responses': True} QUEUES = (DummyQueue, RedisQueue, SqliteQueue, RabbitQueue) DATA_STORES = (DummyDataStore, RedisDataStore, SqliteDataStore, None) SCHEDULES = (DummySchedule, RedisSchedule, SqliteSchedule, None) EVENTS = (DummyEventEmitter, RedisEventEmitter, None, RabbitEventEmitter) class HueyBackendTestCase(unittest.TestCase): def setUp(self): self.sqlite_location = tempfile.mkstemp(prefix='hueytest.')[1] def tearDown(self): os.unlink(self.sqlite_location) def test_queues(self): result_store = DummyDataStore('dummy') for q in QUEUES: if not q: continue if issubclass(q, SqliteQueue): queue = q('test', location=self.sqlite_location) elif issubclass(q, RedisQueue): queue = q('test', **redis_kwargs) else: queue = q('test') queue.flush() queue.write('a') queue.write('b') self.assertEqual(len(queue), 2) self.assertEqual(queue.read(), 'a') self.assertEqual(queue.read(), 'b') self.assertEqual(queue.read(), None) queue.write('c') queue.write('d') queue.write('c') queue.write('x') queue.write('d') self.assertEqual(len(queue), 5) self.assertEqual(queue.remove('c'), 2) self.assertEqual(len(queue), 3) self.assertEqual(queue.read(), 'd') self.assertEqual(queue.read(), 'x') self.assertEqual(queue.read(), 'd') queue.flush() test_huey = Huey(queue, result_store) @test_huey.task() def test_queues_add(k, v): return k + v res = test_queues_add('k', 'v') self.assertEqual(len(queue), 1) task = test_huey.dequeue() test_huey.execute(task) self.assertEqual(res.get(), 'kv') res = test_queues_add('\xce', '\xcf') task = test_huey.dequeue() test_huey.execute(task) self.assertEqual(res.get(), '\xce\xcf') def test_data_stores(self): for d in DATA_STORES: if not d: continue if issubclass(d, SqliteDataStore): data_store = d('test', location=self.sqlite_location) elif issubclass(d, RedisDataStore): data_store = d('test', **redis_kwargs) else: data_store = d('test') data_store.put('k1', 'v1') data_store.put('k2', 'v2') data_store.put('k3', 'v3') self.assertEqual(data_store.peek('k2'), 'v2') self.assertEqual(data_store.get('k2'), 'v2') self.assertEqual(data_store.peek('k2'), EmptyData) self.assertEqual(data_store.get('k2'), EmptyData) self.assertEqual(data_store.peek('k3'), 'v3') data_store.put('k3', 'v3-2') self.assertEqual(data_store.peek('k3'), 'v3-2') def test_schedules(self): for s in SCHEDULES: if not s: continue if issubclass(s, SqliteSchedule): schedule = s('test', location=self.sqlite_location) elif issubclass(s, RedisSchedule): schedule = s('test', **redis_kwargs) else: schedule = s('test') dt1 = datetime.datetime(2013, 1, 1, 0, 0) dt2 = datetime.datetime(2013, 1, 2, 0, 0) dt3 = datetime.datetime(2013, 1, 3, 0, 0) dt4 = datetime.datetime(2013, 1, 4, 0, 0) # Add to schedule out-of-order to ensure sorting is performed by # the schedule. schedule.add('s2', dt2) schedule.add('s1', dt1) schedule.add('s4', dt4) schedule.add('s3', dt3) # Ensure that asking for a timestamp previous to any item in the # schedule returns empty list. self.assertEqual( schedule.read(dt1 - datetime.timedelta(days=1)), []) # Ensure the upper boundary is inclusive of whatever timestamp # is passed in. self.assertEqual(schedule.read(dt3), ['s1', 's2', 's3']) self.assertEqual(schedule.read(dt3), []) # Ensure the schedule is flushed and an empty schedule returns an # empty list. self.assertEqual(schedule.read(dt4), ['s4']) self.assertEqual(schedule.read(dt4), []) def test_events(self): for e in EVENTS: if not e: continue e = e('test') messages = ['a', 'b', 'c', 'd'] for message in messages: e.emit(message) if hasattr(e, '_events'): self.assertEqual(e._events, deque(['d', 'c', 'b', 'a']))