async def test_checkout_checkin_asyncio(mocker, redis_pool: TransportPool, get_total_redis_connections): """Check in/out many connections concurrently (using asyncio tasks) Unlike using threads, this should grow the pool """ # mocker.spy in pytest-mock runs afoul of this change in 3.8.1 # https://bugs.python.org/issue38857 # We therefore use mocker.spy for python 3.7, or the new AsyncMock in 3.8 # See: https://github.com/pytest-dev/pytest-mock/issues/178 if sys.version_info >= (3, 8): from unittest.mock import AsyncMock redis_pool.grow = AsyncMock(wraps=redis_pool.grow) redis_pool._create_transport = AsyncMock( wraps=redis_pool._create_transport) redis_pool._close_transport = AsyncMock( wraps=redis_pool._close_transport) else: mocker.spy(redis_pool, "grow") mocker.spy(redis_pool, "_create_transport") mocker.spy(redis_pool, "_close_transport") async def _check_in_out(): transport = await redis_pool.checkout() # Ensure we do something here in order to slow down the execution # time, thereby ensuring our pool starts to fill up. We also need to # use the connection to ensure the connection is lazy loaded await transport.send_event(EventMessage(api_name="api", event_name="event"), options={}) await asyncio.sleep(0.02) await redis_pool.checkin(transport) async def _check_in_out_loop(): for _ in range(0, 500 // 20): await _check_in_out() tasks = [asyncio.create_task(_check_in_out_loop()) for _ in range(0, 20)] await asyncio.wait(tasks) await redis_pool.close() assert redis_pool.grow.call_count == 20 assert redis_pool._create_transport.call_count == 20 assert redis_pool._close_transport.call_count == 20 assert await get_total_redis_connections() == 1
async def test_checkout_checkin_threaded(mocker, redis_pool: TransportPool, run_in_many_threads, get_total_redis_connections): """Check in/out many connections concurrently (using threads) Note that this will not grow the pool. See the doc string for TransportPool """ # mocker.spy in pytest-mock runs afoul of this change in 3.8.1 # https://bugs.python.org/issue38857 # We therefore use mocker.spy for python 3.7, or the new AsyncMock in 3.8. # See: https://github.com/pytest-dev/pytest-mock/issues/178 if sys.version_info >= (3, 8): from unittest.mock import AsyncMock redis_pool.grow = AsyncMock(wraps=redis_pool.grow) redis_pool._create_transport = AsyncMock( wraps=redis_pool._create_transport) redis_pool._close_transport = AsyncMock( wraps=redis_pool._close_transport) else: mocker.spy(redis_pool, "grow") mocker.spy(redis_pool, "_create_transport") mocker.spy(redis_pool, "_close_transport") async def _check_in_out(): transport = await redis_pool.checkout() # Ensure we do something here in order to slow down the execution # time, thereby ensuring our pool starts to fill up. We also need to # use the connection to ensure the connection is lazy loaded await transport.send_event(EventMessage(api_name="api", event_name="event"), options={}) await asyncio.sleep(0.02) await redis_pool.checkin(transport) run_in_many_threads(_check_in_out, executions=500, max_workers=20) # We're running in a thread, so we never grow the pool. Instead # we just return one-off connections which will be closed # when they get checked back in assert not redis_pool.grow.called assert redis_pool._create_transport.call_count == 500 assert redis_pool._close_transport.call_count == 500 assert await get_total_redis_connections() == 1