"""认证相关。""" from __future__ import annotations from httpx import AsyncClient from .conftest import DEV_CODE, auth, login, unwrap async def test_login_creates_user_and_me_works(client: AsyncClient) -> None: user = await login(client, "13800000001") me = unwrap(await client.get("/api/v1/auth/me", headers=user["headers"])) assert me["user"]["phone"] == "138****0001" # 手机号对外必须打码 assert me["workspaces"] == [] async def test_login_is_idempotent_for_same_phone(client: AsyncClient) -> None: first = await login(client, "13800000002") second = await login(client, "13800000002") assert first["user_id"] == second["user_id"] async def test_wrong_code_rejected(client: AsyncClient) -> None: await client.post("/api/v1/auth/sms/send", json={"phone": "13800000003"}) resp = await client.post("/api/v1/auth/login", json={"phone": "13800000003", "code": "000000"}) assert resp.status_code == 400 assert resp.json()["code"] == 2010 async def test_code_can_only_be_used_once(client: AsyncClient) -> None: await client.post("/api/v1/auth/sms/send", json={"phone": "13800000004"}) ok = await client.post("/api/v1/auth/login", json={"phone": "13800000004", "code": DEV_CODE}) assert ok.status_code == 200 again = await client.post("/api/v1/auth/login", json={"phone": "13800000004", "code": DEV_CODE}) assert again.json()["code"] == 2010 async def test_sms_throttled(client: AsyncClient, monkeypatch) -> None: # 全局测试默认关掉了节流(SMS_THROTTLE_SECONDS=0),这里显式打开 from app.config import get_settings monkeypatch.setattr(get_settings(), "sms_throttle_seconds", 60) payload = {"phone": "13800000005"} assert (await client.post("/api/v1/auth/sms/send", json=payload)).status_code == 200 second = await client.post("/api/v1/auth/sms/send", json=payload) assert second.json()["code"] == 2011 async def test_refresh_token_cannot_be_used_as_access_token(client: AsyncClient) -> None: user = await login(client) resp = await client.get("/api/v1/auth/me", headers=auth(user["refresh_token"])) assert resp.status_code == 401 assert resp.json()["code"] == 2003 async def test_access_token_cannot_be_used_to_refresh(client: AsyncClient) -> None: user = await login(client) resp = await client.post("/api/v1/auth/refresh", json={"refresh_token": user["token"]}) assert resp.status_code == 401 assert resp.json()["code"] == 2003 async def test_refresh_returns_working_token_pair(client: AsyncClient) -> None: user = await login(client) data = unwrap( await client.post("/api/v1/auth/refresh", json={"refresh_token": user["refresh_token"]}) ) me = await client.get("/api/v1/auth/me", headers=auth(data["access_token"])) assert me.status_code == 200 async def test_requires_token(client: AsyncClient) -> None: resp = await client.get("/api/v1/auth/me") assert resp.status_code == 401 assert resp.json()["code"] == 2001 assert resp.json()["request_id"] != "-" async def test_unknown_path_returns_envelope(client: AsyncClient) -> None: resp = await client.get("/api/v1/nope") assert resp.status_code == 404 assert set(resp.json()) == {"code", "message", "data", "request_id"}