Rework polling and start covering

This commit is contained in:
Alex Root Junior 2019-12-10 01:14:58 +02:00
parent 38c725db46
commit db397e3a05
6 changed files with 84 additions and 12 deletions

View file

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
from contextlib import asynccontextmanager
from typing import Any, Optional, TypeVar from typing import Any, Optional, TypeVar
from ...utils.mixins import ContextInstanceMixin, DataMixin from ...utils.mixins import ContextInstanceMixin, DataMixin
@ -32,11 +33,15 @@ class BaseBot(ContextInstanceMixin, DataMixin):
async def close(self): async def close(self):
await self.session.close() await self.session.close()
async def __aenter__(self): @asynccontextmanager
return self async def context(self, auto_close: bool = True):
token = self.set_current(self)
async def __aexit__(self, exc_type, exc_val, exc_tb): try:
await self.session.close() yield self
finally:
if auto_close:
await self.close()
self.reset_current(token)
def __hash__(self): def __hash__(self):
return hash(self.__token) return hash(self.__token)

View file

@ -5,6 +5,8 @@ import datetime
import json import json
from typing import Any, Callable, Optional, TypeVar, Union from typing import Any, Callable, Optional, TypeVar, Union
from aiogram.utils.exceptions import TelegramAPIError
from ...methods import Response, TelegramMethod from ...methods import Response, TelegramMethod
from ..telegram import PRODUCTION, TelegramAPIServer from ..telegram import PRODUCTION, TelegramAPIServer
@ -32,7 +34,7 @@ class BaseSession(abc.ABC):
def raise_for_status(self, response: Response[T]) -> None: def raise_for_status(self, response: Response[T]) -> None:
if response.ok: if response.ok:
return return
raise Exception(response.description) raise TelegramAPIError(response.description)
@abc.abstractmethod @abc.abstractmethod
async def close(self): # pragma: no cover async def close(self): # pragma: no cover

View file

@ -24,3 +24,9 @@ class User(TelegramObject):
"""Users or bots username""" """Users or bots username"""
language_code: Optional[str] = None language_code: Optional[str] = None
"""IETF language tag of the user's language""" """IETF language tag of the user's language"""
@property
def full_name(self):
if self.last_name:
return f"{self.first_name} {self.last_name}"
return self.first_name

View file

@ -48,10 +48,16 @@ class TestBaseBot:
mocked_close.assert_awaited() mocked_close.assert_awaited()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_context_manager(self): @pytest.mark.parametrize("close", [True, False])
async def test_context_manager(self, close: bool):
with patch( with patch(
"aiogram.api.client.session.aiohttp.AiohttpSession.close", new_callable=CoroutineMock "aiogram.api.client.session.aiohttp.AiohttpSession.close", new_callable=CoroutineMock
) as mocked_close: ) as mocked_close:
async with BaseBot("42:TEST", session=AiohttpSession()) as bot: async with BaseBot("42:TEST", session=AiohttpSession()).context(
auto_close=close
) as bot:
assert isinstance(bot, BaseBot) assert isinstance(bot, BaseBot)
mocked_close.assert_awaited() if close:
mocked_close.assert_awaited()
else:
mocked_close.assert_not_awaited()

View file

@ -0,0 +1,20 @@
import pytest
from aiogram.api.types import User
class TestUser:
@pytest.mark.parametrize(
"first,last,result",
[
["User", None, "User"],
["", None, ""],
[" ", None, " "],
["User", "Name", "User Name"],
["User", " ", "User "],
[" ", " ", " "],
],
)
def test_full_name(self, first: str, last: str, result: bool):
user = User(id=42, is_bot=False, first_name=first, last_name=last)
assert user.full_name == result

View file

@ -4,9 +4,11 @@ import time
import pytest import pytest
from aiogram import Bot from aiogram import Bot
from aiogram.api.methods import GetUpdates, SendMessage
from aiogram.api.types import Chat, Message, Update, User from aiogram.api.types import Chat, Message, Update, User
from aiogram.dispatcher.dispatcher import Dispatcher from aiogram.dispatcher.dispatcher import Dispatcher
from aiogram.dispatcher.router import Router from aiogram.dispatcher.router import Router
from tests.mocked_bot import MockedBot
class TestDispatcher: class TestDispatcher:
@ -77,12 +79,43 @@ class TestDispatcher:
assert result == "test" assert result == "test"
assert handled assert handled
@pytest.mark.skip
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_listen_updates(self): async def test_listen_updates(self, bot: MockedBot):
pass dispatcher = Dispatcher()
bot.add_result_for(
GetUpdates, ok=True, result=[Update(update_id=update_id) for update_id in range(42)]
)
index = 0
async for update in dispatcher._listen_updates(bot=bot):
assert update.update_id == index
index += 1
if index == 42:
break
@pytest.mark.asyncio
async def test_silent_call_request(self, bot: MockedBot, caplog):
dispatcher = Dispatcher()
bot.add_result_for(SendMessage, ok=False, error_code=400, description="Kaboom")
await dispatcher._silent_call_request(SendMessage(chat_id=42, text="test"))
log_records = [rec.message for rec in caplog.records]
assert len(log_records) == 1
assert "Failed to make answer" in log_records[0]
@pytest.mark.skip @pytest.mark.skip
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_polling(self): async def test_polling(self):
pass pass
@pytest.mark.skip
@pytest.mark.asyncio
async def test_process_update(self):
pass
@pytest.mark.skip
@pytest.mark.asyncio
async def test_run_polling(self):
pass
@pytest.mark.skip
def test_run(self):
pass