kin: BATON-002 [Research] UX Designer
This commit is contained in:
commit
057e500d5f
29 changed files with 3530 additions and 0 deletions
103
tests/conftest.py
Normal file
103
tests/conftest.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
"""
|
||||
Shared fixtures for the baton backend test suite.
|
||||
|
||||
IMPORTANT: Environment variables and the aiosqlite monkey-patch must be
|
||||
applied before any backend module is imported. This module is loaded first
|
||||
by pytest and all assignments happen at module-level.
|
||||
|
||||
Python 3.14 incompatibility with aiosqlite <= 0.22.1:
|
||||
Connection.__await__ unconditionally calls self._thread.start().
|
||||
When 'async with await conn' is used, the thread is already running by
|
||||
the time __aenter__ tries to start it again → RuntimeError.
|
||||
The monkey-patch below guards the start so threads are only started once.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
# ── 1. Env vars — must precede all backend imports ──────────────────────────
|
||||
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")
|
||||
|
||||
# ── 2. aiosqlite monkey-patch ────────────────────────────────────────────────
|
||||
import aiosqlite
|
||||
|
||||
def _safe_aiosqlite_await(self): # type: ignore[override]
|
||||
"""Start the worker thread only if it has not been started yet."""
|
||||
if not self._thread._started.is_set():
|
||||
self._thread.start()
|
||||
return self._connect().__await__()
|
||||
|
||||
aiosqlite.core.Connection.__await__ = _safe_aiosqlite_await # type: ignore[method-assign]
|
||||
|
||||
# ── 3. Normal imports ────────────────────────────────────────────────────────
|
||||
import tempfile
|
||||
import contextlib
|
||||
from typing import AsyncGenerator
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import respx
|
||||
from httpx import AsyncClient, ASGITransport
|
||||
|
||||
from backend import config
|
||||
|
||||
|
||||
# ── 4. DB-path helper ────────────────────────────────────────────────────────
|
||||
|
||||
@contextlib.contextmanager
|
||||
def temp_db():
|
||||
"""Context manager that sets config.DB_PATH to a temp file and cleans up."""
|
||||
path = tempfile.mktemp(suffix=".db")
|
||||
original = config.DB_PATH
|
||||
config.DB_PATH = path
|
||||
try:
|
||||
yield path
|
||||
finally:
|
||||
config.DB_PATH = original
|
||||
for ext in ("", "-wal", "-shm"):
|
||||
try:
|
||||
os.unlink(path + ext)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
# ── 5. App client factory ────────────────────────────────────────────────────
|
||||
|
||||
def make_app_client():
|
||||
"""
|
||||
Async context manager that:
|
||||
1. Assigns a fresh temp-file DB path
|
||||
2. Mocks Telegram setWebhook and sendMessage
|
||||
3. Runs the FastAPI lifespan (startup → test → shutdown)
|
||||
4. Yields an httpx.AsyncClient wired to the app
|
||||
"""
|
||||
tg_set_url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/setWebhook"
|
||||
send_url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendMessage"
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def _ctx():
|
||||
with temp_db():
|
||||
from backend.main import app
|
||||
|
||||
mock_router = respx.mock(assert_all_called=False)
|
||||
mock_router.post(tg_set_url).mock(
|
||||
return_value=httpx.Response(200, json={"ok": True, "result": True})
|
||||
)
|
||||
mock_router.post(send_url).mock(
|
||||
return_value=httpx.Response(200, json={"ok": True})
|
||||
)
|
||||
|
||||
with mock_router:
|
||||
async with app.router.lifespan_context(app):
|
||||
transport = ASGITransport(app=app)
|
||||
async with AsyncClient(
|
||||
transport=transport, base_url="http://testserver"
|
||||
) as client:
|
||||
yield client
|
||||
|
||||
return _ctx()
|
||||
Loading…
Add table
Add a link
Reference in a new issue