Only surface Telegram delivery errors while updates are still pending, and register the webhook after the aiohttp webhook site starts listening.
142 lines
4.1 KiB
Python
142 lines
4.1 KiB
Python
import ast
|
|
import asyncio
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from aiogram.exceptions import TelegramNetworkError
|
|
|
|
from bot.main_bot import _run_telegram_startup_step
|
|
|
|
|
|
def test_backend_startup_does_not_run_panel_sync_inline():
|
|
source = Path("backend/bot/main_bot.py").read_text(encoding="utf-8")
|
|
tree = ast.parse(source)
|
|
|
|
forbidden_imports = [
|
|
node
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.ImportFrom) and node.module == "bot.handlers.admin.sync_admin"
|
|
]
|
|
forbidden_calls = [
|
|
node
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.Call)
|
|
and isinstance(node.func, ast.Name)
|
|
and node.func.id == "perform_sync"
|
|
]
|
|
|
|
assert forbidden_imports == []
|
|
assert forbidden_calls == []
|
|
|
|
|
|
def test_worker_starts_backup_task_without_enabled_guard():
|
|
source = Path("backend/main_worker.py").read_text(encoding="utf-8")
|
|
tree = ast.parse(source)
|
|
|
|
guarded_backup_tasks = [
|
|
node
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.If)
|
|
and isinstance(node.test, ast.Attribute)
|
|
and node.test.attr == "BACKUP_ENABLED"
|
|
]
|
|
|
|
assert "BackupWorker" in source
|
|
assert guarded_backup_tasks == []
|
|
|
|
|
|
def test_telegram_webhook_configuration_is_deferred_until_site_start():
|
|
main_source = Path("backend/bot/main_bot.py").read_text(encoding="utf-8")
|
|
web_source = Path("backend/bot/app/web/web_server.py").read_text(encoding="utf-8")
|
|
tree = ast.parse(main_source)
|
|
startup_node = next(
|
|
node
|
|
for node in ast.walk(tree)
|
|
if isinstance(node, ast.AsyncFunctionDef) and node.name == "on_startup_configured"
|
|
)
|
|
|
|
startup_set_webhook_calls = [
|
|
node
|
|
for node in ast.walk(startup_node)
|
|
if isinstance(node, ast.Attribute) and node.attr == "set_webhook"
|
|
]
|
|
|
|
assert startup_set_webhook_calls == []
|
|
assert "after_webhooks_started=_after_webhooks_started" in main_source
|
|
assert web_source.index("await site.start()") < web_source.index(
|
|
"await after_webhooks_started()"
|
|
)
|
|
|
|
|
|
def test_telegram_startup_network_error_retries_until_success_without_traceback(caplog):
|
|
calls = []
|
|
|
|
async def failing_step():
|
|
calls.append("try")
|
|
if len(calls) >= 3:
|
|
return
|
|
try:
|
|
raise OSError("Temporary failure in name resolution")
|
|
except OSError as exc:
|
|
raise TelegramNetworkError(
|
|
method=object(),
|
|
message="ClientConnectorDNSError: Cannot connect to host api.telegram.org:443",
|
|
) from exc
|
|
|
|
with caplog.at_level(logging.INFO):
|
|
result = asyncio.run(
|
|
_run_telegram_startup_step(
|
|
"registering mini app menu button",
|
|
failing_step,
|
|
"unexpected",
|
|
retry_delay_seconds=0,
|
|
)
|
|
)
|
|
|
|
assert result is True
|
|
assert calls == ["try", "try", "try"]
|
|
assert "Telegram network error while registering mini app menu button" in caplog.text
|
|
assert (
|
|
"Telegram step succeeded while registering mini app menu button on attempt 3" in caplog.text
|
|
)
|
|
assert "api.telegram.org" in caplog.text
|
|
assert "Temporary failure in name resolution" in caplog.text
|
|
assert "Traceback" not in caplog.text
|
|
|
|
|
|
def test_telegram_startup_step_returns_true_on_success():
|
|
calls = []
|
|
|
|
async def successful_step():
|
|
calls.append("ok")
|
|
|
|
result = asyncio.run(
|
|
_run_telegram_startup_step(
|
|
"setting bot commands",
|
|
successful_step,
|
|
"unexpected",
|
|
)
|
|
)
|
|
|
|
assert result is True
|
|
assert calls == ["ok"]
|
|
|
|
|
|
def test_telegram_startup_step_can_be_limited_for_tests(caplog):
|
|
async def failing_step():
|
|
raise TelegramNetworkError(method=object(), message="temporary dns failure")
|
|
|
|
with caplog.at_level(logging.WARNING):
|
|
result = asyncio.run(
|
|
_run_telegram_startup_step(
|
|
"setting bot commands",
|
|
failing_step,
|
|
"unexpected",
|
|
attempts=2,
|
|
retry_delay_seconds=0,
|
|
)
|
|
)
|
|
|
|
assert result is False
|
|
assert "after 2 attempts" in caplog.text
|