292 lines
20 KiB
XML
292 lines
20 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
|
||
<hashTree>
|
||
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="品牌活动-登山活动1300人并发报名" enabled="true">
|
||
<stringProp name="TestPlan.comments">每个线程使用独立用户和 Cookie 登录,登录完成后在报名接口前集合并发。仅限本地或经授权的测试环境。</stringProp>
|
||
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
||
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
|
||
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
||
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="业务参数" enabled="true">
|
||
<collectionProp name="Arguments.arguments">
|
||
<elementProp name="activityId" elementType="Argument">
|
||
<stringProp name="Argument.name">activityId</stringProp>
|
||
<stringProp name="Argument.value">${__P(activityId,11619eee67574256ad8ccc8a16630023)}</stringProp>
|
||
<stringProp name="Argument.metadata">=</stringProp>
|
||
</elementProp>
|
||
<elementProp name="courseId" elementType="Argument">
|
||
<stringProp name="Argument.name">courseId</stringProp>
|
||
<stringProp name="Argument.value">${__P(courseId,986bf4d48a5948e1810857483f9e5af2)}</stringProp>
|
||
<stringProp name="Argument.metadata">=</stringProp>
|
||
</elementProp>
|
||
<elementProp name="redisHost" elementType="Argument">
|
||
<stringProp name="Argument.name">redisHost</stringProp>
|
||
<stringProp name="Argument.value">${__P(redisHost,127.0.0.1)}</stringProp>
|
||
<stringProp name="Argument.metadata">=</stringProp>
|
||
</elementProp>
|
||
<elementProp name="redisPort" elementType="Argument">
|
||
<stringProp name="Argument.name">redisPort</stringProp>
|
||
<stringProp name="Argument.value">${__P(redisPort,6378)}</stringProp>
|
||
<stringProp name="Argument.metadata">=</stringProp>
|
||
</elementProp>
|
||
<elementProp name="testPassword" elementType="Argument">
|
||
<stringProp name="Argument.name">testPassword</stringProp>
|
||
<stringProp name="Argument.value">${__P(testPassword,LoadTestOnly@123)}</stringProp>
|
||
<stringProp name="Argument.metadata">=</stringProp>
|
||
</elementProp>
|
||
</collectionProp>
|
||
</elementProp>
|
||
</TestPlan>
|
||
<hashTree>
|
||
<CSVDataSet guiclass="TestBeanGUI" testclass="CSVDataSet" testname="读取数据库人员CSV" enabled="true">
|
||
<stringProp name="delimiter">,</stringProp>
|
||
<stringProp name="fileEncoding">UTF-8</stringProp>
|
||
<stringProp name="filename">${__P(usersFile,jmeter/data/brand-activity-users.csv)}</stringProp>
|
||
<boolProp name="ignoreFirstLine">false</boolProp>
|
||
<boolProp name="quotedData">true</boolProp>
|
||
<boolProp name="recycle">false</boolProp>
|
||
<stringProp name="shareMode">shareMode.all</stringProp>
|
||
<boolProp name="stopThread">true</boolProp>
|
||
<stringProp name="variableNames"></stringProp>
|
||
</CSVDataSet>
|
||
<hashTree/>
|
||
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="独立用户登录并并发报名" enabled="true">
|
||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
|
||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||
<stringProp name="LoopController.loops">1</stringProp>
|
||
</elementProp>
|
||
<stringProp name="ThreadGroup.num_threads">${__P(threads,10)}</stringProp>
|
||
<stringProp name="ThreadGroup.ramp_time">${__P(loginRampSeconds,30)}</stringProp>
|
||
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||
<stringProp name="ThreadGroup.duration"></stringProp>
|
||
<stringProp name="ThreadGroup.delay"></stringProp>
|
||
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||
</ThreadGroup>
|
||
<hashTree>
|
||
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP默认配置" enabled="true">
|
||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义变量" enabled="true">
|
||
<collectionProp name="Arguments.arguments"/>
|
||
</elementProp>
|
||
<stringProp name="HTTPSampler.domain">${__P(host,127.0.0.1)}</stringProp>
|
||
<stringProp name="HTTPSampler.port">${__P(port,80)}</stringProp>
|
||
<stringProp name="HTTPSampler.protocol">${__P(protocol,http)}</stringProp>
|
||
<stringProp name="HTTPSampler.connect_timeout">${__P(connectTimeout,10000)}</stringProp>
|
||
<stringProp name="HTTPSampler.response_timeout">${__P(responseTimeout,120000)}</stringProp>
|
||
<stringProp name="HTTPSampler.contentEncoding">UTF-8</stringProp>
|
||
</ConfigTestElement>
|
||
<hashTree/>
|
||
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="每线程独立Cookie" enabled="true">
|
||
<collectionProp name="CookieManager.cookies"/>
|
||
<boolProp name="CookieManager.clearEachIteration">true</boolProp>
|
||
<boolProp name="CookieManager.controlledByThreadGroup">false</boolProp>
|
||
</CookieManager>
|
||
<hashTree/>
|
||
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="请求头" enabled="true">
|
||
<collectionProp name="HeaderManager.headers">
|
||
<elementProp name="Content-Type" elementType="Header">
|
||
<stringProp name="Header.name">Content-Type</stringProp>
|
||
<stringProp name="Header.value">application/x-www-form-urlencoded;charset=UTF-8</stringProp>
|
||
</elementProp>
|
||
<elementProp name="Accept" elementType="Header">
|
||
<stringProp name="Header.name">Accept</stringProp>
|
||
<stringProp name="Header.value">application/json, text/plain, */*</stringProp>
|
||
</elementProp>
|
||
</collectionProp>
|
||
</HeaderManager>
|
||
<hashTree/>
|
||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="01-获取图形验证码" enabled="true">
|
||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="请求参数" enabled="true">
|
||
<collectionProp name="Arguments.arguments"/>
|
||
</elementProp>
|
||
<stringProp name="HTTPSampler.path">/platform/login/captcha</stringProp>
|
||
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
|
||
</HTTPSamplerProxy>
|
||
<hashTree>
|
||
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="提取验证码Key" enabled="true">
|
||
<stringProp name="JSONPostProcessor.referenceNames">captchaKey</stringProp>
|
||
<stringProp name="JSONPostProcessor.jsonPathExprs">$.data.key</stringProp>
|
||
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
|
||
<stringProp name="JSONPostProcessor.defaultValues">NOT_FOUND</stringProp>
|
||
</JSONPostProcessor>
|
||
<hashTree/>
|
||
</hashTree>
|
||
<JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="02-从本地Redis读取压测验证码" enabled="true">
|
||
<stringProp name="cacheKey">true</stringProp>
|
||
<stringProp name="filename"></stringProp>
|
||
<stringProp name="parameters"></stringProp>
|
||
<stringProp name="scriptLanguage">groovy</stringProp>
|
||
<stringProp name="script"><![CDATA[
|
||
def captchaKey = vars.get('captchaKey')
|
||
if (!captchaKey || captchaKey == 'NOT_FOUND') {
|
||
throw new IllegalStateException('获取验证码Key失败')
|
||
}
|
||
def redisKey = 'budwk5mini:ucenter:captcha:' + captchaKey
|
||
def socket = new Socket(vars.get('redisHost'), vars.get('redisPort') as int)
|
||
socket.soTimeout = 3000
|
||
try {
|
||
def keyBytes = redisKey.getBytes('UTF-8')
|
||
def command = '*2\r\n$3\r\nGET\r\n$' + keyBytes.length + '\r\n' + redisKey + '\r\n'
|
||
socket.outputStream.write(command.getBytes('UTF-8'))
|
||
socket.outputStream.flush()
|
||
def reader = new BufferedReader(new InputStreamReader(socket.inputStream, 'UTF-8'))
|
||
def header = reader.readLine()
|
||
if (!header || !header.startsWith('$') || header == '$-1') {
|
||
throw new IllegalStateException('Redis中未找到验证码:' + redisKey)
|
||
}
|
||
def captchaCode = reader.readLine()
|
||
if (!captchaCode) {
|
||
throw new IllegalStateException('验证码内容为空')
|
||
}
|
||
vars.put('captchaCode', captchaCode)
|
||
} finally {
|
||
socket.close()
|
||
}
|
||
]]></stringProp>
|
||
</JSR223Sampler>
|
||
<hashTree/>
|
||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="03-获取登录RSA公钥" enabled="true">
|
||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="请求参数" enabled="true">
|
||
<collectionProp name="Arguments.arguments"/>
|
||
</elementProp>
|
||
<stringProp name="HTTPSampler.path">/platform/login/publicKey</stringProp>
|
||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||
</HTTPSamplerProxy>
|
||
<hashTree>
|
||
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="提取公钥和KeyId" enabled="true">
|
||
<stringProp name="JSONPostProcessor.referenceNames">publicKey;keyId</stringProp>
|
||
<stringProp name="JSONPostProcessor.jsonPathExprs">$.data.publicKey;$.data.keyId</stringProp>
|
||
<stringProp name="JSONPostProcessor.match_numbers">1;1</stringProp>
|
||
<stringProp name="JSONPostProcessor.defaultValues">NOT_FOUND;NOT_FOUND</stringProp>
|
||
</JSONPostProcessor>
|
||
<hashTree/>
|
||
</hashTree>
|
||
<JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="04-RSA加密测试密码" enabled="true">
|
||
<stringProp name="cacheKey">true</stringProp>
|
||
<stringProp name="filename"></stringProp>
|
||
<stringProp name="parameters"></stringProp>
|
||
<stringProp name="scriptLanguage">groovy</stringProp>
|
||
<stringProp name="script"><![CDATA[
|
||
import java.security.KeyFactory
|
||
import java.security.spec.X509EncodedKeySpec
|
||
import javax.crypto.Cipher
|
||
|
||
def publicKeyText = vars.get('publicKey')
|
||
if (!publicKeyText || publicKeyText == 'NOT_FOUND') {
|
||
throw new IllegalStateException('获取RSA公钥失败')
|
||
}
|
||
def keyBytes = Base64.decoder.decode(publicKeyText)
|
||
def publicKey = KeyFactory.getInstance('RSA').generatePublic(new X509EncodedKeySpec(keyBytes))
|
||
def cipher = Cipher.getInstance('RSA/ECB/PKCS1Padding')
|
||
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
|
||
def encrypted = cipher.doFinal(vars.get('testPassword').getBytes('UTF-8'))
|
||
vars.put('encryptedPassword', Base64.encoder.encodeToString(encrypted))
|
||
]]></stringProp>
|
||
</JSR223Sampler>
|
||
<hashTree/>
|
||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="05-人员账号登录" enabled="true">
|
||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="登录参数" enabled="true">
|
||
<collectionProp name="Arguments.arguments">
|
||
<elementProp name="username" elementType="HTTPArgument">
|
||
<boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">username</stringProp><stringProp name="Argument.value">${loginname}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp>
|
||
</elementProp>
|
||
<elementProp name="password" elementType="HTTPArgument">
|
||
<boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">password</stringProp><stringProp name="Argument.value">${encryptedPassword}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp>
|
||
</elementProp>
|
||
<elementProp name="platformKey" elementType="HTTPArgument">
|
||
<boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">platformKey</stringProp><stringProp name="Argument.value">${captchaKey}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp>
|
||
</elementProp>
|
||
<elementProp name="platformCaptcha" elementType="HTTPArgument">
|
||
<boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">platformCaptcha</stringProp><stringProp name="Argument.value">${captchaCode}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp>
|
||
</elementProp>
|
||
<elementProp name="keyId" elementType="HTTPArgument">
|
||
<boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">keyId</stringProp><stringProp name="Argument.value">${keyId}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp>
|
||
</elementProp>
|
||
</collectionProp>
|
||
</elementProp>
|
||
<stringProp name="HTTPSampler.path">/platform/login/doLogin</stringProp>
|
||
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
|
||
</HTTPSamplerProxy>
|
||
<hashTree>
|
||
<JSR223PostProcessor guiclass="TestBeanGUI" testclass="JSR223PostProcessor" testname="断言登录成功" enabled="true">
|
||
<stringProp name="scriptLanguage">groovy</stringProp>
|
||
<stringProp name="script"><![CDATA[
|
||
import groovy.json.JsonSlurper
|
||
try {
|
||
def json = new JsonSlurper().parseText(prev.getResponseDataAsString())
|
||
if (json.code != 0) {
|
||
prev.setSuccessful(false)
|
||
prev.setResponseMessage('登录失败:' + json.msg)
|
||
}
|
||
} catch (Exception e) {
|
||
prev.setSuccessful(false)
|
||
prev.setResponseMessage('登录响应不是有效JSON:' + e.message)
|
||
}
|
||
]]></stringProp>
|
||
</JSR223PostProcessor>
|
||
<hashTree/>
|
||
</hashTree>
|
||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="06-报名资格预校验" enabled="true">
|
||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="校验参数" enabled="true">
|
||
<collectionProp name="Arguments.arguments">
|
||
<elementProp name="courseId" elementType="HTTPArgument"><boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">courseId</stringProp><stringProp name="Argument.value">${courseId}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp></elementProp>
|
||
<elementProp name="currentFamilyNumber" elementType="HTTPArgument"><boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">currentFamilyNumber</stringProp><stringProp name="Argument.value">0</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp></elementProp>
|
||
</collectionProp>
|
||
</elementProp>
|
||
<stringProp name="HTTPSampler.path">/platform/trainSignUp/apply/validateSignUp</stringProp>
|
||
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
|
||
</HTTPSamplerProxy>
|
||
<hashTree/>
|
||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="07-集合后并发提交登山活动报名" enabled="true">
|
||
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="报名参数" enabled="true">
|
||
<collectionProp name="Arguments.arguments">
|
||
<elementProp name="activityId" elementType="HTTPArgument"><boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">activityId</stringProp><stringProp name="Argument.value">${activityId}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp></elementProp>
|
||
<elementProp name="courseId" elementType="HTTPArgument"><boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">courseId</stringProp><stringProp name="Argument.value">${courseId}</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp></elementProp>
|
||
<elementProp name="mobileColumnsValue" elementType="HTTPArgument"><boolProp name="HTTPArgument.always_encode">true</boolProp><stringProp name="Argument.name">mobileColumnsValue</stringProp><stringProp name="Argument.value">[]</stringProp><stringProp name="Argument.metadata">=</stringProp><boolProp name="HTTPArgument.use_equals">true</boolProp></elementProp>
|
||
</collectionProp>
|
||
</elementProp>
|
||
<stringProp name="HTTPSampler.path">/platform/trainSignUp/apply/doSignUp</stringProp>
|
||
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
|
||
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
|
||
</HTTPSamplerProxy>
|
||
<hashTree>
|
||
<SyncTimer guiclass="TestBeanGUI" testclass="SyncTimer" testname="等待本线程组全部人员后同时报名" enabled="true">
|
||
<intProp name="groupSize">0</intProp>
|
||
<stringProp name="timeoutInMs">${__P(syncTimeoutMs,180000)}</stringProp>
|
||
</SyncTimer>
|
||
<hashTree/>
|
||
<JSR223PostProcessor guiclass="TestBeanGUI" testclass="JSR223PostProcessor" testname="断言报名成功" enabled="true">
|
||
<stringProp name="scriptLanguage">groovy</stringProp>
|
||
<stringProp name="script"><![CDATA[
|
||
import groovy.json.JsonSlurper
|
||
try {
|
||
def json = new JsonSlurper().parseText(prev.getResponseDataAsString())
|
||
if (json.code != 0 || json.msg != '报名成功') {
|
||
prev.setSuccessful(false)
|
||
prev.setResponseMessage('报名未成功;expectedAuthorized=' + vars.get('expectedAuthorized') + ';返回:' + json.msg)
|
||
}
|
||
} catch (Exception e) {
|
||
prev.setSuccessful(false)
|
||
prev.setResponseMessage('报名响应不是有效JSON;expectedAuthorized=' + vars.get('expectedAuthorized') + ';' + e.message)
|
||
}
|
||
]]></stringProp>
|
||
</JSR223PostProcessor>
|
||
<hashTree/>
|
||
</hashTree>
|
||
</hashTree>
|
||
</hashTree>
|
||
</hashTree>
|
||
</jmeterTestPlan>
|