233 lines
6.3 KiB
Python
233 lines
6.3 KiB
Python
from unittest import TestCase, main
|
|
|
|
import eventlet
|
|
from eventlet import Queue
|
|
from eventlet import pools
|
|
from eventlet.support import six
|
|
|
|
|
|
class IntPool(pools.Pool):
|
|
def create(self):
|
|
self.current_integer = getattr(self, 'current_integer', 0) + 1
|
|
return self.current_integer
|
|
|
|
|
|
class TestIntPool(TestCase):
|
|
def setUp(self):
|
|
self.pool = IntPool(min_size=0, max_size=4)
|
|
|
|
def test_integers(self):
|
|
# Do not actually use this pattern in your code. The pool will be
|
|
# exhausted, and unrestoreable.
|
|
# If you do a get, you should ALWAYS do a put, probably like this:
|
|
# try:
|
|
# thing = self.pool.get()
|
|
# do stuff
|
|
# finally:
|
|
# self.pool.put(thing)
|
|
|
|
# with self.pool.some_api_name() as thing:
|
|
# do stuff
|
|
self.assertEqual(self.pool.get(), 1)
|
|
self.assertEqual(self.pool.get(), 2)
|
|
self.assertEqual(self.pool.get(), 3)
|
|
self.assertEqual(self.pool.get(), 4)
|
|
|
|
def test_free(self):
|
|
self.assertEqual(self.pool.free(), 4)
|
|
gotten = self.pool.get()
|
|
self.assertEqual(self.pool.free(), 3)
|
|
self.pool.put(gotten)
|
|
self.assertEqual(self.pool.free(), 4)
|
|
|
|
def test_exhaustion(self):
|
|
waiter = Queue(0)
|
|
|
|
def consumer():
|
|
gotten = None
|
|
try:
|
|
gotten = self.pool.get()
|
|
finally:
|
|
waiter.put(gotten)
|
|
|
|
eventlet.spawn(consumer)
|
|
|
|
one, two, three, four = (
|
|
self.pool.get(), self.pool.get(), self.pool.get(), self.pool.get())
|
|
self.assertEqual(self.pool.free(), 0)
|
|
|
|
# Let consumer run; nothing will be in the pool, so he will wait
|
|
eventlet.sleep(0)
|
|
|
|
# Wake consumer
|
|
self.pool.put(one)
|
|
|
|
# wait for the consumer
|
|
self.assertEqual(waiter.get(), one)
|
|
|
|
def test_blocks_on_pool(self):
|
|
waiter = Queue(0)
|
|
|
|
def greedy():
|
|
self.pool.get()
|
|
self.pool.get()
|
|
self.pool.get()
|
|
self.pool.get()
|
|
# No one should be waiting yet.
|
|
self.assertEqual(self.pool.waiting(), 0)
|
|
# The call to the next get will unschedule this routine.
|
|
self.pool.get()
|
|
# So this put should never be called.
|
|
waiter.put('Failed!')
|
|
|
|
killable = eventlet.spawn(greedy)
|
|
|
|
# no one should be waiting yet.
|
|
self.assertEqual(self.pool.waiting(), 0)
|
|
|
|
# Wait for greedy
|
|
eventlet.sleep(0)
|
|
|
|
# Greedy should be blocking on the last get
|
|
self.assertEqual(self.pool.waiting(), 1)
|
|
|
|
# Send will never be called, so balance should be 0.
|
|
self.assertFalse(not waiter.full())
|
|
|
|
eventlet.kill(killable)
|
|
|
|
def test_ordering(self):
|
|
# normal case is that items come back out in the
|
|
# same order they are put
|
|
one, two = self.pool.get(), self.pool.get()
|
|
self.pool.put(one)
|
|
self.pool.put(two)
|
|
self.assertEqual(self.pool.get(), one)
|
|
self.assertEqual(self.pool.get(), two)
|
|
|
|
def test_putting_to_queue(self):
|
|
timer = eventlet.Timeout(0.1)
|
|
try:
|
|
size = 2
|
|
self.pool = IntPool(min_size=0, max_size=size)
|
|
queue = Queue()
|
|
results = []
|
|
|
|
def just_put(pool_item, index):
|
|
self.pool.put(pool_item)
|
|
queue.put(index)
|
|
for index in six.moves.range(size + 1):
|
|
pool_item = self.pool.get()
|
|
eventlet.spawn(just_put, pool_item, index)
|
|
|
|
for _ in six.moves.range(size + 1):
|
|
x = queue.get()
|
|
results.append(x)
|
|
self.assertEqual(sorted(results), list(six.moves.range(size + 1)))
|
|
finally:
|
|
timer.cancel()
|
|
|
|
def test_resize(self):
|
|
pool = IntPool(max_size=2)
|
|
a = pool.get()
|
|
b = pool.get()
|
|
self.assertEqual(pool.free(), 0)
|
|
|
|
# verify that the pool discards excess items put into it
|
|
pool.resize(1)
|
|
pool.put(a)
|
|
pool.put(b)
|
|
self.assertEqual(pool.free(), 1)
|
|
|
|
# resize larger and assert that there are more free items
|
|
pool.resize(2)
|
|
self.assertEqual(pool.free(), 2)
|
|
|
|
def test_create_contention(self):
|
|
creates = [0]
|
|
|
|
def sleep_create():
|
|
creates[0] += 1
|
|
eventlet.sleep()
|
|
return "slept"
|
|
|
|
p = pools.Pool(max_size=4, create=sleep_create)
|
|
|
|
def do_get():
|
|
x = p.get()
|
|
self.assertEqual(x, "slept")
|
|
p.put(x)
|
|
|
|
gp = eventlet.GreenPool()
|
|
for i in six.moves.range(100):
|
|
gp.spawn_n(do_get)
|
|
gp.waitall()
|
|
self.assertEqual(creates[0], 4)
|
|
|
|
|
|
class TestAbstract(TestCase):
|
|
mode = 'static'
|
|
|
|
def test_abstract(self):
|
|
# Going for 100% coverage here
|
|
# A Pool cannot be used without overriding create()
|
|
pool = pools.Pool()
|
|
self.assertRaises(NotImplementedError, pool.get)
|
|
|
|
|
|
class TestIntPool2(TestCase):
|
|
mode = 'static'
|
|
|
|
def setUp(self):
|
|
self.pool = IntPool(min_size=3, max_size=3)
|
|
|
|
def test_something(self):
|
|
self.assertEqual(len(self.pool.free_items), 3)
|
|
# Cover the clause in get where we get from the free list instead of creating
|
|
# an item on get
|
|
gotten = self.pool.get()
|
|
self.assertEqual(gotten, 1)
|
|
|
|
|
|
class TestOrderAsStack(TestCase):
|
|
mode = 'static'
|
|
|
|
def setUp(self):
|
|
self.pool = IntPool(max_size=3, order_as_stack=True)
|
|
|
|
def test_ordering(self):
|
|
# items come out in the reverse order they are put
|
|
one, two = self.pool.get(), self.pool.get()
|
|
self.pool.put(one)
|
|
self.pool.put(two)
|
|
self.assertEqual(self.pool.get(), two)
|
|
self.assertEqual(self.pool.get(), one)
|
|
|
|
|
|
class RaisePool(pools.Pool):
|
|
def create(self):
|
|
raise RuntimeError()
|
|
|
|
|
|
class TestCreateRaises(TestCase):
|
|
mode = 'static'
|
|
|
|
def setUp(self):
|
|
self.pool = RaisePool(max_size=3)
|
|
|
|
def test_it(self):
|
|
self.assertEqual(self.pool.free(), 3)
|
|
self.assertRaises(RuntimeError, self.pool.get)
|
|
self.assertEqual(self.pool.free(), 3)
|
|
|
|
|
|
ALWAYS = RuntimeError('I always fail')
|
|
SOMETIMES = RuntimeError('I fail half the time')
|
|
|
|
|
|
class TestTookTooLong(Exception):
|
|
pass
|
|
|
|
if __name__ == '__main__':
|
|
main()
|