mirror of
https://github.com/Balshgit/gpt_chat_bot.git
synced 2025-12-16 21:20:39 +03:00
add gpt model health check (#21)
This commit is contained in:
@@ -2,18 +2,18 @@ import asyncio
|
||||
from asyncio import AbstractEventLoop
|
||||
from unittest import mock
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
import telegram
|
||||
from assertpy import assert_that
|
||||
from faker import Faker
|
||||
from httpx import AsyncClient
|
||||
from httpx import AsyncClient, Response
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
|
||||
from constants import BotStagesEnum
|
||||
from core.bot import BotApplication, BotQueue
|
||||
from main import Application
|
||||
from settings.config import AppSettings, settings
|
||||
from tests.integration.bot.conftest import mocked_ask_question_api
|
||||
from tests.integration.bot.networking import MockedRequest
|
||||
from tests.integration.factories.bot import (
|
||||
BotCallBackQueryFactory,
|
||||
@@ -21,6 +21,7 @@ from tests.integration.factories.bot import (
|
||||
BotUpdateFactory,
|
||||
CallBackFactory,
|
||||
)
|
||||
from tests.integration.utils import mocked_ask_question_api
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.asyncio,
|
||||
@@ -31,11 +32,6 @@ pytestmark = [
|
||||
faker = Faker()
|
||||
|
||||
|
||||
async def test_bot_updates(rest_client: AsyncClient) -> None:
|
||||
response = await rest_client.get("/api/healthcheck")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
async def test_bot_webhook_endpoint(
|
||||
rest_client: AsyncClient,
|
||||
main_application: Application,
|
||||
@@ -169,8 +165,8 @@ async def test_about_bot_callback_action(
|
||||
|
||||
assert mocked_reply_text.call_args.args == (
|
||||
f"Бот использует бесплатную модель {settings.GPT_MODEL} для ответов на вопросы. "
|
||||
f"Принимает запросы на разных языках.\n\nБот так же умеет переводить русские голосовые сообщения в текст. "
|
||||
f"Просто пришлите голосовуху и получите поток сознания в виде текста, но без знаков препинания",
|
||||
f"\nПринимает запросы на разных языках.\n\nБот так же умеет переводить русские голосовые сообщения "
|
||||
f"в текст. Просто пришлите голосовуху и получите поток сознания в виде текста, но без знаков препинания",
|
||||
)
|
||||
assert mocked_reply_text.call_args.kwargs == {"parse_mode": "Markdown"}
|
||||
|
||||
@@ -198,7 +194,10 @@ async def test_ask_question_action(
|
||||
) -> None:
|
||||
with mock.patch.object(
|
||||
telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs)
|
||||
) as mocked_send_message, mocked_ask_question_api(host=test_settings.GPT_BASE_HOST):
|
||||
) as mocked_send_message, mocked_ask_question_api(
|
||||
host=test_settings.GPT_BASE_HOST,
|
||||
return_value=Response(status_code=httpx.codes.OK, text="Привет! Как я могу помочь вам сегодня?"),
|
||||
):
|
||||
bot_update = BotUpdateFactory(message=BotMessageFactory.create_instance(text="Привет!"))
|
||||
bot_update["message"].pop("entities")
|
||||
|
||||
@@ -214,6 +213,55 @@ async def test_ask_question_action(
|
||||
)
|
||||
|
||||
|
||||
async def test_ask_question_action_not_success(
|
||||
main_application: Application,
|
||||
test_settings: AppSettings,
|
||||
) -> None:
|
||||
with mock.patch.object(
|
||||
telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs)
|
||||
) as mocked_send_message, mocked_ask_question_api(
|
||||
host=test_settings.GPT_BASE_HOST, return_value=Response(status_code=httpx.codes.INTERNAL_SERVER_ERROR)
|
||||
):
|
||||
bot_update = BotUpdateFactory(message=BotMessageFactory.create_instance(text="Привет!"))
|
||||
bot_update["message"].pop("entities")
|
||||
|
||||
await main_application.bot_app.application.process_update(
|
||||
update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot)
|
||||
)
|
||||
assert_that(mocked_send_message.call_args.kwargs).is_equal_to(
|
||||
{
|
||||
"text": "Что-то пошло не так, попробуйте еще раз или обратитесь к администратору",
|
||||
"chat_id": bot_update["message"]["chat"]["id"],
|
||||
},
|
||||
include=["text", "chat_id"],
|
||||
)
|
||||
|
||||
|
||||
async def test_ask_question_action_critical_error(
|
||||
main_application: Application,
|
||||
test_settings: AppSettings,
|
||||
) -> None:
|
||||
with mock.patch.object(
|
||||
telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs)
|
||||
) as mocked_send_message, mocked_ask_question_api(
|
||||
host=test_settings.GPT_BASE_HOST,
|
||||
side_effect=Exception(),
|
||||
):
|
||||
bot_update = BotUpdateFactory(message=BotMessageFactory.create_instance(text="Привет!"))
|
||||
bot_update["message"].pop("entities")
|
||||
|
||||
await main_application.bot_app.application.process_update(
|
||||
update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot)
|
||||
)
|
||||
assert_that(mocked_send_message.call_args.kwargs).is_equal_to(
|
||||
{
|
||||
"text": "Вообще всё сломалось :(",
|
||||
"chat_id": bot_update["message"]["chat"]["id"],
|
||||
},
|
||||
include=["text", "chat_id"],
|
||||
)
|
||||
|
||||
|
||||
async def test_no_update_message(
|
||||
main_application: Application,
|
||||
test_settings: AppSettings,
|
||||
|
||||
@@ -4,19 +4,16 @@ pytest framework. A common change is to allow monkeypatching of the class member
|
||||
enforcing slots in the subclasses."""
|
||||
import asyncio
|
||||
from asyncio import AbstractEventLoop
|
||||
from contextlib import contextmanager
|
||||
from datetime import tzinfo
|
||||
from typing import Any, AsyncGenerator, Iterator
|
||||
from typing import Any, AsyncGenerator
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import respx
|
||||
from httpx import AsyncClient, Response
|
||||
from httpx import AsyncClient
|
||||
from pytest_asyncio.plugin import SubRequest
|
||||
from telegram import Bot, User
|
||||
from telegram.ext import Application, ApplicationBuilder, Defaults, ExtBot
|
||||
|
||||
from constants import CHAT_GPT_BASE_URI
|
||||
from core.bot import BotApplication
|
||||
from core.handlers import bot_event_handlers
|
||||
from main import Application as AppApplication
|
||||
@@ -255,15 +252,3 @@ async def rest_client(
|
||||
headers={"Content-Type": "application/json"},
|
||||
) as client:
|
||||
yield client
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mocked_ask_question_api(host: str) -> Iterator[respx.MockRouter]:
|
||||
with respx.mock(
|
||||
assert_all_mocked=True,
|
||||
assert_all_called=True,
|
||||
base_url=host,
|
||||
) as respx_mock:
|
||||
ask_question_route = respx_mock.post(url=CHAT_GPT_BASE_URI, name="ask_question")
|
||||
ask_question_route.return_value = Response(status_code=200, text="Привет! Как я могу помочь вам сегодня?")
|
||||
yield respx_mock
|
||||
56
bot_microservice/tests/integration/test_system.py
Normal file
56
bot_microservice/tests/integration/test_system.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import httpx
|
||||
import pytest
|
||||
from faker import Faker
|
||||
from httpx import AsyncClient, Response
|
||||
|
||||
from settings.config import AppSettings
|
||||
from tests.integration.utils import mocked_ask_question_api
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.asyncio,
|
||||
pytest.mark.enable_socket,
|
||||
]
|
||||
|
||||
|
||||
faker = Faker()
|
||||
|
||||
|
||||
async def test_bot_updates(rest_client: AsyncClient) -> None:
|
||||
response = await rest_client.get("/api/healthcheck")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
async def test_bot_healthcheck_is_ok(
|
||||
rest_client: AsyncClient,
|
||||
test_settings: AppSettings,
|
||||
) -> None:
|
||||
with mocked_ask_question_api(
|
||||
host=test_settings.GPT_BASE_HOST,
|
||||
return_value=Response(status_code=httpx.codes.OK, text="Привет! Как я могу помочь вам сегодня?"),
|
||||
):
|
||||
response = await rest_client.get("/api/bot-healthcheck")
|
||||
assert response.status_code == httpx.codes.OK
|
||||
|
||||
|
||||
async def test_bot_healthcheck_invalid_request_model(
|
||||
rest_client: AsyncClient,
|
||||
test_settings: AppSettings,
|
||||
) -> None:
|
||||
with mocked_ask_question_api(
|
||||
host=test_settings.GPT_BASE_HOST,
|
||||
return_value=Response(status_code=httpx.codes.OK, text="Invalid request model"),
|
||||
):
|
||||
response = await rest_client.get("/api/bot-healthcheck")
|
||||
assert response.status_code == httpx.codes.INTERNAL_SERVER_ERROR
|
||||
|
||||
|
||||
async def test_bot_healthcheck_not_ok(
|
||||
rest_client: AsyncClient,
|
||||
test_settings: AppSettings,
|
||||
) -> None:
|
||||
with mocked_ask_question_api(
|
||||
host=test_settings.GPT_BASE_HOST,
|
||||
side_effect=Exception(),
|
||||
):
|
||||
response = await rest_client.get("/api/bot-healthcheck")
|
||||
assert response.status_code == httpx.codes.INTERNAL_SERVER_ERROR
|
||||
22
bot_microservice/tests/integration/utils.py
Normal file
22
bot_microservice/tests/integration/utils.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from contextlib import contextmanager
|
||||
from typing import Any, Iterator
|
||||
|
||||
import respx
|
||||
from httpx import Response
|
||||
|
||||
from constants import CHAT_GPT_BASE_URI
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mocked_ask_question_api(
|
||||
host: str, return_value: Response | None = None, side_effect: Any | None = None
|
||||
) -> Iterator[respx.MockRouter]:
|
||||
with respx.mock(
|
||||
assert_all_mocked=True,
|
||||
assert_all_called=True,
|
||||
base_url=host,
|
||||
) as respx_mock:
|
||||
ask_question_route = respx_mock.post(url=CHAT_GPT_BASE_URI, name="ask_question")
|
||||
ask_question_route.return_value = return_value
|
||||
ask_question_route.side_effect = side_effect
|
||||
yield respx_mock
|
||||
Reference in New Issue
Block a user