"""认证 E2E:登录取 token → /auth/me 依赖注入回查 sys_user → 反例(错密码/坏 token/已删用户)。 全程跑在同一个事件循环(httpx.ASGITransport),避免单例 async engine 跨循环。 """ import asyncio import httpx import main as appmod from config.database.mysql import get_engine, get_session_factory from model.sys_user import SysUser from repositories.sys_user import SysUserRepo from service.auth import hash_password USER = "auth_test_u" PWD = "Test@1234" async def seed() -> int: async with get_session_factory()() as s: repo = SysUserRepo(s) existing = await repo.get_by_username(USER) if existing: return existing.id u = SysUser(username=USER, password_hash=hash_password(PWD), phone="13800001111", user_type="EMPLOYEE", employee_role="理财顾问", status="正常") return (await repo.add(u)).id async def cleanup(uid: int) -> None: async with get_session_factory()() as s: await SysUserRepo(s).delete(uid) async def run(): uid = await seed() try: transport = httpx.ASGITransport(app=appmod.app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as c: # 错密码 → 400 r = await c.post("/api/auth/login", json={"username": USER, "password": "wrong"}) assert r.status_code == 400 and r.json()["code"] == 400, r.text # 正常登录 → token r = await c.post("/api/auth/login", json={"username": USER, "password": PWD}) assert r.status_code == 200, r.text token = r.json()["data"]["token"] assert token # /auth/me:依赖注入按 id 回查 sys_user r = await c.get("/api/auth/me", headers={"Authorization": f"Bearer {token}"}) me = r.json()["data"]["user"] assert r.status_code == 200 and me["id"] == uid and me["employee_role"] == "理财顾问", r.text # 缺 token / 坏 token → 401 assert (await c.get("/api/auth/me")).status_code == 401 assert (await c.get("/api/auth/me", headers={"Authorization": "Bearer abc.def.ghi"})).status_code == 401 # 删除用户后 token 回查失败 → 401 await cleanup(uid) assert (await c.get("/api/auth/me", headers={"Authorization": f"Bearer {token}"})).status_code == 401 # 不存在用户登录 → 400 r = await c.post("/api/auth/login", json={"username": "no_such_user", "password": PWD}) assert r.status_code == 400 print("AUTH TESTS PASSED") finally: await get_engine().dispose() if __name__ == "__main__": asyncio.run(run())