- Remove old review reports (keep latest only) - Move docs/ to deploy/docs-backup/ - Move performance-testing/ to deploy/ - Clean up test output files - Organize root directory
236 lines
5.4 KiB
JavaScript
236 lines
5.4 KiB
JavaScript
// Sub2API Test Scenarios Configuration
|
||
// 测试场景配置
|
||
|
||
// ============= 场景定义 =============
|
||
|
||
export const scenarios = {
|
||
// 基线测试场景
|
||
baseline: {
|
||
executor: 'ramping-vus',
|
||
startVUs: 10,
|
||
stages: [
|
||
{ duration: '2m', target: 10 }, // 预热
|
||
{ duration: '3m', target: 50 }, // 正常负载
|
||
{ duration: '1m', target: 0 }, // 冷却
|
||
],
|
||
tags: { test_type: 'baseline' },
|
||
},
|
||
|
||
// 负载测试场景
|
||
load: {
|
||
executor: 'ramping-vus',
|
||
startVUs: 20,
|
||
stages: [
|
||
{ duration: '2m', target: 20 }, // 预热
|
||
{ duration: '2m', target: 100 }, // 正常负载
|
||
{ duration: '2m', target: 200 }, // 峰值负载
|
||
{ duration: '2m', target: 200 }, // 持续峰值
|
||
{ duration: '2m', target: 0 }, // 冷却
|
||
],
|
||
tags: { test_type: 'load' },
|
||
},
|
||
|
||
// 压力测试场景
|
||
stress: {
|
||
executor: 'ramping-vus',
|
||
startVUs: 50,
|
||
stages: [
|
||
{ duration: '1m', target: 50 }, // 预热
|
||
{ duration: '2m', target: 200 }, // 正常负载
|
||
{ duration: '2m', target: 500 }, // 高负载
|
||
{ duration: '3m', target: 1000 }, // 极限负载
|
||
{ duration: '2m', target: 0 }, // 冷却
|
||
],
|
||
tags: { test_type: 'stress' },
|
||
},
|
||
|
||
// 浸泡测试场景
|
||
soak: {
|
||
executor: 'constant-vus',
|
||
vus: 100,
|
||
duration: '8h',
|
||
tags: { test_type: 'soak' },
|
||
},
|
||
|
||
// 尖峰测试场景
|
||
spike: {
|
||
executor: 'ramping-vus',
|
||
startVUs: 50,
|
||
stages: [
|
||
{ duration: '30s', target: 50 }, // 基线
|
||
{ duration: '1m', target: 1000 }, // 尖峰
|
||
{ duration: '1m', target: 1000 }, // 保持尖峰
|
||
{ duration: '30s', target: 50 }, // 恢复
|
||
{ duration: '2m', target: 0 }, // 冷却
|
||
],
|
||
tags: { test_type: 'spike' },
|
||
},
|
||
|
||
// Gateway 专用测试场景
|
||
gatewayLoad: {
|
||
executor: 'ramping-vus',
|
||
startVUs: 10,
|
||
stages: [
|
||
{ duration: '2m', target: 10 }, // 预热
|
||
{ duration: '5m', target: 100 }, // 正常负载
|
||
{ duration: '3m', target: 200 }, // 峰值负载
|
||
{ duration: '2m', target: 0 }, // 冷却
|
||
],
|
||
tags: { test_type: 'gateway_load' },
|
||
},
|
||
};
|
||
|
||
// ============= 场景权重 =============
|
||
|
||
// 混合场景中各接口的权重分布
|
||
export const scenarioWeights = {
|
||
// 典型用户行为分布
|
||
typicalUser: {
|
||
healthCheck: 0.20, // 健康检查(高频)
|
||
auth: 0.10, // 认证
|
||
apiKeys: 0.25, // API Key 管理
|
||
gateway: 0.40, // Gateway API(核心业务)
|
||
admin: 0.05, // 管理接口
|
||
},
|
||
|
||
// 高负载场景
|
||
highLoad: {
|
||
healthCheck: 0.10,
|
||
auth: 0.05,
|
||
apiKeys: 0.15,
|
||
gateway: 0.65, // Gateway 占比更高
|
||
admin: 0.05,
|
||
},
|
||
|
||
// 管理员场景
|
||
adminHeavy: {
|
||
healthCheck: 0.05,
|
||
auth: 0.15,
|
||
apiKeys: 0.30,
|
||
gateway: 0.30,
|
||
admin: 0.20,
|
||
},
|
||
};
|
||
|
||
// ============= 用户行为模拟 =============
|
||
|
||
export const userBehaviors = {
|
||
// 轻度用户
|
||
light: {
|
||
thinkTime: { min: 1, max: 5 }, // 秒
|
||
requestsPerSession: 10,
|
||
gatewayRequests: 3,
|
||
},
|
||
|
||
// 中度用户
|
||
medium: {
|
||
thinkTime: { min: 0.5, max: 3 },
|
||
requestsPerSession: 25,
|
||
gatewayRequests: 15,
|
||
},
|
||
|
||
// 重度用户
|
||
heavy: {
|
||
thinkTime: { min: 0.1, max: 1 },
|
||
requestsPerSession: 50,
|
||
gatewayRequests: 40,
|
||
},
|
||
};
|
||
|
||
// ============= Gateway 请求模板 =============
|
||
|
||
export const gatewayRequestTemplates = {
|
||
// OpenAI Chat Completion
|
||
openaiChat: {
|
||
method: 'POST',
|
||
path: '/v1/chat/completions',
|
||
body: {
|
||
model: 'gpt-3.5-turbo',
|
||
messages: [
|
||
{ role: 'system', content: 'You are a helpful assistant.' },
|
||
{ role: 'user', content: 'Hello, how are you?' }
|
||
],
|
||
max_tokens: 100,
|
||
temperature: 0.7,
|
||
},
|
||
},
|
||
|
||
// OpenAI Streaming
|
||
openaiStream: {
|
||
method: 'POST',
|
||
path: '/v1/chat/completions',
|
||
body: {
|
||
model: 'gpt-3.5-turbo',
|
||
messages: [
|
||
{ role: 'user', content: 'Write a short story about a robot.' }
|
||
],
|
||
max_tokens: 500,
|
||
stream: true,
|
||
},
|
||
},
|
||
|
||
// Claude Messages (Anthropic)
|
||
claudeMessages: {
|
||
method: 'POST',
|
||
path: '/v1/messages',
|
||
body: {
|
||
model: 'claude-3-5-haiku-20241022',
|
||
max_tokens: 100,
|
||
messages: [
|
||
{ role: 'user', content: 'Hello, how are you?' }
|
||
],
|
||
},
|
||
},
|
||
|
||
// Gemini Generate Content
|
||
geminiGenerate: {
|
||
method: 'POST',
|
||
path: '/v1beta/models/gemini-pro:generateContent',
|
||
body: {
|
||
contents: [
|
||
{
|
||
parts: [{ text: 'Hello, how are you?' }]
|
||
}
|
||
],
|
||
generationConfig: {
|
||
maxOutputTokens: 100,
|
||
},
|
||
},
|
||
},
|
||
};
|
||
|
||
// ============= 导出便捷函数 =============
|
||
|
||
/**
|
||
* 根据权重随机选择场景
|
||
*/
|
||
export function selectScenarioByWeight(scenarios) {
|
||
const entries = Object.entries(scenarios);
|
||
const totalWeight = entries.reduce((sum, [, weight]) => sum + weight, 0);
|
||
let random = Math.random() * totalWeight;
|
||
|
||
for (const [scenario, weight] of entries) {
|
||
random -= weight;
|
||
if (random <= 0) {
|
||
return scenario;
|
||
}
|
||
}
|
||
|
||
return entries[0][0];
|
||
}
|
||
|
||
/**
|
||
* 生成随机思考时间
|
||
*/
|
||
export function randomThinkTime(behavior) {
|
||
const { min, max } = userBehaviors[behavior]?.thinkTime || userBehaviors.medium.thinkTime;
|
||
return min + Math.random() * (max - min);
|
||
}
|
||
|
||
/**
|
||
* 获取指定类型的场景配置
|
||
*/
|
||
export function getScenario(name) {
|
||
return scenarios[name] || scenarios.baseline;
|
||
}
|