import json import urllib.request import urllib.error BASE = "http://localhost:8902" def req(method, path, token=None, body=None): url = BASE + path data = json.dumps(body).encode() if body is not None else None r = urllib.request.Request(url, data=data, method=method) r.add_header("Content-Type", "application/json") if token: r.add_header("Authorization", "Bearer " + token) try: with urllib.request.urlopen(r, timeout=10) as resp: return resp.status, json.loads(resp.read().decode()) except urllib.error.HTTPError as e: return e.code, json.loads(e.read().decode()) print("=== 1) 登录 admin ===") _, login = req("POST", "/api/auth/login", body={"username": "admin", "password": "123456"}) TOKEN = login.get("data", {}).get("token", "") assert TOKEN, "登录失败" print("token:", TOKEN[:12] + "...") print("\n=== 2) seed 初始化权限与角色 ===") s, seed = req("POST", "/api/rbac/seed", TOKEN, {}) print("HTTP", s, "->", seed.get("data")) print("\n=== 3) /api/permissions 权限列表(应含 MENU+BUTTON, 无废弃package:view) ===") _, perms = req("GET", "/api/permissions", TOKEN) plist = perms.get("data", {}).get("list", []) codes = [p["code"] for p in plist] print("权限总数:", len(plist), "| MENU:", sum(1 for c in codes if c.endswith(':view') or c in ('dashboard:view','role:manage','user:manage'))) print("menu去重内 sample:", [c for c in codes if c in ('inbound:view','inventory:view','role:manage')]) print("BUTTON sample:", [c for c in codes if c in ('inbound:create','material:edit','inbound:export','outbound:export','inspection:export','inventory:export')]) assert "inbound:view" in codes, "缺 inbound:view" assert "inbound:create" in codes, "缺按钮权限" assert "package:view" not in codes, "废弃 package:view 未清除!" print("\n=== 4) /api/roles 角色列表 ===") _, roles = req("GET", "/api/roles", TOKEN) rlist = roles.get("data", {}).get("list", []) print("角色数:", len(rlist), "|", [(r["code"], len(r.get("permissionCodes", []))) for r in rlist]) admin_role = next(r for r in rlist if r["code"] == "admin") print("admin 权限示例:", admin_role.get("permissionCodes", [])[:4], "...") assert any(r["code"] == "admin" for r in rlist) print("\n=== 5) 新建自定义角色 test-role ===") _, cr = req("POST", "/api/roles", TOKEN, { "name": "E2E测试角色", "code": "e2e_test_role", "remark": "验证用", "permissionCodes": ["inventory:view", "inventory:export"] }) print("创建:", cr.get("code"), cr.get("message")) rid = cr.get("data", {}).get("id") assert rid, "创建角色失败" print("\n=== 6a) 编辑角色(变更权限) ===") _, ur = req("POST", "/api/roles/update", TOKEN, { "id": rid, "name": "E2E测试角色改", "permissionCodes": ["inventory:view", "inbound:view", "inbound:export", "inventory:export"] }) print("编辑:", ur.get("code"), ur.get("message")) print("\n=== 6b) 删除内置角色应被拒 ===") admin_role_id = next(r for r in rlist if r["code"] == "admin")["id"] _, dr = req("POST", "/api/roles/delete", TOKEN, {"id": admin_role_id}) print("删内置角色 -> code:", dr.get("code"), "msg:", dr.get("message")) assert dr.get("code") != 0, "内置角色不应被删除!" print("\n=== 7) 删除测试角色 ===") _, dr2 = req("POST", "/api/roles/delete", TOKEN, {"id": rid}) print("删测试角色 -> code:", dr2.get("code")) print("\n=== 8) /user/info 返回权限码(admin 应含全部) ===") _, info = req("GET", "/api/user/info", TOKEN) pc = info.get("data", {}).get("permissionCodes", []) print("admin 权限码数:", len(pc), "| 含 role:manage:", "role:manage" in pc, "| 含 inbound:create:", "inbound:create" in pc) assert "role:manage" in pc, "admin 应可见角色管理" print("\nALL PASS ✅")