This commit is contained in:
fit2-zhao 2021-01-06 18:27:10 +08:00
commit d1c179fc5c
14 changed files with 626 additions and 321 deletions

412
README.md
View File

@ -80,199 +80,225 @@ v1.1.0 是 v1.0.0 之后的功能版本。
## 功能列表
<table>
<tbody>
<tr>
<td rowspan="17">测试跟踪</td>
<td>项目管理</td>
<td>多项目支持,测试用例、测试计划与项目关联</td>
</tr>
<tr>
<td rowspan="4">测试用例管理</td>
<td>在线编辑用例</td>
</tr>
<tr>
<td>以树状形式展示项目的模块及其用例</td>
</tr>
<tr>
<td>自定义用例属性</td>
</tr>
<tr>
<td>快速导入用例到系统</td>
</tr>
<tr>
<td rowspan="4">测试用例评审</td>
<td>基于已有用例发起评审</td>
</tr>
<tr>
<td>在线更新评审结果</td>
</tr>
<tr>
<td>支持多人在线添加评审评论</td>
</tr>
<tr>
<td>灵活的评审人分配形式</td>
</tr>
<tr>
<td rowspan="8">测试计划跟踪</td>
<td>基于已有用例发起测试计划</td>
</tr>
<tr>
<td>在线更新用例执行结果</td>
</tr>
<tr>
<td>灵活的用例分配方式</td>
</tr>
<tr>
<td>在线生成测试报告,支持自定义测试报告模板</td>
</tr>
<tr>
<td>与平台中的接口测试、性能测试功能结合,自动更新关联用例的结果</td>
</tr>
<tr>
<td>记录测试用例关联的缺陷</td>
</tr>
<tr>
<td>缺陷记录支持关联到 Jira/TAPD 平台</td>
</tr>
<tr>
<td>测试报告支持分享、导出</td>
</tr>
<tr>
<td rowspan="19">接口测试</td>
<td rowspan="12">测试脚本</td>
<td>在线编辑接口测试内容</td>
</tr>
<tr>
<td>支持参数化测试</td>
</tr>
<tr>
<td>灵活多样的断言支持</td>
</tr>
<tr>
<td>支持多接口的场景化测试</td>
</tr>
<tr>
<td>测试场景复用</td>
</tr>
<tr>
<td>测试场景支持引用已有环境信息</td>
</tr>
<tr>
<td>测试环境信息管理</td>
</tr>
<tr>
<td>通过浏览器插件快速录制测试脚本</td>
</tr>
<tr>
<td>支持前后置 BeanShell/Python 脚本</td>
</tr>
<tr>
<td>上传并引用自定义 Jar 包</td>
</tr>
<tr>
<td>多协议支持,支持 HTTP、Dubbo、SQL、TCP 类型请求</td>
</tr>
<tr>
<td>支持等待时间、条件判断等逻辑控制功能</td>
</tr>
<tr>
<td rowspan="4">测试执行</td>
<td>内置定时任务支持</td>
</tr>
<tr>
<td>通过 Jenkins 插件触发测试执行</td>
</tr>
<tr>
<td>多个接口测试一键合并执行</td>
</tr>
<tr>
<td>一键创建性能测试</td>
</tr>
<tr>
<td rowspan="3">测试报告</td>
<td>测试执行后自动生成动态实时测试报告</td>
</tr>
<tr>
<td>测试报告导出</td>
</tr>
<tr>
<td>通过邮件、IM 工具等通知执行结果</td>
</tr>
<tr>
<td rowspan="12">性能测试</td>
<td rowspan="6">测试脚本</td>
<td>完全兼容&nbsp;JMeter&nbsp;脚本</td>
</tr>
<tr>
<td>在线调整压力参数</td>
</tr>
<tr>
<td>分布式压力测试</td>
</tr>
<tr>
<td>支持参数化测试</td>
</tr>
<tr>
<td>通过浏览器插件快速录制测试脚本</td>
</tr>
<tr>
<td>多协议支持</td>
</tr>
<tr>
<td rowspan="2">测试执行</td>
<td>内置定时任务支持</td>
</tr>
<tr>
<td>通过 Jenkins 插件触发测试执行</td>
</tr>
<tr>
<td rowspan="4">测试报告</td>
<td>测试执行后自动生成测试报告</td>
</tr>
<tr>
<td>丰富的测试报告展现形式</td>
</tr>
<tr>
<td>测试报告导出</td>
</tr>
<tr>
<td>查看测试日志详情</td>
</tr>
<tr>
<td rowspan="9">系统管理</td>
<td rowspan="3">用户租户管理</td>
<td>支持多级租户体系</td>
</tr>
<tr>
<td>支持多种租户角色</td>
</tr>
<tr>
<td>LDAP 认证对接</td>
</tr>
<tr>
<td>测试资源管理</td>
<td>性能测试资源池管理</td>
</tr>
<tr>
<td rowspan="2">消息通知配置</td>
<td>IM 工具通知(如企业微信、钉钉)</td>
</tr>
<tr>
<td>邮件通知配置</td>
</tr>
<tr>
<td rowspan="3">集成与扩展</td>
<td>完善的&nbsp;API&nbsp;列表</td>
</tr>
<tr>
<td>支持对接&nbsp;Jenkins&nbsp;等持续集成工具</td>
</tr>
<tr>
<td>支持对接 Jira/TAPD 等缺陷管理工具</td>
</tr>
</tbody>
</table>
</head>
<body link="blue" vlink="purple" class="xl65">
<table width="505.15" border="0" cellpadding="0" cellspacing="0" style='width:505.15pt;border-collapse:collapse;table-layout:fixed;'>
<col width="73" class="xl65" style='mso-width-source:userset;mso-width-alt:3114;'/>
<col width="95.55" class="xl65" style='mso-width-source:userset;mso-width-alt:4076;'/>
<col width="336.60" class="xl65" style='mso-width-source:userset;mso-width-alt:14361;'/>
<col width="91.55" span="253" class="xl65" style='mso-width-source:userset;mso-width-alt:3906;'/>
<tr height="22.55" style='height:22.55pt;mso-height-source:userset;mso-height-alt:451;'>
<td class="xl68" height="424.85" width="73" rowspan="19" style='height:424.85pt;width:73.00pt;border-right:.5pt solid #3F3F3F;border-bottom:.5pt solid #A5A5A5;' x:str>测试跟踪</td>
<td class="xl76" width="95.55" rowspan="8" style='width:95.55pt;border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>测试用例管理</td>
<td class="xl70" width="336.60" style='width:336.60pt;' x:str>在线编辑用例</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl77" x:str>编辑窗口支持上传附件</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>查看与编辑窗口显示评审评论</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>以树状形式展示项目的模块及其用例</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持测试用例模块树拖拽排序</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>自定义用例等级/用例类型/测试方式</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持Excel/Xmind格式快速导入用例到系统</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持Excel格式快速导出用例到本地</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="4" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>测试用例评审</td>
<td class="xl73" x:str>基于已有用例发起评审</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持添加多个评审人</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>在线更新评审结果</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持多人在线添加评审评论</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="7" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>测试计划跟踪</td>
<td class="xl73" x:str>基于已有用例发起测试计划</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持在线更新用例执行结果</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>在线生成测试报告,支持自定义测试报告模板</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>与平台中的接口测试、性能测试功能联动,自动更新关联用例的结果</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>记录测试用例关联的缺陷</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>缺陷记录支持关联到 Jira/TAPD</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持PDF格式测试报告导出</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl75" height="603.45" rowspan="27" style='height:603.45pt;border-right:.5pt solid #3F3F3F;border-bottom:.5pt solid #A5A5A5;' x:str>接口测试</td>
<td class="xl72" rowspan="13" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>接口定义</td>
<td class="xl73" x:str>在线编辑接口测试内容</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持 HTTP/Dubbo/SQL/TCP 类型接口请求</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持接口快捷调制</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持接口列表和用例列表切换显示</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持用例编辑窗口正则/jsonpath/Xpath等多种类型的断言规则</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持用例编辑窗口正则/jsonpath/Xpath类型的参数提取</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持用例编辑窗口前后置 BeanShell/Python 脚本</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>测试环境信息管理</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持单接口测试引用环境信息</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持通过浏览器插件快速录制测试脚本</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持Metersphere json/Postman/Swagger格式快速导入用例到系统</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持Metersphere json格式快速导出用例到本地</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持上传并引用自定义 Jar 包</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="12" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>接口自动化</td>
<td class="xl73" x:str>创建多接口的场景化测试</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持自定义场景标签</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持多层级场景嵌套结构</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持接口列表快速导入测试场景</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持测试场景复用</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持添加自定义请求/自定义脚本</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持添加等待时间/条件判断等多类型逻辑控制器</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>场景调试支持引用已有环境信息</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持定时任务</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持通过 Jenkins 插件触发测试执行</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>Jenkins 插件支持 Pipeline 方式调用</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持一键创建性能测试</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="2" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>测试报告</td>
<td class="xl73" x:str>测试执行后自动生成测试报告</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持PDF格式测试报告导出</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl75" height="178.80" rowspan="8" style='height:178.80pt;border-right:.5pt solid #3F3F3F;border-bottom:.5pt solid #A5A5A5;' x:str>性能测试</td>
<td class="xl72" rowspan="4" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>性能测试脚本</td>
<td class="xl73" x:str>支持上传JMX/CSV/JAR格式文件创建性能测试</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持分线程组配置压力参数</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持下载 JTL 文件</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持通过浏览器插件快速录制测试脚本</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="2" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>测试执行</td>
<td class="xl73" x:str>内置定时任务支持</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持通过 Jenkins 插件触发测试执行</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="2" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>测试报告</td>
<td class="xl73" x:str>测试执行后自动生成动态实时测试报告</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持PDF格式测试报告导出</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl75" height="223.50" rowspan="10" style='height:223.50pt;border-right:.5pt solid #3F3F3F;border-bottom:.5pt solid #A5A5A5;' x:str>系统管理</td>
<td class="xl72" rowspan="3" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>用户租户管理</td>
<td class="xl73" x:str>支持多级租户体系</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持多种租户角色</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持LDAP 认证对接</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" x:str>测试资源管理</td>
<td class="xl73" x:str>性能测试资源池管理</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="2" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>消息通知配置</td>
<td class="xl73" x:str>支持企业微信/钉钉等多种IM 工具通知配置</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持邮件通知配置</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" rowspan="3" style='border-right:.5pt solid #A5A5A5;border-bottom:.5pt solid #A5A5A5;' x:str>集成与扩展</td>
<td class="xl73" x:str>配置API 列表</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持对接 Jenkins 等持续集成工具</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl73" x:str>支持对接 Jira/TAPD 等缺陷管理工具</td>
</tr>
<tr height="22.35" style='height:22.35pt;mso-height-source:userset;mso-height-alt:447;'>
<td class="xl72" x:str>项目管理</td>
<td class="xl73" x:str>多项目支持,测试用例、测试计划与项目关联</td>
</tr>
</table>
</body>
详细的版本规划请参考 [版本路线图](https://github.com/metersphere/metersphere/blob/master/ROADMAP.md)

View File

@ -65,10 +65,12 @@ public abstract class ApiImportAbstractParser implements ApiImportParser {
protected ApiModule getSelectModule(String moduleId) {
apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
if (StringUtils.isNotBlank(moduleId)) {
if (StringUtils.isNotBlank(moduleId) && !StringUtils.equals("root", moduleId)) {
ApiModule module = new ApiModule();
ApiModuleDTO moduleDTO = apiModuleService.getNode(moduleId);
BeanUtils.copyBean(module, moduleDTO);
if (moduleDTO != null) {
BeanUtils.copyBean(module, moduleDTO);
}
return module;
}
return null;

View File

@ -6,7 +6,6 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.ApiModuleDTO;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.Body;
@ -15,10 +14,13 @@ import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
public class MsParser extends ApiImportAbstractParser {
@ -77,9 +79,9 @@ public class MsParser extends ApiImportAbstractParser {
ApiDefinitionResult apiDefinition = buildApiDefinition(request.getId(), requestName, path, method);
apiDefinition.setModuleId(module.getId());
apiDefinition.setProjectId(this.projectId);
parseBody(requestObject, request.getBody());
parseHeader(requestObject, request.getHeaders());
parsePath(request, apiDefinition);
apiDefinition.setRequest(JSONObject.toJSONString(request));
results.add(apiDefinition);
});
@ -87,6 +89,36 @@ public class MsParser extends ApiImportAbstractParser {
return apiImport;
}
private void parsePath(MsHTTPSamplerProxy request, ApiDefinitionResult apiDefinition) {
if (StringUtils.isNotBlank(request.getPath())) {
String[] split = request.getPath().split("\\?");
String path = split[0];
parseQueryParameters(split, request.getArguments());
request.setPath(path);
apiDefinition.setPath(path);
} else {
request.setPath("/");
apiDefinition.setPath("/");
}
apiDefinition.setName(apiDefinition.getPath() + " [" + apiDefinition.getMethod() + "]");
}
private void parseQueryParameters(String[] split, List<KeyValue> arguments) {
if (split.length > 1) {
try {
String queryParams = split[1];
queryParams = URLDecoder.decode(queryParams, "UTF-8");
String[] params = queryParams.split("&");
for (String param : params) {
String[] kv = param.split("=");
arguments.add(new KeyValue(kv[0], kv[1]));
}
} catch (UnsupportedEncodingException e) {
LogUtil.info(e.getMessage(), e);
return;
}
}
}
private void parseHeader(JSONObject requestObject, List<KeyValue> msHeaders) {
JSONArray headers = requestObject.getJSONArray("headers");
if (CollectionUtils.isNotEmpty(headers)) {

View File

@ -61,6 +61,16 @@ public class PostmanParser extends ApiImportAbstractParser {
MsHTTPSamplerProxy request = buildRequest(requestItem.getName(), url.getRaw(), requestDesc.getMethod());
ApiDefinitionResult apiDefinition =
buildApiDefinition(request.getId(), requestItem.getName(), url.getRaw(), requestDesc.getMethod());
if (StringUtils.isNotBlank(request.getPath())) {
String path = request.getPath().split("\\?")[0];
path = path.replace("{{", "${");
path = path.replace("}}", "}");
request.setPath(path);
apiDefinition.setPath(path);
} else {
request.setPath("/");
apiDefinition.setPath("/");
}
parseBody(request.getBody(), requestDesc);
request.setArguments(parseKeyValue(url.getQuery()));
request.setHeaders(parseKeyValue(requestDesc.getHeader()));

View File

@ -213,20 +213,22 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
public int editNode(DragModuleRequest request) {
request.setUpdateTime(System.currentTimeMillis());
checkApiModuleExist(request);
List<ApiDefinitionResult> apiModule = queryByModuleIds(request.getNodeIds());
List<ApiDefinitionResult> apiDefinitionResults = queryByModuleIds(request.getNodeIds());
apiModule.forEach(apiDefinition -> {
StringBuilder path = new StringBuilder(apiDefinition.getModulePath());
List<String> pathLists = Arrays.asList(path.toString().split("/"));
pathLists.set(request.getLevel(), request.getName());
path.delete(0, path.length());
for (int i = 1; i < pathLists.size(); i++) {
path = path.append("/").append(pathLists.get(i));
apiDefinitionResults.forEach(apiDefinition -> {
if (StringUtils.isNotBlank(apiDefinition.getModulePath())) {
StringBuilder path = new StringBuilder(apiDefinition.getModulePath());
List<String> pathLists = Arrays.asList(path.toString().split("/"));
pathLists.set(request.getLevel(), request.getName());
path.delete(0, path.length());
for (int i = 1; i < pathLists.size(); i++) {
path = path.append("/").append(pathLists.get(i));
}
apiDefinition.setModulePath(path.toString());
}
apiDefinition.setModulePath(path.toString());
});
batchUpdateApiDefinition(apiModule);
batchUpdateApiDefinition(apiDefinitionResults);
return apiModuleMapper.updateByPrimaryKeySelective(request);
}

View File

@ -96,15 +96,27 @@ public class JmeterDocumentParser implements DocumentParser {
processCheckoutArguments(ele);
processCheckoutResponseAssertion(ele);
} else if (nodeNameEquals(ele, CONCURRENCY_THREAD_GROUP)) {
processConcurrencyThreadGroup(ele);
processThreadGroupName(ele);
processCheckoutTimer(ele);
processCheckoutBackendListener(ele);
} else if (nodeNameEquals(ele, VARIABLE_THROUGHPUT_TIMER)) {
processVariableThroughputTimer(ele);
} else if (nodeNameEquals(ele, THREAD_GROUP)) {
processThreadGroup(ele);
//
processConcurrencyThreadGroup(ele);
Object threadType = context.getProperty("threadType");
if (threadType instanceof List) {
Object o = ((List<?>) threadType).get(0);
((List<?>) threadType).remove(0);
if ("DURATION".equals(o)) {
processThreadGroup(ele);
}
if ("ITERATION".equals(o)) {
processIterationThreadGroup(ele);
}
} else {
processThreadGroup(ele);
}
processThreadGroupName(ele);
processCheckoutTimer(ele);
processCheckoutBackendListener(ele);
} else if (nodeNameEquals(ele, BACKEND_LISTENER)) {
@ -772,22 +784,120 @@ public class JmeterDocumentParser implements DocumentParser {
*/
removeChildren(threadGroup);
// elementProp
Object targetLevels = context.getProperty("TargetLevel");
String threads = "10";
if (targetLevels instanceof List) {
Object o = ((List<?>) targetLevels).get(0);
((List<?>) targetLevels).remove(0);
threads = o.toString();
}
Object rampUps = context.getProperty("RampUp");
String rampUp = "1";
if (rampUps instanceof List) {
Object o = ((List<?>) rampUps).get(0);
((List<?>) rampUps).remove(0);
rampUp = o.toString();
}
Object steps = context.getProperty("Steps");
String step = "2";
if (steps instanceof List) {
Object o = ((List<?>) steps).get(0);
((List<?>) steps).remove(0);
step = o.toString();
}
Object holds = context.getProperty("Hold");
String hold = "2";
if (holds instanceof List) {
Object o = ((List<?>) holds).get(0);
((List<?>) holds).remove(0);
hold = o.toString();
}
Element elementProp = document.createElement("elementProp");
elementProp.setAttribute("name", "ThreadGroup.main_controller");
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
threadGroup.appendChild(elementProp);
threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
threadGroup.appendChild(createStringProp(document, "TargetLevel", "2"));
threadGroup.appendChild(createStringProp(document, "RampUp", "12"));
threadGroup.appendChild(createStringProp(document, "Steps", "2"));
threadGroup.appendChild(createStringProp(document, "Hold", "1"));
threadGroup.appendChild(createStringProp(document, "TargetLevel", threads));
threadGroup.appendChild(createStringProp(document, "RampUp", rampUp));
threadGroup.appendChild(createStringProp(document, "Steps", step));
threadGroup.appendChild(createStringProp(document, "Hold", hold));
threadGroup.appendChild(createStringProp(document, "LogFilename", ""));
// bzm - Concurrency Thread Group "Thread Iterations Limit:" 设置为空
// threadGroup.appendChild(createStringProp(document, "Iterations", "1"));
threadGroup.appendChild(createStringProp(document, "Unit", "S"));
}
private void processIterationThreadGroup(Element threadGroup) {
// 检查 threadgroup 后面的hashtree是否为空
Node hashTree = threadGroup.getNextSibling();
while (!(hashTree instanceof Element)) {
hashTree = hashTree.getNextSibling();
}
if (!hashTree.hasChildNodes()) {
MSException.throwException(Translator.get("jmx_content_valid"));
}
// 重命名 tagName
Document document = threadGroup.getOwnerDocument();
removeChildren(threadGroup);
// 选择按照迭代次数处理线程组
/*
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">100</stringProp>
<stringProp name="ThreadGroup.ramp_time">5</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">10</stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
*/
// elementProp
Object targetLevels = context.getProperty("TargetLevel");
String threads = "10";
if (targetLevels instanceof List) {
Object o = ((List<?>) targetLevels).get(0);
((List<?>) targetLevels).remove(0);
threads = o.toString();
}
Object iterateNum = context.getProperty("iterateNum");
String loops = "1";
if (iterateNum instanceof List) {
Object o = ((List<?>) iterateNum).get(0);
((List<?>) iterateNum).remove(0);
loops = o.toString();
}
Object rampUps = context.getProperty("iterateRampUpTime");
String rampUp = "10";
if (rampUps instanceof List) {
Object o = ((List<?>) rampUps).get(0);
((List<?>) rampUps).remove(0);
rampUp = o.toString();
}
Element elementProp = document.createElement("elementProp");
elementProp.setAttribute("name", "ThreadGroup.main_controller");
elementProp.setAttribute("elementType", "LoopController");
elementProp.setAttribute("guiclass", "LoopControlPanel");
elementProp.setAttribute("testclass", "LoopController");
elementProp.setAttribute("testname", "Loop Controller");
elementProp.setAttribute("enabled", "true");
elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false));
elementProp.appendChild(createStringProp(document, "LoopController.loops", loops));
threadGroup.appendChild(elementProp);
threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
threadGroup.appendChild(createStringProp(document, "ThreadGroup.num_threads", threads));
threadGroup.appendChild(createStringProp(document, "ThreadGroup.ramp_time", rampUp));
threadGroup.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false)); // 不指定执行时间
threadGroup.appendChild(createStringProp(document, "Hold", "1"));
threadGroup.appendChild(createStringProp(document, "ThreadGroup.duration", "10"));
threadGroup.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
threadGroup.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
}
private void processCheckoutTimer(Element element) {
/*
<kg.apc.jmeter.timers.VariableThroughputTimer guiclass="kg.apc.jmeter.timers.VariableThroughputTimerGui" testclass="kg.apc.jmeter.timers.VariableThroughputTimer" testname="jp@gc - Throughput Shaping Timer" enabled="true">
@ -856,37 +966,14 @@ public class JmeterDocumentParser implements DocumentParser {
return unit;
}
private void processConcurrencyThreadGroup(Element concurrencyThreadGroup) {
String testname = concurrencyThreadGroup.getAttribute("testname");
concurrencyThreadGroup.setAttribute("testname", testname + "-" + context.getResourceIndex());
if (concurrencyThreadGroup.getChildNodes().getLength() > 0) {
final NodeList childNodes = concurrencyThreadGroup.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (invalid(ele)) {
continue;
}
if (nodeNameEquals(ele, STRING_PROP)) {
parseStringProp(ele);
}
}
}
}
private void processThreadGroupName(Element threadGroup) {
String testname = threadGroup.getAttribute("testname");
threadGroup.setAttribute("testname", testname + "-" + context.getResourceIndex());
}
private void processVariableThroughputTimer(Element variableThroughputTimer) {
Object durations = context.getProperty("duration");
Integer duration;
if (durations instanceof List) {
Object o = ((List<?>) durations).get(0);
duration = (Integer) o;
((List<?>) durations).remove(0);
} else {
duration = (Integer) durations;
}
// 设置rps时长
Integer duration = Integer.MAX_VALUE;
Object rpsLimits = context.getProperty("rpsLimit");
String rpsLimit;
if (rpsLimits instanceof List) {

@ -1 +1 @@
Subproject commit 9f4a9bbf46fc1333dbcccea21f83e27e3ec10b1f
Subproject commit 068127ce59ea8b016434ed52a9de4a7a4b13bdb4

View File

@ -21,45 +21,85 @@
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.duration')">
<el-input-number
:disabled="true"
:placeholder="$t('load_test.duration')"
v-model="threadGroup.duration"
:min="1"
size="mini"/>
<el-form-item>
<el-radio-group v-model="threadGroup.threadType">
<el-radio label="DURATION">{{ $t('load_test.by_duration') }}</el-radio>
<el-radio label="ITERATION">{{ $t('load_test.by_iteration') }}</el-radio>
</el-radio-group>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="rpsLimitEnable"/>
&nbsp;
<el-input-number
:disabled="true"
:placeholder="$t('load_test.input_rps_limit')"
v-model="threadGroup.rpsLimit"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="true"
placeholder=""
:min="1"
:max="threadGroup.duration"
v-model="threadGroup.rampUpTime"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
<el-input-number
:disabled="true"
placeholder=""
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
<div v-if="threadGroup.threadType === 'DURATION'">
<el-form-item :label="$t('load_test.duration')">
<el-input-number
:disabled="true"
v-model="threadGroup.duration"
:min="1"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="true "
v-model="threadGroup.rpsLimit"
@change="calculateChart(threadGroup)"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="true"
:min="1"
:max="threadGroup.duration"
v-model="threadGroup.rampUpTime"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
<el-input-number
:disabled="true"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
</div>
<div v-if="threadGroup.threadType === 'ITERATION'">
<el-form-item :label="$t('load_test.iterate_num')">
<el-input-number
:disabled="true"
v-model="threadGroup.iterateNum"
:min="1"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="true || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
@change="calculateChart(threadGroup)"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="true"
:min="1"
v-model="threadGroup.iterateRampUp"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_seconds')"/>
</div>
</el-form>
</el-col>
<el-col :span="14">
@ -83,6 +123,10 @@ const STEPS = "Steps";
const DURATION = "duration";
const RPS_LIMIT = "rpsLimit";
const RPS_LIMIT_ENABLE = "rpsLimitEnable";
const THREAD_TYPE = "threadType";
const ITERATE_NUM = "iterateNum";
const ITERATE_RAMP_UP = "iterateRampUpTime";
const hexToRgba = function (hex, opacity) {
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
+ parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')';
@ -128,6 +172,9 @@ export default {
case RAMP_UP:
this.threadGroups[i].rampUpTime = item.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[i].iterateRampUp = item.value;
break;
case DURATION:
if (item.unit) {
this.threadGroups[i].duration = item.value;
@ -144,6 +191,12 @@ export default {
case RPS_LIMIT_ENABLE:
this.threadGroups[i].rpsLimitEnable = item.value;
break;
case THREAD_TYPE:
this.threadGroups[i].threadType = item.value;
break;
case ITERATE_NUM:
this.threadGroups[i].iterateNum = item.value;
break;
default:
break;
}
@ -157,6 +210,9 @@ export default {
case RAMP_UP:
this.threadGroups[0].rampUpTime = d.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[0].iterateRampUp = d.value;
break;
case DURATION:
if (d.unit) {
this.threadGroups[0].duration = d.value;
@ -173,6 +229,12 @@ export default {
case RPS_LIMIT_ENABLE:
this.threadGroups[0].rpsLimitEnable = d.value;
break;
case THREAD_TYPE:
this.threadGroups[0].threadType = d.value;
break;
case ITERATE_NUM:
this.threadGroups[0].iterateNum = d.value;
break;
default:
break;
}

View File

@ -298,6 +298,9 @@ export default {
tg.rampUpTime = tg.rampUpTime || 5;
tg.step = tg.step || 5;
tg.rpsLimit = tg.rpsLimit || 10;
tg.threadType = tg.threadType || 'DURATION';
tg.iterateNum = tg.iterateNum || 1;
tg.iterateRampUp = tg.iterateRampUp || 10;
handler.calculateChart(tg);
});
}

View File

@ -33,45 +33,83 @@
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.duration')">
<el-input-number
:disabled="isReadOnly"
v-model="threadGroup.duration"
:min="1"
@change="calculateChart(threadGroup)"
size="mini"/>
<el-form-item>
<el-radio-group v-model="threadGroup.threadType">
<el-radio label="DURATION">{{ $t('load_test.by_duration') }}</el-radio>
<el-radio label="ITERATION">{{ $t('load_test.by_iteration') }}</el-radio>
</el-radio-group>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
@change="calculateChart(threadGroup)"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="isReadOnly"
:min="1"
:max="threadGroup.duration"
v-model="threadGroup.rampUpTime"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
<el-input-number
:disabled="isReadOnly"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
<div v-if="threadGroup.threadType === 'DURATION'">
<el-form-item :label="$t('load_test.duration')">
<el-input-number
:disabled="isReadOnly"
v-model="threadGroup.duration"
:min="1"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
@change="calculateChart(threadGroup)"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="isReadOnly"
:min="1"
:max="threadGroup.duration"
v-model="threadGroup.rampUpTime"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
<el-input-number
:disabled="isReadOnly"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
</div>
<div v-if="threadGroup.threadType === 'ITERATION'">
<el-form-item :label="$t('load_test.iterate_num')">
<el-input-number
:disabled="isReadOnly"
v-model="threadGroup.iterateNum"
:min="1"
@change="calculateChart(threadGroup)"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="isReadOnly"
:min="1"
v-model="threadGroup.iterateRampUp"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_seconds')"/>
</div>
</el-form>
</el-col>
<el-col :span="14">
@ -91,11 +129,14 @@ import {findTestPlan, findThreadGroup} from "@/business/components/performance/t
const TARGET_LEVEL = "TargetLevel";
const RAMP_UP = "RampUp";
const ITERATE_RAMP_UP = "iterateRampUpTime";
const STEPS = "Steps";
const DURATION = "duration";
const RPS_LIMIT = "rpsLimit";
const RPS_LIMIT_ENABLE = "rpsLimitEnable";
const HOLD = "Hold";
const THREAD_TYPE = "threadType";
const ITERATE_NUM = "iterateNum";
const hexToRgba = function (hex, opacity) {
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
@ -186,6 +227,9 @@ export default {
case RAMP_UP:
this.threadGroups[i].rampUpTime = item.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[i].iterateRampUp = item.value;
break;
case DURATION:
if (item.unit) {
this.threadGroups[i].duration = item.value;
@ -202,9 +246,19 @@ export default {
case RPS_LIMIT_ENABLE:
this.threadGroups[i].rpsLimitEnable = item.value;
break;
case THREAD_TYPE:
this.threadGroups[i].threadType = item.value;
break;
case ITERATE_NUM:
this.threadGroups[i].iterateNum = item.value;
break;
default:
break;
}
//
this.$set(this.threadGroups[i], "threadType", this.threadGroups[i].threadType || 'DURATION');
this.$set(this.threadGroups[i], "iterateNum", this.threadGroups[i].iterateNum || 1);
this.$set(this.threadGroups[i], "iterateRampUp", this.threadGroups[i].iterateRampUp || 10);
})
this.calculateChart(this.threadGroups[i]);
} else {
@ -215,6 +269,9 @@ export default {
case RAMP_UP:
this.threadGroups[0].rampUpTime = d.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[0].iterateRampUp = d.value;
break;
case DURATION:
if (d.unit) {
this.threadGroups[0].duration = d.value;
@ -231,9 +288,18 @@ export default {
case RPS_LIMIT_ENABLE:
this.threadGroups[0].rpsLimitEnable = d.value;
break;
case THREAD_TYPE:
this.threadGroups[0].threadType = d.value;
break;
case ITERATE_NUM:
this.threadGroups[0].iterateNum = d.value;
break;
default:
break;
}
this.$set(this.threadGroups[0], "threadType", this.threadGroups[0].threadType || 'DURATION');
this.$set(this.threadGroups[0], "iterateNum", this.threadGroups[0].iterateNum || 1);
this.$set(this.threadGroups[0], "iterateRampUp", this.threadGroups[0].iterateRampUp || 10);
this.calculateChart(this.threadGroups[0]);
}
}
@ -461,7 +527,7 @@ export default {
for (let i = 0; i < this.threadGroups.length; i++) {
if (!this.threadGroups[i].threadNumber || !this.threadGroups[i].duration
|| !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step) {
|| !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step || !this.threadGroups[i].iterateNum) {
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
this.$emit('changeActive', '1');
return false;
@ -488,6 +554,9 @@ export default {
{key: RPS_LIMIT, value: this.threadGroups[i].rpsLimit},
{key: RPS_LIMIT_ENABLE, value: this.threadGroups[i].rpsLimitEnable},
{key: HOLD, value: this.threadGroups[i].duration - this.threadGroups[i].rampUpTime},
{key: THREAD_TYPE, value: this.threadGroups[i].threadType},
{key: ITERATE_NUM, value: this.threadGroups[i].iterateNum},
{key: ITERATE_RAMP_UP, value: this.threadGroups[i].iterateRampUp},
]);
}
return result;

@ -1 +1 @@
Subproject commit 010ad7a5f072a5e9d368c756a2473bbd20781433
Subproject commit 7d43154a7c19732407a8e9ace8a7d1ea13c91f36

View File

@ -438,6 +438,10 @@ export default {
input_rps_limit: 'Please enter a limit',
ramp_up_time_within: 'In',
ramp_up_time_minutes: 'seconds, separate',
ramp_up_time_seconds: 'seconds add concurrent users',
iterate_num: 'Iterations: ',
by_iteration: 'By iterations',
by_duration: 'By duration',
ramp_up_time_times: 'add concurrent users',
advanced_config_error: 'Advanced configuration verification failed',
domain_bind: 'Domain bind',

View File

@ -434,6 +434,10 @@ export default {
input_rps_limit: '请输入限制',
ramp_up_time_within: '在',
ramp_up_time_minutes: '秒内,分',
ramp_up_time_seconds: '秒内增加并发用户',
iterate_num: '迭代次数 (次): ',
by_iteration: '按迭代次数',
by_duration: '按持续时间',
ramp_up_time_times: '次增加并发用户',
advanced_config_error: '高级配置校验失败',
domain_bind: '域名绑定',

View File

@ -434,6 +434,10 @@ export default {
input_rps_limit: '請輸入限制',
ramp_up_time_within: '在',
ramp_up_time_minutes: '秒內,分',
ramp_up_time_seconds: '秒內增加並發用戶',
iterate_num: '迭代次數 (次): ',
by_iteration: '按迭代次數',
by_duration: '按壓測時長',
ramp_up_time_times: '次增加並發用戶',
advanced_config_error: '高級配置校驗失敗',
domain_bind: '域名綁定',