|
@@ -1,8 +1,19 @@
|
|
|
import sys
|
|
|
import unittest2 as unittest
|
|
|
|
|
|
+from itertools import cycle
|
|
|
+
|
|
|
from celery.concurrency import processes as mp
|
|
|
from celery.datastructures import ExceptionInfo
|
|
|
+from celery.utils import noop
|
|
|
+
|
|
|
+from celery.tests.utils import skip_if_quick
|
|
|
+
|
|
|
+
|
|
|
+class Object(object): # for writeable attributes.
|
|
|
+
|
|
|
+ def __init__(self, **kwargs):
|
|
|
+ [setattr(self, k, v) for k, v in kwargs.items()]
|
|
|
|
|
|
|
|
|
def to_excinfo(exc):
|
|
@@ -12,6 +23,19 @@ def to_excinfo(exc):
|
|
|
return ExceptionInfo(sys.exc_info())
|
|
|
|
|
|
|
|
|
+class MockResult(object):
|
|
|
+
|
|
|
+ def __init__(self, value, pid):
|
|
|
+ self.value = value
|
|
|
+ self.pid = pid
|
|
|
+
|
|
|
+ def worker_pids(self):
|
|
|
+ return [self.pid]
|
|
|
+
|
|
|
+ def get(self):
|
|
|
+ return self.value
|
|
|
+
|
|
|
+
|
|
|
class MockPool(object):
|
|
|
started = False
|
|
|
closed = False
|
|
@@ -22,6 +46,9 @@ class MockPool(object):
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
self.started = True
|
|
|
self._state = mp.RUN
|
|
|
+ self.processes = kwargs.get("processes")
|
|
|
+ self._pool = [Object(pid=i) for i in range(self.processes)]
|
|
|
+ self._current_proc = cycle(xrange(self.processes)).next
|
|
|
|
|
|
def close(self):
|
|
|
self.closed = True
|
|
@@ -37,10 +64,23 @@ class MockPool(object):
|
|
|
pass
|
|
|
|
|
|
|
|
|
+class ExeMockPool(MockPool):
|
|
|
+
|
|
|
+ def apply_async(self, target, args=(), kwargs={}, callback=noop):
|
|
|
+ from threading import Timer
|
|
|
+ res = target(*args, **kwargs)
|
|
|
+ Timer(0.1, callback, (res, )).start()
|
|
|
+ return MockResult(res, self._current_proc())
|
|
|
+
|
|
|
+
|
|
|
class TaskPool(mp.TaskPool):
|
|
|
Pool = MockPool
|
|
|
|
|
|
|
|
|
+class ExeMockTaskPool(mp.TaskPool):
|
|
|
+ Pool = ExeMockPool
|
|
|
+
|
|
|
+
|
|
|
class test_TaskPool(unittest.TestCase):
|
|
|
|
|
|
def test_start(self):
|
|
@@ -60,6 +100,24 @@ class test_TaskPool(unittest.TestCase):
|
|
|
pool.terminate()
|
|
|
self.assertTrue(_pool.terminated)
|
|
|
|
|
|
+ def test_pingback(self):
|
|
|
+ for i in xrange(10):
|
|
|
+ self.assertEqual(mp.pingback(i), i)
|
|
|
+
|
|
|
+ def test_on_worker_error(self):
|
|
|
+ scratch = [None]
|
|
|
+
|
|
|
+ def errback(einfo):
|
|
|
+ scratch[0] = einfo
|
|
|
+
|
|
|
+ pool = TaskPool(10)
|
|
|
+ exc = KeyError("foo")
|
|
|
+ pool.on_worker_error([errback], exc)
|
|
|
+
|
|
|
+ self.assertTrue(scratch[0])
|
|
|
+ self.assertIs(scratch[0].exception, exc)
|
|
|
+ self.assertTrue(scratch[0].traceback)
|
|
|
+
|
|
|
def test_on_ready_exception(self):
|
|
|
scratch = [None]
|
|
|
|
|
@@ -71,6 +129,25 @@ class test_TaskPool(unittest.TestCase):
|
|
|
pool.on_ready([], [errback], exc)
|
|
|
self.assertEqual(exc, scratch[0])
|
|
|
|
|
|
+ def test_safe_apply_callback(self):
|
|
|
+
|
|
|
+ _good_called = [0]
|
|
|
+ _evil_called = [0]
|
|
|
+
|
|
|
+ def good(x):
|
|
|
+ _good_called[0] = 1
|
|
|
+ return x
|
|
|
+
|
|
|
+ def evil(x):
|
|
|
+ _evil_called[0] = 1
|
|
|
+ raise KeyError(x)
|
|
|
+
|
|
|
+ pool = TaskPool(10)
|
|
|
+ self.assertIsNone(pool.safe_apply_callback(good, 10))
|
|
|
+ self.assertIsNone(pool.safe_apply_callback(evil, 10))
|
|
|
+ self.assertTrue(_good_called[0])
|
|
|
+ self.assertTrue(_evil_called[0])
|
|
|
+
|
|
|
def test_on_ready_value(self):
|
|
|
scratch = [None]
|
|
|
|
|
@@ -91,3 +168,21 @@ class test_TaskPool(unittest.TestCase):
|
|
|
pool = TaskPool(10)
|
|
|
pool.start()
|
|
|
pool.apply_async(lambda x: x, (2, ), {})
|
|
|
+
|
|
|
+ def test_info(self):
|
|
|
+ pool = TaskPool(10)
|
|
|
+ procs = [Object(pid=i) for i in range(pool.limit)]
|
|
|
+ pool._pool = Object(_pool=procs)
|
|
|
+ info = pool.info
|
|
|
+ self.assertEqual(info["max-concurrency"], pool.limit)
|
|
|
+ self.assertEqual(len(info["processes"]), pool.limit)
|
|
|
+
|
|
|
+ @skip_if_quick
|
|
|
+ def test_diagnose(self):
|
|
|
+ pool = ExeMockTaskPool(10)
|
|
|
+ pool.start()
|
|
|
+
|
|
|
+ r = pool.diagnose(timeout=None)
|
|
|
+ self.assertEqual(len(r["active"]), pool.limit)
|
|
|
+ self.assertFalse(r["waiting"])
|
|
|
+ self.assertTrue(r["iterations"])
|