Skip to content

Commit fab28fc

Browse files
committed
Added unit tests for cache
1 parent 9558526 commit fab28fc

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

tests/unit_tests/test_cache.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import asyncio
2+
import pytest
3+
from unittest import mock
4+
5+
from async_substrate_interface.utils.cache import CachedFetcher
6+
7+
8+
@pytest.mark.asyncio
9+
async def test_cached_fetcher_fetches_and_caches():
10+
"""Tests that CachedFetcher correctly fetches and caches results."""
11+
# Setup
12+
mock_method = mock.AsyncMock(side_effect=lambda x: f"result_{x}")
13+
fetcher = CachedFetcher(max_size=2, method=mock_method)
14+
15+
# First call should trigger the method
16+
result1 = await fetcher.execute("key1")
17+
assert result1 == "result_key1"
18+
mock_method.assert_awaited_once_with("key1")
19+
20+
# Second call with the same key should use the cache
21+
result2 = await fetcher.execute("key1")
22+
assert result2 == "result_key1"
23+
# Ensure the method was NOT called again
24+
assert mock_method.await_count == 1
25+
26+
# Third call with a new key triggers a method call
27+
result3 = await fetcher.execute("key2")
28+
assert result3 == "result_key2"
29+
assert mock_method.await_count == 2
30+
31+
@pytest.mark.asyncio
32+
async def test_cached_fetcher_handles_inflight_requests():
33+
"""Tests that CachedFetcher waits for in-flight results instead of re-fetching."""
34+
# Create an event to control when the mock returns
35+
event = asyncio.Event()
36+
37+
async def slow_method(x):
38+
await event.wait()
39+
return f"slow_result_{x}"
40+
41+
fetcher = CachedFetcher(max_size=2, method=slow_method)
42+
43+
# Start first request
44+
task1 = asyncio.create_task(fetcher.execute("key1"))
45+
await asyncio.sleep(0.1) # Let the task start and be inflight
46+
47+
# Second request for the same key while the first is in-flight
48+
task2 = asyncio.create_task(fetcher.execute("key1"))
49+
await asyncio.sleep(0.1)
50+
51+
# Release the inflight request
52+
event.set()
53+
result1, result2 = await asyncio.gather(task1, task2)
54+
assert result1 == result2 == "slow_result_key1"
55+
56+
@pytest.mark.asyncio
57+
async def test_cached_fetcher_propagates_errors():
58+
"""Tests that CachedFetcher correctly propagates errors."""
59+
async def error_method(x):
60+
raise ValueError("Boom!")
61+
62+
fetcher = CachedFetcher(max_size=2, method=error_method)
63+
64+
with pytest.raises(ValueError, match="Boom!"):
65+
await fetcher.execute("key1")
66+
67+
@pytest.mark.asyncio
68+
async def test_cached_fetcher_eviction():
69+
"""Tests that LRU eviction works in CachedFetcher."""
70+
mock_method = mock.AsyncMock(side_effect=lambda x: f"val_{x}")
71+
fetcher = CachedFetcher(max_size=2, method=mock_method)
72+
73+
# Fill cache
74+
await fetcher.execute("key1")
75+
await fetcher.execute("key2")
76+
assert list(fetcher._cache.cache.keys()) == list(fetcher._cache.cache.keys())
77+
78+
# Insert a new key to trigger eviction
79+
await fetcher.execute("key3")
80+
# key1 should be evicted
81+
assert "key1" not in fetcher._cache.cache
82+
assert "key2" in fetcher._cache.cache
83+
assert "key3" in fetcher._cache.cache

0 commit comments

Comments
 (0)