Переписал почти все тесты
feat: улучшено логирование и обработка скорингов в PostService и RagApiClient - Добавлены отладочные сообщения для передачи скорингов в функции обработки постов. - Обновлено логирование успешного получения скорингов из RAG API с дополнительной информацией. - Оптимизирована обработка скорингов в функции get_text_message для улучшения отладки. - Обновлены тесты для проверки новых функциональных возможностей и обработки ошибок.
This commit is contained in:
251
tests/test_server_prometheus.py
Normal file
251
tests/test_server_prometheus.py
Normal file
@@ -0,0 +1,251 @@
|
||||
"""
|
||||
Тесты для helper_bot.server_prometheus: MetricsServer, start_metrics_server, stop_metrics_server.
|
||||
"""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from aiohttp import web
|
||||
|
||||
from helper_bot.server_prometheus import (
|
||||
MetricsServer,
|
||||
start_metrics_server,
|
||||
stop_metrics_server,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
class TestMetricsServer:
|
||||
"""Тесты для класса MetricsServer."""
|
||||
|
||||
def test_init_sets_host_port_and_routes(self):
|
||||
"""При инициализации задаются host, port и маршруты /metrics, /health."""
|
||||
server = MetricsServer(host="127.0.0.1", port=9090)
|
||||
assert server.host == "127.0.0.1"
|
||||
assert server.port == 9090
|
||||
assert server.runner is None
|
||||
assert server.site is None
|
||||
paths = []
|
||||
for res in server.app.router.resources():
|
||||
info = res.get_info()
|
||||
path = info.get("path") or info.get("formatter")
|
||||
if path:
|
||||
paths.append(path)
|
||||
assert "/metrics" in paths
|
||||
assert "/health" in paths
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics")
|
||||
async def test_metrics_handler_success_returns_prometheus_content(
|
||||
self, mock_metrics_module
|
||||
):
|
||||
"""metrics_handler при успехе возвращает 200 и данные метрик."""
|
||||
mock_metrics_module.get_metrics.return_value = b"# TYPE bot_commands_total counter"
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.metrics_handler(request)
|
||||
|
||||
assert response.status == 200
|
||||
assert response.body == b"# TYPE bot_commands_total counter"
|
||||
assert "text/plain" in response.content_type
|
||||
mock_metrics_module.get_metrics.assert_called_once()
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics", None)
|
||||
async def test_metrics_handler_when_metrics_none_returns_500(self):
|
||||
"""metrics_handler при недоступности metrics возвращает 500."""
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.metrics_handler(request)
|
||||
|
||||
assert response.status == 500
|
||||
assert "Metrics not available" in response.text
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics")
|
||||
async def test_metrics_handler_on_exception_returns_500(
|
||||
self, mock_metrics_module
|
||||
):
|
||||
"""metrics_handler при исключении в get_metrics возвращает 500."""
|
||||
mock_metrics_module.get_metrics.side_effect = RuntimeError("metrics error")
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.metrics_handler(request)
|
||||
|
||||
assert response.status == 500
|
||||
assert "Error generating metrics" in response.text
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics")
|
||||
async def test_health_handler_success_returns_ok(self, mock_metrics_module):
|
||||
"""health_handler при успехе возвращает 200 OK."""
|
||||
mock_metrics_module.get_metrics.return_value = b"some_metrics_data"
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.health_handler(request)
|
||||
|
||||
assert response.status == 200
|
||||
assert response.text == "OK"
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics", None)
|
||||
async def test_health_handler_when_metrics_none_returns_503(self):
|
||||
"""health_handler при недоступности metrics возвращает 503."""
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.health_handler(request)
|
||||
|
||||
assert response.status == 503
|
||||
assert "Metrics not available" in response.text
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics")
|
||||
async def test_health_handler_empty_metrics_returns_503(
|
||||
self, mock_metrics_module
|
||||
):
|
||||
"""health_handler при пустых метриках возвращает 503."""
|
||||
mock_metrics_module.get_metrics.return_value = b""
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.health_handler(request)
|
||||
|
||||
assert response.status == 503
|
||||
assert "Empty metrics" in response.text
|
||||
|
||||
@patch("helper_bot.server_prometheus.metrics")
|
||||
async def test_health_handler_get_metrics_raises_returns_503(
|
||||
self, mock_metrics_module
|
||||
):
|
||||
"""health_handler при исключении get_metrics возвращает 503."""
|
||||
mock_metrics_module.get_metrics.side_effect = ValueError("gen failed")
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
request = MagicMock(spec=web.Request)
|
||||
|
||||
response = await server.health_handler(request)
|
||||
|
||||
assert response.status == 503
|
||||
assert "Metrics generation failed" in response.text
|
||||
|
||||
@patch("helper_bot.server_prometheus.web.AppRunner")
|
||||
@patch("helper_bot.server_prometheus.web.TCPSite")
|
||||
async def test_start_creates_runner_and_site(
|
||||
self, mock_tcp_site_cls, mock_app_runner_cls
|
||||
):
|
||||
"""start() создаёт AppRunner и TCPSite и запускает сервер."""
|
||||
mock_runner = MagicMock()
|
||||
mock_runner.setup = AsyncMock()
|
||||
mock_app_runner_cls.return_value = mock_runner
|
||||
mock_site = MagicMock()
|
||||
mock_site.start = AsyncMock()
|
||||
mock_tcp_site_cls.return_value = mock_site
|
||||
server = MetricsServer(host="0.0.0.0", port=19998)
|
||||
|
||||
await server.start()
|
||||
|
||||
mock_app_runner_cls.assert_called_once_with(server.app)
|
||||
mock_runner.setup.assert_awaited_once()
|
||||
mock_tcp_site_cls.assert_called_once_with(mock_runner, "0.0.0.0", 19998)
|
||||
mock_site.start.assert_awaited_once()
|
||||
assert server.runner is mock_runner
|
||||
assert server.site is mock_site
|
||||
|
||||
async def test_stop_stops_site_and_cleans_runner(self):
|
||||
"""stop() останавливает site и очищает runner."""
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
server.site = MagicMock()
|
||||
server.site.stop = AsyncMock()
|
||||
server.runner = MagicMock()
|
||||
server.runner.cleanup = AsyncMock()
|
||||
|
||||
await server.stop()
|
||||
|
||||
server.site.stop.assert_awaited_once()
|
||||
server.runner.cleanup.assert_awaited_once()
|
||||
|
||||
async def test_stop_when_site_none_does_not_raise(self):
|
||||
"""stop() при site=None не падает."""
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
server.site = None
|
||||
server.runner = None
|
||||
|
||||
await server.stop()
|
||||
|
||||
@patch.object(MetricsServer, "start", new_callable=AsyncMock)
|
||||
@patch.object(MetricsServer, "stop", new_callable=AsyncMock)
|
||||
async def test_context_manager_enters_and_exits(
|
||||
self, mock_stop, mock_start
|
||||
):
|
||||
"""Использование как async context manager вызывает start и stop."""
|
||||
mock_start.return_value = None
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
|
||||
async with server:
|
||||
pass
|
||||
|
||||
mock_start.assert_awaited_once()
|
||||
mock_stop.assert_awaited_once()
|
||||
|
||||
@patch.object(MetricsServer, "start", new_callable=AsyncMock)
|
||||
@patch.object(MetricsServer, "stop", new_callable=AsyncMock)
|
||||
async def test_context_manager_exit_calls_stop_on_exception(
|
||||
self, mock_stop, mock_start
|
||||
):
|
||||
"""При исключении внутри контекста stop всё равно вызывается."""
|
||||
mock_start.return_value = None
|
||||
server = MetricsServer(host="0.0.0.0", port=8080)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
async with server:
|
||||
raise ValueError("test")
|
||||
|
||||
mock_stop.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
class TestStartStopMetricsServer:
|
||||
"""Тесты для start_metrics_server и stop_metrics_server."""
|
||||
|
||||
@patch("helper_bot.server_prometheus.MetricsServer")
|
||||
async def test_start_metrics_server_creates_and_starts_server(
|
||||
self, mock_server_cls
|
||||
):
|
||||
"""start_metrics_server создаёт MetricsServer и вызывает start()."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.start = AsyncMock()
|
||||
mock_server_cls.return_value = mock_instance
|
||||
|
||||
result = await start_metrics_server("0.0.0.0", 8080)
|
||||
|
||||
mock_server_cls.assert_called_once_with("0.0.0.0", 8080)
|
||||
mock_instance.start.assert_awaited_once()
|
||||
assert result is mock_instance
|
||||
|
||||
@patch("helper_bot.server_prometheus.MetricsServer")
|
||||
async def test_stop_metrics_server_when_running_stops_and_clears_global(
|
||||
self, mock_server_cls
|
||||
):
|
||||
"""stop_metrics_server при запущенном сервере останавливает его и обнуляет глобальную переменную."""
|
||||
import helper_bot.server_prometheus as mod
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.stop = AsyncMock()
|
||||
old_server = mod.metrics_server
|
||||
mod.metrics_server = mock_instance
|
||||
try:
|
||||
await stop_metrics_server()
|
||||
mock_instance.stop.assert_awaited_once()
|
||||
assert mod.metrics_server is None
|
||||
finally:
|
||||
mod.metrics_server = old_server
|
||||
|
||||
async def test_stop_metrics_server_when_none_does_not_raise(self):
|
||||
"""stop_metrics_server при metrics_server=None не падает."""
|
||||
import helper_bot.server_prometheus as mod
|
||||
old_server = mod.metrics_server
|
||||
mod.metrics_server = None
|
||||
try:
|
||||
await stop_metrics_server()
|
||||
assert mod.metrics_server is None
|
||||
finally:
|
||||
mod.metrics_server = old_server
|
||||
Reference in New Issue
Block a user