mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
parent
0bd7fc2c7e
commit
086806e202
6 changed files with 413 additions and 13 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import pytest
|
||||
|
||||
from aiogram.api.client.base import BaseBot
|
||||
from aiogram.api.client.session.aiohttp import AiohttpSession
|
||||
from aiogram.api.client.session.httpx import HttpxSession
|
||||
from aiogram.api.methods import GetMe
|
||||
|
||||
try:
|
||||
|
|
@ -13,7 +13,7 @@ except ImportError:
|
|||
class TestBaseBot:
|
||||
def test_init(self):
|
||||
base_bot = BaseBot("42:TEST")
|
||||
assert isinstance(base_bot.session, AiohttpSession)
|
||||
assert isinstance(base_bot.session, HttpxSession)
|
||||
assert base_bot.id == 42
|
||||
|
||||
def test_hashable(self):
|
||||
|
|
@ -32,7 +32,7 @@ class TestBaseBot:
|
|||
method = GetMe()
|
||||
|
||||
with patch(
|
||||
"aiogram.api.client.session.aiohttp.AiohttpSession.make_request",
|
||||
"aiogram.api.client.session.httpx.HttpxSession.make_request",
|
||||
new_callable=CoroutineMock,
|
||||
) as mocked_make_request:
|
||||
await base_bot(method)
|
||||
|
|
@ -40,11 +40,11 @@ class TestBaseBot:
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close(self):
|
||||
base_bot = BaseBot("42:TEST", session=AiohttpSession())
|
||||
base_bot = BaseBot("42:TEST", session=HttpxSession())
|
||||
await base_bot.session.create_session()
|
||||
|
||||
with patch(
|
||||
"aiogram.api.client.session.aiohttp.AiohttpSession.close", new_callable=CoroutineMock
|
||||
"aiogram.api.client.session.httpx.HttpxSession.close", new_callable=CoroutineMock
|
||||
) as mocked_close:
|
||||
await base_bot.close()
|
||||
mocked_close.assert_awaited()
|
||||
|
|
@ -53,11 +53,9 @@ class TestBaseBot:
|
|||
@pytest.mark.parametrize("close", [True, False])
|
||||
async def test_context_manager(self, close: bool):
|
||||
with patch(
|
||||
"aiogram.api.client.session.aiohttp.AiohttpSession.close", new_callable=CoroutineMock
|
||||
"aiogram.api.client.session.httpx.HttpxSession.close", new_callable=CoroutineMock
|
||||
) as mocked_close:
|
||||
async with BaseBot("42:TEST", session=AiohttpSession()).context(
|
||||
auto_close=close
|
||||
) as bot:
|
||||
async with BaseBot("42:TEST", session=HttpxSession()).context(auto_close=close) as bot:
|
||||
assert isinstance(bot, BaseBot)
|
||||
if close:
|
||||
mocked_close.assert_awaited()
|
||||
|
|
|
|||
156
tests/test_api/test_client/test_session/test_httpx_session.py
Normal file
156
tests/test_api/test_client/test_session/test_httpx_session.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
import re
|
||||
from typing import AsyncContextManager, AsyncGenerator
|
||||
|
||||
import aiohttp
|
||||
import httpx
|
||||
import pytest
|
||||
import respx
|
||||
from aresponses import ResponsesMockServer
|
||||
from pip._vendor.packaging.version import Version
|
||||
from respx import HTTPXMock
|
||||
|
||||
from aiogram.api.client.session.httpx import HttpxSession
|
||||
from aiogram.api.client.telegram import PRODUCTION
|
||||
from aiogram.api.methods import Request, TelegramMethod
|
||||
from aiogram.api.types import InputFile
|
||||
|
||||
try:
|
||||
from asynctest import CoroutineMock, patch
|
||||
except ImportError:
|
||||
from unittest.mock import AsyncMock as CoroutineMock, patch # type: ignore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def httpx_mock():
|
||||
with respx.mock() as httpx_mock:
|
||||
yield httpx_mock
|
||||
|
||||
|
||||
class BareInputFile(InputFile):
|
||||
async def read(self, chunk_size: int):
|
||||
yield b""
|
||||
|
||||
|
||||
class TestHttpxSession:
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_session(self):
|
||||
session = HttpxSession()
|
||||
|
||||
assert session._client is None
|
||||
httpx_session = await session.create_session()
|
||||
assert session._client is not None
|
||||
assert isinstance(httpx_session, httpx.AsyncClient)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close_session(self):
|
||||
session = HttpxSession()
|
||||
await session.create_session()
|
||||
|
||||
with patch("httpx.AsyncClient.aclose", new=CoroutineMock()) as mocked_close:
|
||||
await session.close()
|
||||
mocked_close.assert_called_once()
|
||||
|
||||
def test_build_form_data_with_data_only(self):
|
||||
request = Request(
|
||||
method="method",
|
||||
data={
|
||||
"str": "value",
|
||||
"int": 42,
|
||||
"bool": True,
|
||||
"null": None,
|
||||
"list": ["foo"],
|
||||
"dict": {"bar": "baz"},
|
||||
},
|
||||
)
|
||||
|
||||
session = HttpxSession()
|
||||
form, files = session.build_form_data(request)
|
||||
|
||||
fields = list(form.keys()) + list(files.keys())
|
||||
assert len(fields) == 5
|
||||
assert all(isinstance(field, str) for field in fields)
|
||||
assert "null" not in fields
|
||||
|
||||
def test_build_form_data_with_files(self):
|
||||
request = Request(
|
||||
method="method",
|
||||
data={"key": "value"},
|
||||
files={"document": BareInputFile(filename="file.txt")},
|
||||
)
|
||||
|
||||
session = HttpxSession()
|
||||
form, files = session.build_form_data(request)
|
||||
|
||||
assert len(form) + len(files) == 2
|
||||
assert "document" in files
|
||||
assert files["document"][1] == "file.txt"
|
||||
assert isinstance(files["document"][0], BareInputFile)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_make_request(self, httpx_mock: HTTPXMock):
|
||||
httpx_mock.post(
|
||||
url=re.compile(r".*/bot42:TEST/method"),
|
||||
status_code=200,
|
||||
content='{"ok": true, "result": 42}',
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
session = HttpxSession()
|
||||
|
||||
class TestMethod(TelegramMethod[int]):
|
||||
__returning__ = int
|
||||
|
||||
def build_request(self) -> Request:
|
||||
return Request(method="method", data={})
|
||||
|
||||
call = TestMethod()
|
||||
with patch(
|
||||
"aiogram.api.client.session.base.BaseSession.raise_for_status"
|
||||
) as patched_raise_for_status:
|
||||
result = await session.make_request("42:TEST", call)
|
||||
assert isinstance(result, int)
|
||||
assert result == 42
|
||||
|
||||
assert patched_raise_for_status.called_once()
|
||||
|
||||
# Update right Version if httpx still didn't implement it
|
||||
@pytest.mark.skipif(
|
||||
Version(httpx.__version__) <= Version("0.12.0"),
|
||||
reason="old httpx doesn't support chunk_size",
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_stream_content(self, httpx_mock: HTTPXMock):
|
||||
|
||||
httpx_mock.get(
|
||||
url=re.compile(".*"), status_code=200, content=b"\f" * 10,
|
||||
)
|
||||
|
||||
session = HttpxSession()
|
||||
stream = session.stream_content(
|
||||
"https://www.python.org/static/img/python-logo.png", timeout=5, chunk_size=1
|
||||
)
|
||||
assert isinstance(stream, AsyncGenerator)
|
||||
|
||||
size = 0
|
||||
async for chunk in stream:
|
||||
assert isinstance(chunk, bytes)
|
||||
chunk_size = len(chunk)
|
||||
assert chunk_size == 1
|
||||
size += chunk_size
|
||||
assert size == 10
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_context_manager(self):
|
||||
session = HttpxSession()
|
||||
assert isinstance(session, AsyncContextManager)
|
||||
|
||||
with patch(
|
||||
"aiogram.api.client.session.httpx.HttpxSession.create_session",
|
||||
new_callable=CoroutineMock,
|
||||
) as mocked_create_session, patch(
|
||||
"aiogram.api.client.session.httpx.HttpxSession.close", new_callable=CoroutineMock
|
||||
) as mocked_close:
|
||||
async with session as ctx:
|
||||
assert session == ctx
|
||||
mocked_close.awaited_once()
|
||||
mocked_create_session.awaited_once()
|
||||
Loading…
Add table
Add a link
Reference in a new issue