179 lines
5.8 KiB
Python
179 lines
5.8 KiB
Python
import httpx
|
|
import pytest
|
|
|
|
from takopi.telegram.client_api import (
|
|
HttpBotClient,
|
|
TelegramRetryAfter,
|
|
retry_after_from_payload,
|
|
)
|
|
from takopi.telegram.api_models import User
|
|
|
|
|
|
def _response() -> httpx.Response:
|
|
request = httpx.Request("POST", "https://example.com")
|
|
return httpx.Response(200, request=request)
|
|
|
|
|
|
def test_retry_after_from_payload() -> None:
|
|
assert retry_after_from_payload({}) is None
|
|
assert retry_after_from_payload({"parameters": {"retry_after": 2}}) == 2.0
|
|
|
|
|
|
def test_parse_envelope_invalid_payload() -> None:
|
|
client = HttpBotClient("token", http_client=httpx.AsyncClient())
|
|
assert (
|
|
client._parse_telegram_envelope(
|
|
method="sendMessage",
|
|
resp=_response(),
|
|
payload="nope",
|
|
)
|
|
is None
|
|
)
|
|
|
|
|
|
def test_parse_envelope_rate_limited() -> None:
|
|
client = HttpBotClient("token", http_client=httpx.AsyncClient())
|
|
payload = {"ok": False, "error_code": 429, "parameters": {"retry_after": 1}}
|
|
with pytest.raises(TelegramRetryAfter) as exc:
|
|
client._parse_telegram_envelope(
|
|
method="sendMessage",
|
|
resp=_response(),
|
|
payload=payload,
|
|
)
|
|
assert exc.value.retry_after == 1.0
|
|
|
|
|
|
def test_parse_envelope_api_error() -> None:
|
|
client = HttpBotClient("token", http_client=httpx.AsyncClient())
|
|
payload = {"ok": False, "error_code": 400, "description": "boom"}
|
|
assert (
|
|
client._parse_telegram_envelope(
|
|
method="sendMessage",
|
|
resp=_response(),
|
|
payload=payload,
|
|
)
|
|
is None
|
|
)
|
|
|
|
|
|
def test_parse_envelope_ok() -> None:
|
|
client = HttpBotClient("token", http_client=httpx.AsyncClient())
|
|
payload = {"ok": True, "result": {"message_id": 1}}
|
|
assert client._parse_telegram_envelope(
|
|
method="sendMessage",
|
|
resp=_response(),
|
|
payload=payload,
|
|
) == {"message_id": 1}
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_client_methods_build_params_and_decode() -> None:
|
|
payloads = {
|
|
"getUpdates": [{"update_id": 1}],
|
|
"getFile": {"file_path": "path"},
|
|
"sendMessage": {"message_id": 1, "chat": {"id": 1, "type": "private"}},
|
|
"sendDocument": {"message_id": 2, "chat": {"id": 1, "type": "private"}},
|
|
"editMessageText": {"message_id": 3, "chat": {"id": 1, "type": "private"}},
|
|
"deleteMessage": True,
|
|
"setMyCommands": True,
|
|
"getMe": {"id": 7},
|
|
"answerCallbackQuery": True,
|
|
"getChat": {"id": 5, "type": "private"},
|
|
"getChatMember": {"status": "member"},
|
|
"createForumTopic": {"message_thread_id": 11},
|
|
"editForumTopic": True,
|
|
}
|
|
|
|
class _StubClient(HttpBotClient):
|
|
def __init__(self) -> None:
|
|
super().__init__("token", http_client=httpx.AsyncClient())
|
|
self.calls: list[tuple[str, dict | None, dict | None, dict | None]] = []
|
|
|
|
async def _request(
|
|
self,
|
|
method: str,
|
|
*,
|
|
json: dict | None = None,
|
|
data: dict | None = None,
|
|
files: dict | None = None,
|
|
) -> object | None:
|
|
self.calls.append((method, json, data, files))
|
|
return payloads.get(method)
|
|
|
|
client = _StubClient()
|
|
|
|
updates = await client.get_updates(offset=10, allowed_updates=["message"])
|
|
assert updates and updates[0].update_id == 1
|
|
|
|
assert await client.get_file("file") is not None
|
|
|
|
msg = await client.send_message(
|
|
1,
|
|
"hi",
|
|
reply_to_message_id=2,
|
|
disable_notification=True,
|
|
message_thread_id=3,
|
|
entities=[{"type": "bold", "offset": 0, "length": 2}],
|
|
parse_mode="Markdown",
|
|
reply_markup={"inline_keyboard": []},
|
|
)
|
|
assert msg and msg.message_id == 1
|
|
|
|
doc = await client.send_document(
|
|
1,
|
|
"file.txt",
|
|
b"data",
|
|
reply_to_message_id=2,
|
|
message_thread_id=3,
|
|
disable_notification=True,
|
|
caption="doc",
|
|
)
|
|
assert doc and doc.message_id == 2
|
|
|
|
edit = await client.edit_message_text(
|
|
1,
|
|
2,
|
|
"edit",
|
|
entities=[{"type": "italic", "offset": 0, "length": 4}],
|
|
parse_mode="Markdown",
|
|
reply_markup={"inline_keyboard": []},
|
|
)
|
|
assert edit and edit.message_id == 3
|
|
|
|
assert await client.delete_message(1, 2) is True
|
|
assert await client.set_my_commands(
|
|
[{"command": "ping", "description": "pong"}],
|
|
scope={"type": "chat"},
|
|
language_code="en",
|
|
)
|
|
assert await client.answer_callback_query("cb", text="ok", show_alert=True) is True
|
|
assert await client.get_chat(1) is not None
|
|
assert await client.get_chat_member(1, 2) is not None
|
|
assert await client.create_forum_topic(1, "topic") is not None
|
|
assert await client.edit_forum_topic(1, 2, "topic") is True
|
|
|
|
await client.close()
|
|
|
|
send_call = next(call for call in client.calls if call[0] == "sendMessage")
|
|
assert send_call[1]["disable_notification"] is True
|
|
assert send_call[1]["reply_to_message_id"] == 2
|
|
assert send_call[1]["message_thread_id"] == 3
|
|
assert send_call[1]["entities"]
|
|
assert send_call[1]["parse_mode"] == "Markdown"
|
|
assert send_call[1]["link_preview_options"] == {"is_disabled": True}
|
|
assert send_call[1]["reply_markup"]
|
|
|
|
doc_call = next(call for call in client.calls if call[0] == "sendDocument")
|
|
assert doc_call[2]["caption"] == "doc"
|
|
assert doc_call[3]["document"][0] == "file.txt"
|
|
|
|
edit_call = next(call for call in client.calls if call[0] == "editMessageText")
|
|
assert edit_call[1]["link_preview_options"] == {"is_disabled": True}
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_decode_result_invalid_payload_returns_none() -> None:
|
|
client = HttpBotClient("token", http_client=httpx.AsyncClient())
|
|
assert client._decode_result(method="getMe", payload=["bad"], model=User) is None
|
|
await client.close()
|