Merge branch 'BATON-ARCH-013-backend_dev'
This commit is contained in:
commit
59eb117589
1 changed files with 84 additions and 0 deletions
84
tests/test_arch_013.py
Normal file
84
tests/test_arch_013.py
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
"""
|
||||||
|
Tests for BATON-ARCH-013: Keep-alive mechanism / health endpoint.
|
||||||
|
|
||||||
|
Acceptance criteria:
|
||||||
|
1. GET /health returns HTTP 200 OK.
|
||||||
|
2. Response body contains JSON with {"status": "ok"}.
|
||||||
|
3. Endpoint does not require authorization (no token, no secret header needed).
|
||||||
|
4. Keep-alive loop is started when APP_URL is set, and NOT started when APP_URL is unset.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
os.environ.setdefault("BOT_TOKEN", "test-bot-token")
|
||||||
|
os.environ.setdefault("CHAT_ID", "-1001234567890")
|
||||||
|
os.environ.setdefault("WEBHOOK_SECRET", "test-webhook-secret")
|
||||||
|
os.environ.setdefault("WEBHOOK_URL", "https://example.com/api/webhook/telegram")
|
||||||
|
os.environ.setdefault("FRONTEND_ORIGIN", "http://localhost:3000")
|
||||||
|
|
||||||
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tests.conftest import make_app_client, temp_db
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Criterion 1 & 2 & 3 — GET /health → 200 OK, {"status": "ok"}, no auth
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_health_returns_200_ok():
|
||||||
|
"""GET /health должен вернуть HTTP 200 без какого-либо заголовка авторизации."""
|
||||||
|
async with make_app_client() as client:
|
||||||
|
response = await client.get("/health")
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_health_returns_status_ok():
|
||||||
|
"""GET /health должен вернуть JSON содержащий {"status": "ok"}."""
|
||||||
|
async with make_app_client() as client:
|
||||||
|
response = await client.get("/health")
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
assert data.get("status") == "ok"
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Criterion 4 — keep-alive task lifecycle
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_keepalive_started_when_app_url_set():
|
||||||
|
"""Keep-alive задача должна стартовать при наличии APP_URL."""
|
||||||
|
from backend.main import app
|
||||||
|
|
||||||
|
with temp_db():
|
||||||
|
with patch("backend.telegram.set_webhook", new_callable=AsyncMock):
|
||||||
|
with patch("backend.config.APP_URL", "https://example.com"):
|
||||||
|
with patch("backend.main._keep_alive_loop", new_callable=AsyncMock) as mock_loop:
|
||||||
|
async with app.router.lifespan_context(app):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# asyncio.create_task вызывается с корутиной _keep_alive_loop — проверяем что она была вызвана
|
||||||
|
assert mock_loop.called
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_keepalive_not_started_when_app_url_unset():
|
||||||
|
"""Keep-alive задача НЕ должна стартовать при отсутствии APP_URL."""
|
||||||
|
from backend.main import app
|
||||||
|
|
||||||
|
with temp_db():
|
||||||
|
with patch("backend.telegram.set_webhook", new_callable=AsyncMock):
|
||||||
|
with patch("backend.config.APP_URL", None):
|
||||||
|
with patch("backend.main._keep_alive_loop", new_callable=AsyncMock) as mock_loop:
|
||||||
|
async with app.router.lifespan_context(app):
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert not mock_loop.called
|
||||||
Loading…
Add table
Add a link
Reference in a new issue