# ============================================================ # 免登录云部署:每个浏览器访客只看到自己的项目/会话/个人世界 # ============================================================ from __future__ import annotations import pytest from fastapi.testclient import TestClient @pytest.fixture() def open_app(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_PATH", str(tmp_path / "open.db")) monkeypatch.setenv("APS_WORLD_PATH", str(tmp_path / "world.json")) monkeypatch.setenv("APS_AUTH_ENABLED", "0") from server.db.database import reset_engine from server.state import store as world_store world_store._stores.clear() reset_engine() from server.gateway.app import create_app app = create_app() yield app reset_engine() world_store._stores.clear() def _client(app, visitor: str) -> TestClient: client = TestClient(app) client.headers["X-APS-Visitor-ID"] = visitor return client def test_anonymous_visitors_get_distinct_identities(open_app): alpha = _client(open_app, "visitor-alpha-0001") bravo = _client(open_app, "visitor-bravo-0002") user_a = alpha.get("/api/auth/me").json()["user"] user_b = bravo.get("/api/auth/me").json()["user"] assert user_a["auth_kind"] == "anonymous" assert user_a["user_id"] != user_b["user_id"] def test_anonymous_visitors_only_see_own_projects_and_sessions(open_app): alpha = _client(open_app, "visitor-alpha-0001") bravo = _client(open_app, "visitor-bravo-0002") assert alpha.post( "/api/projects", json={"id": "proj_anon_a", "name": "访客 A 项目"}, ).status_code == 200 alpha_workspace = alpha.get("/api/workspace").json() assert [row["id"] for row in alpha_workspace["projects"]] == ["proj_anon_a"] bravo_workspace = bravo.get("/api/workspace").json() assert bravo_workspace["projects"] == [] assert bravo.get("/api/projects/proj_anon_a/members").status_code == 404 bravo_session = next(row for row in bravo_workspace["sessions"] if row["scope"] == "personal") assert bravo.get(f"/api/sessions/{bravo_session['id']}/messages").status_code == 200 alpha_personal = next( row for row in alpha_workspace["sessions"] if row["scope"] == "personal" ) assert alpha_personal["id"] != bravo_session["id"] assert bravo.get(f"/api/sessions/{alpha_personal['id']}/messages").status_code == 404 def test_same_visitor_reuses_own_workspace(open_app): first = _client(open_app, "visitor-same-0001") first.post("/api/projects", json={"id": "proj_anon_same", "name": "同一访客项目"}) cookie = first.cookies.get("aps_anonymous_id") assert cookie second = TestClient(open_app) second.cookies.set("aps_anonymous_id", cookie) workspace = second.get("/api/workspace").json() assert [row["id"] for row in workspace["projects"]] == ["proj_anon_same"] def test_anonymous_cookie_survives_localstorage_reset(open_app): first = _client(open_app, "visitor-ls-reset-0001") first.post("/api/projects", json={"id": "proj_anon_cookie", "name": "Cookie 项目"}) cookie = first.cookies.get("aps_anonymous_id") assert cookie # 模拟 localStorage 被清空:新浏览器上下文没有访客头,只有服务端 Cookie。 second = TestClient(open_app) second.cookies.set("aps_anonymous_id", cookie) second.headers["X-APS-Visitor-ID"] = "visitor-recreated-0001" workspace = second.get("/api/workspace").json() assert [row["id"] for row in workspace["projects"]] == ["proj_anon_cookie"]