187 lines
4.3 KiB
Python
187 lines
4.3 KiB
Python
import asyncio
|
|
from functools import partial
|
|
|
|
import pytest
|
|
from great_ai.external.async_lru import alru_cache
|
|
|
|
alru_cache_attrs = [
|
|
"hits",
|
|
"misses",
|
|
"tasks",
|
|
"closed",
|
|
"cache_info",
|
|
"cache_clear",
|
|
"invalidate",
|
|
"close",
|
|
"open",
|
|
]
|
|
|
|
alru_cache_calable_attrs = alru_cache_attrs.copy()
|
|
for attr in ["hits", "misses", "tasks", "closed"]:
|
|
alru_cache_calable_attrs.remove(attr)
|
|
|
|
|
|
def test_alru_cache_not_callable(loop):
|
|
with pytest.raises(NotImplementedError):
|
|
alru_cache("foo")
|
|
|
|
|
|
def test_alru_cache_not_coroutine(loop):
|
|
with pytest.raises(RuntimeError):
|
|
|
|
@alru_cache
|
|
def not_coro(val):
|
|
return val
|
|
|
|
|
|
def test_alru_cache_deco(loop, check_lru):
|
|
asyncio.set_event_loop(loop)
|
|
|
|
@alru_cache
|
|
async def coro():
|
|
pass
|
|
|
|
assert asyncio.iscoroutinefunction(coro)
|
|
|
|
for attr in alru_cache_attrs:
|
|
assert hasattr(coro, attr)
|
|
for attr in alru_cache_calable_attrs:
|
|
assert callable(getattr(coro, attr))
|
|
|
|
assert isinstance(coro._cache, dict)
|
|
assert isinstance(coro.tasks, set)
|
|
check_lru(coro, hits=0, misses=0, cache=0, tasks=0)
|
|
|
|
awaitable = coro()
|
|
assert asyncio.iscoroutine(awaitable)
|
|
loop.run_until_complete(awaitable)
|
|
|
|
|
|
def test_alru_cache_deco_called(check_lru, loop):
|
|
asyncio.set_event_loop(loop)
|
|
|
|
@alru_cache()
|
|
async def coro():
|
|
pass
|
|
|
|
assert asyncio.iscoroutinefunction(coro)
|
|
|
|
for attr in alru_cache_attrs:
|
|
assert hasattr(coro, attr)
|
|
for attr in alru_cache_calable_attrs:
|
|
assert callable(getattr(coro, attr))
|
|
|
|
assert isinstance(coro._cache, dict)
|
|
assert isinstance(coro.tasks, set)
|
|
check_lru(coro, hits=0, misses=0, cache=0, tasks=0)
|
|
|
|
awaitable = coro()
|
|
assert asyncio.iscoroutine(awaitable)
|
|
loop.run_until_complete(awaitable)
|
|
|
|
|
|
def test_alru_cache_fn_called(check_lru, loop):
|
|
asyncio.set_event_loop(loop)
|
|
|
|
async def coro():
|
|
pass
|
|
|
|
coro_wrapped = alru_cache(coro)
|
|
|
|
assert asyncio.iscoroutinefunction(coro_wrapped)
|
|
|
|
for attr in alru_cache_attrs:
|
|
assert hasattr(coro_wrapped, attr)
|
|
for attr in alru_cache_calable_attrs:
|
|
assert callable(getattr(coro_wrapped, attr))
|
|
|
|
assert isinstance(coro_wrapped._cache, dict)
|
|
assert isinstance(coro_wrapped.tasks, set)
|
|
check_lru(coro_wrapped, hits=0, misses=0, cache=0, tasks=0)
|
|
|
|
awaitable = coro_wrapped()
|
|
assert asyncio.iscoroutine(awaitable)
|
|
loop.run_until_complete(awaitable)
|
|
|
|
|
|
def test_alru_cache_origin(loop):
|
|
asyncio.set_event_loop(loop)
|
|
|
|
async def coro():
|
|
pass
|
|
|
|
coro_wrapped = alru_cache(coro)
|
|
|
|
assert coro_wrapped._origin is coro
|
|
|
|
coro_wrapped = alru_cache(partial(coro))
|
|
|
|
assert coro_wrapped._origin is coro
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_alru_cache_await_same_result_async(check_lru, loop):
|
|
calls = 0
|
|
val = object()
|
|
|
|
@alru_cache()
|
|
async def coro():
|
|
nonlocal calls
|
|
calls += 1
|
|
|
|
return val
|
|
|
|
coros = [coro() for _ in range(100)]
|
|
ret = await asyncio.gather(*coros)
|
|
expected = [val] * 100
|
|
assert ret == expected
|
|
check_lru(coro, hits=99, misses=1, cache=1, tasks=0)
|
|
|
|
assert calls == 1
|
|
assert await coro() is val
|
|
check_lru(coro, hits=100, misses=1, cache=1, tasks=0)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_alru_cache_await_same_result_coroutine(check_lru, loop):
|
|
calls = 0
|
|
val = object()
|
|
|
|
@alru_cache()
|
|
async def coro():
|
|
nonlocal calls
|
|
calls += 1
|
|
|
|
return val
|
|
|
|
coros = [coro() for _ in range(100)]
|
|
ret = await asyncio.gather(*coros)
|
|
expected = [val] * 100
|
|
assert ret == expected
|
|
check_lru(coro, hits=99, misses=1, cache=1, tasks=0)
|
|
|
|
assert calls == 1
|
|
assert await coro() is val
|
|
check_lru(coro, hits=100, misses=1, cache=1, tasks=0)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_alru_cache_dict_not_shared(check_lru, loop):
|
|
async def coro(val):
|
|
return val
|
|
|
|
coro1 = alru_cache()(coro)
|
|
coro2 = alru_cache()(coro)
|
|
|
|
ret1 = await coro1(1)
|
|
check_lru(coro1, hits=0, misses=1, cache=1, tasks=0)
|
|
|
|
ret2 = await coro2(1)
|
|
check_lru(coro2, hits=0, misses=1, cache=1, tasks=0)
|
|
|
|
assert ret1 == ret2
|
|
|
|
assert coro1._cache[1].result() == coro2._cache[1].result()
|
|
assert coro1._cache != coro2._cache
|
|
assert coro1._cache.keys() == coro2._cache.keys()
|
|
assert coro1._cache is not coro2._cache
|