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

@@ -18,6 +18,7 @@ from app.features.auth.deps import get_auth_service
from app.features.auth.router import router as auth_router
from app.features.auth.service import AuthService
from app.features.user.models import User
from tests.conftest import install_test_error_handlers
def _mock_current_user() -> User:
@@ -35,7 +36,7 @@ def _mock_current_user() -> User:
@pytest.fixture
def preset_auth_app() -> FastAPI:
app = FastAPI()
app = install_test_error_handlers(FastAPI())
app.include_router(auth_router)
fixed_user = _mock_current_user()
@@ -197,10 +198,9 @@ async def test_upload_avatar_cos_calls_storage_and_presigns(
uid = str(uuid.uuid4())
public = f"https://{bucket}.cos.{region}.myqcloud.com/avatars/{uid}.jpg"
for attr, val in (
("tencent_cos_secret_id", "sid"),
("tencent_cos_secret_key", "sk"),
("tencent_secret_id", "sid"),
("tencent_secret_key", "sk"),
("tencent_cos_bucket", bucket),
("tencent_cos_region", region),
("tencent_cos_base_url", f"https://{bucket}.cos.{region}.myqcloud.com"),
):
monkeypatch.setattr(settings, attr, val, raising=False)
@@ -214,19 +214,27 @@ async def test_upload_avatar_cos_calls_storage_and_presigns(
fixed_user.id = uid
fixed_user.avatar_url = None
async def _fake_update_avatar(u: str, url: str):
async def _fake_upload_avatar(
user_id: str,
file_content: bytes,
content_type: str,
*,
old_avatar_url: str | None,
):
_ = (user_id, file_content, content_type, old_avatar_url)
url = mock_storage.upload(f"avatars/{uid}.jpg", b"jpeg", "image/jpeg")
fixed_user.avatar_url = url
return fixed_user
mock_service = MagicMock(spec=AuthService)
mock_service.update_avatar_url = AsyncMock(side_effect=_fake_update_avatar)
mock_service.upload_avatar = AsyncMock(side_effect=_fake_upload_avatar)
app = FastAPI()
app = install_test_error_handlers(FastAPI())
app.include_router(auth_router)
app.dependency_overrides[get_auth_service] = lambda: mock_service
app.dependency_overrides[get_current_user] = lambda: fixed_user
transport = ASGITransport(app=app)
transport = ASGITransport(app=app, raise_app_exceptions=False)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
r = await ac.post(
"/api/auth/me/avatar",
@@ -235,8 +243,7 @@ async def test_upload_avatar_cos_calls_storage_and_presigns(
)
assert r.status_code == 200
assert r.json()["avatar_url"] == "https://example.com/signed-avatar"
body = r.json()
assert body["avatar_url"] == "https://example.com/signed-avatar"
mock_storage.upload.assert_called_once()
assert mock_storage.upload.call_args[0][0] == f"avatars/{uid}.jpg"
mock_storage.get_url.assert_called_once()
assert mock_storage.get_url.call_args[0][0] == f"avatars/{uid}.jpg"