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()
 |