import tempfile import unittest from pathlib import Path from types import SimpleNamespace from typing import Any from unittest.mock import AsyncMock from telegram.constants import ChatType from telegram.ext import ApplicationHandlerStop from assistant_bot.auth import authentication_guard from assistant_bot.storage import AssistantStorage class AuthenticationGuardTests(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: self.temporary_directory = tempfile.TemporaryDirectory() self.storage = AssistantStorage( Path(self.temporary_directory.name) / "assistant.sqlite3" ) def tearDown(self) -> None: self.temporary_directory.cleanup() def make_update_and_context(self, text: str) -> tuple[Any, Any]: message = SimpleNamespace(text=text, reply_text=AsyncMock()) update = SimpleNamespace( effective_user=SimpleNamespace(id=42), effective_chat=SimpleNamespace(type=ChatType.PRIVATE), effective_message=message, inline_query=None, ) context = SimpleNamespace( application=SimpleNamespace( bot_data={ "storage": self.storage, "assistant_password": "секрет", } ) ) return update, context async def test_correct_password_authorizes_user(self) -> None: update, context = self.make_update_and_context("секрет") with self.assertRaises(ApplicationHandlerStop): await authentication_guard(update, context) self.assertTrue(self.storage.is_user_authorized(42)) update.effective_message.reply_text.assert_awaited_once_with( "Пароль принят. Доступ открыт — повторно вводить его не нужно." ) async def test_wrong_password_does_not_authorize_user(self) -> None: update, context = self.make_update_and_context("неверно") with self.assertRaises(ApplicationHandlerStop): await authentication_guard(update, context) self.assertFalse(self.storage.is_user_authorized(42)) update.effective_message.reply_text.assert_awaited_once_with( "Неверный пароль. Попробуй еще раз." ) async def test_authorized_user_passes_guard(self) -> None: self.storage.authorize_user(42) update, context = self.make_update_and_context("обычное сообщение") await authentication_guard(update, context) update.effective_message.reply_text.assert_not_awaited() if __name__ == "__main__": unittest.main()