/** * k6 压测脚本 - 场景二:活跃用户互动 * * 模拟用户行为: * 1. 浏览帖子列表 * 2. 查看帖子详情 * 3. 点赞帖子 * 4. 发表评论 * 5. 评论点赞 * 6. 送花(注意:同一目标1小时只能送一次) * * 运行命令: * k6 run --out web-dashboard scenario-active.js * * 快速测试: * k6 run --out web-dashboard -e QUICK_TEST=true scenario-active.js */ import { ACTIVE_OPTIONS, QUICK_TEST_OPTIONS, TEST_DATA } from './config.js'; import { httpGet, httpPost, checkResponse, parseResponse, thinkTime, shortWait, randomComment, randomInt, getTokenCount, API } from './utils/helpers.js'; // ============================================ // 压测配置 // ============================================ const isQuickTest = __ENV.QUICK_TEST === 'true'; export const options = isQuickTest ? QUICK_TEST_OPTIONS : ACTIVE_OPTIONS; // ============================================ // 初始化阶段 // ============================================ export function setup() { const tokenCount = getTokenCount(); console.log(`========================================`); console.log(`场景:活跃用户互动(读写混合)`); console.log(`Token 数量:${tokenCount}`); console.log(`模式:${isQuickTest ? '快速测试' : '正式压测'}`); console.log(`注意:写操作可能产生并发冲突,错误率会略高`); console.log(`========================================`); if (tokenCount === 0) { throw new Error('没有可用的 Token,请先在 tokens.txt 中添加 Token'); } return { tokenCount }; } // ============================================ // 主测试函数 // ============================================ export default function(data) { const vuId = __VU; const iteration = __ITER; // 存储动态数据 let postIds = []; let commentIds = []; let currentPostId = null; // ================== // 步骤1: 获取帖子列表 // ================== let res = httpGet(API.POSTS.LIST, { SortType: 1, PageIndex: 1, PageSize: TEST_DATA.pageSize, }, vuId); checkResponse(res, 'GetPosts'); // 解析帖子列表 const postsData = parseResponse(res); if (postsData && postsData.items && postsData.items.length > 0) { postIds = postsData.items.map(item => item.postId); } if (postIds.length === 0) { console.log(`VU ${vuId}: 没有获取到帖子,跳过本次迭代`); thinkTime(); return; } thinkTime(); // ================== // 步骤2: 查看帖子详情 // ================== // 选择一个帖子(基于VU和迭代次数,分散请求) const postIndex = (vuId + iteration) % postIds.length; currentPostId = postIds[postIndex]; res = httpGet(API.POSTS.DETAIL, { PostId: currentPostId, }, vuId); checkResponse(res, 'GetPostDetail'); shortWait(); // 获取评论列表 res = httpGet(API.COMMENTS.LIST, { PostId: currentPostId, SortType: 2, PageIndex: 1, PageSize: TEST_DATA.commentPageSize, }, vuId); checkResponse(res, 'GetPostComments'); // 解析评论列表 const commentsData = parseResponse(res); if (commentsData && commentsData.items && commentsData.items.length > 0) { commentIds = commentsData.items.map(item => item.commentId); } thinkTime(); // ================== // 步骤3: 点赞帖子 // ================== // 随机决定是点赞还是取消点赞(模拟真实用户行为) const likeAction = Math.random() > 0.3 ? 1 : 2; // 70%点赞,30%取消 res = httpPost(API.POSTS.LIKE, { postId: currentPostId, action: likeAction, }, vuId); checkResponse(res, 'LikePost'); shortWait(); // ================== // 步骤4: 发表评论 // ================== // 每隔几次迭代发表一次评论(避免评论过多) if (iteration % 3 === 0) { res = httpPost(API.COMMENTS.PUBLISH, { postId: currentPostId, content: randomComment(), parentCommentId: '', replyToUserId: '', }, vuId); checkResponse(res, 'PublishComment'); shortWait(); } // ================== // 步骤5: 评论点赞 // ================== if (commentIds.length > 0) { // 随机选择一个评论点赞 const commentIndex = randomInt(0, commentIds.length - 1); const commentId = commentIds[commentIndex]; const commentLikeAction = Math.random() > 0.3 ? 1 : 2; res = httpPost(API.COMMENTS.LIKE, { commentId: commentId, action: commentLikeAction, }, vuId); checkResponse(res, 'LikeComment'); shortWait(); } // ================== // 步骤6: 送花 // ================== // 送花有时间限制(同一目标1小时只能送一次) // 压测时会产生大量"请等待"的错误响应,这是正常的 // 每隔多次迭代尝试送一次花 if (iteration % 5 === 0) { // 给帖子送花 res = httpPost(API.FLOWERS.SEND, { targetId: currentPostId, targetType: 'Post', }, vuId); // 送花可能因为时间限制失败,不强制检查成功 checkResponse(res, 'SendFlower-Post'); shortWait(); } // ================== // 步骤7: 继续浏览(混合读操作) // ================== // 翻页获取更多帖子 res = httpGet(API.POSTS.LIST, { SortType: 1, PageIndex: 2, PageSize: TEST_DATA.pageSize, }, vuId); checkResponse(res, 'GetPosts-Page2'); thinkTime(); // 查看另一个帖子 if (postIds.length > 1) { const anotherIndex = (postIndex + 1) % postIds.length; const anotherPostId = postIds[anotherIndex]; res = httpGet(API.POSTS.DETAIL, { PostId: anotherPostId, }, vuId); checkResponse(res, 'GetPostDetail-Another'); // 也给这个帖子点赞 res = httpPost(API.POSTS.LIKE, { postId: anotherPostId, action: 1, }, vuId); checkResponse(res, 'LikePost-Another'); } thinkTime(); } // ============================================ // 结束阶段 // ============================================ export function teardown(data) { console.log(`========================================`); console.log(`压测结束`); console.log(`注意:送花接口的失败可能是时间限制导致的,属于正常业务逻辑`); console.log(`========================================`); }