Files
core/tests/test_redis_functionality.py
Untone 4b88a8c449
Some checks failed
Deploy on push / deploy (push) Failing after 1m11s
ci-testing
2025-08-17 11:09:29 +03:00

304 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Качественные тесты функциональности Redis сервиса.
Тестируем реальное поведение, а не просто наличие методов.
"""
import pytest
import asyncio
import json
from services.redis import RedisService
class TestRedisFunctionality:
"""Тесты реальной функциональности Redis"""
@pytest.fixture
async def redis_service(self):
"""Создает тестовый Redis сервис"""
service = RedisService("redis://localhost:6379/1") # Используем БД 1 для тестов
await service.connect()
yield service
await service.disconnect()
@pytest.mark.asyncio
async def test_redis_connection_lifecycle(self, redis_service):
"""Тест жизненного цикла подключения к Redis"""
# Проверяем что подключение активно
assert redis_service.is_connected is True
# Отключаемся
await redis_service.disconnect()
assert redis_service.is_connected is False
# Подключаемся снова
await redis_service.connect()
assert redis_service.is_connected is True
@pytest.mark.asyncio
async def test_redis_basic_operations(self, redis_service):
"""Тест базовых операций Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Тест SET/GET
await redis_service.set("test_key", "test_value")
result = await redis_service.get("test_key")
assert result == "test_value"
# Тест SET с TTL - используем правильный параметр 'ex'
await redis_service.set("test_key_ttl", "test_value_ttl", ex=1)
result = await redis_service.get("test_key_ttl")
assert result == "test_value_ttl"
# Ждем истечения TTL
await asyncio.sleep(1.1)
result = await redis_service.get("test_key_ttl")
assert result is None
# Тест DELETE
await redis_service.set("test_key_delete", "test_value")
await redis_service.delete("test_key_delete")
result = await redis_service.get("test_key_delete")
assert result is None
# Тест EXISTS
await redis_service.set("test_key_exists", "test_value")
exists = await redis_service.exists("test_key_exists")
assert exists is True
exists = await redis_service.exists("non_existent_key")
assert exists is False
@pytest.mark.asyncio
async def test_redis_hash_operations(self, redis_service):
"""Тест операций с хешами Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Тест HSET/HGET
await redis_service.hset("test_hash", "field1", "value1")
await redis_service.hset("test_hash", "field2", "value2")
result = await redis_service.hget("test_hash", "field1")
assert result == "value1"
result = await redis_service.hget("test_hash", "field2")
assert result == "value2"
# Тест HGETALL
all_fields = await redis_service.hgetall("test_hash")
assert all_fields == {"field1": "value1", "field2": "value2"}
@pytest.mark.asyncio
async def test_redis_set_operations(self, redis_service):
"""Тест операций с множествами Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Тест SADD
await redis_service.sadd("test_set", "member1")
await redis_service.sadd("test_set", "member2")
await redis_service.sadd("test_set", "member3")
# Тест SMEMBERS
members = await redis_service.smembers("test_set")
assert len(members) == 3
assert "member1" in members
assert "member2" in members
assert "member3" in members
# Тест SREM
await redis_service.srem("test_set", "member2")
members = await redis_service.smembers("test_set")
assert len(members) == 2
assert "member2" not in members
@pytest.mark.asyncio
async def test_redis_serialization(self, redis_service):
"""Тест сериализации/десериализации данных"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Тест с простыми типами
test_data = {
"string": "test_string",
"number": 42,
"boolean": True,
"list": [1, 2, 3],
"dict": {"nested": "value"}
}
# Сериализуем и сохраняем
await redis_service.serialize_and_set("test_serialization", test_data)
# Получаем и десериализуем
result = await redis_service.get_and_deserialize("test_serialization")
assert result == test_data
# Тест с None
await redis_service.serialize_and_set("test_none", None)
result = await redis_service.get_and_deserialize("test_none")
assert result is None
@pytest.mark.asyncio
async def test_redis_pipeline(self, redis_service):
"""Тест pipeline операций Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Создаем pipeline через правильный метод
pipeline = redis_service.pipeline()
assert pipeline is not None
# Добавляем команды в pipeline
pipeline.set("key1", "value1")
pipeline.set("key2", "value2")
pipeline.set("key3", "value3")
# Выполняем pipeline
results = await pipeline.execute()
# Проверяем результаты
assert len(results) == 3
# Проверяем что данные сохранились
value1 = await redis_service.get("key1")
value2 = await redis_service.get("key2")
value3 = await redis_service.get("key3")
assert value1 == "value1"
assert value2 == "value2"
assert value3 == "value3"
@pytest.mark.asyncio
async def test_redis_publish_subscribe(self, redis_service):
"""Тест pub/sub функциональности Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Создаем список для хранения полученных сообщений
received_messages = []
# Функция для обработки сообщений
async def message_handler(channel, message):
received_messages.append((channel, message))
# Подписываемся на канал - используем правильный способ
# Создаем pubsub объект из клиента
if redis_service._client:
pubsub = redis_service._client.pubsub()
await pubsub.subscribe("test_channel")
# Запускаем прослушивание в фоне
async def listen_messages():
async for message in pubsub.listen():
if message["type"] == "message":
await message_handler(message["channel"], message["data"])
# Запускаем прослушивание
listener_task = asyncio.create_task(listen_messages())
# Ждем немного для установки соединения
await asyncio.sleep(0.1)
# Публикуем сообщение
await redis_service.publish("test_channel", "test_message")
# Ждем получения сообщения
await asyncio.sleep(0.1)
# Останавливаем прослушивание
listener_task.cancel()
await pubsub.unsubscribe("test_channel")
await pubsub.close()
# Проверяем что сообщение получено
assert len(received_messages) > 0
# Проверяем канал и сообщение - учитываем возможные различия в кодировке
channel = received_messages[0][0]
message = received_messages[0][1]
# Канал может быть в байтах или строке
if isinstance(channel, bytes):
channel = channel.decode('utf-8')
assert channel == "test_channel"
# Сообщение может быть в байтах или строке
if isinstance(message, bytes):
message = message.decode('utf-8')
assert message == "test_message"
else:
pytest.skip("Redis client not available")
@pytest.mark.asyncio
async def test_redis_error_handling(self, redis_service):
"""Тест обработки ошибок Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Тест с несуществующей командой
try:
await redis_service.execute("NONEXISTENT_COMMAND")
print("⚠️ Несуществующая команда выполнилась без ошибки")
except Exception as e:
print(f"✅ Ошибка обработана корректно: {e}")
# Тест с неправильными аргументами
try:
await redis_service.execute("SET", "key") # Недостаточно аргументов
print("⚠️ SET с недостаточными аргументами выполнился без ошибки")
except Exception as e:
print(f"✅ Ошибка обработана корректно: {e}")
@pytest.mark.asyncio
async def test_redis_performance(self, redis_service):
"""Тест производительности Redis операций"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Тест массовой записи
start_time = asyncio.get_event_loop().time()
for i in range(100):
await redis_service.set(f"perf_key_{i}", f"perf_value_{i}")
write_time = asyncio.get_event_loop().time() - start_time
# Тест массового чтения
start_time = asyncio.get_event_loop().time()
for i in range(100):
await redis_service.get(f"perf_key_{i}")
read_time = asyncio.get_event_loop().time() - start_time
# Проверяем что операции выполняются достаточно быстро
assert write_time < 1.0 # Запись 100 ключей должна занимать менее 1 секунды
assert read_time < 1.0 # Чтение 100 ключей должно занимать менее 1 секунды
print(f"Write time: {write_time:.3f}s, Read time: {read_time:.3f}s")
@pytest.mark.asyncio
async def test_redis_data_persistence(self, redis_service):
"""Тест персистентности данных Redis"""
# Очищаем тестовую БД
await redis_service.execute("FLUSHDB")
# Сохраняем данные
test_data = {"persistent": "data", "number": 123}
await redis_service.serialize_and_set("persistent_key", test_data)
# Проверяем что данные сохранились
result = await redis_service.get_and_deserialize("persistent_key")
assert result == test_data
# Переподключаемся к Redis
await redis_service.disconnect()
await redis_service.connect()
# Проверяем что данные все еще доступны
result = await redis_service.get_and_deserialize("persistent_key")
assert result == test_data