feat(测试计划): 性能测试用例可以调整压力配置#1001972
--story=1001972 --user=lyh 性能测试添加到测试计划后,可以重新调整压力配置并不影响原有的配置 https://www.tapd.cn/55049933/s/1044891
This commit is contained in:
parent
a148886e06
commit
98ddf35ef7
|
@ -1,8 +1,7 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TestPlanLoadCase implements Serializable {
|
||||
|
@ -22,5 +21,9 @@ public class TestPlanLoadCase implements Serializable {
|
|||
|
||||
private String createUser;
|
||||
|
||||
private String testResourcePoolId;
|
||||
|
||||
private String loadConfiguration;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -643,6 +643,76 @@ public class TestPlanLoadCaseExample {
|
|||
addCriterion("create_user not between", value1, value2, "createUser");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdIsNull() {
|
||||
addCriterion("test_resource_pool_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdIsNotNull() {
|
||||
addCriterion("test_resource_pool_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdEqualTo(String value) {
|
||||
addCriterion("test_resource_pool_id =", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdNotEqualTo(String value) {
|
||||
addCriterion("test_resource_pool_id <>", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdGreaterThan(String value) {
|
||||
addCriterion("test_resource_pool_id >", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("test_resource_pool_id >=", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdLessThan(String value) {
|
||||
addCriterion("test_resource_pool_id <", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("test_resource_pool_id <=", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdLike(String value) {
|
||||
addCriterion("test_resource_pool_id like", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdNotLike(String value) {
|
||||
addCriterion("test_resource_pool_id not like", value, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdIn(List<String> values) {
|
||||
addCriterion("test_resource_pool_id in", values, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdNotIn(List<String> values) {
|
||||
addCriterion("test_resource_pool_id not in", values, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdBetween(String value1, String value2) {
|
||||
addCriterion("test_resource_pool_id between", value1, value2, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestResourcePoolIdNotBetween(String value1, String value2) {
|
||||
addCriterion("test_resource_pool_id not between", value1, value2, "testResourcePoolId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
|
|
@ -16,15 +16,21 @@ public interface TestPlanLoadCaseMapper {
|
|||
|
||||
int insertSelective(TestPlanLoadCase record);
|
||||
|
||||
List<TestPlanLoadCase> selectByExampleWithBLOBs(TestPlanLoadCaseExample example);
|
||||
|
||||
List<TestPlanLoadCase> selectByExample(TestPlanLoadCaseExample example);
|
||||
|
||||
TestPlanLoadCase selectByPrimaryKey(String id);
|
||||
|
||||
int updateByExampleSelective(@Param("record") TestPlanLoadCase record, @Param("example") TestPlanLoadCaseExample example);
|
||||
|
||||
int updateByExampleWithBLOBs(@Param("record") TestPlanLoadCase record, @Param("example") TestPlanLoadCaseExample example);
|
||||
|
||||
int updateByExample(@Param("record") TestPlanLoadCase record, @Param("example") TestPlanLoadCaseExample example);
|
||||
|
||||
int updateByPrimaryKeySelective(TestPlanLoadCase record);
|
||||
|
||||
int updateByPrimaryKeyWithBLOBs(TestPlanLoadCase record);
|
||||
|
||||
int updateByPrimaryKey(TestPlanLoadCase record);
|
||||
}
|
|
@ -10,6 +10,10 @@
|
|||
<result column="create_time" jdbcType="BIGINT" property="createTime" />
|
||||
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
||||
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
|
||||
<result column="test_resource_pool_id" jdbcType="VARCHAR" property="testResourcePoolId" />
|
||||
</resultMap>
|
||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlanLoadCase">
|
||||
<result column="load_configuration" jdbcType="LONGVARCHAR" property="loadConfiguration" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
<where>
|
||||
|
@ -71,8 +75,27 @@
|
|||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, test_plan_id, load_case_id, load_report_id, `status`, create_time, update_time,
|
||||
create_user
|
||||
create_user, test_resource_pool_id
|
||||
</sql>
|
||||
<sql id="Blob_Column_List">
|
||||
load_configuration
|
||||
</sql>
|
||||
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanLoadCaseExample" resultMap="ResultMapWithBLOBs">
|
||||
select
|
||||
<if test="distinct">
|
||||
distinct
|
||||
</if>
|
||||
<include refid="Base_Column_List" />
|
||||
,
|
||||
<include refid="Blob_Column_List" />
|
||||
from test_plan_load_case
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanLoadCaseExample" resultMap="BaseResultMap">
|
||||
select
|
||||
<if test="distinct">
|
||||
|
@ -87,9 +110,11 @@
|
|||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
|
||||
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
,
|
||||
<include refid="Blob_Column_List" />
|
||||
from test_plan_load_case
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</select>
|
||||
|
@ -106,10 +131,12 @@
|
|||
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanLoadCase">
|
||||
insert into test_plan_load_case (id, test_plan_id, load_case_id,
|
||||
load_report_id, `status`, create_time,
|
||||
update_time, create_user)
|
||||
update_time, create_user, test_resource_pool_id,
|
||||
load_configuration)
|
||||
values (#{id,jdbcType=VARCHAR}, #{testPlanId,jdbcType=VARCHAR}, #{loadCaseId,jdbcType=VARCHAR},
|
||||
#{loadReportId,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
|
||||
#{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR})
|
||||
#{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}, #{testResourcePoolId,jdbcType=VARCHAR},
|
||||
#{loadConfiguration,jdbcType=LONGVARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanLoadCase">
|
||||
insert into test_plan_load_case
|
||||
|
@ -138,6 +165,12 @@
|
|||
<if test="createUser != null">
|
||||
create_user,
|
||||
</if>
|
||||
<if test="testResourcePoolId != null">
|
||||
test_resource_pool_id,
|
||||
</if>
|
||||
<if test="loadConfiguration != null">
|
||||
load_configuration,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null">
|
||||
|
@ -164,6 +197,12 @@
|
|||
<if test="createUser != null">
|
||||
#{createUser,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="testResourcePoolId != null">
|
||||
#{testResourcePoolId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="loadConfiguration != null">
|
||||
#{loadConfiguration,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanLoadCaseExample" resultType="java.lang.Long">
|
||||
|
@ -199,11 +238,33 @@
|
|||
<if test="record.createUser != null">
|
||||
create_user = #{record.createUser,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.testResourcePoolId != null">
|
||||
test_resource_pool_id = #{record.testResourcePoolId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.loadConfiguration != null">
|
||||
load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExampleWithBLOBs" parameterType="map">
|
||||
update test_plan_load_case
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
|
||||
load_case_id = #{record.loadCaseId,jdbcType=VARCHAR},
|
||||
load_report_id = #{record.loadReportId,jdbcType=VARCHAR},
|
||||
`status` = #{record.status,jdbcType=VARCHAR},
|
||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||
create_user = #{record.createUser,jdbcType=VARCHAR},
|
||||
test_resource_pool_id = #{record.testResourcePoolId,jdbcType=VARCHAR},
|
||||
load_configuration = #{record.loadConfiguration,jdbcType=LONGVARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExample" parameterType="map">
|
||||
update test_plan_load_case
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
|
@ -213,7 +274,8 @@
|
|||
`status` = #{record.status,jdbcType=VARCHAR},
|
||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||
create_user = #{record.createUser,jdbcType=VARCHAR}
|
||||
create_user = #{record.createUser,jdbcType=VARCHAR},
|
||||
test_resource_pool_id = #{record.testResourcePoolId,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -242,9 +304,28 @@
|
|||
<if test="createUser != null">
|
||||
create_user = #{createUser,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="testResourcePoolId != null">
|
||||
test_resource_pool_id = #{testResourcePoolId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="loadConfiguration != null">
|
||||
load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanLoadCase">
|
||||
update test_plan_load_case
|
||||
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
|
||||
load_case_id = #{loadCaseId,jdbcType=VARCHAR},
|
||||
load_report_id = #{loadReportId,jdbcType=VARCHAR},
|
||||
`status` = #{status,jdbcType=VARCHAR},
|
||||
create_time = #{createTime,jdbcType=BIGINT},
|
||||
update_time = #{updateTime,jdbcType=BIGINT},
|
||||
create_user = #{createUser,jdbcType=VARCHAR},
|
||||
test_resource_pool_id = #{testResourcePoolId,jdbcType=VARCHAR},
|
||||
load_configuration = #{loadConfiguration,jdbcType=LONGVARCHAR}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanLoadCase">
|
||||
update test_plan_load_case
|
||||
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
|
||||
|
@ -253,7 +334,8 @@
|
|||
`status` = #{status,jdbcType=VARCHAR},
|
||||
create_time = #{createTime,jdbcType=BIGINT},
|
||||
update_time = #{updateTime,jdbcType=BIGINT},
|
||||
create_user = #{createUser,jdbcType=VARCHAR}
|
||||
create_user = #{createUser,jdbcType=VARCHAR},
|
||||
test_resource_pool_id = #{testResourcePoolId,jdbcType=VARCHAR}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
</mapper>
|
|
@ -8,5 +8,16 @@ import lombok.Setter;
|
|||
public class RunTestPlanRequest extends TestPlanRequest {
|
||||
private String userId;
|
||||
private String triggerMode;
|
||||
/**
|
||||
* 测试计划用例跑性能测试时需要设置此值
|
||||
*/
|
||||
private String testPlanLoadId;
|
||||
/**
|
||||
* 压力配置信息
|
||||
*/
|
||||
private String ownLoadConfiguration;
|
||||
/**
|
||||
* 资源池ID
|
||||
*/
|
||||
private String ownTestPoolId;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,15 @@ package io.metersphere.performance.service;
|
|||
import com.alibaba.excel.util.CollectionUtils;
|
||||
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
|
||||
import io.metersphere.base.domain.LoadTestWithBLOBs;
|
||||
import io.metersphere.base.domain.TestPlanLoadCase;
|
||||
import io.metersphere.base.mapper.LoadTestMapper;
|
||||
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.performance.engine.EngineContext;
|
||||
import io.metersphere.performance.engine.EngineFactory;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -30,11 +33,35 @@ public class JmeterFileService {
|
|||
private LoadTestMapper loadTestMapper;
|
||||
@Resource
|
||||
private ExtLoadTestReportMapper extLoadTestReportMapper;
|
||||
@Resource
|
||||
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
|
||||
|
||||
public byte[] downloadZip(String testId, double[] ratios, String reportId, int resourceIndex) {
|
||||
try {
|
||||
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(testId);
|
||||
TestPlanLoadCase testPlanLoadCase = null;
|
||||
if (loadTest == null) {
|
||||
// 通过测试计划执行性能用例时,testId为测试计划性能用例表的主键ID,根据ID查询用例自身的压力配置
|
||||
testPlanLoadCase = testPlanLoadCaseMapper.selectByPrimaryKey(testId);
|
||||
if (testPlanLoadCase != null) {
|
||||
loadTest = loadTestMapper.selectByPrimaryKey(testPlanLoadCase.getLoadCaseId());
|
||||
if (loadTest != null) {
|
||||
// 用例自身设置了资源池ID
|
||||
if (StringUtils.isNotBlank(testPlanLoadCase.getTestResourcePoolId())) {
|
||||
loadTest.setTestResourcePoolId(testPlanLoadCase.getTestResourcePoolId());
|
||||
}
|
||||
// 用例自身设置了压力配置
|
||||
if (StringUtils.isNotBlank(testPlanLoadCase.getLoadConfiguration())) {
|
||||
loadTest.setLoadConfiguration(testPlanLoadCase.getLoadConfiguration());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EngineContext context = EngineFactory.createContext(loadTest, ratios, reportId, resourceIndex);
|
||||
if (testPlanLoadCase != null) {
|
||||
// ID
|
||||
context.setTestId(testPlanLoadCase.getId());
|
||||
}
|
||||
return zipFilesToByteArray(context);
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
|
|
|
@ -41,6 +41,7 @@ import io.metersphere.service.QuotaService;
|
|||
import io.metersphere.service.ScheduleService;
|
||||
import io.metersphere.track.service.TestCaseService;
|
||||
import io.metersphere.track.service.TestPlanLoadCaseService;
|
||||
import org.apache.commons.beanutils.BeanUtilsBean;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
|
@ -109,6 +110,8 @@ public class PerformanceTestService {
|
|||
@Lazy
|
||||
@Resource
|
||||
private TestPlanLoadCaseService testPlanLoadCaseService;
|
||||
@Resource
|
||||
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
|
||||
|
||||
public List<LoadTestDTO> list(QueryTestPlanRequest request) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
|
@ -318,8 +321,21 @@ public class PerformanceTestService {
|
|||
checkKafka();
|
||||
|
||||
LogUtil.info("Load test started " + loadTest.getName());
|
||||
LoadTestWithBLOBs copyTest = new LoadTestWithBLOBs();
|
||||
BeanUtils.copyBean(copyTest, loadTest);
|
||||
// 如果是执行测试计划用例,把EngineFactory.createEngine参数对象的id 设置为测试计划用例id
|
||||
// 设置用例id目的是当 JmeterFileService 下载zip,拼装 jmx 文件时,如果用例自身带有压力配置,使用用例自身压力配置拼装 jmx
|
||||
String testPlanLoadId = request.getTestPlanLoadId();
|
||||
if (StringUtils.isNotBlank(testPlanLoadId)) {
|
||||
copyTest.setId(testPlanLoadId);
|
||||
// 设置本次报告中的压力配置信息
|
||||
TestPlanLoadCase testPlanLoadCase = testPlanLoadCaseMapper.selectByPrimaryKey(testPlanLoadId);
|
||||
if (testPlanLoadCase != null && StringUtils.isNotBlank(testPlanLoadCase.getLoadConfiguration())) {
|
||||
loadTest.setLoadConfiguration(testPlanLoadCase.getLoadConfiguration());
|
||||
}
|
||||
}
|
||||
// engine type (NODE)
|
||||
final Engine engine = EngineFactory.createEngine(loadTest);
|
||||
final Engine engine = EngineFactory.createEngine(copyTest);
|
||||
if (engine == null) {
|
||||
MSException.throwException(String.format("Test cannot be run,test ID:%s", request.getId()));
|
||||
}
|
||||
|
@ -363,6 +379,9 @@ public class PerformanceTestService {
|
|||
} else {
|
||||
testReport.setUserId(SessionUtils.getUser().getId());
|
||||
}
|
||||
// 只更新已设置的属性,其它未设置属性不更新
|
||||
LoadTestWithBLOBs updateTest = new LoadTestWithBLOBs();
|
||||
updateTest.setId(loadTest.getId());
|
||||
// 启动测试
|
||||
try {
|
||||
// 启动插入 report
|
||||
|
@ -376,8 +395,8 @@ public class PerformanceTestService {
|
|||
|
||||
engine.start();
|
||||
// 启动正常修改状态 starting
|
||||
loadTest.setStatus(PerformanceTestStatus.Starting.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
updateTest.setStatus(PerformanceTestStatus.Starting.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(updateTest);
|
||||
|
||||
LoadTestReportDetail reportDetail = new LoadTestReportDetail();
|
||||
reportDetail.setContent(HEADERS);
|
||||
|
@ -397,9 +416,9 @@ public class PerformanceTestService {
|
|||
// 启动失败之后清理任务
|
||||
engine.stop();
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
loadTest.setStatus(PerformanceTestStatus.Error.name());
|
||||
loadTest.setDescription(e.getMessage());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
updateTest.setStatus(PerformanceTestStatus.Error.name());
|
||||
updateTest.setDescription(e.getMessage());
|
||||
loadTestMapper.updateByPrimaryKeySelective(updateTest);
|
||||
loadTestReportMapper.deleteByPrimaryKey(testReport.getId());
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -100,4 +100,14 @@ public class TestPlanLoadCaseController {
|
|||
public List<TestPlanLoadCaseDTO> getAllCases(@PathVariable String planId) {
|
||||
return testPlanLoadCaseService.getAllCases(planId);
|
||||
}
|
||||
|
||||
@GetMapping("/get-load-config/{loadCaseId}")
|
||||
public String getPlanLoadCaseConfig(@PathVariable String loadCaseId) {
|
||||
return testPlanLoadCaseService.getPlanLoadCaseConfig(loadCaseId);
|
||||
}
|
||||
|
||||
@GetMapping("/get/{loadCaseId}")
|
||||
public TestPlanLoadCase getTestPlanLoadCase(@PathVariable String loadCaseId) {
|
||||
return testPlanLoadCaseService.getTestPlanLoadCase(loadCaseId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -396,4 +396,22 @@ public class TestPlanLoadCaseService {
|
|||
});
|
||||
return cases;
|
||||
}
|
||||
|
||||
public String getPlanLoadCaseConfig(String loadCaseId) {
|
||||
if (StringUtils.isBlank(loadCaseId)) {
|
||||
return "";
|
||||
}
|
||||
TestPlanLoadCase testPlanLoadCase = testPlanLoadCaseMapper.selectByPrimaryKey(loadCaseId);
|
||||
if (testPlanLoadCase != null) {
|
||||
return testPlanLoadCase.getLoadConfiguration();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public TestPlanLoadCase getTestPlanLoadCase(String loadCaseId) {
|
||||
if (StringUtils.isBlank(loadCaseId)) {
|
||||
return new TestPlanLoadCase();
|
||||
}
|
||||
return testPlanLoadCaseMapper.selectByPrimaryKey(loadCaseId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1046,7 +1046,7 @@ public class TestPlanService {
|
|||
String caseID = entry.getValue();
|
||||
RunTestPlanRequest performanceRequest = new RunTestPlanRequest();
|
||||
performanceRequest.setId(caseID);
|
||||
performanceRequest.setTestPlanLoadId(caseID);
|
||||
performanceRequest.setTestPlanLoadId(id);
|
||||
if (StringUtils.equals(ReportTriggerMode.API.name(), triggerMode)) {
|
||||
performanceRequest.setTriggerMode(ReportTriggerMode.TEST_PLAN_API.name());
|
||||
} else if (StringUtils.equals(ReportTriggerMode.MANUAL.name(), triggerMode)) {
|
||||
|
|
|
@ -17,6 +17,13 @@ CREATE TABLE `plugin` (
|
|||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE utf8mb4_general_ci;
|
||||
|
||||
|
||||
alter table test_plan_load_case
|
||||
add test_resource_pool_id varchar(50) null;
|
||||
|
||||
alter table test_plan_load_case
|
||||
add load_configuration longtext null;
|
||||
|
||||
update test_case_node set name = '未规划用例' where name = '默认模块' and `level` = 1;
|
||||
update test_case set node_path = replace (`node_path`,'/默认模块','/未规划用例') where node_path like '/默认模块%';
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<el-dialog :close-on-click-modal="false" :visible.sync="visible" :title="$t('load_test.pressure_config')"
|
||||
width="61%" top="8vh" @close="close" v-loading="result.loading" :destroy-on-close="true">
|
||||
<performance-load-config :test-id="loadTestId" :load-case-id="loadCaseId" :resource-pool="poolId"
|
||||
@fileChange="fileChange" ref="pressureConfig" style="height: 50vh; overflow-y: auto;"/>
|
||||
<template v-slot:footer>
|
||||
<el-button @click="close" size="medium">{{ $t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit" size="medium" style="margin-left: 10px;">
|
||||
{{ $t('commons.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import PerformanceLoadConfig from "@/business/components/track/plan/view/comonents/load/PerformanceLoadConfig";
|
||||
|
||||
export default {
|
||||
name: "LoadCaseConfig",
|
||||
components: {
|
||||
PerformanceLoadConfig
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
loadTestId: "",
|
||||
result: {},
|
||||
loadCaseId: "",
|
||||
poolId: ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(loadTestId, loadCaseId) {
|
||||
this.visible = true;
|
||||
this.loadTestId = loadTestId;
|
||||
this.loadCaseId = loadCaseId;
|
||||
this.result = this.$get("/test/plan/load/case/get/" + loadCaseId, res => {
|
||||
this.poolId = res.data ? res.data.testResourcePoolId : "";
|
||||
})
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
},
|
||||
fileChange(threadGroups) {
|
||||
let handler = this.$refs.pressureConfig;
|
||||
|
||||
let csvSet = new Set;
|
||||
threadGroups.forEach(tg => {
|
||||
tg.threadNumber = tg.threadNumber || 10;
|
||||
tg.duration = tg.duration || 10;
|
||||
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;
|
||||
|
||||
if (tg.csvFiles) {
|
||||
tg.csvFiles.map(item => csvSet.add(item));
|
||||
}
|
||||
});
|
||||
|
||||
this.$set(handler, "threadGroups", threadGroups);
|
||||
this.$refs.pressureConfig.threadGroups = threadGroups;
|
||||
|
||||
handler.calculateTotalChart();
|
||||
},
|
||||
onSubmit() {
|
||||
if (!this.$refs.pressureConfig.validConfig()) {
|
||||
return false;
|
||||
}
|
||||
// 压力配置
|
||||
let loadConfiguration = JSON.stringify(this.$refs.pressureConfig.convertProperty());
|
||||
let testResourcePoolId = this.$refs.pressureConfig.resourcePool;
|
||||
let params = {
|
||||
id: this.loadCaseId,
|
||||
loadConfiguration,
|
||||
testResourcePoolId
|
||||
}
|
||||
this.result = this.$post("/test/plan/load/case/update", params, () => {
|
||||
this.visible = false;
|
||||
this.$success(this.$t("commons.modify_success"));
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,747 @@
|
|||
<template>
|
||||
<div v-loading="result.loading" class="pressure-config-container">
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form :inline="true">
|
||||
<el-form-item :label="$t('load_test.select_resource_pool')">
|
||||
<el-select v-model="resourcePool" :disabled="isReadOnly" size="mini" @change="resourcePoolChange">
|
||||
<el-option
|
||||
v-for="item in resourcePools"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:disabled="!item.performance"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.serialize_threadgroups')">
|
||||
<el-switch v-model="serializeThreadGroups"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.autostop_threadgroups')">
|
||||
<el-switch v-model="autoStop"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.reaches_duration')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly || !autoStop"
|
||||
v-model="autoStopDelay"
|
||||
:min="1"
|
||||
:max="9999"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.autostop_delay')"/>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-collapse v-model="activeNames" accordion>
|
||||
<el-collapse-item :name="index"
|
||||
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
||||
:key="index">
|
||||
<template slot="title">
|
||||
<el-row>
|
||||
<el-col :span="14">
|
||||
<el-tooltip :content="threadGroup.attributes.testname" placement="top">
|
||||
<div style="padding-right:20px; font-size: 16px;" class="wordwrap">
|
||||
{{ threadGroup.attributes.testname }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
|
||||
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
|
||||
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
|
||||
</el-tag>
|
||||
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
|
||||
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
|
||||
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
|
||||
</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-form :inline="true">
|
||||
<el-form-item :label="$t('load_test.thread_num')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
v-model="threadGroup.threadNumber"
|
||||
@change="calculateTotalChart()"
|
||||
:min="1"
|
||||
:max="maxThreadNumbers"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.on_sample_error')">
|
||||
<el-select v-model="threadGroup.onSampleError" :disabled="isReadOnly" size="mini">
|
||||
<el-option
|
||||
v-for="item in onSampleErrors"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item>
|
||||
<el-radio-group v-model="threadGroup.threadType" @change="calculateTotalChart()">
|
||||
<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>
|
||||
<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"
|
||||
:max="9999"
|
||||
@change="calculateTotalChart()"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-radio-group v-model="threadGroup.unit" @change="changeUnit(threadGroup)">
|
||||
<el-radio label="S">{{ $t('schedule.cron.seconds') }}</el-radio>
|
||||
<el-radio label="M">{{ $t('schedule.cron.minutes') }}</el-radio>
|
||||
<el-radio label="H">{{ $t('schedule.cron.hours') }}</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()"/>
|
||||
|
||||
<el-input-number
|
||||
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
|
||||
v-model="threadGroup.rpsLimit"
|
||||
@change="calculateTotalChart()"
|
||||
:min="1"
|
||||
:max="99999"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<div v-if="threadGroup.tgType === 'com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup'">
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
:min="1"
|
||||
v-if="rampUpTimeVisible"
|
||||
:max="getDuration(threadGroup)"
|
||||
v-model="threadGroup.rampUpTime"
|
||||
@change="calculateTotalChart()"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_minutes', [getUnitLabel(threadGroup)])">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
:min="1"
|
||||
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
||||
v-model="threadGroup.step"
|
||||
@change="calculateTotalChart()"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
|
||||
</div>
|
||||
|
||||
<div v-if="threadGroup.tgType === 'ThreadGroup'">
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
v-if="rampUpTimeVisible"
|
||||
:min="1"
|
||||
:max="getDuration(threadGroup)"
|
||||
v-model="threadGroup.rampUpTime"
|
||||
@change="calculateTotalChart()"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_seconds', [getUnitLabel(threadGroup)])"/>
|
||||
</div>
|
||||
|
||||
</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"
|
||||
:max="9999999"
|
||||
@change="calculateTotalChart()"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.rps_limit')">
|
||||
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
|
||||
|
||||
<el-input-number
|
||||
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
|
||||
v-model="threadGroup.rpsLimit"
|
||||
:min="1"
|
||||
:max="99999"
|
||||
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', [getUnitLabel(threadGroup)])"/>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="title">{{ $t('load_test.pressure_prediction_chart') }}</div>
|
||||
<ms-chart class="chart-container" ref="chart1" :options="options" :autoresize="true"></ms-chart>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from "echarts";
|
||||
import MsChart from "@/business/components/common/chart/MsChart";
|
||||
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
|
||||
import {hasPermission} from "@/common/js/utils";
|
||||
|
||||
const HANDLER = "handler";
|
||||
const THREAD_GROUP_TYPE = "tgType";
|
||||
const ON_SAMPLE_ERROR = "onSampleError";
|
||||
const SERIALIZE_THREAD_GROUPS = "serializeThreadGroups";
|
||||
const AUTO_STOP = "autoStop";
|
||||
const AUTO_STOP_DELAY = "autoStopDelay";
|
||||
const TARGET_LEVEL = "TargetLevel";
|
||||
const RAMP_UP = "RampUp";
|
||||
const ITERATE_RAMP_UP = "iterateRampUpTime";
|
||||
const STEPS = "Steps";
|
||||
const DURATION = "duration";
|
||||
const UNIT = "unit";
|
||||
const RPS_LIMIT = "rpsLimit";
|
||||
const RPS_LIMIT_ENABLE = "rpsLimitEnable";
|
||||
const HOLD = "Hold";
|
||||
const THREAD_TYPE = "threadType";
|
||||
const ITERATE_NUM = "iterateNum";
|
||||
const ENABLED = "enabled";
|
||||
const DELETED = "deleted";
|
||||
|
||||
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 + ')';
|
||||
};
|
||||
const hexToRgb = function (hex) {
|
||||
return 'rgb(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5))
|
||||
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "PerformanceLoadConfig",
|
||||
components: {MsChart},
|
||||
props: {
|
||||
test: {
|
||||
type: Object
|
||||
},
|
||||
testId: {
|
||||
type: String
|
||||
},
|
||||
loadCaseId: {
|
||||
type: String
|
||||
},
|
||||
resourcePool: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
threadNumber: 0,
|
||||
duration: 0,
|
||||
rampUpTime: 0,
|
||||
step: 0,
|
||||
rpsLimit: 0,
|
||||
rpsLimitEnable: false,
|
||||
options: {},
|
||||
resourcePools: [],
|
||||
activeNames: ["0"],
|
||||
threadGroups: [],
|
||||
maxThreadNumbers: 5000,
|
||||
serializeThreadGroups: false,
|
||||
autoStop: false,
|
||||
autoStopDelay: 30,
|
||||
isReadOnly: false,
|
||||
rampUpTimeVisible: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
onSampleErrors() {
|
||||
return [
|
||||
{value: 'continue', label: this.$t('load_test.continue')},
|
||||
{value: 'startnextloop', label: this.$t('load_test.startnextloop')},
|
||||
{value: 'stopthread', label: this.$t('load_test.stopthread')},
|
||||
{value: 'stoptest', label: this.$t('load_test.stoptest')},
|
||||
{value: 'stoptestnow', label: this.$t('load_test.stoptestnow')},
|
||||
];
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.testId) {
|
||||
this.getJmxContent();
|
||||
} else {
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
this.getResourcePools();
|
||||
this.isReadOnly = !hasPermission('PROJECT_PERFORMANCE_TEST:READ+EDIT');
|
||||
},
|
||||
watch: {
|
||||
testId() {
|
||||
if (this.testId) {
|
||||
this.getJmxContent();
|
||||
} else {
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
this.getResourcePools();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getResourcePools() {
|
||||
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
|
||||
this.resourcePools = response.data;
|
||||
// 如果当前的资源池无效 设置 null
|
||||
if (response.data.filter(p => p.id === this.resourcePool).length === 0) {
|
||||
this.resourcePool = null;
|
||||
}
|
||||
|
||||
this.resourcePoolChange();
|
||||
});
|
||||
},
|
||||
getLoadConfig() {
|
||||
this.$get('/test/plan/load/case/get-load-config/' + this.loadCaseId, (response) => {
|
||||
if (response.data) {
|
||||
let data = JSON.parse(response.data);
|
||||
let oldVersion;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let d = data[i];
|
||||
d.forEach(item => {
|
||||
switch (item.key) {
|
||||
case TARGET_LEVEL:
|
||||
this.threadGroups[i].threadNumber = item.value;
|
||||
break;
|
||||
case RAMP_UP:
|
||||
this.threadGroups[i].rampUpTime = item.value;
|
||||
break;
|
||||
case ITERATE_RAMP_UP:
|
||||
this.threadGroups[i].iterateRampUp = item.value;
|
||||
break;
|
||||
case DURATION:
|
||||
this.threadGroups[i].duration = item.value;
|
||||
oldVersion = item.unit;
|
||||
break;
|
||||
case UNIT:
|
||||
this.threadGroups[i].unit = item.value;
|
||||
break;
|
||||
case STEPS:
|
||||
this.threadGroups[i].step = item.value;
|
||||
break;
|
||||
case RPS_LIMIT:
|
||||
this.threadGroups[i].rpsLimit = item.value;
|
||||
break;
|
||||
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;
|
||||
case ENABLED:
|
||||
this.threadGroups[i].enabled = item.value;
|
||||
break;
|
||||
case DELETED:
|
||||
this.threadGroups[i].deleted = item.value;
|
||||
break;
|
||||
case HANDLER:
|
||||
this.threadGroups[i].handler = item.value;
|
||||
break;
|
||||
case THREAD_GROUP_TYPE:
|
||||
this.threadGroups[i].tgType = item.value;
|
||||
break;
|
||||
case ON_SAMPLE_ERROR:
|
||||
this.threadGroups[i].onSampleError = item.value;
|
||||
break;
|
||||
case SERIALIZE_THREAD_GROUPS:
|
||||
this.serializeThreadGroups = item.value;// 所有的线程组值一样
|
||||
break;
|
||||
case AUTO_STOP:
|
||||
this.autoStop = item.value;// 所有的线程组值一样
|
||||
break;
|
||||
case AUTO_STOP_DELAY:
|
||||
this.autoStopDelay = item.value;// 所有的线程组值一样
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//
|
||||
this.$set(this.threadGroups[i], "unit", this.threadGroups[i].unit || 'S');
|
||||
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.$set(this.threadGroups[i], "enabled", this.threadGroups[i].enabled || 'true');
|
||||
this.$set(this.threadGroups[i], "deleted", this.threadGroups[i].deleted || 'false');
|
||||
this.$set(this.threadGroups[i], "onSampleError", this.threadGroups[i].onSampleError || 'continue');
|
||||
});
|
||||
}
|
||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||
// 处理老版本的问题
|
||||
if (oldVersion) {
|
||||
break;
|
||||
}
|
||||
// 恢复成单位需要的值
|
||||
switch (this.threadGroups[i].unit) {
|
||||
case 'M':
|
||||
this.threadGroups[i].duration = this.threadGroups[i].duration / 60;
|
||||
break;
|
||||
case 'H':
|
||||
this.threadGroups[i].duration = this.threadGroups[i].duration / 60 / 60;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
});
|
||||
},
|
||||
getJmxContent() {
|
||||
if (this.testId) {
|
||||
let threadGroups = [];
|
||||
this.$get('/performance/get-jmx-content/' + this.testId, (response) => {
|
||||
response.data.forEach(d => {
|
||||
threadGroups = threadGroups.concat(findThreadGroup(d.jmx, d.name));
|
||||
threadGroups.forEach(tg => {
|
||||
tg.options = {};
|
||||
});
|
||||
});
|
||||
this.threadGroups = threadGroups;
|
||||
this.$emit('fileChange', threadGroups);
|
||||
this.getLoadConfig();
|
||||
});
|
||||
}
|
||||
},
|
||||
resourcePoolChange() {
|
||||
let result = this.resourcePools.filter(p => p.id === this.resourcePool);
|
||||
if (result.length === 1) {
|
||||
let threadNumber = 0;
|
||||
result[0].resources.forEach(resource => {
|
||||
threadNumber += JSON.parse(resource.configuration).maxConcurrency;
|
||||
});
|
||||
this.$set(this, 'maxThreadNumbers', threadNumber);
|
||||
this.threadGroups.forEach(tg => {
|
||||
if (tg.threadNumber > threadNumber) {
|
||||
this.$set(tg, "threadNumber", threadNumber);
|
||||
}
|
||||
});
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
},
|
||||
calculateTotalChart() {
|
||||
this.rampUpTimeVisible = false;
|
||||
this.$nextTick(() => {
|
||||
this.rampUpTimeVisible = true;
|
||||
this._calculateTotalChart();
|
||||
});
|
||||
},
|
||||
_calculateTotalChart() {
|
||||
let handler = this;
|
||||
|
||||
let color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
|
||||
handler.options = {
|
||||
color: color,
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
series: []
|
||||
};
|
||||
|
||||
for (let i = 0; i < handler.threadGroups.length; i++) {
|
||||
let tg = handler.threadGroups[i];
|
||||
|
||||
if (tg.enabled === 'false' ||
|
||||
tg.deleted === 'true' ||
|
||||
tg.threadType === 'ITERATION') {
|
||||
continue;
|
||||
}
|
||||
if (this.getDuration(tg) < tg.rampUpTime) {
|
||||
tg.rampUpTime = tg.duration;
|
||||
}
|
||||
if (tg.rampUpTime < tg.step) {
|
||||
tg.step = tg.rampUpTime;
|
||||
}
|
||||
let seriesData = {
|
||||
name: tg.attributes.testname,
|
||||
data: [],
|
||||
type: 'line',
|
||||
smooth: false,
|
||||
symbolSize: 5,
|
||||
showSymbol: false,
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: hexToRgba(color[i % color.length], 0.3),
|
||||
}, {
|
||||
offset: 0.8,
|
||||
color: hexToRgba(color[i % color.length], 0),
|
||||
}], false),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: hexToRgb(color[i % color.length]),
|
||||
borderColor: 'rgba(137,189,2,0.27)',
|
||||
borderWidth: 12
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
let timePeriod = Math.floor(tg.rampUpTime / tg.step);
|
||||
let timeInc = timePeriod;
|
||||
|
||||
let threadPeriod = Math.floor(tg.threadNumber / tg.step);
|
||||
let threadInc1 = Math.floor(tg.threadNumber / tg.step);
|
||||
let threadInc2 = Math.ceil(tg.threadNumber / tg.step);
|
||||
let inc2count = tg.threadNumber - tg.step * threadInc1;
|
||||
|
||||
let times = 1;
|
||||
switch (tg.unit) {
|
||||
case 'M':
|
||||
times *= 60;
|
||||
break;
|
||||
case 'H':
|
||||
times *= 3600;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
let duration = tg.duration * times;
|
||||
for (let j = 0; j <= duration; j++) {
|
||||
// x 轴
|
||||
let xAxis = handler.options.xAxis.data;
|
||||
if (xAxis.indexOf(j) < 0) {
|
||||
xAxis.push(j);
|
||||
}
|
||||
if (tg.tgType === 'ThreadGroup') {
|
||||
seriesData.step = undefined;
|
||||
|
||||
if (j === 0) {
|
||||
seriesData.data.push(['0', 0]);
|
||||
}
|
||||
if (j >= tg.rampUpTime) {
|
||||
if (xAxis.indexOf(duration) < 0) {
|
||||
xAxis.push(duration);
|
||||
}
|
||||
|
||||
seriesData.data.push([j + '', tg.threadNumber]);
|
||||
seriesData.data.push([duration + '', tg.threadNumber]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
seriesData.step = 'start';
|
||||
if (j > timePeriod) {
|
||||
timePeriod += timeInc;
|
||||
if (inc2count > 0) {
|
||||
threadPeriod = threadPeriod + threadInc2;
|
||||
inc2count--;
|
||||
} else {
|
||||
threadPeriod = threadPeriod + threadInc1;
|
||||
}
|
||||
if (threadPeriod > tg.threadNumber) {
|
||||
threadPeriod = tg.threadNumber;
|
||||
// 预热结束
|
||||
if (xAxis.indexOf(duration) < 0) {
|
||||
xAxis.push(duration);
|
||||
}
|
||||
|
||||
seriesData.data.push([j + '', threadPeriod]);
|
||||
seriesData.data.push([duration + '', threadPeriod]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
seriesData.data.push([j + '', threadPeriod]);
|
||||
}
|
||||
}
|
||||
// x 轴排序
|
||||
handler.options.xAxis.data = handler.options.xAxis.data.sort((a, b) => a - b);
|
||||
handler.options.series.push(seriesData);
|
||||
}
|
||||
// console.log(JSON.stringify(handler.options));
|
||||
},
|
||||
validConfig() {
|
||||
if (!this.resourcePool) {
|
||||
this.$warning(this.$t('load_test.resource_pool_is_null'));
|
||||
// 资源池为空,设置参数为资源池所在Tab的name
|
||||
this.$emit('changeActive', '1');
|
||||
return false;
|
||||
}
|
||||
|
||||
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].iterateNum) {
|
||||
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
||||
this.$emit('changeActive', '1');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.threadGroups[i].rpsLimitEnable && !this.threadGroups[i].rpsLimit) {
|
||||
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
||||
this.$emit('changeActive', '1');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
getHold(tg) {
|
||||
if (tg.unit === 'S') {
|
||||
return tg.duration - tg.rampUpTime;
|
||||
}
|
||||
if (tg.unit === 'M') {
|
||||
return tg.duration * 60 - tg.rampUpTime;
|
||||
}
|
||||
if (tg.unit === 'H') {
|
||||
return tg.duration * 60 * 60 - tg.rampUpTime;
|
||||
}
|
||||
return tg.duration - tg.rampUpTime;
|
||||
},
|
||||
getDuration(tg) {
|
||||
if (tg.unit === 'S') {
|
||||
return tg.duration;
|
||||
}
|
||||
if (tg.unit === 'M') {
|
||||
return tg.duration * 60;
|
||||
}
|
||||
if (tg.unit === 'H') {
|
||||
return tg.duration * 60 * 60;
|
||||
}
|
||||
return tg.duration;
|
||||
},
|
||||
changeUnit(tg) {
|
||||
this.rampUpTimeVisible = false;
|
||||
this.$nextTick(() => {
|
||||
this.rampUpTimeVisible = true;
|
||||
this.calculateTotalChart();
|
||||
});
|
||||
},
|
||||
getUnitLabel(tg) {
|
||||
if (tg.unit === 'S') {
|
||||
return this.$t('schedule.cron.seconds');
|
||||
}
|
||||
if (tg.unit === 'M') {
|
||||
return this.$t('schedule.cron.minutes');
|
||||
}
|
||||
if (tg.unit === 'H') {
|
||||
return this.$t('schedule.cron.hours');
|
||||
}
|
||||
return this.$t('schedule.cron.seconds');
|
||||
},
|
||||
convertProperty() {
|
||||
/// todo:下面4个属性是jmeter ConcurrencyThreadGroup plugin的属性,这种硬编码不太好吧,在哪能转换这种属性?
|
||||
let result = [];
|
||||
|
||||
// 再组织数据
|
||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||
result.push([
|
||||
{key: HANDLER, value: this.threadGroups[i].handler},
|
||||
{key: TARGET_LEVEL, value: this.threadGroups[i].threadNumber},
|
||||
{key: RAMP_UP, value: this.threadGroups[i].rampUpTime},
|
||||
{key: STEPS, value: this.threadGroups[i].step},
|
||||
{key: DURATION, value: this.getDuration(this.threadGroups[i])},
|
||||
{key: UNIT, value: this.threadGroups[i].unit},
|
||||
{key: RPS_LIMIT, value: this.threadGroups[i].rpsLimit},
|
||||
{key: RPS_LIMIT_ENABLE, value: this.threadGroups[i].rpsLimitEnable},
|
||||
{key: HOLD, value: this.getHold(this.threadGroups[i])},
|
||||
{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},
|
||||
{key: ENABLED, value: this.threadGroups[i].enabled},
|
||||
{key: DELETED, value: this.threadGroups[i].deleted},
|
||||
{key: ON_SAMPLE_ERROR, value: this.threadGroups[i].onSampleError},
|
||||
{key: THREAD_GROUP_TYPE, value: this.threadGroups[i].tgType},
|
||||
{key: SERIALIZE_THREAD_GROUPS, value: this.serializeThreadGroups},
|
||||
{key: AUTO_STOP, value: this.autoStop},
|
||||
{key: AUTO_STOP_DELAY, value: this.autoStopDelay},
|
||||
]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.pressure-config-container .el-input {
|
||||
width: 130px;
|
||||
|
||||
}
|
||||
|
||||
.pressure-config-container .config-form-label {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.pressure-config-container .input-bottom-border input {
|
||||
border: 0;
|
||||
border-bottom: 1px solid #DCDFE6;
|
||||
}
|
||||
|
||||
/deep/ .el-collapse-item__content {
|
||||
padding-left: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-left-width: 8px;
|
||||
border-left-style: solid;
|
||||
border-left-color: #F5F7FA;
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.el-col .el-form {
|
||||
margin-top: 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.el-col {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
.wordwrap {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
|
@ -111,6 +111,7 @@
|
|||
<ms-plan-run-mode @handleRunBatch="runBatch" ref="runMode"/>
|
||||
|
||||
<load-case-report :report-id="reportId" ref="loadCaseReport" @refresh="initTable"/>
|
||||
<load-case-config ref="loadCaseConfig"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -132,6 +133,7 @@ import MsTable from "@/business/components/common/components/table/MsTable";
|
|||
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
|
||||
import MsCreateTimeColumn from "@/business/components/common/components/table/MsCreateTimeColumn";
|
||||
import MsUpdateTimeColumn from "@/business/components/common/components/table/MsUpdateTimeColumn";
|
||||
import LoadCaseConfig from "@/business/components/track/plan/view/comonents/load/LoadCaseConfig";
|
||||
|
||||
export default {
|
||||
name: "TestPlanLoadCaseList",
|
||||
|
@ -145,7 +147,8 @@ export default {
|
|||
TestPlanLoadCaseListHeader,
|
||||
MsTablePagination,
|
||||
MsPerformanceTestStatus,
|
||||
MsPlanRunMode
|
||||
MsPlanRunMode,
|
||||
LoadCaseConfig
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -170,13 +173,20 @@ export default {
|
|||
isDisable: this.isReadOnly,
|
||||
permissions: ['PROJECT_TRACK_PLAN:READ+RUN']
|
||||
},
|
||||
{
|
||||
tip: '修改压力配置',
|
||||
icon: "el-icon-setting",
|
||||
exec: this.changeLoadConfig,
|
||||
type: 'danger',
|
||||
isDisable: this.isReadOnly,
|
||||
},
|
||||
{
|
||||
tip: this.$t('test_track.plan_view.cancel_relevance'), icon: "el-icon-unlock",
|
||||
exec: this.handleDelete,
|
||||
type: 'danger',
|
||||
isDisable: this.isReadOnly,
|
||||
permissions: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']
|
||||
}
|
||||
},
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
|
@ -405,6 +415,10 @@ export default {
|
|||
this.initTable();
|
||||
});
|
||||
},
|
||||
changeLoadConfig(loadCase) {
|
||||
const {loadCaseId, id} = loadCase;
|
||||
this.$refs.loadCaseConfig.open(loadCaseId, id);
|
||||
},
|
||||
getReport(data) {
|
||||
const {loadReportId} = data;
|
||||
this.reportId = loadReportId;
|
||||
|
|
Loading…
Reference in New Issue