test_cache.pyβ’8.74 kB
"""μΊμ κ΄λ¦¬ ν
μ€νΈ"""
import pytest
import json
from unittest.mock import Mock, patch, AsyncMock
from src.utils.cache import CacheManager
from src.exceptions import CacheError
class TestCacheManager:
"""μΊμ λ§€λμ ν
μ€νΈ"""
@pytest.fixture
def cache_config(self):
"""ν
μ€νΈμ© μΊμ μ€μ """
return {
"host": "localhost",
"port": 6379,
"db": 0,
"password": None
}
@pytest.fixture
def cache_manager(self, cache_config):
"""ν
μ€νΈμ© μΊμ λ§€λμ """
return CacheManager(cache_config)
def test_cache_manager_initialization(self, cache_manager, cache_config):
"""μΊμ λ§€λμ μ΄κΈ°ν ν
μ€νΈ"""
assert cache_manager.config == cache_config
assert cache_manager.redis_client is None
assert cache_manager.default_ttl == 300
def test_connection_url_generation(self, cache_manager):
"""Redis μ°κ²° URL μμ± ν
μ€νΈ"""
expected_url = "redis://localhost:6379/0"
assert cache_manager.connection_url == expected_url
def test_connection_url_with_password(self):
"""λΉλ°λ²νΈκ° μλ Redis URL ν
μ€νΈ"""
config = {
"host": "localhost",
"port": 6379,
"db": 1,
"password": "secret123"
}
cache_manager = CacheManager(config)
expected_url = "redis://:secret123@localhost:6379/1"
assert cache_manager.connection_url == expected_url
@pytest.mark.asyncio
async def test_successful_connection(self, cache_manager):
"""μ±κ³΅μ μΈ Redis μ°κ²° ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_from_url.return_value = mock_redis
await cache_manager.connect()
assert cache_manager.redis_client == mock_redis
assert cache_manager.is_connected
mock_from_url.assert_called_once()
mock_redis.ping.assert_called_once()
@pytest.mark.asyncio
async def test_connection_failure(self, cache_manager):
"""Redis μ°κ²° μ€ν¨ ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_from_url.side_effect = Exception("Connection failed")
with pytest.raises(CacheError):
await cache_manager.connect()
assert cache_manager.redis_client is None
assert not cache_manager.is_connected
@pytest.mark.asyncio
async def test_get_existing_key(self, cache_manager):
"""μ‘΄μ¬νλ ν€ μ‘°ν ν
μ€νΈ"""
test_data = {"message": "hello", "number": 42}
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_redis.get.return_value = json.dumps(test_data)
mock_from_url.return_value = mock_redis
await cache_manager.connect()
result = await cache_manager.get("test_key")
assert result == test_data
mock_redis.get.assert_called_once_with("test_key")
@pytest.mark.asyncio
async def test_get_nonexistent_key(self, cache_manager):
"""μ‘΄μ¬νμ§ μλ ν€ μ‘°ν ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_redis.get.return_value = None
mock_from_url.return_value = mock_redis
await cache_manager.connect()
result = await cache_manager.get("nonexistent_key")
assert result is None
mock_redis.get.assert_called_once_with("nonexistent_key")
@pytest.mark.asyncio
async def test_set_with_default_ttl(self, cache_manager):
"""κΈ°λ³Έ TTLλ‘ λ°μ΄ν° μ μ₯ ν
μ€νΈ"""
test_data = {"message": "hello"}
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_redis.setex.return_value = True
mock_from_url.return_value = mock_redis
await cache_manager.connect()
result = await cache_manager.set("test_key", test_data)
assert result is True
mock_redis.setex.assert_called_once_with(
"test_key",
300, # default TTL
json.dumps(test_data, ensure_ascii=False)
)
@pytest.mark.asyncio
async def test_set_with_custom_ttl(self, cache_manager):
"""컀μ€ν
TTLλ‘ λ°μ΄ν° μ μ₯ ν
μ€νΈ"""
test_data = {"message": "hello"}
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_redis.setex.return_value = True
mock_from_url.return_value = mock_redis
await cache_manager.connect()
result = await cache_manager.set("test_key", test_data, ttl=600)
assert result is True
mock_redis.setex.assert_called_once_with(
"test_key",
600,
json.dumps(test_data, ensure_ascii=False)
)
@pytest.mark.asyncio
async def test_delete_key(self, cache_manager):
"""ν€ μμ ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_redis.delete.return_value = 1
mock_from_url.return_value = mock_redis
await cache_manager.connect()
result = await cache_manager.delete("test_key")
assert result is True
mock_redis.delete.assert_called_once_with("test_key")
@pytest.mark.asyncio
async def test_invalidate_pattern(self, cache_manager):
"""ν¨ν΄ λ§€μΉμΌλ‘ ν€ λ¬΄ν¨ν ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_redis.keys.return_value = ["market:test1", "market:test2"]
mock_redis.delete.return_value = 2
mock_from_url.return_value = mock_redis
await cache_manager.connect()
await cache_manager.invalidate_pattern("market:*")
mock_redis.keys.assert_called_once_with("market:*")
mock_redis.delete.assert_called_once_with("market:test1", "market:test2")
@pytest.mark.asyncio
async def test_operation_without_connection(self, cache_manager):
"""μ°κ²° μμ΄ μμ
μ μμΈ ν
μ€νΈ"""
with pytest.raises(CacheError):
await cache_manager.get("test_key")
with pytest.raises(CacheError):
await cache_manager.set("test_key", {"data": "test"})
@pytest.mark.asyncio
async def test_health_check_success(self, cache_manager):
"""ν¬μ€μ²΄ν¬ μ±κ³΅ ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
mock_redis.ping.return_value = True
mock_from_url.return_value = mock_redis
await cache_manager.connect()
is_healthy = await cache_manager.health_check()
assert is_healthy is True
@pytest.mark.asyncio
async def test_health_check_failure(self, cache_manager):
"""ν¬μ€μ²΄ν¬ μ€ν¨ ν
μ€νΈ"""
with patch('redis.asyncio.from_url') as mock_from_url:
mock_redis = AsyncMock()
# μ°κ²°μ μ±κ³΅νμ§λ§ ν¬μ€μ²΄ν¬μμ μ€ν¨
connect_call = [True] # 첫 νΈμΆμ μ±κ³΅
def ping_side_effect(*args, **kwargs):
if connect_call[0]:
connect_call[0] = False
return True # μ°κ²° μ μ±κ³΅
else:
raise Exception("Redis error") # ν¬μ€μ²΄ν¬ μ μ€ν¨
mock_redis.ping.side_effect = ping_side_effect
mock_from_url.return_value = mock_redis
await cache_manager.connect()
is_healthy = await cache_manager.health_check()
assert is_healthy is False