live-forum/server/k6/scenario-active.js
2026-03-24 11:27:37 +08:00

242 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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(`========================================`);
}