133 lines
4.3 KiB
Python
133 lines
4.3 KiB
Python
"""Тесты для utils/logger.py — проверка настройки логирования."""
|
|
|
|
import logging
|
|
import os
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from utils.logger import setup_logging
|
|
|
|
|
|
def test_console_handler_added() -> None:
|
|
"""setup_logging добавляет StreamHandler на stdout."""
|
|
with _isolated_logger() as root:
|
|
handlers = [h for h in root.handlers if isinstance(h, logging.StreamHandler)]
|
|
assert len(handlers) >= 1
|
|
|
|
|
|
def test_default_level_is_info() -> None:
|
|
"""Уровень по умолчанию — INFO."""
|
|
with _isolated_logger() as root:
|
|
assert root.level == logging.INFO
|
|
|
|
|
|
def test_custom_level_from_env() -> None:
|
|
"""LOG_LEVEL из окружения влияет на уровень."""
|
|
os.environ["LOG_LEVEL"] = "DEBUG"
|
|
try:
|
|
with _isolated_logger() as root:
|
|
assert root.level == logging.DEBUG
|
|
finally:
|
|
os.environ.pop("LOG_LEVEL", None)
|
|
|
|
|
|
def test_invalid_level_defaults_to_info() -> None:
|
|
"""Неизвестный LOG_LEVEL fallback на INFO."""
|
|
os.environ["LOG_LEVEL"] = "NOTAREALLEVEL"
|
|
try:
|
|
with _isolated_logger() as root:
|
|
assert root.level == logging.INFO
|
|
finally:
|
|
os.environ.pop("LOG_LEVEL", None)
|
|
|
|
|
|
def test_file_handler_when_logs_dir_exists() -> None:
|
|
"""FileHandler добавляется если директория logs существует."""
|
|
orig_cwd = os.getcwd()
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
logs_dir = Path(tmpdir) / "logs"
|
|
logs_dir.mkdir()
|
|
os.chdir(logs_dir.parent)
|
|
|
|
try:
|
|
with _isolated_logger() as root:
|
|
file_handlers = [h for h in root.handlers if isinstance(h, logging.FileHandler)]
|
|
assert len(file_handlers) >= 1
|
|
# Закрыть file handler чтобы освободить файл на Windows
|
|
for h in file_handlers:
|
|
h.close()
|
|
finally:
|
|
os.chdir(orig_cwd)
|
|
|
|
|
|
def test_no_file_handler_when_logs_dir_missing() -> None:
|
|
"""FileHandler не добавляется если директории logs нет."""
|
|
orig_cwd = os.getcwd()
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
os.chdir(tmpdir)
|
|
# Убедиться что logs/ нет
|
|
logs_dir = Path("logs")
|
|
if logs_dir.exists():
|
|
import shutil
|
|
shutil.rmtree(logs_dir)
|
|
|
|
try:
|
|
with _isolated_logger() as root:
|
|
file_handlers = [h for h in root.handlers if isinstance(h, logging.FileHandler)]
|
|
assert len(file_handlers) == 0
|
|
finally:
|
|
os.chdir(orig_cwd)
|
|
|
|
|
|
def test_aiohttp_suppressed() -> None:
|
|
"""Логгер aiohttp подавлен до WARNING."""
|
|
with _isolated_logger():
|
|
aiohttp_logger = logging.getLogger("aiohttp")
|
|
assert aiohttp_logger.level == logging.WARNING
|
|
|
|
|
|
def test_discord_level_is_info() -> None:
|
|
"""Логгер discord установлен на INFO."""
|
|
with _isolated_logger():
|
|
discord_logger = logging.getLogger("discord")
|
|
assert discord_logger.level == logging.INFO
|
|
|
|
|
|
def test_log_message_format() -> None:
|
|
"""Формат сообщения: время, уровень, имя модуля, текст."""
|
|
import io
|
|
import sys
|
|
|
|
with _isolated_logger() as root:
|
|
# Replace stdout with our buffer
|
|
buffer = io.StringIO()
|
|
for handler in root.handlers:
|
|
if isinstance(handler, logging.StreamHandler):
|
|
handler.stream = buffer
|
|
|
|
test_logger = logging.getLogger("test_module")
|
|
test_logger.info("test message")
|
|
|
|
output = buffer.getvalue()
|
|
assert "INFO" in output
|
|
assert "test_module" in output
|
|
assert "test message" in output
|
|
|
|
|
|
import contextlib
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def _isolated_logger():
|
|
"""Создать изолированный root-логгер без handlers из других тестов."""
|
|
old_handlers = logging.getLogger().handlers[:]
|
|
old_level = logging.getLogger().level
|
|
logging.getLogger().handlers.clear()
|
|
|
|
yield setup_logging()
|
|
|
|
# Restore
|
|
logging.getLogger().handlers.clear()
|
|
logging.getLogger().handlers.extend(old_handlers)
|
|
logging.getLogger().setLevel(old_level)
|