refactor(api): TOML 配置 SSOT、统一错误契约、Auth/事务加固与可观测性 (#33)

配置 SSOT(TOML + .env)
统一错误契约
Auth 与事务边界
Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client
可观测性(OpenTelemetry + LGTM)
This commit is contained in:
Sully
2026-05-22 13:44:50 +08:00
committed by GitHub
parent f09ae248f9
commit 53e0065e3e
298 changed files with 15247 additions and 4344 deletions

View File

@@ -7,6 +7,8 @@ import pytest
from httpx import ASGITransport, AsyncClient
from app.core.dependencies import get_current_user
from app.core.errors import register_exception_handlers
from app.core.middleware import RequestIdMiddleware
from app.features.auth.deps import get_auth_service
from app.features.auth.router import router as auth_router
from app.features.payment.deps import get_payment_order_service
@@ -22,6 +24,8 @@ async def test_wechat_notify_returns_fixed_message_on_service_error() -> None:
raise RuntimeError("wechat_sdk_secret_123")
app = FastAPI()
app.add_middleware(RequestIdMiddleware)
register_exception_handlers(app)
app.include_router(payment_router)
app.dependency_overrides[get_payment_order_service] = lambda: BoomOrderService()
@@ -62,12 +66,9 @@ async def test_avatar_upload_500_detail_sanitized(
return_value="https://test-bucket.cos.ap-shanghai.myqcloud.com/avatars/user-contract-test/abc.jpg"
)
monkeypatch.setattr(deps, "get_object_storage", lambda: mock_storage)
monkeypatch.setattr(settings, "tencent_cos_secret_id", "sid", raising=False)
monkeypatch.setattr(settings, "tencent_cos_secret_key", "sk", raising=False)
monkeypatch.setattr(settings, "tencent_secret_id", "sid", raising=False)
monkeypatch.setattr(settings, "tencent_secret_key", "sk", raising=False)
monkeypatch.setattr(settings, "tencent_cos_bucket", "test-bucket", raising=False)
monkeypatch.setattr(
settings, "tencent_cos_region", "ap-shanghai", raising=False
)
monkeypatch.setattr(
settings,
"tencent_cos_base_url",
@@ -76,22 +77,25 @@ async def test_avatar_upload_500_detail_sanitized(
)
class BoomAuth:
async def update_avatar_url(self, user_id: str, avatar_url: str):
async def upload_avatar(self, user_id, file_content, content_type, **kwargs):
raise RuntimeError("db_connection_secret_xyz")
app = FastAPI()
app.add_middleware(RequestIdMiddleware)
register_exception_handlers(app)
app.include_router(auth_router)
app.dependency_overrides[get_current_user] = lambda: fake_user
app.dependency_overrides[get_auth_service] = lambda: BoomAuth()
transport = ASGITransport(app=app)
transport = ASGITransport(app=app, raise_app_exceptions=False)
files = {"file": ("a.jpg", BytesIO(_minimal_jpeg_bytes()), "image/jpeg")}
async with AsyncClient(transport=transport, base_url="http://test") as client:
r = await client.post("/api/auth/me/avatar", files=files)
assert r.status_code == 500
body = r.json()
detail = body.get("detail", "")
assert detail == "处理图片失败,请重试"
assert "secret" not in str(detail).lower()
assert body.get("error_code") == "INTERNAL_ERROR"
message = body.get("message", "")
assert message == "服务器内部错误"
assert "secret" not in str(message).lower()
assert "db_connection" not in r.text