import urllib.request, urllib.error, http.cookiejar, json, sys, time BASE = "http://127.0.0.1:3000" def opener_with_cookies(): cj = http.cookiejar.CookieJar() return urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)) def call(op, path, method="GET", data=None): url = BASE + path body = json.dumps(data).encode() if data is not None else None req = urllib.request.Request(url, data=body, method=method) if body: req.add_header("Content-Type", "application/json") try: r = op.open(req, timeout=10) return r.status, r.read() except urllib.error.HTTPError as e: return e.code, e.read() anon = opener_with_cookies() auth = opener_with_cookies() results = [] def check(name, cond, extra=""): results.append((name, cond)); print(("PASS" if cond else "FAIL"), name, extra) # 鉴权 st, _ = call(anon, "/api/resources"); check("未登录API=401", st == 401, f"got {st}") st, body = call(anon, "/login"); check("登录页200", st == 200, f"got {st}") st, body = call(anon, "/"); check("未登录/=登录页", st == 200 and b"loginForm" in body, f"got {st}") st, _ = call(anon, "/index.html"); check("未登录index.html=登录页", st == 200 and b"loginForm" in _, f"got {st}") st, _ = call(auth, "/api/auth/login", "POST", {"password": "wrong"}); check("错密码401", st == 401, f"got {st}") st, body = call(auth, "/api/auth/login", "POST", {"password": "test123"}); check("登录成功", st == 200 and json.loads(body).get("ok"), f"got {st}") # 资源与流 st, body = call(auth, "/api/resources"); d = json.loads(body) check("资源列表5项", st == 200 and len(d["list"]) == 5, f"{len(d.get('list',[]))}项") first = d["list"][0]["file"] tid = "t%d" % int(time.time()) st, body = call(auth, "/api/streams", "POST", {"id": tid, "name": "临时测试流"}) check("创建流", st == 200 and json.loads(body).get("ok"), body[:80].decode("utf-8","ignore")) st, body = call(anon, "/hls/%s/index.m3u8" % tid); check("新流m3u8可达", st == 200, f"got {st}") st, body = call(auth, "/api/streams/%s/playlist/add" % tid, "POST", {"file": first}) check("新流加歌", st == 200, f"got {st}") st, body = call(auth, "/api/streams"); d = json.loads(body) check("流列表含新流", any(s["id"] == tid for s in d["list"]), "") # 清理 st, body = call(auth, "/api/streams/%s" % tid, "DELETE", {}) check("删除流", st == 200, f"got {st}") # 缓存/日志 st, body = call(auth, "/api/system/cache"); d = json.loads(body) check("缓存信息", st == 200 and "total" in d, f"{d.get('total')}B") st, body = call(auth, "/api/system/logs?tail=5") check("日志接口", st == 200 and len(json.loads(body).get("lines", [])) > 0, "") # 登出 st, _ = call(auth, "/api/auth/logout", "POST"); check("登出", st == 200, f"got {st}") st, _ = call(auth, "/api/resources"); check("登出后401", st == 401, f"got {st}") print("\n=== 汇总:", sum(1 for _, c in results if c), "/", len(results), "通过 ===") sys.exit(0 if all(c for _, c in results) else 1)