242 lines
6.8 KiB
JavaScript
242 lines
6.8 KiB
JavaScript
/**
|
||
* 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(`========================================`);
|
||
}
|