mirror of
https://github.com/karpathy/nanochat.git
synced 2026-05-22 15:47:58 +00:00
- Alembic async migrations: users, conversations, messages, is_favorited - FastAPI auth service: Google + GitHub OAuth, RS256 JWT, refresh cookie - /auth/me, /auth/refresh, /auth/validate (service-to-service) - rate limiting 10/min on OAuth routes, CORS locked to FRONTEND_URL Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
2.8 KiB
Python
85 lines
2.8 KiB
Python
"""Shared pytest fixtures: RSA keys, in-memory DB, FastAPI test client."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import uuid
|
|
from collections.abc import AsyncIterator
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
from cryptography.hazmat.primitives import serialization
|
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
from httpx import ASGITransport, AsyncClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
|
|
|
|
def _make_rsa_pair() -> tuple[str, str]:
|
|
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
|
private = key.private_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PrivateFormat.PKCS8,
|
|
encryption_algorithm=serialization.NoEncryption(),
|
|
).decode()
|
|
public = key.public_key().public_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
|
).decode()
|
|
return private, public
|
|
|
|
|
|
@pytest.fixture(scope="session", autouse=True)
|
|
def _test_environment():
|
|
private, public = _make_rsa_pair()
|
|
os.environ["JWT_PRIVATE_KEY"] = private
|
|
os.environ["JWT_PUBLIC_KEY"] = public
|
|
os.environ["INTERNAL_API_KEY"] = "test-internal-key"
|
|
os.environ["FRONTEND_URL"] = "http://localhost:3000"
|
|
os.environ["AUTH_BASE_URL"] = "http://localhost:8001"
|
|
os.environ["SESSION_SECRET"] = "test-session-secret"
|
|
os.environ["DATABASE_URL"] = "sqlite+aiosqlite:///:memory:"
|
|
os.environ["GOOGLE_CLIENT_ID"] = "g-id"
|
|
os.environ["GOOGLE_CLIENT_SECRET"] = "g-secret"
|
|
os.environ["GITHUB_CLIENT_ID"] = "gh-id"
|
|
os.environ["GITHUB_CLIENT_SECRET"] = "gh-secret"
|
|
|
|
from src.config import get_settings
|
|
|
|
get_settings.cache_clear()
|
|
yield
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def session_factory() -> AsyncIterator[async_sessionmaker[AsyncSession]]:
|
|
from src.database import Base, override_session_factory
|
|
from src.models.user import User # noqa: F401 — register on Base
|
|
|
|
engine = create_async_engine(
|
|
f"sqlite+aiosqlite:///file:test_{uuid.uuid4().hex}?mode=memory&cache=shared&uri=true",
|
|
connect_args={"uri": True},
|
|
)
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
factory = async_sessionmaker(engine, expire_on_commit=False)
|
|
override_session_factory(factory)
|
|
try:
|
|
yield factory
|
|
finally:
|
|
await engine.dispose()
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def db_session(session_factory) -> AsyncIterator[AsyncSession]:
|
|
async with session_factory() as session:
|
|
yield session
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def client(session_factory) -> AsyncIterator[AsyncClient]:
|
|
from src.main import create_app
|
|
|
|
app = create_app()
|
|
transport = ASGITransport(app=app)
|
|
async with AsyncClient(transport=transport, base_url="http://testserver") as ac:
|
|
yield ac
|