refactor: centralize settings and application services

This commit is contained in:
kandrusyak
2026-07-27 17:47:39 +03:00
parent 248e90faf5
commit ab029a4c67
10 changed files with 296 additions and 78 deletions

View File

@@ -1,11 +1,11 @@
import tempfile
import unittest
from pathlib import Path
from unittest.mock import Mock, patch
from zoneinfo import ZoneInfo
from assistant_bot import application as application_module
from assistant_bot.auth import authentication_guard
from assistant_bot.config import AppSettings
from assistant_bot.handlers import (
ask_command,
help_command,
@@ -22,23 +22,26 @@ from assistant_bot.handlers import (
class ApplicationRegistrationTests(unittest.TestCase):
def test_registers_the_current_public_handlers_in_order(self) -> None:
with tempfile.TemporaryDirectory() as directory, patch.multiple(
application_module,
get_assistant_password=Mock(return_value="secret"),
get_bot_token=Mock(return_value="123456:TEST"),
get_db_path=Mock(
return_value=Path(directory) / "assistant.sqlite3"
),
get_assistant_mode=Mock(return_value="local"),
get_ollama_base_url=Mock(return_value="http://localhost:11434"),
get_whisper_model=Mock(return_value="small"),
get_whisper_device=Mock(return_value="cpu"),
get_whisper_compute_type=Mock(return_value="int8"),
get_whisper_language=Mock(return_value="ru"),
get_local_timezone=Mock(return_value=ZoneInfo("UTC")),
get_voice_max_duration_seconds=Mock(return_value=120),
):
application = application_module.create_application()
with tempfile.TemporaryDirectory() as directory:
settings = AppSettings(
bot_token="123456:TEST",
assistant_password="secret",
db_path=Path(directory) / "assistant.sqlite3",
mode="local",
timezone=ZoneInfo("UTC"),
voice_max_duration_seconds=120,
ollama_base_url="http://localhost:11434",
ollama_model="qwen3.5:9b",
yandex_cloud_folder=None,
yandex_cloud_model="yandexgpt/latest",
yandex_stt_model="general",
yandex_stt_language="ru-RU",
whisper_model="small",
whisper_device="cpu",
whisper_compute_type="int8",
whisper_language="ru",
)
application = application_module.create_application(settings)
self.assertEqual(
[handler.callback for handler in application.handlers[-1]],

View File

@@ -4,11 +4,13 @@ from pathlib import Path
from types import SimpleNamespace
from typing import Any
from unittest.mock import AsyncMock
from zoneinfo import ZoneInfo
from telegram.constants import ChatType, ParseMode
from telegram.ext import ApplicationHandlerStop
from assistant_bot.auth import authentication_guard
from assistant_bot.services import SERVICES_KEY, ApplicationServices
from assistant_bot.storage import AssistantStorage
from assistant_bot.telegram_utils import render_markdown_chunks
@@ -34,8 +36,14 @@ class AuthenticationGuardTests(unittest.IsolatedAsyncioTestCase):
context = SimpleNamespace(
application=SimpleNamespace(
bot_data={
"storage": self.storage,
"assistant_password": "секрет",
SERVICES_KEY: ApplicationServices(
storage=self.storage,
ai_client=SimpleNamespace(),
timezone=ZoneInfo("UTC"),
speech_recognizer=SimpleNamespace(),
voice_max_duration_seconds=120,
assistant_password="секрет",
),
}
)
)

View File

@@ -5,6 +5,35 @@ from unittest.mock import patch
from assistant_bot import config
class AppSettingsTests(unittest.TestCase):
def test_loads_complete_startup_configuration_once(self) -> None:
environment = {
config.TOKEN_ENV_NAME: "token",
config.PASSWORD_ENV_NAME: "secret",
config.MODE_ENV_NAME: "local",
config.DB_ENV_NAME: "data/test.sqlite3",
config.TIMEZONE_ENV_NAME: "UTC",
config.WHISPER_LANGUAGE_ENV_NAME: "auto",
}
with patch(
"assistant_bot.config.load_env_file"
) as load_env_file, patch.dict(
os.environ,
environment,
clear=True,
):
settings = config.load_app_settings()
load_env_file.assert_called_once_with()
self.assertEqual(settings.bot_token, "token")
self.assertEqual(settings.assistant_password, "secret")
self.assertEqual(settings.mode, "local")
self.assertEqual(settings.db_path, config.PROJECT_ROOT / "data/test.sqlite3")
self.assertEqual(settings.timezone.key, "UTC")
self.assertIsNone(settings.whisper_language)
self.assertIsNone(settings.yandex_cloud_folder)
class WhisperConfigTests(unittest.TestCase):
def test_gpu_int8_defaults(self) -> None:
variable_names = (

View File

@@ -3,10 +3,12 @@ from pathlib import Path
from types import SimpleNamespace
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
from zoneinfo import ZoneInfo
from telegram.constants import ParseMode
from assistant_bot.handlers import private_voice
from assistant_bot.services import SERVICES_KEY, ApplicationServices
from assistant_bot.telegram_utils import render_markdown_chunks
@@ -31,8 +33,14 @@ class VoiceHandlerTests(unittest.IsolatedAsyncioTestCase):
bot=bot,
application=SimpleNamespace(
bot_data={
"speech_recognizer": recognizer,
"voice_max_duration": 120,
SERVICES_KEY: ApplicationServices(
storage=SimpleNamespace(),
ai_client=SimpleNamespace(),
timezone=ZoneInfo("UTC"),
speech_recognizer=recognizer,
voice_max_duration_seconds=120,
assistant_password="secret",
),
}
),
)