diff --git a/backend/API_TEST_REPORT.md b/backend/API_TEST_REPORT.md new file mode 100644 index 0000000..7790195 --- /dev/null +++ b/backend/API_TEST_REPORT.md @@ -0,0 +1,227 @@ +# Backend API Test Report + +更新时间:2026-04-18 + +## 说明 +- 本轮基于单机 Docker Compose 环境验收。 +- Apifox 项目当前约 186 条 endpoint,含重复文档项、内部接口和管理接口映射。 +- 为避免长脚本挂死,本轮改成按模块分批验收。 +- 详细结果以 JSON 明细为准: + - [API_TEST_RESULTS_auth_user.json](/C:/Users/toyas/Desktop/本科毕业设计/参考/workspace/HA-OVP/backend/API_TEST_RESULTS_auth_user.json) + - [API_TEST_RESULTS_content_comment_recommend.json](/C:/Users/toyas/Desktop/本科毕业设计/参考/workspace/HA-OVP/backend/API_TEST_RESULTS_content_comment_recommend.json) + - [API_TEST_RESULTS_admin.json](/C:/Users/toyas/Desktop/本科毕业设计/参考/workspace/HA-OVP/backend/API_TEST_RESULTS_admin.json) + +## 汇总 +- `auth + user`:29 项,`29` 通过,`0` 失败 +- `content + comment + recommend`:63 项,`63` 通过,`0` 失败 +- `admin`:23 项,`23` 通过,`0` 失败,`0` 未测 + +## 最新重测 +- 运行态排查确认: + - `video-user`、`video-comment` 容器此前实际运行的是旧 JAR,和本地源码不一致 + - 重新构建并覆盖容器内 `/app/app.jar` 后,`video-user`、`video-content`、`video-comment` 已与本地源码对齐 +- 公开接口放行修复已生效: + - `GET /user/profile/public/{userId}` 现为 `200` + - `GET /user/profile/search` 现为 `200` + - `GET /user/follow/following/{userId}` 现为 `200` + - `GET /user/follow/followers/{userId}` 现为 `200` + - `GET /content/category/tree` 现为 `200` + - `GET /content/tag/list` 现为 `200` + - `GET /content/tag/page` 现为 `200` +- `POST /content/video` 已打通,最新实测返回 `200`,成功创建视频 `id=17` +- 评论链有进展: + - `GET /comment/public/list?videoId=17...` 返回 `200` + - 评论已成功落库到 `videoId=17` + - `POST /comment` 已恢复为正常快速返回,最新实测 `200`,耗时约 `1207ms` + - `POST /comment/reply` 已返回 `200` + - `POST /comment/like/{id}` 已返回 `200` + - `GET /comment/reply/public/list/{commentId}` 已返回 `200` +- 评论交互短测已补齐: + - `POST /comment`:`200`,约 `279ms` + - `POST /comment/like/{id}`:`200`,约 `294ms` + - `DELETE /comment/like/{id}`:`200`,约 `291ms` + - `POST /comment/reply`:`200`,约 `281ms` + - `GET /comment/reply/public/list/{commentId}`:`200`,约 `264ms` + - `GET /comment/reply/public/hot/{commentId}`:`200`,约 `258ms` + - `POST /comment/reply/like/{id}`:`200`,约 `262ms` + - `DELETE /comment/reply/like/{id}`:`200`,约 `263ms` + - `DELETE /comment/reply/{id}`:`200`,约 `284ms` + - `DELETE /comment/{id}`:`200`,约 `263ms` +- 评论详情/置顶链复测: + - `GET /comment/public/detail/{id}`:`200`,约 `718ms` + - `POST /comment/top/{id}?videoId=17`:`200`,约 `426ms` + - `DELETE /comment/top/{id}?videoId=17`:`200`,约 `333ms` + - `top/untop` 需要“视频作者身份 + 正确的 videoId 参数”;旧失败结论来自测试前提不成立 + - 服务端已补充校验:评论必须属于传入的 `videoId` +- 视频主链短测已补齐: + - `GET /content/video/public/17`:`200`,约 `281ms` + - `GET /content/video/17`:`200`,约 `312ms` + - `PUT /content/video`:`200`,约 `370ms` + - `GET /content/tag/video/17`:`200`,约 `248ms` + - `POST /content/video/like/17`:`200`,约 `325ms` + - `DELETE /content/video/like/17`:`200`,约 `303ms` + - `POST /content/video/coin/17?amount=1`:`200`,约 `262ms` + - `POST /content/video/share/17?platform=wechat`:`200`,约 `275ms` + - `POST /content/video/play`:`200`,约 `295ms` + - `POST /content/video/favorite`:`200`,约 `345ms` + - `DELETE /content/video/favorite/17`:`200`,约 `270ms` + - `GET /content/video/user/30`:作者登录视角已恢复可见审核中视频 + - `POST /content/video/favorite` 的慢失败根因是收藏数同步回写 `video-user` 时遇到锁等待,现已改为 `afterCommit + async best-effort` +- 内容链残余现象: + - 视频详情/视频列表里的 `userNickname`、`userAvatar` 为空问题已修复 + - 根因是 `video-content` 前台详情/列表里对 Feign 返回码使用了 `Integer == Integer` 比较,远程 `200` 没命中成功分支 +- 弹幕和统计链已打通: + - `POST /content/danmaku`:`200`,约 `411ms` + - `GET /content/danmaku/all/17`:`200`,约 `270ms` + - `GET /content/danmaku/time?videoId=17&startTime=0&endTime=30`:`200`,约 `263ms` + - `GET /content/stat/daily/17?...`:`200`,约 `254ms` + - `GET /content/stat/play/trend/17?...`:`200`,约 `245ms` + - `GET /content/stat/interaction/17`:`200`,约 `251ms` + - RocketMQ 路由当前仍异常,但 `video-content` 已补全主表降级更新;弹幕发送后 `danmakuCount` 已能从 `0` 正常变为 `1` +- 后台视频审核链已打通: + - `POST /admin/platform/content/video/review/17?status=1&reason=ok`:`200` + - `GET /admin/platform/content/video/17`:`200` + - 根因一:`video-admin -> video-content` 之前没有透传 `adminId` + - 根因二:`content_video_review.reviewer_id` 外键错误指向了 `video_auth.auth_user` + - 现已改为透传 `X-Admin-Id`,并把审核记录外键改到 `video_admin.admin_user` +- 最后一轮收尾项: + - `GET /auth/username/30`:`200`,已作为公开接口放行 + - `GET /admin/platform/comment/10`:`200` + - `PUT /admin/platform/content/video/disable/17`:`200` + - 为避免环境被留在下架状态,`videoId=17` 已重新审核恢复为发布状态 +- 原未测接口空白已补齐: + - `POST /admin/auth/logout`:`200` + - `GET /auth/admin/login/stats`:`200` + - `PUT /auth/admin/reset-password/{userId}`:`200` + - `PUT /auth/admin/lock/{userId}/{locked}`:`200` + - `POST /content/video/upload`:`200` + - `DELETE /content/video/{id}`:`200` + - `POST /content/video/review/{videoId}`:内部审核接口已打通,普通用户访问已 `403` + - `GET /content/category/admin/list`:`200` + - `POST /content/category/admin`:`200` + - `PUT /content/category/admin`:`200` + - `DELETE /content/category/admin/{categoryId}`:`200` + - `DELETE /content/tag/{id}`:`200` + - `POST /recommend/behavior`:`200` + - `POST /recommend/interest/update`:`200` + - `GET /recommend/similar/{videoId}`:`200` + - `GET /recommend/tag/{tagId}`:`200` + - `recommend/interest/update` 的 500 根因是 MyBatis `Map` foreach 写法错误,现已修复 +- 登录链复测: + - `POST /auth/login` 最新实测 `200`,耗时约 `994ms` + +## 已通过 + +### 核心认证与用户链 +- `POST /auth/register` +- `POST /auth/login` +- `POST /auth/login`:不带验证码会被拦截 +- `POST /auth/refresh` +- `GET /auth/username/{userId}` +- `GET /auth/current` +- `GET /user/profile/current` +- `PUT /user/profile` +- `GET /user/setting` +- `PUT /user/setting` +- `POST /user/follow/{followId}` +- `GET /user/follow/check/{followId}` +- `GET /user/notification/list` +- `GET /user/notification/unread/count` +- `PUT /user/notification/read` +- `POST /user/message` +- `GET /user/message/list` +- `GET /user/message/detail/{targetId}` +- `GET /user/message/unread/count` +- `PUT /user/message/read/{senderId}` +- `POST /auth/logout` +- `DELETE /user/follow/{followId}` +- `GET /auth/admin/login/stats` +- `PUT /auth/admin/reset-password/{userId}` +- `PUT /auth/admin/lock/{userId}/{locked}` + +### 内容/评论/推荐中已确认正常的部分 +- `GET /content/category/list` +- `GET /content/category/tree` +- `POST /content/category` +- `PUT /content/category` +- `DELETE /content/category/{id}` +- `POST /content/tag` +- `GET /content/tag/list` +- `GET /content/tag/page` +- `POST /content/favorite` +- `GET /content/favorite/list` +- `PUT /content/favorite` +- `POST /content/video` +- `POST /content/video/upload` +- `GET /content/video/public/{id}` +- `GET /content/video/public/list` +- `GET /content/video/{id}` +- `GET /content/video/list` +- `GET /content/video/user/{userId}` +- `PUT /content/video` +- `DELETE /content/video/{id}` +- `POST /content/video/review/{videoId}` +- `GET /content/tag/video/{videoId}` +- `POST /content/video/like/{videoId}` +- `DELETE /content/video/like/{videoId}` +- `POST /content/video/coin/{videoId}` +- `POST /content/video/share/{videoId}` +- `POST /content/video/play` +- `POST /content/video/favorite` +- `GET /content/favorite/{favoriteId}/videos` +- `DELETE /content/video/favorite/{videoId}` +- `DELETE /content/favorite/{id}` +- `GET /content/category/admin/list` +- `POST /content/category/admin` +- `PUT /content/category/admin` +- `DELETE /content/category/admin/{categoryId}` +- `DELETE /content/tag/{id}` +- `POST /content/danmaku` +- `GET /content/danmaku/all/{videoId}` +- `GET /content/danmaku/time` +- `GET /content/stat/daily/{videoId}` +- `GET /content/stat/play/trend/{videoId}` +- `GET /content/stat/interaction/{videoId}` +- `POST /recommend/behavior` +- `POST /recommend/interest/update` +- `GET /recommend/similar/{videoId}` +- `GET /recommend/tag/{tagId}` +- `GET /comment/public/list` +- `GET /comment/public/detail/{id}` +- `GET /comment/public/stat/{videoId}` +- `POST /comment` +- `DELETE /comment/{id}` +- `POST /comment/reply` +- `POST /comment/like/{id}` +- `DELETE /comment/like/{id}` +- `POST /comment/top/{id}` +- `DELETE /comment/top/{id}` +- `GET /comment/reply/public/list/{commentId}` +- `GET /comment/reply/public/hot/{commentId}` +- `POST /comment/reply/like/{id}` +- `DELETE /comment/reply/like/{id}` +- `DELETE /comment/reply/{id}` + +### 后台链 +- `POST /admin/auth/login` +- `POST /admin/auth/login`:不带验证码会被拦截 +- `POST /admin/auth/logout` +- `GET /admin/auth/info` +- `GET /admin/platform/user/list` +- `GET /admin/platform/user/{userId}` +- `PUT /admin/platform/user/{userId}/status/{status}` +- `PUT /admin/platform/user/{userId}/reset-password` +- `POST /auth/login`:禁用用户后登录被拦截 +- `POST /auth/login`:后台重置密码后可重新登录 +- `GET /admin/platform/content/category/list` +- `POST /admin/platform/content/category` +- `PUT /admin/platform/content/category` +- `DELETE /admin/platform/content/category/{categoryId}` +- `GET /admin/platform/comment/list` +- `GET /admin/platform/comment/stats` +- `GET /admin/platform/comment/{commentId}` +- `GET /admin/platform/content/video/list` +- `GET /admin/platform/content/video/{videoId}` +- `POST /admin/platform/content/video/review/{videoId}` +- `PUT /admin/platform/content/video/disable/{videoId}` +- `GET /admin/dashboard/stats` diff --git a/backend/API_TEST_RESULTS_admin.json b/backend/API_TEST_RESULTS_admin.json new file mode 100644 index 0000000..26cc7ae --- /dev/null +++ b/backend/API_TEST_RESULTS_admin.json @@ -0,0 +1,193 @@ +{ + "generatedAt": "2026-04-18T16:00:30", + "ids": { + "userA": 10, + "userB": 11 + }, + "results": [ + { + "method": "POST", + "path": "/admin/auth/login", + "status": "PASSED", + "http": 403, + "apiCode": null, + "note": "后台无验证码登录应被拦截" + }, + { + "method": "POST", + "path": "/admin/auth/login", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台登录" + }, + { + "method": "GET", + "path": "/admin/auth/info", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "管理员信息" + }, + { + "method": "GET", + "path": "/admin/platform/user/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台用户列表" + }, + { + "method": "GET", + "path": "/admin/platform/user/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台用户详情" + }, + { + "method": "PUT", + "path": "/admin/platform/user/{userId}/status/{status}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台禁用用户" + }, + { + "method": "POST", + "path": "/auth/login", + "status": "PASSED", + "http": 200, + "apiCode": 403, + "note": "禁用用户登录被拦截" + }, + { + "method": "PUT", + "path": "/admin/platform/user/{userId}/status/{status}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台启用用户" + }, + { + "method": "PUT", + "path": "/admin/platform/user/{userId}/reset-password", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台重置密码" + }, + { + "method": "POST", + "path": "/auth/login", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "重置密码后登录" + }, + { + "method": "GET", + "path": "/admin/platform/content/category/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台分类列表" + }, + { + "method": "POST", + "path": "/admin/platform/content/category", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台添加分类" + }, + { + "method": "PUT", + "path": "/admin/platform/content/category", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台更新分类" + }, + { + "method": "DELETE", + "path": "/admin/platform/content/category/{categoryId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台删除分类" + }, + { + "method": "GET", + "path": "/admin/platform/comment/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台评论列表" + }, + { + "method": "GET", + "path": "/admin/platform/comment/stats", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台评论统计" + }, + { + "method": "GET", + "path": "/admin/platform/comment/{commentId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台评论详情(commentId=10)" + }, + { + "method": "GET", + "path": "/admin/platform/content/video/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台视频列表" + }, + { + "method": "GET", + "path": "/admin/platform/content/video/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台视频详情(videoId=17)" + }, + { + "method": "PUT", + "path": "/admin/platform/content/video/disable/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台下架视频(videoId=17,已复原)" + }, + { + "method": "GET", + "path": "/admin/dashboard/stats", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台仪表盘" + }, + { + "method": "POST", + "path": "/admin/platform/content/video/review/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台审核视频(videoId=17)" + }, + { + "method": "POST", + "path": "/admin/auth/logout", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台退出登录" + } + ] +} diff --git a/backend/API_TEST_RESULTS_auth_user.json b/backend/API_TEST_RESULTS_auth_user.json new file mode 100644 index 0000000..3e3c8b6 --- /dev/null +++ b/backend/API_TEST_RESULTS_auth_user.json @@ -0,0 +1,245 @@ +{ + "generatedAt": "2026-04-18T16:00:30", + "users": [ + "uabe2d2951", + "ub5af3642a" + ], + "ids": { + "userA": 10, + "userB": 11 + }, + "results": [ + { + "method": "POST", + "path": "/auth/login", + "status": "PASSED", + "http": 400, + "apiCode": null, + "note": "无验证码登录应被拦截" + }, + { + "method": "POST", + "path": "/auth/register", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "用户A注册" + }, + { + "method": "POST", + "path": "/auth/login", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "用户A登录" + }, + { + "method": "GET", + "path": "/auth/current", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "当前用户" + }, + { + "method": "POST", + "path": "/auth/refresh", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "刷新令牌" + }, + { + "method": "GET", + "path": "/auth/username/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": null, + "note": "根据ID获取用户名(公开放行后通过)" + }, + { + "method": "GET", + "path": "/user/profile/current", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "当前资料" + }, + { + "method": "GET", + "path": "/user/profile/public/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "公开资料(公开路由修复后通过)" + }, + { + "method": "PUT", + "path": "/user/profile", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "更新资料" + }, + { + "method": "GET", + "path": "/user/profile/search", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "搜索用户(公开路由修复后通过)" + }, + { + "method": "GET", + "path": "/user/setting", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "获取设置" + }, + { + "method": "PUT", + "path": "/user/setting", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "更新设置" + }, + { + "method": "POST", + "path": "/user/follow/{followId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "B关注A" + }, + { + "method": "GET", + "path": "/user/follow/check/{followId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "检查关注" + }, + { + "method": "GET", + "path": "/user/follow/following/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "关注列表(公开路由修复后通过)" + }, + { + "method": "GET", + "path": "/user/follow/followers/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "粉丝列表(公开路由修复后通过)" + }, + { + "method": "GET", + "path": "/user/notification/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "通知列表" + }, + { + "method": "GET", + "path": "/user/notification/unread/count", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "未读通知" + }, + { + "method": "PUT", + "path": "/user/notification/read", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "全部通知已读" + }, + { + "method": "POST", + "path": "/user/message", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "发送私信" + }, + { + "method": "GET", + "path": "/user/message/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "会话列表" + }, + { + "method": "GET", + "path": "/user/message/detail/{targetId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "会话详情" + }, + { + "method": "GET", + "path": "/user/message/unread/count", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "未读私信数" + }, + { + "method": "PUT", + "path": "/user/message/read/{senderId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "私信已读" + }, + { + "method": "POST", + "path": "/auth/logout", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "登出" + }, + { + "method": "DELETE", + "path": "/user/follow/{followId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "取消关注" + }, + { + "method": "GET", + "path": "/auth/admin/login/stats", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "认证登录统计(内部接口直连通过)" + }, + { + "method": "PUT", + "path": "/auth/admin/reset-password/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部重置用户密码(恢复为原密码)" + }, + { + "method": "PUT", + "path": "/auth/admin/lock/{userId}/{locked}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部锁定/解锁用户(双向均通过)" + } + ] +} diff --git a/backend/API_TEST_RESULTS_content_comment_recommend.json b/backend/API_TEST_RESULTS_content_comment_recommend.json new file mode 100644 index 0000000..bcdbbdd --- /dev/null +++ b/backend/API_TEST_RESULTS_content_comment_recommend.json @@ -0,0 +1,572 @@ +{ + "generatedAt": "2026-04-18T16:00:30", + "results": [ + { + "module": "video-content", + "method": "GET", + "path": "/content/category/tree", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "分类树(公开路由修复后通过)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/category/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "分类列表" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/category", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "新增分类" + }, + { + "module": "video-content", + "method": "PUT", + "path": "/content/category", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "更新分类" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/category/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "删除分类" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/tag", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "添加标签(used)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/tag", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "添加标签(temp)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/tag/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "标签列表(公开路由修复后通过)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/tag/page", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "标签分页(公开路由修复后通过)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/favorite", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "创建收藏夹" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/favorite/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "收藏夹列表" + }, + { + "module": "video-content", + "method": "PUT", + "path": "/content/favorite", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "更新收藏夹" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "创建视频(已打通,videoId=17)" + }, + { + "module": "video-admin", + "method": "POST", + "path": "/admin/platform/content/video/review/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "后台审核视频(短测通过,发布成功)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/video/public/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "公开视频详情(短测通过,281ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/video/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "登录后视频详情(短测通过,312ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/video/public/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "公开视频列表" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/video/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "登录后视频列表" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/video/user/{userId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "用户视频列表(作者登录视角已修正,822ms)" + }, + { + "module": "video-content", + "method": "PUT", + "path": "/content/video", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "更新视频(短测通过,370ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/tag/video/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "视频标签(登录态短测通过,248ms)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/like/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "点赞视频(短测通过,325ms)" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/video/like/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "取消点赞视频(短测通过,303ms)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/coin/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "投币视频(短测通过,262ms)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/share/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "分享视频(短测通过,275ms)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/play", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "播放记录(短测通过,295ms)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/favorite", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "收藏视频(修复收藏统计阻塞后通过,345ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/favorite/{favoriteId}/videos", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "收藏夹视频列表" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/video/favorite/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "取消收藏视频(短测通过,270ms)" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/favorite/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "删除收藏夹" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/danmaku", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "发送弹幕(短测通过,411ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/danmaku/all/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "全部弹幕(短测通过,270ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/danmaku/time", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "时间段弹幕(短测通过,263ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/stat/daily/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "视频日统计(短测通过,254ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/stat/play/trend/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "播放趋势(短测通过,245ms)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/stat/interaction/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "互动统计(短测通过,251ms;MQ失败时主表降级已生效)" + }, + { + "module": "video-comment", + "method": "POST", + "path": "/comment", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "添加评论(短测通过,279ms)" + }, + { + "module": "video-comment", + "method": "GET", + "path": "/comment/public/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "评论列表" + }, + { + "module": "video-comment", + "method": "GET", + "path": "/comment/public/detail/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "评论详情(短测通过,718ms)" + }, + { + "module": "video-comment", + "method": "GET", + "path": "/comment/public/stat/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "评论统计" + }, + { + "module": "video-comment", + "method": "POST", + "path": "/comment/like/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "点赞评论(短测通过,294ms)" + }, + { + "module": "video-comment", + "method": "DELETE", + "path": "/comment/like/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "取消点赞评论(短测通过,291ms)" + }, + { + "module": "video-comment", + "method": "POST", + "path": "/comment/top/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "置顶评论(视频作者 + 正确videoId,426ms)" + }, + { + "module": "video-comment", + "method": "DELETE", + "path": "/comment/top/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "取消置顶评论(视频作者 + 正确videoId,333ms)" + }, + { + "module": "video-comment", + "method": "POST", + "path": "/comment/reply", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "添加回复(短测通过,281ms)" + }, + { + "module": "video-comment", + "method": "GET", + "path": "/comment/reply/public/list/{commentId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "回复列表(短测通过,264ms)" + }, + { + "module": "video-comment", + "method": "GET", + "path": "/comment/reply/public/hot/{commentId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "热门回复(短测通过,258ms)" + }, + { + "module": "video-comment", + "method": "POST", + "path": "/comment/reply/like/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "点赞回复(短测通过,262ms)" + }, + { + "module": "video-comment", + "method": "DELETE", + "path": "/comment/reply/like/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "取消点赞回复(短测通过,263ms)" + }, + { + "module": "video-comment", + "method": "DELETE", + "path": "/comment/reply/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "删除回复(短测通过,284ms)" + }, + { + "module": "video-comment", + "method": "DELETE", + "path": "/comment/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "删除评论(短测通过,263ms)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/upload", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "上传视频(1秒测试视频,FFmpeg/MinIO链路通过)" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/video/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "删除视频(临时视频id=18,已清理)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/video/review/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部审核接口(内部token直连通过;普通用户访问已403收紧)" + }, + { + "module": "video-content", + "method": "GET", + "path": "/content/category/admin/list", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部分类列表接口(直连通过)" + }, + { + "module": "video-content", + "method": "POST", + "path": "/content/category/admin", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部添加分类接口(直连通过)" + }, + { + "module": "video-content", + "method": "PUT", + "path": "/content/category/admin", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部更新分类接口(直连通过)" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/category/admin/{categoryId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "内部删除分类接口(直连通过)" + }, + { + "module": "video-content", + "method": "DELETE", + "path": "/content/tag/{id}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "删除标签(临时标签已清理)" + }, + { + "module": "video-recommend", + "method": "POST", + "path": "/recommend/behavior", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "记录用户行为(点赞/浏览类推荐行为链路通过)" + }, + { + "module": "video-recommend", + "method": "POST", + "path": "/recommend/interest/update", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "更新用户兴趣(Mapper修复后通过)" + }, + { + "module": "video-recommend", + "method": "GET", + "path": "/recommend/similar/{videoId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "相似视频推荐(当前返回空列表但接口正常)" + }, + { + "module": "video-recommend", + "method": "GET", + "path": "/recommend/tag/{tagId}", + "status": "PASSED", + "http": 200, + "apiCode": 200, + "note": "标签推荐(当前返回空列表但接口正常)" + } + ] +} diff --git a/backend/local_api_test.ps1 b/backend/local_api_test.ps1 new file mode 100644 index 0000000..ebfec7f --- /dev/null +++ b/backend/local_api_test.ps1 @@ -0,0 +1,408 @@ +$ErrorActionPreference = 'Stop' + +function Invoke-Api { + param( + [string]$Method, + [string]$Url, + [hashtable]$Headers = @{}, + $Body = $null, + [string]$ContentType = 'application/json' + ) + $lastResult = $null + for ($attempt = 1; $attempt -le 3; $attempt++) { + try { + $params = @{ + Method = $Method + Uri = $Url + Headers = $Headers + SkipHttpErrorCheck = $true + UseBasicParsing = $true + } + if ($null -ne $Body) { + if ($ContentType -eq 'application/json' -and $Body -isnot [string]) { + $params.ContentType = $ContentType + $params.Body = ($Body | ConvertTo-Json -Depth 20) + } else { + $params.ContentType = $ContentType + $params.Body = $Body + } + } + $resp = Invoke-WebRequest @params + $json = $null + if ($resp.Content) { + try { $json = $resp.Content | ConvertFrom-Json -Depth 50 } catch {} + } + $lastResult = [pscustomobject]@{ ok = $true; http = [int]$resp.StatusCode; json = $json; raw = $resp.Content } + if ($lastResult.http -eq 503 -and $attempt -lt 3) { + Start-Sleep -Seconds 2 + continue + } + return $lastResult + } catch { + $lastResult = [pscustomobject]@{ ok = $false; http = -1; json = $null; raw = $_.Exception.Message } + if ($attempt -lt 3) { + Start-Sleep -Seconds 2 + continue + } + } + } + return $lastResult +} + +$results = New-Object System.Collections.Generic.List[object] +function Add-Result { + param([string]$Module,[string]$Method,[string]$Path,[string]$Status,[string]$Note,[int]$Http = 0,[object]$ApiCode = $null) + $results.Add([pscustomobject]@{ + module = $Module + method = $Method + path = $Path + status = $Status + http = $Http + apiCode = $ApiCode + note = $Note + }) +} + +function Get-UserCaptcha { + $cap = Invoke-RestMethod -UseBasicParsing -Uri 'http://localhost:9000/auth/captcha' + $key = $cap.data.captchaKey + $code = docker exec redis redis-cli -a redis_EsJ8FX --raw GET ('captcha:' + $key) + return [pscustomobject]@{ key = $key; code = $code.Trim('"').Trim() } +} + +function Get-AdminCaptcha { + $cap = Invoke-RestMethod -UseBasicParsing -Uri 'http://localhost:9000/admin/auth/captcha' + $key = $cap.data.captchaKey + $code = docker exec redis redis-cli -a redis_EsJ8FX -n 5 --raw GET ('admin:captcha:' + $key) + return [pscustomobject]@{ key = $key; code = $code.Trim('"').Trim() } +} + +function Register-LoginUser { + param([string]$Prefix,[string]$Password) + $cap = Get-UserCaptcha + $username = $Prefix + [guid]::NewGuid().ToString('N').Substring(0,8) + $digits = -join ((48..57) | Get-Random -Count 9 | ForEach-Object {[char]$_}) + $phone = '13' + $digits + $registerBody = @{ + username = $username + password = $Password + confirmPassword = $Password + email = "$username@example.com" + phone = $phone + captcha = $cap.code + captchaKey = $cap.key + } + $reg = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/register' -Body $registerBody + $cap2 = Get-UserCaptcha + $loginBody = @{ username = $username; password = $Password; captcha = $cap2.code; captchaKey = $cap2.key } + $login = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body $loginBody + $headers = @{ Authorization = 'Bearer ' + $login.json.data.accessToken } + $current = Invoke-Api -Method GET -Url 'http://localhost:9000/auth/current' -Headers $headers + return [pscustomobject]@{ + username = $username + password = $Password + register = $reg + login = $login + headers = $headers + userId = [long]$current.json.data.id + refreshToken = $login.json.data.refreshToken + accessToken = $login.json.data.accessToken + } +} + +function Get-AdminSession { + $cap = Get-AdminCaptcha + $loginBody = @{ username='admin'; password='admin123'; captcha=$cap.code; captchaKey=$cap.key } + $login = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/auth/login' -Body $loginBody + return [pscustomobject]@{ login = $login; headers = @{ Authorization = 'Bearer ' + $login.json.data.token } } +} + +# Security checks +$uNoCaptcha = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ username='nouser'; password='wrong' } +Add-Result 'video-auth' 'POST' '/auth/login' ($(if($uNoCaptcha.http -eq 400){'PASSED'}else{'FAILED'})) '用户端无验证码登录应被拦截' $uNoCaptcha.http ($uNoCaptcha.json.code) +$aNoCaptcha = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/auth/login' -Body @{ username='admin'; password='admin123' } +Add-Result 'video-admin' 'POST' '/admin/auth/login' ($(if($aNoCaptcha.http -eq 403){'PASSED'}else{'FAILED'})) '后台无验证码登录应被拦截' $aNoCaptcha.http ($aNoCaptcha.json.code) + +# Users +$userA = Register-LoginUser -Prefix 'ua' -Password 'Pass@123456' +$userB = Register-LoginUser -Prefix 'ub' -Password 'Pass@123456' +$userC = Register-LoginUser -Prefix 'uc' -Password 'Pass@123456' +$admin = Get-AdminSession + +Add-Result 'video-auth' 'POST' '/auth/register' ($(if($userA.register.json.code -eq 200){'PASSED'}else{'FAILED'})) '创建测试用户A' $userA.register.http $userA.register.json.code +Add-Result 'video-auth' 'POST' '/auth/login' ($(if($userA.login.json.code -eq 200){'PASSED'}else{'FAILED'})) '测试用户A登录' $userA.login.http $userA.login.json.code +Add-Result 'video-auth' 'GET' '/auth/current' ($(if($userA.userId){'PASSED'}else{'FAILED'})) '用户A当前信息' $userA.login.http $userA.login.json.code + +# Auth endpoints +$refresh = Invoke-Api -Method POST -Url "http://localhost:9000/auth/refresh?refreshToken=$($userB.refreshToken)" +Add-Result 'video-auth' 'POST' '/auth/refresh' ($(if($refresh.json.code -eq 200){'PASSED'}else{'FAILED'})) '刷新令牌' $refresh.http $refresh.json.code +$usernameById = Invoke-Api -Method GET -Url ('http://localhost:9000/auth/username/' + $userA.userId) +Add-Result 'video-auth' 'GET' '/auth/username/{userId}' ($(if($usernameById.http -eq 200 -and $usernameById.raw -eq $userA.username){'PASSED'}else{'FAILED'})) '根据ID获取用户名' $usernameById.http $null + +# User profile/settings/search +$publicProfile = Invoke-Api -Method GET -Url ('http://localhost:9000/user/profile/public/' + $userA.userId) +Add-Result 'video-user' 'GET' '/user/profile/public/{userId}' ($(if($publicProfile.json.code -eq 200){'PASSED'}else{'FAILED'})) '公开资料' $publicProfile.http $publicProfile.json.code +$updateProfile = Invoke-Api -Method PUT -Url 'http://localhost:9000/user/profile' -Headers $userA.headers -Body @{ nickname='测试用户A'; signature='签名A'; region='南京'; gender=1 } +Add-Result 'video-user' 'PUT' '/user/profile' ($(if($updateProfile.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新资料' $updateProfile.http $updateProfile.json.code +$searchUser = Invoke-Api -Method GET -Url "http://localhost:9000/user/profile/search?keyword=$($userA.username)&page=1&size=5" +Add-Result 'video-user' 'GET' '/user/profile/search' ($(if($searchUser.json.code -eq 200){'PASSED'}else{'FAILED'})) '搜索用户' $searchUser.http $searchUser.json.code +$getSetting = Invoke-Api -Method GET -Url 'http://localhost:9000/user/setting' -Headers $userA.headers +Add-Result 'video-user' 'GET' '/user/setting' ($(if($getSetting.json.code -eq 200){'PASSED'}else{'FAILED'})) '获取设置' $getSetting.http $getSetting.json.code +$updateSetting = Invoke-Api -Method PUT -Url 'http://localhost:9000/user/setting' -Headers $userA.headers -Body @{ privacyLevel=1; commentNotify=1; likeNotify=1; followNotify=1; systemNotify=1 } +Add-Result 'video-user' 'PUT' '/user/setting' ($(if($updateSetting.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新设置' $updateSetting.http $updateSetting.json.code + +# Follow + notifications +$follow = Invoke-Api -Method POST -Url ('http://localhost:9000/user/follow/' + $userA.userId) -Headers $userB.headers +Add-Result 'video-user' 'POST' '/user/follow/{followId}' ($(if($follow.json.code -eq 200){'PASSED'}else{'FAILED'})) 'B关注A' $follow.http $follow.json.code +$checkFollow = Invoke-Api -Method GET -Url ('http://localhost:9000/user/follow/check/' + $userA.userId) -Headers $userB.headers +Add-Result 'video-user' 'GET' '/user/follow/check/{followId}' ($(if($checkFollow.json.code -eq 200){'PASSED'}else{'FAILED'})) '检查关注' $checkFollow.http $checkFollow.json.code +$following = Invoke-Api -Method GET -Url "http://localhost:9000/user/follow/following/$($userB.userId)?page=1&size=5" +Add-Result 'video-user' 'GET' '/user/follow/following/{userId}' ($(if($following.json.code -eq 200){'PASSED'}else{'FAILED'})) '关注列表' $following.http $following.json.code +$followers = Invoke-Api -Method GET -Url "http://localhost:9000/user/follow/followers/$($userA.userId)?page=1&size=5" +Add-Result 'video-user' 'GET' '/user/follow/followers/{userId}' ($(if($followers.json.code -eq 200){'PASSED'}else{'FAILED'})) '粉丝列表' $followers.http $followers.json.code +$noticeList1 = Invoke-Api -Method GET -Url "http://localhost:9000/user/notification/list?page=1&size=10" -Headers $userA.headers +Add-Result 'video-user' 'GET' '/user/notification/list' ($(if($noticeList1.json.code -eq 200){'PASSED'}else{'FAILED'})) '通知列表' $noticeList1.http $noticeList1.json.code +$noticeUnread1 = Invoke-Api -Method GET -Url 'http://localhost:9000/user/notification/unread/count' -Headers $userA.headers +Add-Result 'video-user' 'GET' '/user/notification/unread/count' ($(if($noticeUnread1.json.code -eq 200){'PASSED'}else{'FAILED'})) '未读通知数' $noticeUnread1.http $noticeUnread1.json.code +$firstNoticeId = $null +if ($noticeList1.json -and $noticeList1.json.data -and $noticeList1.json.data.records -and $noticeList1.json.data.records.Count -gt 0) { + $firstNoticeId = $noticeList1.json.data.records[0].id +} +if ($firstNoticeId) { + $noticeReadOne = Invoke-Api -Method PUT -Url ('http://localhost:9000/user/notification/read/' + $firstNoticeId) -Headers $userA.headers + Add-Result 'video-user' 'PUT' '/user/notification/read/{notificationId}' ($(if($noticeReadOne.json.code -eq 200){'PASSED'}else{'FAILED'})) '标记单条通知已读' $noticeReadOne.http $noticeReadOne.json.code +} +$noticeReadAll = Invoke-Api -Method PUT -Url 'http://localhost:9000/user/notification/read' -Headers $userA.headers +Add-Result 'video-user' 'PUT' '/user/notification/read' ($(if($noticeReadAll.json.code -eq 200){'PASSED'}else{'FAILED'})) '全部通知已读' $noticeReadAll.http $noticeReadAll.json.code + +# Messages +$msgSend = Invoke-Api -Method POST -Url 'http://localhost:9000/user/message' -Headers $userB.headers -Body @{ receiverId = $userA.userId; content = 'hello-from-b' } +Add-Result 'video-user' 'POST' '/user/message' ($(if($msgSend.json.code -eq 200){'PASSED'}else{'FAILED'})) '发送私信' $msgSend.http $msgSend.json.code +$msgList = Invoke-Api -Method GET -Url "http://localhost:9000/user/message/list?page=1&size=10" -Headers $userA.headers +Add-Result 'video-user' 'GET' '/user/message/list' ($(if($msgList.json.code -eq 200){'PASSED'}else{'FAILED'})) '会话列表' $msgList.http $msgList.json.code +$msgDetail = Invoke-Api -Method GET -Url "http://localhost:9000/user/message/detail/$($userB.userId)?page=1&size=10" -Headers $userA.headers +Add-Result 'video-user' 'GET' '/user/message/detail/{targetId}' ($(if($msgDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '会话详情' $msgDetail.http $msgDetail.json.code +$msgUnread = Invoke-Api -Method GET -Url 'http://localhost:9000/user/message/unread/count' -Headers $userA.headers +Add-Result 'video-user' 'GET' '/user/message/unread/count' ($(if($msgUnread.json.code -eq 200){'PASSED'}else{'FAILED'})) '未读私信数' $msgUnread.http $msgUnread.json.code +$msgRead = Invoke-Api -Method PUT -Url ('http://localhost:9000/user/message/read/' + $userB.userId) -Headers $userA.headers +Add-Result 'video-user' 'PUT' '/user/message/read/{senderId}' ($(if($msgRead.json.code -eq 200){'PASSED'}else{'FAILED'})) '私信已读' $msgRead.http $msgRead.json.code + +# Categories and tags +$catTree = Invoke-Api -Method GET -Url 'http://localhost:9000/content/category/tree' +Add-Result 'video-content' 'GET' '/content/category/tree' ($(if($catTree.json.code -eq 200){'PASSED'}else{'FAILED'})) '分类树' $catTree.http $catTree.json.code +$catList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/category/list' +Add-Result 'video-content' 'GET' '/content/category/list' ($(if($catList.json.code -eq 200){'PASSED'}else{'FAILED'})) '分类列表' $catList.http $catList.json.code +$firstCategory = $null +if ($catList.json -and $catList.json.data) { + $firstCategory = @($catList.json.data) | Select-Object -First 1 +} +if (-not $firstCategory) { + throw '无法从 /content/category/list 获取可用分类ID' +} +$categoryId = [long]$firstCategory.id + +$tagUsedName = 'tagused-' + [guid]::NewGuid().ToString('N').Substring(0,6) +$tagTempName = 'tagtmp-' + [guid]::NewGuid().ToString('N').Substring(0,6) +$tagUsedAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/content/tag' -Headers $userA.headers -Body @{ name = $tagUsedName } +$tagTempAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/content/tag' -Headers $userA.headers -Body @{ name = $tagTempName } +$tagList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/tag/list' +$tagPage = Invoke-Api -Method GET -Url "http://localhost:9000/content/tag/page?pageNum=1&pageSize=20" +$tagUsed = $tagList.json.data | Where-Object { $_.name -eq $tagUsedName } | Select-Object -First 1 +$tagTemp = $tagList.json.data | Where-Object { $_.name -eq $tagTempName } | Select-Object -First 1 +Add-Result 'video-content' 'POST' '/content/tag' ($(if($tagUsedAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加标签(used)' $tagUsedAdd.http $tagUsedAdd.json.code +Add-Result 'video-content' 'POST' '/content/tag' ($(if($tagTempAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加标签(temp)' $tagTempAdd.http $tagTempAdd.json.code +Add-Result 'video-content' 'GET' '/content/tag/list' ($(if($tagList.json.code -eq 200){'PASSED'}else{'FAILED'})) '标签列表' $tagList.http $tagList.json.code +Add-Result 'video-content' 'GET' '/content/tag/page' ($(if($tagPage.json.code -eq 200){'PASSED'}else{'FAILED'})) '标签分页' $tagPage.http $tagPage.json.code +if ($tagTemp) { + $tagUpdate = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/tag' -Headers $userA.headers -Body @{ id = $tagTemp.id; name = ($tagTempName + '-u') } + Add-Result 'video-content' 'PUT' '/content/tag' ($(if($tagUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新标签' $tagUpdate.http $tagUpdate.json.code +} + +# Favorites +$favCreate = Invoke-Api -Method POST -Url 'http://localhost:9000/content/favorite' -Headers $userB.headers -Body @{ name='fav-b'; description='desc'; isPrivate=0 } +$favList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/favorite/list' -Headers $userB.headers +$fav = $favList.json.data | Select-Object -First 1 +Add-Result 'video-content' 'POST' '/content/favorite' ($(if($favCreate.json.code -eq 200){'PASSED'}else{'FAILED'})) '创建收藏夹' $favCreate.http $favCreate.json.code +Add-Result 'video-content' 'GET' '/content/favorite/list' ($(if($favList.json.code -eq 200){'PASSED'}else{'FAILED'})) '收藏夹列表' $favList.http $favList.json.code +if ($fav) { + $favUpdate = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/favorite' -Headers $userB.headers -Body @{ id=$fav.id; name='fav-b-upd'; description='desc2'; isPrivate=1 } + $favUpdateStatus = if ($favUpdate.json.code -eq 200) { 'PASSED' } else { 'FAILED' } + Add-Result 'video-content' 'PUT' '/content/favorite' $favUpdateStatus '更新收藏夹' $favUpdate.http $favUpdate.json.code +} + +# Create and publish video +$videoBody = @{ + title = '测试视频标题12345' + description = '测试视频描述' + categoryId = $categoryId + tagIds = @([long]$tagUsed.id) + coverUrl = 'http://example.com/cover.jpg' + videoUrl = 'http://example.com/video.mp4' + duration = 60 + width = 1280 + height = 720 + format = 'mp4' + size = 123456 +} +$createVideo = Invoke-Api -Method POST -Url 'http://localhost:9000/content/video' -Headers $userA.headers -Body $videoBody +$videoId = [long]$createVideo.json.data +Add-Result 'video-content' 'POST' '/content/video' ($(if($createVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '创建视频' $createVideo.http $createVideo.json.code +$adminVideoReview = Invoke-Api -Method POST -Url "http://localhost:9000/admin/platform/content/video/review/$videoId?status=1&reason=ok" -Headers $admin.headers +Add-Result 'video-admin' 'POST' '/admin/platform/content/video/review/{videoId}' ($(if($adminVideoReview.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台审核通过视频' $adminVideoReview.http $adminVideoReview.json.code + +# Video/tag details +$videoPublicDetail = Invoke-Api -Method GET -Url ('http://localhost:9000/content/video/public/' + $videoId) +$videoAuthedDetail = Invoke-Api -Method GET -Url ('http://localhost:9000/content/video/' + $videoId) -Headers $userB.headers +$videoPublicList = Invoke-Api -Method GET -Url "http://localhost:9000/content/video/public/list?pageNum=1&pageSize=10" +$videoAuthedList = Invoke-Api -Method GET -Url "http://localhost:9000/content/video/list?pageNum=1&pageSize=10" -Headers $userB.headers +$videoUserList = Invoke-Api -Method GET -Url "http://localhost:9000/content/video/user/$($userA.userId)?pageNum=1&pageSize=10" +$videoUpdate = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/video' -Headers $userA.headers -Body @{ id = $videoId; title='更新后视频标题12345'; description='更新描述'; categoryId=$categoryId; tagIds=@([long]$tagUsed.id) } +$videoTags = Invoke-Api -Method GET -Url ('http://localhost:9000/content/tag/video/' + $videoId) +Add-Result 'video-content' 'GET' '/content/video/public/{id}' ($(if($videoPublicDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '公开视频详情' $videoPublicDetail.http $videoPublicDetail.json.code +Add-Result 'video-content' 'GET' '/content/video/{id}' ($(if($videoAuthedDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '登录后视频详情' $videoAuthedDetail.http $videoAuthedDetail.json.code +Add-Result 'video-content' 'GET' '/content/video/public/list' ($(if($videoPublicList.json.code -eq 200){'PASSED'}else{'FAILED'})) '公开视频列表' $videoPublicList.http $videoPublicList.json.code +Add-Result 'video-content' 'GET' '/content/video/list' ($(if($videoAuthedList.json.code -eq 200){'PASSED'}else{'FAILED'})) '登录后视频列表' $videoAuthedList.http $videoAuthedList.json.code +Add-Result 'video-content' 'GET' '/content/video/user/{userId}' ($(if($videoUserList.json.code -eq 200){'PASSED'}else{'FAILED'})) '用户视频列表' $videoUserList.http $videoUserList.json.code +Add-Result 'video-content' 'PUT' '/content/video' ($(if($videoUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新视频' $videoUpdate.http $videoUpdate.json.code +Add-Result 'video-content' 'GET' '/content/tag/video/{videoId}' ($(if($videoTags.json.code -eq 200){'PASSED'}else{'FAILED'})) '视频标签' $videoTags.http $videoTags.json.code + +# Interactions +$likeVideo = Invoke-Api -Method POST -Url ('http://localhost:9000/content/video/like/' + $videoId) -Headers $userB.headers +$unlikeVideo = Invoke-Api -Method DELETE -Url ('http://localhost:9000/content/video/like/' + $videoId) -Headers $userB.headers +$coinVideo = Invoke-Api -Method POST -Url "http://localhost:9000/content/video/coin/$videoId?amount=1" -Headers $userB.headers +$shareVideo = Invoke-Api -Method POST -Url "http://localhost:9000/content/video/share/$videoId?platform=wechat" -Headers $userB.headers +$playVideo = Invoke-Api -Method POST -Url 'http://localhost:9000/content/video/play' -Headers $userB.headers -Body @{ videoId = $videoId; playTime = 58; isFinished = 1 } +Add-Result 'video-content' 'POST' '/content/video/like/{videoId}' ($(if($likeVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '点赞视频' $likeVideo.http $likeVideo.json.code +Add-Result 'video-content' 'DELETE' '/content/video/like/{videoId}' ($(if($unlikeVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消点赞视频' $unlikeVideo.http $unlikeVideo.json.code +Add-Result 'video-content' 'POST' '/content/video/coin/{videoId}' ($(if($coinVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '投币视频' $coinVideo.http $coinVideo.json.code +Add-Result 'video-content' 'POST' '/content/video/share/{videoId}' ($(if($shareVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '分享视频' $shareVideo.http $shareVideo.json.code +Add-Result 'video-content' 'POST' '/content/video/play' ($(if($playVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '播放记录' $playVideo.http $playVideo.json.code + +if ($fav) { + $favVideo = Invoke-Api -Method POST -Url 'http://localhost:9000/content/video/favorite' -Headers $userB.headers -Body @{ videoId = $videoId; favoriteId = [long]$fav.id } +$favVideos = Invoke-Api -Method GET -Url "http://localhost:9000/content/favorite/$($fav.id)/videos?pageNum=1&pageSize=10" -Headers $userB.headers + $unfavVideo = Invoke-Api -Method DELETE -Url ('http://localhost:9000/content/video/favorite/' + $videoId) -Headers $userB.headers + Add-Result 'video-content' 'POST' '/content/video/favorite' ($(if($favVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '收藏视频' $favVideo.http $favVideo.json.code + Add-Result 'video-content' 'GET' '/content/favorite/{favoriteId}/videos' ($(if($favVideos.json.code -eq 200){'PASSED'}else{'FAILED'})) '收藏夹视频列表' $favVideos.http $favVideos.json.code + Add-Result 'video-content' 'DELETE' '/content/video/favorite/{videoId}' ($(if($unfavVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消收藏视频' $unfavVideo.http $unfavVideo.json.code + $favDelete = Invoke-Api -Method DELETE -Url ('http://localhost:9000/content/favorite/' + $fav.id) -Headers $userB.headers + Add-Result 'video-content' 'DELETE' '/content/favorite/{id}' ($(if($favDelete.json.code -eq 200){'PASSED'}else{'FAILED'})) '删除收藏夹' $favDelete.http $favDelete.json.code +} + +# Danmaku and stats +$danmakuSend = Invoke-Api -Method POST -Url 'http://localhost:9000/content/danmaku' -Headers $userB.headers -Body @{ videoId=$videoId; content='666'; time=12.5 } +$danmakuAll = Invoke-Api -Method GET -Url ('http://localhost:9000/content/danmaku/all/' + $videoId) +$danmakuTime = Invoke-Api -Method GET -Url "http://localhost:9000/content/danmaku/time?videoId=$videoId&startTime=0&endTime=20" +$statDaily = Invoke-Api -Method GET -Url "http://localhost:9000/content/stat/daily/$videoId?startDate=2026-04-01&endDate=2026-04-30" +$statTrend = Invoke-Api -Method GET -Url ('http://localhost:9000/content/stat/play/trend/' + $videoId) +$statInteraction = Invoke-Api -Method GET -Url ('http://localhost:9000/content/stat/interaction/' + $videoId) +Add-Result 'video-content' 'POST' '/content/danmaku' ($(if($danmakuSend.json.code -eq 200){'PASSED'}else{'FAILED'})) '发送弹幕' $danmakuSend.http $danmakuSend.json.code +Add-Result 'video-content' 'GET' '/content/danmaku/all/{videoId}' ($(if($danmakuAll.json.code -eq 200){'PASSED'}else{'FAILED'})) '全部弹幕' $danmakuAll.http $danmakuAll.json.code +Add-Result 'video-content' 'GET' '/content/danmaku/time' ($(if($danmakuTime.json.code -eq 200){'PASSED'}else{'FAILED'})) '时间段弹幕' $danmakuTime.http $danmakuTime.json.code +Add-Result 'video-content' 'GET' '/content/stat/daily/{videoId}' ($(if($statDaily.json.code -eq 200){'PASSED'}else{'FAILED'})) '视频日统计' $statDaily.http $statDaily.json.code +Add-Result 'video-content' 'GET' '/content/stat/play/trend/{videoId}' ($(if($statTrend.json.code -eq 200){'PASSED'}else{'FAILED'})) '播放趋势' $statTrend.http $statTrend.json.code +Add-Result 'video-content' 'GET' '/content/stat/interaction/{videoId}' ($(if($statInteraction.json.code -eq 200){'PASSED'}else{'FAILED'})) '互动统计' $statInteraction.http $statInteraction.json.code + +# Comment/reply +$commentAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/comment' -Headers $userB.headers -Body @{ videoId = $videoId; content = 'comment-from-b' } +$commentId = [long]$commentAdd.json.data +$commentList = Invoke-Api -Method GET -Url "http://localhost:9000/comment/public/list?videoId=$videoId&pageNum=1&pageSize=10" +$commentDetail = Invoke-Api -Method GET -Url ('http://localhost:9000/comment/public/detail/' + $commentId) +$commentStat = Invoke-Api -Method GET -Url ('http://localhost:9000/comment/public/stat/' + $videoId) +$likeComment = Invoke-Api -Method POST -Url ('http://localhost:9000/comment/like/' + $commentId) -Headers $userA.headers +$unlikeComment = Invoke-Api -Method DELETE -Url ('http://localhost:9000/comment/like/' + $commentId) -Headers $userA.headers +$topComment = Invoke-Api -Method POST -Url "http://localhost:9000/comment/top/$commentId?videoId=$videoId" -Headers $userA.headers +$untopComment = Invoke-Api -Method DELETE -Url "http://localhost:9000/comment/top/$commentId?videoId=$videoId" -Headers $userA.headers +$replyAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/comment/reply' -Headers $userA.headers -Body @{ commentId=$commentId; videoId=$videoId; replyToId=$userB.userId; content='reply-from-a' } +$replyId = [long]$replyAdd.json.data +$replyList = Invoke-Api -Method GET -Url "http://localhost:9000/comment/reply/public/list/$commentId?page=1&size=10" +$replyHot = Invoke-Api -Method GET -Url "http://localhost:9000/comment/reply/public/hot/$commentId?limit=3" +$likeReply = Invoke-Api -Method POST -Url ('http://localhost:9000/comment/reply/like/' + $replyId) -Headers $userB.headers +$unlikeReply = Invoke-Api -Method DELETE -Url ('http://localhost:9000/comment/reply/like/' + $replyId) -Headers $userB.headers +$deleteReply = Invoke-Api -Method DELETE -Url ('http://localhost:9000/comment/reply/' + $replyId) -Headers $userA.headers +Add-Result 'video-comment' 'POST' '/comment' ($(if($commentAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加评论' $commentAdd.http $commentAdd.json.code +Add-Result 'video-comment' 'GET' '/comment/public/list' ($(if($commentList.json.code -eq 200){'PASSED'}else{'FAILED'})) '评论列表' $commentList.http $commentList.json.code +Add-Result 'video-comment' 'GET' '/comment/public/detail/{id}' ($(if($commentDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '评论详情' $commentDetail.http $commentDetail.json.code +Add-Result 'video-comment' 'GET' '/comment/public/stat/{videoId}' ($(if($commentStat.json.code -eq 200){'PASSED'}else{'FAILED'})) '评论统计' $commentStat.http $commentStat.json.code +Add-Result 'video-comment' 'POST' '/comment/like/{id}' ($(if($likeComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '点赞评论' $likeComment.http $likeComment.json.code +Add-Result 'video-comment' 'DELETE' '/comment/like/{id}' ($(if($unlikeComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消点赞评论' $unlikeComment.http $unlikeComment.json.code +Add-Result 'video-comment' 'POST' '/comment/top/{id}' ($(if($topComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '置顶评论' $topComment.http $topComment.json.code +Add-Result 'video-comment' 'DELETE' '/comment/top/{id}' ($(if($untopComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消置顶评论' $untopComment.http $untopComment.json.code +Add-Result 'video-comment' 'POST' '/comment/reply' ($(if($replyAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加回复' $replyAdd.http $replyAdd.json.code +Add-Result 'video-comment' 'GET' '/comment/reply/public/list/{commentId}' ($(if($replyList.json.code -eq 200){'PASSED'}else{'FAILED'})) '回复列表' $replyList.http $replyList.json.code +Add-Result 'video-comment' 'GET' '/comment/reply/public/hot/{commentId}' ($(if($replyHot.json.code -eq 200){'PASSED'}else{'FAILED'})) '热门回复' $replyHot.http $replyHot.json.code +Add-Result 'video-comment' 'POST' '/comment/reply/like/{id}' ($(if($likeReply.json.code -eq 200){'PASSED'}else{'FAILED'})) '点赞回复' $likeReply.http $likeReply.json.code +Add-Result 'video-comment' 'DELETE' '/comment/reply/like/{id}' ($(if($unlikeReply.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消点赞回复' $unlikeReply.http $unlikeReply.json.code +Add-Result 'video-comment' 'DELETE' '/comment/reply/{id}' ($(if($deleteReply.json.code -eq 200){'PASSED'}else{'FAILED'})) '删除回复' $deleteReply.http $deleteReply.json.code + +# Recommend +$similar = Invoke-Api -Method GET -Url "http://localhost:9000/recommend/similar/$videoId?size=10" +$tagRecommend = Invoke-Api -Method GET -Url "http://localhost:9000/recommend/tag/$($tagUsed.id)?size=10" +$behavior = Invoke-Api -Method POST -Url 'http://localhost:9000/recommend/behavior' -Headers $userB.headers -Body @{ videoId = $videoId; behaviorType = 1 } +$interestUpdate = Invoke-Api -Method POST -Url 'http://localhost:9000/recommend/interest/update' -Headers $userB.headers +Add-Result 'video-recommend' 'GET' '/recommend/similar/{videoId}' ($(if($similar.json.code -eq 200){'PASSED'}else{'FAILED'})) '相似推荐' $similar.http $similar.json.code +Add-Result 'video-recommend' 'GET' '/recommend/tag/{tagId}' ($(if($tagRecommend.json.code -eq 200){'PASSED'}else{'FAILED'})) '标签推荐' $tagRecommend.http $tagRecommend.json.code +Add-Result 'video-recommend' 'POST' '/recommend/behavior' ($(if($behavior.json.code -eq 200){'PASSED'}else{'FAILED'})) '记录行为' $behavior.http $behavior.json.code +Add-Result 'video-recommend' 'POST' '/recommend/interest/update' ($(if($interestUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新兴趣' $interestUpdate.http $interestUpdate.json.code + +# Admin detail and management +$adminInfo = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/auth/info' -Headers $admin.headers +Add-Result 'video-admin' 'GET' '/admin/auth/info' ($(if($adminInfo.json.code -eq 200){'PASSED'}else{'FAILED'})) '管理员信息' $adminInfo.http $adminInfo.json.code +$adminUserDetail = Invoke-Api -Method GET -Url ('http://localhost:9000/admin/platform/user/' + $userA.userId) -Headers $admin.headers +Add-Result 'video-admin' 'GET' '/admin/platform/user/{userId}' ($(if($adminUserDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台用户详情' $adminUserDetail.http $adminUserDetail.json.code +$adminDisableUser = Invoke-Api -Method PUT -Url ('http://localhost:9000/admin/platform/user/' + $userC.userId + '/status/0') -Headers $admin.headers +Add-Result 'video-admin' 'PUT' '/admin/platform/user/{userId}/status/{status}' ($(if($adminDisableUser.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台禁用用户' $adminDisableUser.http $adminDisableUser.json.code +$capC = Get-UserCaptcha +$disabledLogin = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ username=$userC.username; password=$userC.password; captcha=$capC.code; captchaKey=$capC.key } +Add-Result 'video-auth' 'POST' '/auth/login' ($(if($disabledLogin.json.code -ne 200){'PASSED'}else{'FAILED'})) '禁用用户登录被拦截' $disabledLogin.http $disabledLogin.json.code +$adminEnableUser = Invoke-Api -Method PUT -Url ('http://localhost:9000/admin/platform/user/' + $userC.userId + '/status/1') -Headers $admin.headers +Add-Result 'video-admin' 'PUT' '/admin/platform/user/{userId}/status/{status}' ($(if($adminEnableUser.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台启用用户' $adminEnableUser.http $adminEnableUser.json.code +$adminResetPwd = Invoke-Api -Method PUT -Url "http://localhost:9000/admin/platform/user/$($userC.userId)/reset-password?newPassword=NewPass@123" -Headers $admin.headers +Add-Result 'video-admin' 'PUT' '/admin/platform/user/{userId}/reset-password' ($(if($adminResetPwd.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台重置密码' $adminResetPwd.http $adminResetPwd.json.code +$capC2 = Get-UserCaptcha +$reloginC = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ username=$userC.username; password='NewPass@123'; captcha=$capC2.code; captchaKey=$capC2.key } +Add-Result 'video-auth' 'POST' '/auth/login' ($(if($reloginC.json.code -eq 200){'PASSED'}else{'FAILED'})) '重置密码后登录' $reloginC.http $reloginC.json.code +$adminVideoDetail = Invoke-Api -Method GET -Url ('http://localhost:9000/admin/platform/content/video/' + $videoId) -Headers $admin.headers +Add-Result 'video-admin' 'GET' '/admin/platform/content/video/{videoId}' ($(if($adminVideoDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台视频详情' $adminVideoDetail.http $adminVideoDetail.json.code +$adminCategoryList = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/content/category/list' -Headers $admin.headers +Add-Result 'video-admin' 'GET' '/admin/platform/content/category/list' ($(if($adminCategoryList.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台分类列表' $adminCategoryList.http $adminCategoryList.json.code +$catCode = 'cat' + [guid]::NewGuid().ToString('N').Substring(0,6) +$adminCatAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/platform/content/category' -Headers $admin.headers -Body @{ name='后台测试分类'; code=$catCode; parentId=0; level=1; sort=99; status=1 } +Add-Result 'video-admin' 'POST' '/admin/platform/content/category' ($(if($adminCatAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台添加分类' $adminCatAdd.http $adminCatAdd.json.code +$adminCategoryList2 = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/content/category/list' -Headers $admin.headers +$adminCat = $adminCategoryList2.json.data | Where-Object { $_.code -eq $catCode } | Select-Object -First 1 +if ($adminCat) { + $adminCatUpd = Invoke-Api -Method PUT -Url 'http://localhost:9000/admin/platform/content/category' -Headers $admin.headers -Body @{ id=$adminCat.id; name='后台测试分类更新'; code=$catCode; parentId=0; level=1; sort=100; status=1 } + $adminCatDel = Invoke-Api -Method DELETE -Url ('http://localhost:9000/admin/platform/content/category/' + $adminCat.id) -Headers $admin.headers + Add-Result 'video-admin' 'PUT' '/admin/platform/content/category' ($(if($adminCatUpd.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台更新分类' $adminCatUpd.http $adminCatUpd.json.code + Add-Result 'video-admin' 'DELETE' '/admin/platform/content/category/{categoryId}' ($(if($adminCatDel.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台删除分类' $adminCatDel.http $adminCatDel.json.code +} +$adminCommentDetail = Invoke-Api -Method GET -Url ('http://localhost:9000/admin/platform/comment/' + $commentId) -Headers $admin.headers +$adminCommentStats = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/comment/stats' -Headers $admin.headers +Add-Result 'video-admin' 'GET' '/admin/platform/comment/{commentId}' ($(if($adminCommentDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台评论详情' $adminCommentDetail.http $adminCommentDetail.json.code +Add-Result 'video-admin' 'GET' '/admin/platform/comment/stats' ($(if($adminCommentStats.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台评论统计' $adminCommentStats.http $adminCommentStats.json.code +$adminCommentDelete = Invoke-Api -Method DELETE -Url ('http://localhost:9000/admin/platform/comment/' + $commentId) -Headers $admin.headers +Add-Result 'video-admin' 'DELETE' '/admin/platform/comment/{commentId}' ($(if($adminCommentDelete.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台删除评论' $adminCommentDelete.http $adminCommentDelete.json.code +$adminDisableVideo = Invoke-Api -Method PUT -Url ('http://localhost:9000/admin/platform/content/video/disable/' + $videoId) -Headers $admin.headers +Add-Result 'video-admin' 'PUT' '/admin/platform/content/video/disable/{videoId}' ($(if($adminDisableVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台下架视频' $adminDisableVideo.http $adminDisableVideo.json.code +$dashboard = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/dashboard/stats' -Headers $admin.headers +Add-Result 'video-admin' 'GET' '/admin/dashboard/stats' ($(if($dashboard.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台仪表盘' $dashboard.http $dashboard.json.code + +$unfollow = Invoke-Api -Method DELETE -Url ('http://localhost:9000/user/follow/' + $userA.userId) -Headers $userB.headers +Add-Result 'video-user' 'DELETE' '/user/follow/{followId}' ($(if($unfollow.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消关注' $unfollow.http $unfollow.json.code + +$out = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('s') + users = @($userA.username,$userB.username,$userC.username) + ids = [pscustomobject]@{ userA=$userA.userId; userB=$userB.userId; userC=$userC.userId; videoId=$videoId; commentId=$commentId; replyId=$replyId; tagUsedId=$tagUsed.id } + results = $results +} +$outPath = 'C:\\Users\\toyas\\Desktop\\本科毕业设计\\参考\\workspace\\HA-OVP\\backend\\API_TEST_RESULTS_LATEST.json' +$out | ConvertTo-Json -Depth 8 | Set-Content -Path $outPath -Encoding UTF8 +$passed = ($results | Where-Object { $_.status -eq 'PASSED' }).Count +$failed = ($results | Where-Object { $_.status -eq 'FAILED' }).Count +[pscustomobject]@{ passed=$passed; failed=$failed; file=$outPath } | ConvertTo-Json -Compress + + + + diff --git a/backend/run_admin_batch.ps1 b/backend/run_admin_batch.ps1 new file mode 100644 index 0000000..305e557 --- /dev/null +++ b/backend/run_admin_batch.ps1 @@ -0,0 +1,165 @@ +$ErrorActionPreference = 'Stop' + +function Invoke-Api { + param( + [string]$Method, + [string]$Url, + [hashtable]$Headers = @{}, + $Body = $null, + [int]$TimeoutSec = 40 + ) + try { + $params = @{ + Method = $Method + Uri = $Url + Headers = $Headers + UseBasicParsing = $true + SkipHttpErrorCheck = $true + TimeoutSec = $TimeoutSec + } + if ($null -ne $Body) { + if ($Body -is [string]) { + $params.ContentType = 'application/json' + $params.Body = $Body + } else { + $params.ContentType = 'application/json' + $params.Body = ($Body | ConvertTo-Json -Depth 20) + } + } + $resp = Invoke-WebRequest @params + $json = $null + if ($resp.Content) { + try { $json = $resp.Content | ConvertFrom-Json -Depth 50 } catch {} + } + [pscustomobject]@{ http = [int]$resp.StatusCode; json = $json; raw = $resp.Content } + } catch { + [pscustomobject]@{ http = -1; json = $null; raw = $_.Exception.Message } + } +} + +function Add-Result { + param( + [System.Collections.Generic.List[object]]$Results, + [string]$Method, + [string]$Path, + [string]$Status, + [string]$Note, + [object]$Resp + ) + $apiCode = $null + if ($Resp -and $Resp.json -and $null -ne $Resp.json.code) { $apiCode = $Resp.json.code } + $Results.Add([pscustomobject]@{ + method = $Method + path = $Path + status = $Status + http = if ($Resp) { $Resp.http } else { $null } + apiCode = $apiCode + note = $Note + }) +} + +function Get-AdminCaptcha { + $cap = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/auth/captcha' + if ($cap.http -ne 200 -or -not $cap.json) { throw "获取后台验证码失败: $($cap.raw)" } + $key = $cap.json.data.captchaKey + $code = docker exec redis redis-cli -a redis_EsJ8FX -n 5 --raw GET ('admin:captcha:' + $key) + [pscustomobject]@{ key = $key; code = $code.Trim('"').Trim() } +} + +$authData = Get-Content 'C:\Users\toyas\Desktop\本科毕业设计\参考\workspace\HA-OVP\backend\API_TEST_RESULTS_auth_user.json' -Raw | ConvertFrom-Json -Depth 20 +$userAId = [long]$authData.ids.userA +$userBId = [long]$authData.ids.userB +$userBName = [string]$authData.users[1] + +$results = [System.Collections.Generic.List[object]]::new() +$cap = Get-AdminCaptcha +$noCaptcha = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/auth/login' -Body @{ username='admin'; password='admin123' } +Add-Result $results 'POST' '/admin/auth/login' ($(if($noCaptcha.http -eq 403){'PASSED'}else{'FAILED'})) '后台无验证码登录应被拦截' $noCaptcha + +$login = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/auth/login' -Body @{ username='admin'; password='admin123'; captcha=$cap.code; captchaKey=$cap.key } +$headers = @{ Authorization = 'Bearer ' + $login.json.data.token } +Add-Result $results 'POST' '/admin/auth/login' ($(if($login.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台登录' $login + +$info = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/auth/info' -Headers $headers +Add-Result $results 'GET' '/admin/auth/info' ($(if($info.json.code -eq 200){'PASSED'}else{'FAILED'})) '管理员信息' $info + +$userList = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/user/list?page=1&size=5' -Headers $headers +Add-Result $results 'GET' '/admin/platform/user/list' ($(if($userList.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台用户列表' $userList +$userDetail = Invoke-Api -Method GET -Url "http://localhost:9000/admin/platform/user/$userAId" -Headers $headers +Add-Result $results 'GET' '/admin/platform/user/{userId}' ($(if($userDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台用户详情' $userDetail +$disable = Invoke-Api -Method PUT -Url "http://localhost:9000/admin/platform/user/$userBId/status/0" -Headers $headers +Add-Result $results 'PUT' '/admin/platform/user/{userId}/status/{status}' ($(if($disable.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台禁用用户' $disable +$capUser = Invoke-WebRequest -UseBasicParsing -SkipHttpErrorCheck -Uri 'http://localhost:9000/auth/captcha' +$capUserJson = $capUser.Content | ConvertFrom-Json +$userKey = $capUserJson.data.captchaKey +$userCode = docker exec redis redis-cli -a redis_EsJ8FX --raw GET ('captcha:' + $userKey) +$disabledLogin = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ username=$userBName; password='Pass@123456'; captcha=$userCode.Trim('"').Trim(); captchaKey=$userKey } +Add-Result $results 'POST' '/auth/login' ($(if($disabledLogin.json.code -ne 200){'PASSED'}else{'FAILED'})) '禁用用户登录被拦截' $disabledLogin +$enable = Invoke-Api -Method PUT -Url "http://localhost:9000/admin/platform/user/$userBId/status/1" -Headers $headers +Add-Result $results 'PUT' '/admin/platform/user/{userId}/status/{status}' ($(if($enable.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台启用用户' $enable +$reset = Invoke-Api -Method PUT -Url "http://localhost:9000/admin/platform/user/$userBId/reset-password?newPassword=NewPass@123" -Headers $headers +Add-Result $results 'PUT' '/admin/platform/user/{userId}/reset-password' ($(if($reset.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台重置密码' $reset +$capUser2 = Invoke-WebRequest -UseBasicParsing -SkipHttpErrorCheck -Uri 'http://localhost:9000/auth/captcha' +$capUserJson2 = $capUser2.Content | ConvertFrom-Json +$userKey2 = $capUserJson2.data.captchaKey +$userCode2 = docker exec redis redis-cli -a redis_EsJ8FX --raw GET ('captcha:' + $userKey2) +$newLogin = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ username=$userBName; password='NewPass@123'; captcha=$userCode2.Trim('"').Trim(); captchaKey=$userKey2 } +Add-Result $results 'POST' '/auth/login' ($(if($newLogin.json.code -eq 200){'PASSED'}else{'FAILED'})) '重置密码后登录' $newLogin + +$categoryList = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/content/category/list' -Headers $headers +Add-Result $results 'GET' '/admin/platform/content/category/list' ($(if($categoryList.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台分类列表' $categoryList +$catCode = 'admcat' + [guid]::NewGuid().ToString('N').Substring(0,6) +$catAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/platform/content/category' -Headers $headers -Body @{ name='后台分类'; code=$catCode; parentId=0; level=1; sort=88; status=1 } +Add-Result $results 'POST' '/admin/platform/content/category' ($(if($catAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台添加分类' $catAdd +$categoryList2 = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/content/category/list' -Headers $headers +$cat = @($categoryList2.json.data | Where-Object { $_.code -eq $catCode }) | Select-Object -First 1 +if ($cat) { + $catUpd = Invoke-Api -Method PUT -Url 'http://localhost:9000/admin/platform/content/category' -Headers $headers -Body @{ id=$cat.id; name='后台分类更新'; code=$catCode; parentId=0; level=1; sort=89; status=1 } + $catDel = Invoke-Api -Method DELETE -Url "http://localhost:9000/admin/platform/content/category/$($cat.id)" -Headers $headers + Add-Result $results 'PUT' '/admin/platform/content/category' ($(if($catUpd.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台更新分类' $catUpd + Add-Result $results 'DELETE' '/admin/platform/content/category/{categoryId}' ($(if($catDel.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台删除分类' $catDel +} + +$commentList = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/comment/list?page=1&size=5' -Headers $headers +Add-Result $results 'GET' '/admin/platform/comment/list' ($(if($commentList.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台评论列表' $commentList +$commentStats = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/comment/stats' -Headers $headers +Add-Result $results 'GET' '/admin/platform/comment/stats' ($(if($commentStats.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台评论统计' $commentStats +$firstComment = $null +if ($commentList.json -and $commentList.json.data -and $commentList.json.data.records) { $firstComment = @($commentList.json.data.records) | Select-Object -First 1 } +if ($firstComment) { + $commentDetail = Invoke-Api -Method GET -Url "http://localhost:9000/admin/platform/comment/$($firstComment.id)" -Headers $headers + Add-Result $results 'GET' '/admin/platform/comment/{commentId}' ($(if($commentDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台评论详情' $commentDetail +} else { + Add-Result $results 'GET' '/admin/platform/comment/{commentId}' 'UNTESTED' '当前库里没有可测评论记录' $null +} + +$videoList = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/platform/content/video/list?page=1&size=5' -Headers $headers +Add-Result $results 'GET' '/admin/platform/content/video/list' ($(if($videoList.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台视频列表' $videoList +$firstVideo = $null +if ($videoList.json -and $videoList.json.data -and $videoList.json.data.records) { $firstVideo = @($videoList.json.data.records) | Select-Object -First 1 } +if ($firstVideo) { + $videoDetail = Invoke-Api -Method GET -Url "http://localhost:9000/admin/platform/content/video/$($firstVideo.id)" -Headers $headers + Add-Result $results 'GET' '/admin/platform/content/video/{videoId}' ($(if($videoDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台视频详情' $videoDetail + $videoDisable = Invoke-Api -Method PUT -Url "http://localhost:9000/admin/platform/content/video/disable/$($firstVideo.id)" -Headers $headers + Add-Result $results 'PUT' '/admin/platform/content/video/disable/{videoId}' ($(if($videoDisable.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台下架视频' $videoDisable +} else { + Add-Result $results 'GET' '/admin/platform/content/video/{videoId}' 'UNTESTED' '当前库里没有可测视频记录' $null + Add-Result $results 'PUT' '/admin/platform/content/video/disable/{videoId}' 'UNTESTED' '当前库里没有可测视频记录' $null +} + +$dashboard = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/dashboard/stats' -Headers $headers +Add-Result $results 'GET' '/admin/dashboard/stats' ($(if($dashboard.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台仪表盘' $dashboard + +$out = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('s') + ids = [pscustomobject]@{ userA=$userAId; userB=$userBId } + results = $results +} + +$outPath = 'C:\Users\toyas\Desktop\本科毕业设计\参考\workspace\HA-OVP\backend\API_TEST_RESULTS_admin.json' +$out | ConvertTo-Json -Depth 8 | Set-Content -Path $outPath -Encoding utf8BOM + +$passed = ($results | Where-Object { $_.status -eq 'PASSED' }).Count +$failed = ($results | Where-Object { $_.status -eq 'FAILED' }).Count +$untested = ($results | Where-Object { $_.status -eq 'UNTESTED' }).Count +[pscustomobject]@{ passed=$passed; failed=$failed; untested=$untested; file=$outPath } | ConvertTo-Json -Compress diff --git a/backend/run_auth_user_batch.ps1 b/backend/run_auth_user_batch.ps1 new file mode 100644 index 0000000..cfab7a1 --- /dev/null +++ b/backend/run_auth_user_batch.ps1 @@ -0,0 +1,237 @@ +$ErrorActionPreference = 'Stop' + +function Invoke-Api { + param( + [string]$Method, + [string]$Url, + [hashtable]$Headers = @{}, + $Body = $null, + [int]$TimeoutSec = 60 + ) + $params = @{ + Method = $Method + Uri = $Url + Headers = $Headers + UseBasicParsing = $true + SkipHttpErrorCheck = $true + TimeoutSec = $TimeoutSec + } + if ($null -ne $Body) { + if ($Body -is [string]) { + $params.ContentType = 'application/json' + $params.Body = $Body + } else { + $params.ContentType = 'application/json' + $params.Body = ($Body | ConvertTo-Json -Depth 20) + } + } + try { + $resp = Invoke-WebRequest @params + $json = $null + if ($resp.Content) { + try { $json = $resp.Content | ConvertFrom-Json -Depth 50 } catch {} + } + [pscustomobject]@{ + http = [int]$resp.StatusCode + json = $json + raw = $resp.Content + } + } catch { + [pscustomobject]@{ + http = -1 + json = $null + raw = $_.Exception.Message + } + } +} + +function Add-Result { + param( + [System.Collections.Generic.List[object]]$Results, + [string]$Method, + [string]$Path, + [string]$Status, + [string]$Note, + [object]$Resp + ) + $apiCode = $null + if ($Resp -and $Resp.json -and $null -ne $Resp.json.code) { + $apiCode = $Resp.json.code + } + $Results.Add([pscustomobject]@{ + method = $Method + path = $Path + status = $Status + http = if ($Resp) { $Resp.http } else { $null } + apiCode = $apiCode + note = $Note + }) +} + +function Get-UserCaptcha { + $cap = Invoke-Api -Method GET -Url 'http://localhost:9000/auth/captcha' + if ($cap.http -ne 200 -or -not $cap.json) { + throw "获取用户验证码失败: $($cap.raw)" + } + $key = $cap.json.data.captchaKey + $code = docker exec redis redis-cli -a redis_EsJ8FX --raw GET ('captcha:' + $key) + [pscustomobject]@{ + key = $key + code = $code.Trim('"').Trim() + } +} + +function Register-LoginUser { + param([string]$Prefix) + + $password = 'Pass@123456' + $username = $Prefix + [guid]::NewGuid().ToString('N').Substring(0, 8) + $digits = -join ((48..57) | Get-Random -Count 9 | ForEach-Object { [char]$_ }) + $cap = Get-UserCaptcha + + $register = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/register' -Body @{ + username = $username + password = $password + confirmPassword = $password + email = "$username@example.com" + phone = '13' + $digits + captcha = $cap.code + captchaKey = $cap.key + } + + $cap2 = Get-UserCaptcha + $login = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ + username = $username + password = $password + captcha = $cap2.code + captchaKey = $cap2.key + } + + $headers = @{ Authorization = 'Bearer ' + $login.json.data.accessToken } + $current = Invoke-Api -Method GET -Url 'http://localhost:9000/auth/current' -Headers $headers + + [pscustomobject]@{ + username = $username + password = $password + register = $register + login = $login + headers = $headers + userId = [long]$current.json.data.id + refreshToken = $login.json.data.refreshToken + } +} + +$results = [System.Collections.Generic.List[object]]::new() + +$uNoCaptcha = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ username = 'nouser'; password = 'wrong' } +Add-Result -Results $results -Method 'POST' -Path '/auth/login' -Status ($(if ($uNoCaptcha.http -eq 400) { 'PASSED' } else { 'FAILED' })) -Note '无验证码登录应被拦截' -Resp $uNoCaptcha + +$userA = Register-LoginUser -Prefix 'ua' +$userB = Register-LoginUser -Prefix 'ub' + +Add-Result -Results $results -Method 'POST' -Path '/auth/register' -Status ($(if ($userA.register.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '用户A注册' -Resp $userA.register +Add-Result -Results $results -Method 'POST' -Path '/auth/login' -Status ($(if ($userA.login.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '用户A登录' -Resp $userA.login + +$current = Invoke-Api -Method GET -Url 'http://localhost:9000/auth/current' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/auth/current' -Status ($(if ($current.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '当前用户' -Resp $current + +$refresh = Invoke-Api -Method POST -Url "http://localhost:9000/auth/refresh?refreshToken=$($userA.refreshToken)" +Add-Result -Results $results -Method 'POST' -Path '/auth/refresh' -Status ($(if ($refresh.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '刷新令牌' -Resp $refresh + +$usernameById = Invoke-Api -Method GET -Url "http://localhost:9000/auth/username/$($userA.userId)" +Add-Result -Results $results -Method 'GET' -Path '/auth/username/{userId}' -Status ($(if ($usernameById.http -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '根据ID获取用户名' -Resp $usernameById + +$profileCurrent = Invoke-Api -Method GET -Url 'http://localhost:9000/user/profile/current' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/profile/current' -Status ($(if ($profileCurrent.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '当前资料' -Resp $profileCurrent + +$profilePublic = Invoke-Api -Method GET -Url "http://localhost:9000/user/profile/public/$($userA.userId)" +Add-Result -Results $results -Method 'GET' -Path '/user/profile/public/{userId}' -Status ($(if ($profilePublic.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '公开资料' -Resp $profilePublic + +$updateProfile = Invoke-Api -Method PUT -Url 'http://localhost:9000/user/profile' -Headers $userA.headers -Body @{ + nickname = '测试用户A' + signature = '签名A' + region = '南京' + gender = 1 +} +Add-Result -Results $results -Method 'PUT' -Path '/user/profile' -Status ($(if ($updateProfile.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '更新资料' -Resp $updateProfile + +$searchUser = Invoke-Api -Method GET -Url "http://localhost:9000/user/profile/search?keyword=$($userA.username)&page=1&size=5" +Add-Result -Results $results -Method 'GET' -Path '/user/profile/search' -Status ($(if ($searchUser.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '搜索用户' -Resp $searchUser + +$getSetting = Invoke-Api -Method GET -Url 'http://localhost:9000/user/setting' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/setting' -Status ($(if ($getSetting.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '获取设置' -Resp $getSetting + +$updateSetting = Invoke-Api -Method PUT -Url 'http://localhost:9000/user/setting' -Headers $userA.headers -Body @{ + privacyLevel = 1 + commentNotify = 1 + likeNotify = 1 + followNotify = 1 + systemNotify = 1 +} +Add-Result -Results $results -Method 'PUT' -Path '/user/setting' -Status ($(if ($updateSetting.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '更新设置' -Resp $updateSetting + +$follow = Invoke-Api -Method POST -Url "http://localhost:9000/user/follow/$($userA.userId)" -Headers $userB.headers +Add-Result -Results $results -Method 'POST' -Path '/user/follow/{followId}' -Status ($(if ($follow.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note 'B关注A' -Resp $follow + +$checkFollow = Invoke-Api -Method GET -Url "http://localhost:9000/user/follow/check/$($userA.userId)" -Headers $userB.headers +Add-Result -Results $results -Method 'GET' -Path '/user/follow/check/{followId}' -Status ($(if ($checkFollow.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '检查关注' -Resp $checkFollow + +$following = Invoke-Api -Method GET -Url "http://localhost:9000/user/follow/following/$($userB.userId)?page=1&size=5" +Add-Result -Results $results -Method 'GET' -Path '/user/follow/following/{userId}' -Status ($(if ($following.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '关注列表' -Resp $following + +$followers = Invoke-Api -Method GET -Url "http://localhost:9000/user/follow/followers/$($userA.userId)?page=1&size=5" +Add-Result -Results $results -Method 'GET' -Path '/user/follow/followers/{userId}' -Status ($(if ($followers.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '粉丝列表' -Resp $followers + +$noticeList = Invoke-Api -Method GET -Url 'http://localhost:9000/user/notification/list?page=1&size=10' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/notification/list' -Status ($(if ($noticeList.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '通知列表' -Resp $noticeList + +$noticeUnread = Invoke-Api -Method GET -Url 'http://localhost:9000/user/notification/unread/count' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/notification/unread/count' -Status ($(if ($noticeUnread.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '未读通知' -Resp $noticeUnread + +$noticeReadAll = Invoke-Api -Method PUT -Url 'http://localhost:9000/user/notification/read' -Headers $userA.headers +Add-Result -Results $results -Method 'PUT' -Path '/user/notification/read' -Status ($(if ($noticeReadAll.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '全部通知已读' -Resp $noticeReadAll + +$msgSend = Invoke-Api -Method POST -Url 'http://localhost:9000/user/message' -Headers $userB.headers -Body @{ + receiverId = $userA.userId + content = 'hello-from-b' +} +Add-Result -Results $results -Method 'POST' -Path '/user/message' -Status ($(if ($msgSend.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '发送私信' -Resp $msgSend + +$msgList = Invoke-Api -Method GET -Url 'http://localhost:9000/user/message/list?page=1&size=10' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/message/list' -Status ($(if ($msgList.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '会话列表' -Resp $msgList + +$msgDetail = Invoke-Api -Method GET -Url "http://localhost:9000/user/message/detail/$($userB.userId)?page=1&size=10" -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/message/detail/{targetId}' -Status ($(if ($msgDetail.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '会话详情' -Resp $msgDetail + +$msgUnread = Invoke-Api -Method GET -Url 'http://localhost:9000/user/message/unread/count' -Headers $userA.headers +Add-Result -Results $results -Method 'GET' -Path '/user/message/unread/count' -Status ($(if ($msgUnread.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '未读私信数' -Resp $msgUnread + +$msgRead = Invoke-Api -Method PUT -Url "http://localhost:9000/user/message/read/$($userB.userId)" -Headers $userA.headers +Add-Result -Results $results -Method 'PUT' -Path '/user/message/read/{senderId}' -Status ($(if ($msgRead.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '私信已读' -Resp $msgRead + +$logout = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/logout' -Headers $userA.headers +Add-Result -Results $results -Method 'POST' -Path '/auth/logout' -Status ($(if ($logout.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '登出' -Resp $logout + +$unfollow = Invoke-Api -Method DELETE -Url "http://localhost:9000/user/follow/$($userA.userId)" -Headers $userB.headers +Add-Result -Results $results -Method 'DELETE' -Path '/user/follow/{followId}' -Status ($(if ($unfollow.json.code -eq 200) { 'PASSED' } else { 'FAILED' })) -Note '取消关注' -Resp $unfollow + +$out = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('s') + users = @($userA.username, $userB.username) + ids = [pscustomobject]@{ + userA = $userA.userId + userB = $userB.userId + } + results = $results +} + +$outPath = 'C:\Users\toyas\Desktop\本科毕业设计\参考\workspace\HA-OVP\backend\API_TEST_RESULTS_auth_user.json' +$out | ConvertTo-Json -Depth 8 | Set-Content -Path $outPath -Encoding utf8BOM + +$passed = ($results | Where-Object { $_.status -eq 'PASSED' }).Count +$failed = ($results | Where-Object { $_.status -eq 'FAILED' }).Count +[pscustomobject]@{ + passed = $passed + failed = $failed + file = $outPath +} | ConvertTo-Json -Compress diff --git a/backend/run_content_comment_recommend_batch.ps1 b/backend/run_content_comment_recommend_batch.ps1 new file mode 100644 index 0000000..6af0c5c --- /dev/null +++ b/backend/run_content_comment_recommend_batch.ps1 @@ -0,0 +1,324 @@ +$ErrorActionPreference = 'Stop' + +function Invoke-Api { + param( + [string]$Method, + [string]$Url, + [hashtable]$Headers = @{}, + $Body = $null, + [int]$TimeoutSec = 25 + ) + try { + $params = @{ + Method = $Method + Uri = $Url + Headers = $Headers + UseBasicParsing = $true + SkipHttpErrorCheck = $true + TimeoutSec = $TimeoutSec + } + if ($null -ne $Body) { + if ($Body -is [string]) { + $params.ContentType = 'application/json' + $params.Body = $Body + } else { + $params.ContentType = 'application/json' + $params.Body = ($Body | ConvertTo-Json -Depth 20) + } + } + $resp = Invoke-WebRequest @params + $json = $null + if ($resp.Content) { + try { $json = $resp.Content | ConvertFrom-Json -Depth 50 } catch {} + } + [pscustomobject]@{ http = [int]$resp.StatusCode; json = $json; raw = $resp.Content } + } catch { + [pscustomobject]@{ http = -1; json = $null; raw = $_.Exception.Message } + } +} + +function Add-Result { + param( + [System.Collections.Generic.List[object]]$Results, + [string]$Module, + [string]$Method, + [string]$Path, + [string]$Status, + [string]$Note, + [object]$Resp + ) + $apiCode = $null + if ($Resp -and $Resp.json -and $null -ne $Resp.json.code) { $apiCode = $Resp.json.code } + $Results.Add([pscustomobject]@{ + module = $Module + method = $Method + path = $Path + status = $Status + http = if ($Resp) { $Resp.http } else { $null } + apiCode = $apiCode + note = $Note + }) + if ($script:ResultPath) { + [pscustomobject]@{ generatedAt = (Get-Date).ToString('s'); results = $Results } | + ConvertTo-Json -Depth 8 | + Set-Content -Path $script:ResultPath -Encoding utf8BOM + } +} + +function Get-UserCaptcha { + $cap = Invoke-Api -Method GET -Url 'http://localhost:9000/auth/captcha' + if ($cap.http -ne 200 -or -not $cap.json) { throw "获取用户验证码失败: $($cap.raw)" } + $key = $cap.json.data.captchaKey + $code = docker exec redis redis-cli -a redis_EsJ8FX --raw GET ('captcha:' + $key) + [pscustomobject]@{ key = $key; code = $code.Trim('"').Trim() } +} + +function Get-AdminCaptcha { + $cap = Invoke-Api -Method GET -Url 'http://localhost:9000/admin/auth/captcha' + if ($cap.http -ne 200 -or -not $cap.json) { throw "获取后台验证码失败: $($cap.raw)" } + $key = $cap.json.data.captchaKey + $code = docker exec redis redis-cli -a redis_EsJ8FX -n 5 --raw GET ('admin:captcha:' + $key) + [pscustomobject]@{ key = $key; code = $code.Trim('"').Trim() } +} + +function Register-LoginUser { + param([string]$Prefix) + $password = 'Pass@123456' + $username = $Prefix + [guid]::NewGuid().ToString('N').Substring(0,8) + $digits = -join ((48..57) | Get-Random -Count 9 | ForEach-Object { [char]$_ }) + $cap = Get-UserCaptcha + $register = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/register' -Body @{ + username = $username + password = $password + confirmPassword = $password + email = "$username@example.com" + phone = '13' + $digits + captcha = $cap.code + captchaKey = $cap.key + } + $cap2 = Get-UserCaptcha + $login = Invoke-Api -Method POST -Url 'http://localhost:9000/auth/login' -Body @{ + username = $username + password = $password + captcha = $cap2.code + captchaKey = $cap2.key + } + $headers = @{ Authorization = 'Bearer ' + $login.json.data.accessToken } + $current = Invoke-Api -Method GET -Url 'http://localhost:9000/auth/current' -Headers $headers + [pscustomobject]@{ + username = $username + password = $password + headers = $headers + userId = [long]$current.json.data.id + } +} + +function Get-AdminSession { + $cap = Get-AdminCaptcha + $login = Invoke-Api -Method POST -Url 'http://localhost:9000/admin/auth/login' -Body @{ + username = 'admin' + password = 'admin123' + captcha = $cap.code + captchaKey = $cap.key + } + [pscustomobject]@{ + headers = @{ Authorization = 'Bearer ' + $login.json.data.token } + login = $login + } +} + +$results = [System.Collections.Generic.List[object]]::new() +$script:ResultPath = 'C:\Users\toyas\Desktop\本科毕业设计\参考\workspace\HA-OVP\backend\API_TEST_RESULTS_content_comment_recommend.json' +$userA = Register-LoginUser -Prefix 'ca' +$userB = Register-LoginUser -Prefix 'cb' +$admin = Get-AdminSession + +# Categories +$catTree = Invoke-Api -Method GET -Url 'http://localhost:9000/content/category/tree' +Add-Result $results 'video-content' 'GET' '/content/category/tree' ($(if($catTree.json.code -eq 200){'PASSED'}else{'FAILED'})) '分类树' $catTree +$catList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/category/list' +Add-Result $results 'video-content' 'GET' '/content/category/list' ($(if($catList.json.code -eq 200){'PASSED'}else{'FAILED'})) '分类列表' $catList +$firstCategory = @($catList.json.data) | Select-Object -First 1 +$categoryId = [long]$firstCategory.id + +$publicCatCode = 'pubcat' + [guid]::NewGuid().ToString('N').Substring(0,6) +$publicCatAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/content/category' -Headers $userA.headers -Body @{ name='公开分类'; code=$publicCatCode; parentId=0; level=1; sort=98; status=1 } +Add-Result $results 'video-content' 'POST' '/content/category' ($(if($publicCatAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '新增分类' $publicCatAdd +$catList2 = Invoke-Api -Method GET -Url 'http://localhost:9000/content/category/list' +$publicCat = @($catList2.json.data | Where-Object { $_.code -eq $publicCatCode }) | Select-Object -First 1 +if ($publicCat) { + $publicCatUpd = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/category' -Headers $userA.headers -Body @{ id=$publicCat.id; name='公开分类更新'; code=$publicCatCode; parentId=0; level=1; sort=99; status=1 } + $publicCatDel = Invoke-Api -Method DELETE -Url "http://localhost:9000/content/category/$($publicCat.id)" -Headers $userA.headers + Add-Result $results 'video-content' 'PUT' '/content/category' ($(if($publicCatUpd.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新分类' $publicCatUpd + Add-Result $results 'video-content' 'DELETE' '/content/category/{id}' ($(if($publicCatDel.json.code -eq 200){'PASSED'}else{'FAILED'})) '删除分类' $publicCatDel +} + +# Tags +$tagUsedName = 'tagused-' + [guid]::NewGuid().ToString('N').Substring(0,6) +$tagTempName = 'tagtmp-' + [guid]::NewGuid().ToString('N').Substring(0,6) +$tagUsedAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/content/tag' -Headers $userA.headers -Body @{ name = $tagUsedName } +$tagTempAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/content/tag' -Headers $userA.headers -Body @{ name = $tagTempName } +$tagList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/tag/list' +$tagPage = Invoke-Api -Method GET -Url 'http://localhost:9000/content/tag/page?pageNum=1&pageSize=20' +$tagUsed = @($tagList.json.data | Where-Object { $_.name -eq $tagUsedName }) | Select-Object -First 1 +$tagTemp = @($tagList.json.data | Where-Object { $_.name -eq $tagTempName }) | Select-Object -First 1 +Add-Result $results 'video-content' 'POST' '/content/tag' ($(if($tagUsedAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加标签(used)' $tagUsedAdd +Add-Result $results 'video-content' 'POST' '/content/tag' ($(if($tagTempAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加标签(temp)' $tagTempAdd +Add-Result $results 'video-content' 'GET' '/content/tag/list' ($(if($tagList.json.code -eq 200){'PASSED'}else{'FAILED'})) '标签列表' $tagList +Add-Result $results 'video-content' 'GET' '/content/tag/page' ($(if($tagPage.json.code -eq 200){'PASSED'}else{'FAILED'})) '标签分页' $tagPage +if ($tagTemp) { + $tagUpdate = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/tag' -Headers $userA.headers -Body @{ id = $tagTemp.id; name = ($tagTempName + '-u') } + Add-Result $results 'video-content' 'PUT' '/content/tag' ($(if($tagUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新标签' $tagUpdate +} + +# Favorite list +$favCreate = Invoke-Api -Method POST -Url 'http://localhost:9000/content/favorite' -Headers $userB.headers -Body @{ name='fav-b'; description='desc'; isPrivate=0 } +$favList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/favorite/list' -Headers $userB.headers +$fav = @($favList.json.data) | Select-Object -First 1 +Add-Result $results 'video-content' 'POST' '/content/favorite' ($(if($favCreate.json.code -eq 200){'PASSED'}else{'FAILED'})) '创建收藏夹' $favCreate +Add-Result $results 'video-content' 'GET' '/content/favorite/list' ($(if($favList.json.code -eq 200){'PASSED'}else{'FAILED'})) '收藏夹列表' $favList +if ($fav) { + $favUpdate = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/favorite' -Headers $userB.headers -Body @{ id=$fav.id; name='fav-b-upd'; description='desc2'; isPrivate=1 } + Add-Result $results 'video-content' 'PUT' '/content/favorite' ($(if($favUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新收藏夹' $favUpdate +} + +# Video create + publish +$videoBody = @{ + title = '测试视频标题12345' + description = '测试视频描述' + categoryId = $categoryId + tagIds = @([long]$tagUsed.id) + coverUrl = 'http://example.com/cover.jpg' + videoUrl = 'http://example.com/video.mp4' + duration = 60 + width = 1280 + height = 720 + format = 'mp4' + size = 123456 +} +$createVideo = Invoke-Api -Method POST -Url 'http://localhost:9000/content/video' -Headers $userA.headers -Body $videoBody +$videoId = [long]$createVideo.json.data +Add-Result $results 'video-content' 'POST' '/content/video' ($(if($createVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '创建视频' $createVideo +$adminVideoReview = Invoke-Api -Method POST -Url "http://localhost:9000/admin/platform/content/video/review/$videoId?status=1&reason=ok" -Headers $admin.headers +Add-Result $results 'video-admin' 'POST' '/admin/platform/content/video/review/{videoId}' ($(if($adminVideoReview.json.code -eq 200){'PASSED'}else{'FAILED'})) '后台审核视频' $adminVideoReview + +# Video read/update/interaction +$videoPublicDetail = Invoke-Api -Method GET -Url "http://localhost:9000/content/video/public/$videoId" +$videoAuthedDetail = Invoke-Api -Method GET -Url "http://localhost:9000/content/video/$videoId" -Headers $userB.headers +$videoPublicList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/video/public/list?pageNum=1&pageSize=10' +$videoAuthedList = Invoke-Api -Method GET -Url 'http://localhost:9000/content/video/list?pageNum=1&pageSize=10' -Headers $userB.headers +$videoUserList = Invoke-Api -Method GET -Url "http://localhost:9000/content/video/user/$($userA.userId)?pageNum=1&pageSize=10" +$videoUpdate = Invoke-Api -Method PUT -Url 'http://localhost:9000/content/video' -Headers $userA.headers -Body @{ id = $videoId; title='更新后视频标题12345'; description='更新描述'; categoryId=$categoryId; tagIds=@([long]$tagUsed.id) } +$videoTags = Invoke-Api -Method GET -Url "http://localhost:9000/content/tag/video/$videoId" +$likeVideo = Invoke-Api -Method POST -Url "http://localhost:9000/content/video/like/$videoId" -Headers $userB.headers +$unlikeVideo = Invoke-Api -Method DELETE -Url "http://localhost:9000/content/video/like/$videoId" -Headers $userB.headers +$coinVideo = Invoke-Api -Method POST -Url "http://localhost:9000/content/video/coin/$videoId?amount=1" -Headers $userB.headers +$shareVideo = Invoke-Api -Method POST -Url "http://localhost:9000/content/video/share/$videoId?platform=wechat" -Headers $userB.headers +$playVideo = Invoke-Api -Method POST -Url 'http://localhost:9000/content/video/play' -Headers $userB.headers -Body @{ videoId = $videoId; playTime = 58; isFinished = 1 } +Add-Result $results 'video-content' 'GET' '/content/video/public/{id}' ($(if($videoPublicDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '公开视频详情' $videoPublicDetail +Add-Result $results 'video-content' 'GET' '/content/video/{id}' ($(if($videoAuthedDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '登录后视频详情' $videoAuthedDetail +Add-Result $results 'video-content' 'GET' '/content/video/public/list' ($(if($videoPublicList.json.code -eq 200){'PASSED'}else{'FAILED'})) '公开视频列表' $videoPublicList +Add-Result $results 'video-content' 'GET' '/content/video/list' ($(if($videoAuthedList.json.code -eq 200){'PASSED'}else{'FAILED'})) '登录后视频列表' $videoAuthedList +Add-Result $results 'video-content' 'GET' '/content/video/user/{userId}' ($(if($videoUserList.json.code -eq 200){'PASSED'}else{'FAILED'})) '用户视频列表' $videoUserList +Add-Result $results 'video-content' 'PUT' '/content/video' ($(if($videoUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新视频' $videoUpdate +Add-Result $results 'video-content' 'GET' '/content/tag/video/{videoId}' ($(if($videoTags.json.code -eq 200){'PASSED'}else{'FAILED'})) '视频标签' $videoTags +Add-Result $results 'video-content' 'POST' '/content/video/like/{videoId}' ($(if($likeVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '点赞视频' $likeVideo +Add-Result $results 'video-content' 'DELETE' '/content/video/like/{videoId}' ($(if($unlikeVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消点赞视频' $unlikeVideo +Add-Result $results 'video-content' 'POST' '/content/video/coin/{videoId}' ($(if($coinVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '投币视频' $coinVideo +Add-Result $results 'video-content' 'POST' '/content/video/share/{videoId}' ($(if($shareVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '分享视频' $shareVideo +Add-Result $results 'video-content' 'POST' '/content/video/play' ($(if($playVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '播放记录' $playVideo + +if ($fav) { + $favVideo = Invoke-Api -Method POST -Url 'http://localhost:9000/content/video/favorite' -Headers $userB.headers -Body @{ videoId = $videoId; favoriteId = [long]$fav.id } + $favVideos = Invoke-Api -Method GET -Url "http://localhost:9000/content/favorite/$($fav.id)/videos?pageNum=1&pageSize=10" -Headers $userB.headers + $unfavVideo = Invoke-Api -Method DELETE -Url "http://localhost:9000/content/video/favorite/$videoId" -Headers $userB.headers + $favDelete = Invoke-Api -Method DELETE -Url "http://localhost:9000/content/favorite/$($fav.id)" -Headers $userB.headers + Add-Result $results 'video-content' 'POST' '/content/video/favorite' ($(if($favVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '收藏视频' $favVideo + Add-Result $results 'video-content' 'GET' '/content/favorite/{favoriteId}/videos' ($(if($favVideos.json.code -eq 200){'PASSED'}else{'FAILED'})) '收藏夹视频列表' $favVideos + Add-Result $results 'video-content' 'DELETE' '/content/video/favorite/{videoId}' ($(if($unfavVideo.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消收藏视频' $unfavVideo + Add-Result $results 'video-content' 'DELETE' '/content/favorite/{id}' ($(if($favDelete.json.code -eq 200){'PASSED'}else{'FAILED'})) '删除收藏夹' $favDelete +} + +# Danmaku/stats +$danmakuSend = Invoke-Api -Method POST -Url 'http://localhost:9000/content/danmaku' -Headers $userB.headers -Body @{ videoId=$videoId; content='666'; time=12.5 } +$danmakuAll = Invoke-Api -Method GET -Url "http://localhost:9000/content/danmaku/all/$videoId" +$danmakuTime = Invoke-Api -Method GET -Url "http://localhost:9000/content/danmaku/time?videoId=$videoId&startTime=0&endTime=20" +$statDaily = Invoke-Api -Method GET -Url "http://localhost:9000/content/stat/daily/$videoId?startDate=2026-04-01&endDate=2026-04-30" +$statTrend = Invoke-Api -Method GET -Url "http://localhost:9000/content/stat/play/trend/$videoId" +$statInteraction = Invoke-Api -Method GET -Url "http://localhost:9000/content/stat/interaction/$videoId" +Add-Result $results 'video-content' 'POST' '/content/danmaku' ($(if($danmakuSend.json.code -eq 200){'PASSED'}else{'FAILED'})) '发送弹幕' $danmakuSend +Add-Result $results 'video-content' 'GET' '/content/danmaku/all/{videoId}' ($(if($danmakuAll.json.code -eq 200){'PASSED'}else{'FAILED'})) '全部弹幕' $danmakuAll +Add-Result $results 'video-content' 'GET' '/content/danmaku/time' ($(if($danmakuTime.json.code -eq 200){'PASSED'}else{'FAILED'})) '时间段弹幕' $danmakuTime +Add-Result $results 'video-content' 'GET' '/content/stat/daily/{videoId}' ($(if($statDaily.json.code -eq 200){'PASSED'}else{'FAILED'})) '视频日统计' $statDaily +Add-Result $results 'video-content' 'GET' '/content/stat/play/trend/{videoId}' ($(if($statTrend.json.code -eq 200){'PASSED'}else{'FAILED'})) '播放趋势' $statTrend +Add-Result $results 'video-content' 'GET' '/content/stat/interaction/{videoId}' ($(if($statInteraction.json.code -eq 200){'PASSED'}else{'FAILED'})) '互动统计' $statInteraction + +# Comment/reply +$commentAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/comment' -Headers $userB.headers -Body @{ videoId = $videoId; content = 'comment-from-b' } +$commentId = [long]$commentAdd.json.data +$commentList = Invoke-Api -Method GET -Url "http://localhost:9000/comment/public/list?videoId=$videoId&pageNum=1&pageSize=10" +$commentDetail = Invoke-Api -Method GET -Url "http://localhost:9000/comment/public/detail/$commentId" +$commentStat = Invoke-Api -Method GET -Url "http://localhost:9000/comment/public/stat/$videoId" +$likeComment = Invoke-Api -Method POST -Url "http://localhost:9000/comment/like/$commentId" -Headers $userA.headers +$unlikeComment = Invoke-Api -Method DELETE -Url "http://localhost:9000/comment/like/$commentId" -Headers $userA.headers +$topComment = Invoke-Api -Method POST -Url "http://localhost:9000/comment/top/$commentId?videoId=$videoId" -Headers $userA.headers +$untopComment = Invoke-Api -Method DELETE -Url "http://localhost:9000/comment/top/$commentId?videoId=$videoId" -Headers $userA.headers +$replyAdd = Invoke-Api -Method POST -Url 'http://localhost:9000/comment/reply' -Headers $userA.headers -Body @{ commentId=$commentId; videoId=$videoId; replyToId=$userB.userId; content='reply-from-a' } +$replyId = [long]$replyAdd.json.data +$replyList = Invoke-Api -Method GET -Url "http://localhost:9000/comment/reply/public/list/$commentId?page=1&size=10" +$replyHot = Invoke-Api -Method GET -Url "http://localhost:9000/comment/reply/public/hot/$commentId?limit=3" +$likeReply = Invoke-Api -Method POST -Url "http://localhost:9000/comment/reply/like/$replyId" -Headers $userB.headers +$unlikeReply = Invoke-Api -Method DELETE -Url "http://localhost:9000/comment/reply/like/$replyId" -Headers $userB.headers +$deleteReply = Invoke-Api -Method DELETE -Url "http://localhost:9000/comment/reply/$replyId" -Headers $userA.headers +Add-Result $results 'video-comment' 'POST' '/comment' ($(if($commentAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加评论' $commentAdd +Add-Result $results 'video-comment' 'GET' '/comment/public/list' ($(if($commentList.json.code -eq 200){'PASSED'}else{'FAILED'})) '评论列表' $commentList +Add-Result $results 'video-comment' 'GET' '/comment/public/detail/{id}' ($(if($commentDetail.json.code -eq 200){'PASSED'}else{'FAILED'})) '评论详情' $commentDetail +Add-Result $results 'video-comment' 'GET' '/comment/public/stat/{videoId}' ($(if($commentStat.json.code -eq 200){'PASSED'}else{'FAILED'})) '评论统计' $commentStat +Add-Result $results 'video-comment' 'POST' '/comment/like/{id}' ($(if($likeComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '点赞评论' $likeComment +Add-Result $results 'video-comment' 'DELETE' '/comment/like/{id}' ($(if($unlikeComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消点赞评论' $unlikeComment +Add-Result $results 'video-comment' 'POST' '/comment/top/{id}' ($(if($topComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '置顶评论' $topComment +Add-Result $results 'video-comment' 'DELETE' '/comment/top/{id}' ($(if($untopComment.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消置顶评论' $untopComment +Add-Result $results 'video-comment' 'POST' '/comment/reply' ($(if($replyAdd.json.code -eq 200){'PASSED'}else{'FAILED'})) '添加回复' $replyAdd +Add-Result $results 'video-comment' 'GET' '/comment/reply/public/list/{commentId}' ($(if($replyList.json.code -eq 200){'PASSED'}else{'FAILED'})) '回复列表' $replyList +Add-Result $results 'video-comment' 'GET' '/comment/reply/public/hot/{commentId}' ($(if($replyHot.json.code -eq 200){'PASSED'}else{'FAILED'})) '热门回复' $replyHot +Add-Result $results 'video-comment' 'POST' '/comment/reply/like/{id}' ($(if($likeReply.json.code -eq 200){'PASSED'}else{'FAILED'})) '点赞回复' $likeReply +Add-Result $results 'video-comment' 'DELETE' '/comment/reply/like/{id}' ($(if($unlikeReply.json.code -eq 200){'PASSED'}else{'FAILED'})) '取消点赞回复' $unlikeReply +Add-Result $results 'video-comment' 'DELETE' '/comment/reply/{id}' ($(if($deleteReply.json.code -eq 200){'PASSED'}else{'FAILED'})) '删除回复' $deleteReply + +# Recommend +$homeRecommend = Invoke-Api -Method GET -Url 'http://localhost:9000/recommend/home' +$hot = Invoke-Api -Method GET -Url 'http://localhost:9000/recommend/hot' +$similar = Invoke-Api -Method GET -Url "http://localhost:9000/recommend/similar/$videoId?size=10" +$tagRecommend = Invoke-Api -Method GET -Url "http://localhost:9000/recommend/tag/$($tagUsed.id)?size=10" +$behavior = Invoke-Api -Method POST -Url 'http://localhost:9000/recommend/behavior' -Headers $userB.headers -Body @{ videoId = $videoId; behaviorType = 1 } +$interestUpdate = Invoke-Api -Method POST -Url 'http://localhost:9000/recommend/interest/update' -Headers $userB.headers +Add-Result $results 'video-recommend' 'GET' '/recommend/home' ($(if($homeRecommend.json.code -eq 200){'PASSED'}else{'FAILED'})) '首页推荐' $homeRecommend +Add-Result $results 'video-recommend' 'GET' '/recommend/hot' ($(if($hot.json.code -eq 200){'PASSED'}else{'FAILED'})) '热门推荐' $hot +Add-Result $results 'video-recommend' 'GET' '/recommend/similar/{videoId}' ($(if($similar.json.code -eq 200){'PASSED'}else{'FAILED'})) '相似推荐' $similar +Add-Result $results 'video-recommend' 'GET' '/recommend/tag/{tagId}' ($(if($tagRecommend.json.code -eq 200){'PASSED'}else{'FAILED'})) '标签推荐' $tagRecommend +Add-Result $results 'video-recommend' 'POST' '/recommend/behavior' ($(if($behavior.json.code -eq 200){'PASSED'}else{'FAILED'})) '记录行为' $behavior +Add-Result $results 'video-recommend' 'POST' '/recommend/interest/update' ($(if($interestUpdate.json.code -eq 200){'PASSED'}else{'FAILED'})) '更新兴趣' $interestUpdate + +$out = [pscustomobject]@{ + generatedAt = (Get-Date).ToString('s') + ids = [pscustomobject]@{ + userA = $userA.userId + userB = $userB.userId + videoId = $videoId + commentId = $commentId + replyId = $replyId + tagUsedId = $tagUsed.id + } + results = $results +} + +$outPath = $script:ResultPath +$out | ConvertTo-Json -Depth 8 | Set-Content -Path $outPath -Encoding utf8BOM + +$passed = ($results | Where-Object { $_.status -eq 'PASSED' }).Count +$failed = ($results | Where-Object { $_.status -eq 'FAILED' }).Count +[pscustomobject]@{ + passed = $passed + failed = $failed + file = $outPath +} | ConvertTo-Json -Compress