"""owner_scope 全链路贯穿集成测试。 验证两个不同用户的 character/preferences 数据互不可见。 """ from collections.abc import AsyncGenerator import pytest from httpx import ASGITransport, AsyncClient from app.main import app @pytest.fixture(autouse=True) def _jwt_enabled(monkeypatch: pytest.MonkeyPatch) -> None: """所有 API 测试需要 JWT_SECRET 配置。""" monkeypatch.setattr("app.core.config.settings.jwt_secret", "test-jwt-secret-for-testing") @pytest.fixture async def client() -> AsyncGenerator[AsyncClient, None]: transport = ASGITransport(app=app) async with AsyncClient(transport=transport, base_url="http://test") as http_client: yield http_client async def _register_and_login(client: AsyncClient, suffix: str) -> dict: """辅助:注册并登录,返回 access_token 和 user_id。""" username = f"user_{suffix}" email = f"{suffix}@test.com" await client.post( "/api/v1/auth/register", json={"username": username, "email": email, "password": "pass"}, ) resp = await client.post( "/api/v1/auth/login", json={"username": username, "password": "pass"}, ) data = resp.json() return { "access_token": data["access_token"], "user_id": data["user"]["id"], } @pytest.mark.asyncio async def test_users_see_own_characters_only(client: AsyncClient) -> None: user_a = await _register_and_login(client, "a") user_b = await _register_and_login(client, "b") # 用户 A 查看角色列表 resp_a = await client.get( "/api/v1/characters", headers={"Authorization": f"Bearer {user_a['access_token']}"}, ) assert resp_a.status_code == 200 # 用户 B 查看角色列表 resp_b = await client.get( "/api/v1/characters", headers={"Authorization": f"Bearer {user_b['access_token']}"}, ) assert resp_b.status_code == 200 # 由于角色是按 owner_scope 过滤的,双方看不到对方的角色 # 因为 seed_default_data 只为第一个用户(admin)创建了角色, # 用户 A 是自己注册的,所以没有角色(注册不自动创建角色) # 这个测试验证查询不会跨用户串数据