feat(性能测试): 支持组合场景场景
This commit is contained in:
parent
739d194854
commit
4a9ccc2ea5
|
@ -2,6 +2,7 @@ package io.metersphere.base.mapper.ext;
|
||||||
|
|
||||||
import io.metersphere.base.domain.LoadTest;
|
import io.metersphere.base.domain.LoadTest;
|
||||||
import io.metersphere.dto.LoadTestDTO;
|
import io.metersphere.dto.LoadTestDTO;
|
||||||
|
import io.metersphere.dto.LoadTestFileDTO;
|
||||||
import io.metersphere.track.request.testplan.QueryTestPlanRequest;
|
import io.metersphere.track.request.testplan.QueryTestPlanRequest;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -16,4 +17,7 @@ public interface ExtLoadTestMapper {
|
||||||
int checkLoadTestOwner(@Param("testId") String testId, @Param("workspaceIds") Set<String> workspaceIds);
|
int checkLoadTestOwner(@Param("testId") String testId, @Param("workspaceIds") Set<String> workspaceIds);
|
||||||
|
|
||||||
LoadTest getNextNum(@Param("projectId") String projectId);
|
LoadTest getNextNum(@Param("projectId") String projectId);
|
||||||
|
|
||||||
|
List<LoadTestFileDTO> getProjectFiles(@Param("projectId") String projectId, @Param("loadTypes") List<String> loadType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,4 +131,16 @@
|
||||||
<select id="getNextNum" resultType="io.metersphere.base.domain.LoadTest">
|
<select id="getNextNum" resultType="io.metersphere.base.domain.LoadTest">
|
||||||
select * from load_test lt where lt.project_id = #{projectId} ORDER BY num DESC LIMIT 1;
|
select * from load_test lt where lt.project_id = #{projectId} ORDER BY num DESC LIMIT 1;
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getProjectFiles" resultType="io.metersphere.dto.LoadTestFileDTO">
|
||||||
|
SELECT file_metadata.*, load_test.id as testId, load_test.name as testName
|
||||||
|
FROM load_test
|
||||||
|
JOIN load_test_file ON load_test.id = load_test_file.test_id
|
||||||
|
JOIN file_metadata ON load_test_file.file_id = file_metadata.id
|
||||||
|
WHERE file_metadata.type IN
|
||||||
|
<foreach collection="loadTypes" item="id" separator="," open="(" close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
AND project_id = #{projectId,jdbcType=VARCHAR}
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
|
@ -1,20 +1,24 @@
|
||||||
package io.metersphere.commons.utils;
|
package io.metersphere.commons.utils;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
|
||||||
|
|
||||||
public class UrlTestUtils {
|
public class UrlTestUtils {
|
||||||
|
|
||||||
public static boolean testUrlWithTimeOut(String urlString, int timeOutMillSeconds) {
|
public static boolean testUrlWithTimeOut(String address, int timeOutMillSeconds) {
|
||||||
try {
|
try {
|
||||||
URL url = new URL(urlString);
|
URL urlObj = new URL(address);
|
||||||
URLConnection co = url.openConnection();
|
HttpURLConnection oc = (HttpURLConnection) urlObj.openConnection();
|
||||||
co.setConnectTimeout(timeOutMillSeconds);
|
oc.setUseCaches(false);
|
||||||
co.connect();
|
oc.setConnectTimeout(timeOutMillSeconds); // 设置超时时间
|
||||||
return true;
|
int status = oc.getResponseCode();// 请求状态
|
||||||
|
if (200 == status) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e);
|
e.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package io.metersphere.dto;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.FileMetadata;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoadTestFileDTO extends FileMetadata {
|
||||||
|
private String testId;
|
||||||
|
private String testName;
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.controller.request.QueryScheduleRequest;
|
import io.metersphere.controller.request.QueryScheduleRequest;
|
||||||
import io.metersphere.dto.DashboardTestDTO;
|
import io.metersphere.dto.DashboardTestDTO;
|
||||||
import io.metersphere.dto.LoadTestDTO;
|
import io.metersphere.dto.LoadTestDTO;
|
||||||
|
import io.metersphere.dto.LoadTestFileDTO;
|
||||||
import io.metersphere.dto.ScheduleDao;
|
import io.metersphere.dto.ScheduleDao;
|
||||||
import io.metersphere.performance.service.PerformanceTestService;
|
import io.metersphere.performance.service.PerformanceTestService;
|
||||||
import io.metersphere.service.CheckPermissionService;
|
import io.metersphere.service.CheckPermissionService;
|
||||||
|
@ -112,6 +113,14 @@ public class PerformanceTestController {
|
||||||
return performanceTestService.getJmxContent(testId);
|
return performanceTestService.getJmxContent(testId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/project/{loadType}/{projectId}/{goPage}/{pageSize}")
|
||||||
|
public Pager<List<LoadTestFileDTO>> getProjectFiles(@PathVariable String projectId, @PathVariable String loadType,
|
||||||
|
@PathVariable int goPage, @PathVariable int pageSize) {
|
||||||
|
checkPermissionService.checkProjectOwner(projectId);
|
||||||
|
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||||
|
return PageUtils.setPageInfo(page, performanceTestService.getProjectFiles(projectId, loadType));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/delete")
|
@PostMapping("/delete")
|
||||||
public void delete(@RequestBody DeleteTestPlanRequest request) {
|
public void delete(@RequestBody DeleteTestPlanRequest request) {
|
||||||
checkPermissionService.checkPerformanceTestOwner(request.getId());
|
checkPermissionService.checkPerformanceTestOwner(request.getId());
|
||||||
|
|
|
@ -9,6 +9,7 @@ import io.metersphere.config.KafkaProperties;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.performance.engine.EngineContext;
|
import io.metersphere.performance.engine.EngineContext;
|
||||||
import io.metersphere.performance.parse.xml.reader.DocumentParser;
|
import io.metersphere.performance.parse.xml.reader.DocumentParser;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
@ -639,6 +640,25 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
((List<?>) holds).remove(0);
|
((List<?>) holds).remove(0);
|
||||||
hold = o.toString();
|
hold = o.toString();
|
||||||
}
|
}
|
||||||
|
Object deleteds = context.getProperty("deleted");
|
||||||
|
String deleted = "false";
|
||||||
|
if (deleteds instanceof List) {
|
||||||
|
Object o = ((List<?>) deleteds).get(0);
|
||||||
|
((List<?>) deleteds).remove(0);
|
||||||
|
deleted = o.toString();
|
||||||
|
}
|
||||||
|
Object enableds = context.getProperty("enabled");
|
||||||
|
String enabled = "true";
|
||||||
|
if (enableds instanceof List) {
|
||||||
|
Object o = ((List<?>) enableds).get(0);
|
||||||
|
((List<?>) enableds).remove(0);
|
||||||
|
enabled = o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
threadGroup.setAttribute("enabled", enabled);
|
||||||
|
if (BooleanUtils.toBoolean(deleted)) {
|
||||||
|
threadGroup.setAttribute("enabled", "false");
|
||||||
|
}
|
||||||
Element elementProp = document.createElement("elementProp");
|
Element elementProp = document.createElement("elementProp");
|
||||||
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
||||||
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
|
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
|
||||||
|
|
|
@ -16,6 +16,7 @@ import io.metersphere.controller.request.OrderRequest;
|
||||||
import io.metersphere.controller.request.QueryScheduleRequest;
|
import io.metersphere.controller.request.QueryScheduleRequest;
|
||||||
import io.metersphere.dto.DashboardTestDTO;
|
import io.metersphere.dto.DashboardTestDTO;
|
||||||
import io.metersphere.dto.LoadTestDTO;
|
import io.metersphere.dto.LoadTestDTO;
|
||||||
|
import io.metersphere.dto.LoadTestFileDTO;
|
||||||
import io.metersphere.dto.ScheduleDao;
|
import io.metersphere.dto.ScheduleDao;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.job.sechedule.PerformanceTestJob;
|
import io.metersphere.job.sechedule.PerformanceTestJob;
|
||||||
|
@ -38,6 +39,7 @@ import javax.annotation.Resource;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -126,21 +128,54 @@ public class PerformanceTestService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String save(SaveTestPlanRequest request, List<MultipartFile> files) {
|
public String save(SaveTestPlanRequest request, List<MultipartFile> files) {
|
||||||
if (files == null) {
|
|
||||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
|
||||||
}
|
|
||||||
checkQuota(request, true);
|
checkQuota(request, true);
|
||||||
final LoadTestWithBLOBs loadTest = saveLoadTest(request);
|
LoadTestWithBLOBs loadTest = saveLoadTest(request);
|
||||||
files.forEach(file -> {
|
|
||||||
final FileMetadata fileMetadata = fileService.saveFile(file);
|
// 新选择了一个文件,删除原来的文件
|
||||||
|
List<FileMetadata> importFiles = request.getUpdatedFileList();
|
||||||
|
List<String> importFileIds = importFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
|
||||||
|
// 导入项目里其他的文件
|
||||||
|
this.importFiles(importFileIds, loadTest.getId());
|
||||||
|
// 保存上传的问题件
|
||||||
|
this.saveUploadFiles(files, loadTest.getId());
|
||||||
|
// 直接上传了jmx,用于API导入的场景
|
||||||
|
String jmx = request.getJmx();
|
||||||
|
if (StringUtils.isNotBlank(jmx)) {
|
||||||
|
byte[] bytes = jmx.getBytes(StandardCharsets.UTF_8);
|
||||||
|
FileMetadata fileMetadata = fileService.saveFile(bytes, request.getName() + ".jmx", (long) bytes.length);
|
||||||
LoadTestFile loadTestFile = new LoadTestFile();
|
LoadTestFile loadTestFile = new LoadTestFile();
|
||||||
loadTestFile.setTestId(loadTest.getId());
|
loadTestFile.setTestId(loadTest.getId());
|
||||||
loadTestFile.setFileId(fileMetadata.getId());
|
loadTestFile.setFileId(fileMetadata.getId());
|
||||||
loadTestFileMapper.insert(loadTestFile);
|
loadTestFileMapper.insert(loadTestFile);
|
||||||
});
|
}
|
||||||
return loadTest.getId();
|
return loadTest.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveUploadFiles(List<MultipartFile> files, String testId) {
|
||||||
|
if (files != null) {
|
||||||
|
files.forEach(file -> {
|
||||||
|
final FileMetadata fileMetadata = fileService.saveFile(file);
|
||||||
|
LoadTestFile loadTestFile = new LoadTestFile();
|
||||||
|
loadTestFile.setTestId(testId);
|
||||||
|
loadTestFile.setFileId(fileMetadata.getId());
|
||||||
|
loadTestFileMapper.insert(loadTestFile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importFiles(List<String> importFileIds, String testId) {
|
||||||
|
importFileIds.forEach(fileId -> {
|
||||||
|
if (StringUtils.isBlank(fileId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileMetadata fileMetadata = fileService.copyFile(fileId);
|
||||||
|
LoadTestFile loadTestFile = new LoadTestFile();
|
||||||
|
loadTestFile.setTestId(testId);
|
||||||
|
loadTestFile.setFileId(fileMetadata.getId());
|
||||||
|
loadTestFileMapper.insert(loadTestFile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private LoadTestWithBLOBs saveLoadTest(SaveTestPlanRequest request) {
|
private LoadTestWithBLOBs saveLoadTest(SaveTestPlanRequest request) {
|
||||||
|
|
||||||
LoadTestExample example = new LoadTestExample();
|
LoadTestExample example = new LoadTestExample();
|
||||||
|
@ -183,15 +218,19 @@ public class PerformanceTestService {
|
||||||
// 相减
|
// 相减
|
||||||
List<String> deleteFileIds = ListUtils.subtract(originFileIds, updatedFileIds);
|
List<String> deleteFileIds = ListUtils.subtract(originFileIds, updatedFileIds);
|
||||||
fileService.deleteFileByIds(deleteFileIds);
|
fileService.deleteFileByIds(deleteFileIds);
|
||||||
|
// 导入项目里其他的文件
|
||||||
if (files != null) {
|
List<String> addFileIds = ListUtils.subtract(updatedFileIds, originFileIds);
|
||||||
files.forEach(file -> {
|
this.importFiles(addFileIds, request.getId());
|
||||||
final FileMetadata fileMetadata = fileService.saveFile(file);
|
this.saveUploadFiles(files, request.getId());
|
||||||
LoadTestFile loadTestFile = new LoadTestFile();
|
// 直接上传了jmx,用于API导入的场景
|
||||||
loadTestFile.setTestId(request.getId());
|
String jmx = request.getJmx();
|
||||||
loadTestFile.setFileId(fileMetadata.getId());
|
if (StringUtils.isNotBlank(jmx)) {
|
||||||
loadTestFileMapper.insert(loadTestFile);
|
byte[] bytes = jmx.getBytes(StandardCharsets.UTF_8);
|
||||||
});
|
FileMetadata fileMetadata = fileService.saveFile(bytes, request.getName() + ".jmx", (long) bytes.length);
|
||||||
|
LoadTestFile loadTestFile = new LoadTestFile();
|
||||||
|
loadTestFile.setTestId(request.getId());
|
||||||
|
loadTestFile.setFileId(fileMetadata.getId());
|
||||||
|
loadTestFileMapper.insert(loadTestFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTest.setName(request.getName());
|
loadTest.setName(request.getName());
|
||||||
|
@ -508,4 +547,14 @@ public class PerformanceTestService {
|
||||||
return Optional.of(loadTest.getNum() + 1).orElse(100001);
|
return Optional.of(loadTest.getNum() + 1).orElse(100001);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<LoadTestFileDTO> getProjectFiles(String projectId, String loadType) {
|
||||||
|
List<String> loadTypes = new ArrayList<>();
|
||||||
|
loadTypes.add(StringUtils.upperCase(loadType));
|
||||||
|
if (StringUtils.equalsIgnoreCase(loadType, "resource")) {
|
||||||
|
loadTypes.add(FileType.CSV.name());
|
||||||
|
loadTypes.add(FileType.JAR.name());
|
||||||
|
}
|
||||||
|
return extLoadTestMapper.getProjectFiles(projectId, loadTypes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,4 +169,10 @@ public class FileService {
|
||||||
public FileMetadata getFileMetadataById(String fileId) {
|
public FileMetadata getFileMetadataById(String fileId) {
|
||||||
return fileMetadataMapper.selectByPrimaryKey(fileId);
|
return fileMetadataMapper.selectByPrimaryKey(fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FileMetadata> getProjectJMXs(String projectId) {
|
||||||
|
FileMetadataExample example = new FileMetadataExample();
|
||||||
|
fileMetadataMapper.selectByExample(example);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,14 @@
|
||||||
package io.metersphere.track.request.testplan;
|
package io.metersphere.track.request.testplan;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.FileMetadata;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
public class SaveTestPlanRequest extends TestPlanRequest {
|
public class SaveTestPlanRequest extends TestPlanRequest {
|
||||||
|
private List<FileMetadata> updatedFileList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class TestPlanRequest {
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private String scenarioDefinition;
|
private String jmx;
|
||||||
|
|
||||||
private Long createTime;
|
private Long createTime;
|
||||||
|
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-collapse v-model="activeNames">
|
<el-collapse v-model="activeNames">
|
||||||
<el-collapse-item :title="threadGroup.attributes.testname" :name="index"
|
<el-collapse-item :title="threadGroup.attributes.testname" :name="index"
|
||||||
v-for="(threadGroup, index) in threadGroups"
|
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
||||||
:key="index">
|
:key="index">
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-form :inline="true">
|
<el-form :inline="true">
|
||||||
<el-form-item :label="$t('load_test.thread_num')">
|
<el-form-item :label="$t('load_test.thread_num')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:placeholder="$t('load_test.input_thread_num')"
|
:placeholder="$t('load_test.input_thread_num')"
|
||||||
v-model="threadGroup.threadNumber"
|
v-model="threadGroup.threadNumber"
|
||||||
:min="1"
|
:min="1"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br>
|
<br>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
|
@ -31,72 +31,72 @@
|
||||||
<div v-if="threadGroup.threadType === 'DURATION'">
|
<div v-if="threadGroup.threadType === 'DURATION'">
|
||||||
<el-form-item :label="$t('load_test.duration')">
|
<el-form-item :label="$t('load_test.duration')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
v-model="threadGroup.duration"
|
v-model="threadGroup.duration"
|
||||||
:min="1"
|
:min="1"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br>
|
<br>
|
||||||
<el-form-item :label="$t('load_test.rps_limit')">
|
<el-form-item :label="$t('load_test.rps_limit')">
|
||||||
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
|
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
|
||||||
|
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true "
|
:disabled="true "
|
||||||
v-model="threadGroup.rpsLimit"
|
v-model="threadGroup.rpsLimit"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
:min="1"
|
:min="1"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br>
|
<br>
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="threadGroup.duration"
|
:max="threadGroup.duration"
|
||||||
v-model="threadGroup.rampUpTime"
|
v-model="threadGroup.rampUpTime"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
|
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
||||||
v-model="threadGroup.step"
|
v-model="threadGroup.step"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
|
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="threadGroup.threadType === 'ITERATION'">
|
<div v-if="threadGroup.threadType === 'ITERATION'">
|
||||||
<el-form-item :label="$t('load_test.iterate_num')">
|
<el-form-item :label="$t('load_test.iterate_num')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
v-model="threadGroup.iterateNum"
|
v-model="threadGroup.iterateNum"
|
||||||
:min="1"
|
:min="1"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br>
|
<br>
|
||||||
<el-form-item :label="$t('load_test.rps_limit')">
|
<el-form-item :label="$t('load_test.rps_limit')">
|
||||||
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
|
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
|
||||||
|
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true || !threadGroup.rpsLimitEnable"
|
:disabled="true || !threadGroup.rpsLimitEnable"
|
||||||
v-model="threadGroup.rpsLimit"
|
v-model="threadGroup.rpsLimit"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
:min="1"
|
:min="1"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br>
|
<br>
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:min="1"
|
:min="1"
|
||||||
v-model="threadGroup.iterateRampUp"
|
v-model="threadGroup.iterateRampUp"
|
||||||
@change="calculateChart(threadGroup)"
|
@change="calculateChart(threadGroup)"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('load_test.ramp_up_time_seconds')"/>
|
<el-form-item :label="$t('load_test.ramp_up_time_seconds')"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -126,14 +126,16 @@ const RPS_LIMIT_ENABLE = "rpsLimitEnable";
|
||||||
const THREAD_TYPE = "threadType";
|
const THREAD_TYPE = "threadType";
|
||||||
const ITERATE_NUM = "iterateNum";
|
const ITERATE_NUM = "iterateNum";
|
||||||
const ITERATE_RAMP_UP = "iterateRampUpTime";
|
const ITERATE_RAMP_UP = "iterateRampUpTime";
|
||||||
|
const ENABLED = "enabled";
|
||||||
|
const DELETED = "deleted";
|
||||||
|
|
||||||
const hexToRgba = function (hex, opacity) {
|
const hexToRgba = function (hex, opacity) {
|
||||||
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
|
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
|
||||||
+ parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')';
|
+ parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')';
|
||||||
}
|
}
|
||||||
const hexToRgb = function (hex) {
|
const hexToRgb = function (hex) {
|
||||||
return 'rgb(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5))
|
return 'rgb(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5))
|
||||||
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
|
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -163,83 +165,51 @@ export default {
|
||||||
calculateLoadConfiguration: function (data) {
|
calculateLoadConfiguration: function (data) {
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
let d = data[i];
|
let d = data[i];
|
||||||
if (d instanceof Array) {
|
d.forEach(item => {
|
||||||
d.forEach(item => {
|
switch (item.key) {
|
||||||
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:
|
|
||||||
if (item.unit) {
|
|
||||||
this.threadGroups[i].duration = item.value;
|
|
||||||
} else {
|
|
||||||
this.threadGroups[i].duration = item.value * 60;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.calculateChart(this.threadGroups[i]);
|
|
||||||
} else {
|
|
||||||
switch (d.key) {
|
|
||||||
case TARGET_LEVEL:
|
case TARGET_LEVEL:
|
||||||
this.threadGroups[0].threadNumber = d.value;
|
this.threadGroups[i].threadNumber = item.value;
|
||||||
break;
|
break;
|
||||||
case RAMP_UP:
|
case RAMP_UP:
|
||||||
this.threadGroups[0].rampUpTime = d.value;
|
this.threadGroups[i].rampUpTime = item.value;
|
||||||
break;
|
break;
|
||||||
case ITERATE_RAMP_UP:
|
case ITERATE_RAMP_UP:
|
||||||
this.threadGroups[0].iterateRampUp = d.value;
|
this.threadGroups[i].iterateRampUp = item.value;
|
||||||
break;
|
break;
|
||||||
case DURATION:
|
case DURATION:
|
||||||
if (d.unit) {
|
if (item.unit) {
|
||||||
this.threadGroups[0].duration = d.value;
|
this.threadGroups[i].duration = item.value;
|
||||||
} else {
|
} else {
|
||||||
this.threadGroups[0].duration = d.value * 60;
|
this.threadGroups[i].duration = item.value * 60;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STEPS:
|
case STEPS:
|
||||||
this.threadGroups[0].step = d.value;
|
this.threadGroups[i].step = item.value;
|
||||||
break;
|
break;
|
||||||
case RPS_LIMIT:
|
case RPS_LIMIT:
|
||||||
this.threadGroups[0].rpsLimit = d.value;
|
this.threadGroups[i].rpsLimit = item.value;
|
||||||
break;
|
break;
|
||||||
case RPS_LIMIT_ENABLE:
|
case RPS_LIMIT_ENABLE:
|
||||||
this.threadGroups[0].rpsLimitEnable = d.value;
|
this.threadGroups[i].rpsLimitEnable = item.value;
|
||||||
break;
|
break;
|
||||||
case THREAD_TYPE:
|
case THREAD_TYPE:
|
||||||
this.threadGroups[0].threadType = d.value;
|
this.threadGroups[i].threadType = item.value;
|
||||||
break;
|
break;
|
||||||
case ITERATE_NUM:
|
case ITERATE_NUM:
|
||||||
this.threadGroups[0].iterateNum = d.value;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.calculateChart(this.threadGroups[0]);
|
})
|
||||||
}
|
this.calculateChart(this.threadGroups[i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLoadConfig() {
|
getLoadConfig() {
|
||||||
|
@ -307,6 +277,9 @@ export default {
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < handler.threadGroups.length; i++) {
|
for (let i = 0; i < handler.threadGroups.length; i++) {
|
||||||
|
if (handler.threadGroups[i].enabled === 'false' || handler.threadGroups[i].deleted === 'true') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let seriesData = {
|
let seriesData = {
|
||||||
name: handler.threadGroups[i].attributes.testname,
|
name: handler.threadGroups[i].attributes.testname,
|
||||||
data: [],
|
data: [],
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<el-card shadow="always" class="ms-card-index-2">
|
<el-card shadow="always" class="ms-card-index-2">
|
||||||
<span class="ms-card-data">
|
<span class="ms-card-data">
|
||||||
<span class="ms-card-data-digital">{{ avgTransactions }}</span>
|
<span class="ms-card-data-digital">{{ avgTransactions }}</span>
|
||||||
<span class="ms-card-data-unit"> Transactions/s</span>
|
<span class="ms-card-data-unit"> TPS</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="ms-card-desc">Avg.Transactions</span>
|
<span class="ms-card-desc">Avg.Transactions</span>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
class="input-with-select"
|
class="input-with-select"
|
||||||
maxlength="30" show-word-limit
|
maxlength="30" show-word-limit
|
||||||
>
|
>
|
||||||
<template slot="prepend">测试名称</template>
|
<template slot="prepend">{{ $t('load_test.name') }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" :offset="2">
|
<el-col :span="12" :offset="2">
|
||||||
|
@ -32,6 +32,7 @@
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('load_test.pressure_config')">
|
<el-tab-pane :label="$t('load_test.pressure_config')">
|
||||||
<performance-pressure-config :is-read-only="isReadOnly" :test="test" :test-id="testId"
|
<performance-pressure-config :is-read-only="isReadOnly" :test="test" :test-id="testId"
|
||||||
|
@fileChange="fileChange"
|
||||||
ref="pressureConfig" @changeActive="changeTabActive"/>
|
ref="pressureConfig" @changeActive="changeTabActive"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
|
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
|
||||||
|
@ -305,6 +306,9 @@ export default {
|
||||||
|
|
||||||
this.$set(handler, "threadGroups", threadGroups);
|
this.$set(handler, "threadGroups", threadGroups);
|
||||||
|
|
||||||
|
this.$refs.basicConfig.threadGroups = threadGroups;
|
||||||
|
this.$refs.pressureConfig.threadGroups = threadGroups;
|
||||||
|
|
||||||
threadGroups.forEach(tg => {
|
threadGroups.forEach(tg => {
|
||||||
handler.calculateChart(tg);
|
handler.calculateChart(tg);
|
||||||
})
|
})
|
||||||
|
@ -317,7 +321,6 @@ export default {
|
||||||
|
|
||||||
.testplan-config {
|
.testplan-config {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select {
|
.el-select {
|
||||||
|
|
|
@ -1,25 +1,89 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-loading="result.loading">
|
<div v-loading="result.loading">
|
||||||
<el-upload
|
<el-row type="flex" justify="space-between" align="middle">
|
||||||
accept=".jmx,.csv,.jar"
|
<h4>{{ $t('load_test.scenario_list') }}</h4>
|
||||||
drag
|
</el-row>
|
||||||
action=""
|
<el-row type="flex" justify="start" align="middle">
|
||||||
:limit="fileNumLimit"
|
<el-upload
|
||||||
multiple
|
style="padding-right: 10px;"
|
||||||
:show-file-list="false"
|
accept=".jmx"
|
||||||
:before-upload="beforeUpload"
|
action=""
|
||||||
:http-request="handleUpload"
|
:limit="fileNumLimit"
|
||||||
:on-exceed="handleExceed"
|
:show-file-list="false"
|
||||||
:disabled="isReadOnly"
|
:before-upload="beforeUploadJmx"
|
||||||
:file-list="fileList">
|
:http-request="handleUpload"
|
||||||
<i class="el-icon-upload"/>
|
:on-exceed="handleExceed"
|
||||||
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
|
:disabled="isReadOnly"
|
||||||
<template v-slot:tip>
|
:file-list="fileList">
|
||||||
<div class="el-upload__tip">{{ $t('load_test.upload_type') }}</div>
|
<ms-table-button :is-tester-permission="true" icon="el-icon-upload2"
|
||||||
</template>
|
:content="$t('load_test.upload_jmx')"/>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
|
<ms-table-button :is-tester-permission="true" icon="el-icon-circle-plus-outline"
|
||||||
|
:content="$t('load_test.load_exist_jmx')" @click="loadJMX()"/>
|
||||||
|
<ms-table-button :is-tester-permission="true" icon="el-icon-share"
|
||||||
|
@click="loadApiAutomation()"
|
||||||
|
:content="$t('load_test.load_api_automation_jmx')"/>
|
||||||
|
</el-row>
|
||||||
|
<el-table class="basic-config" :data="threadGroups.filter(tg=>tg.deleted=='false')">
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('load_test.scenario_name')">
|
||||||
|
<template v-slot:default="{row}">
|
||||||
|
{{ row.attributes.testname }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="Enable/Disable">
|
||||||
|
<template v-slot:default="{row}">
|
||||||
|
<el-switch v-model="row.enabled"
|
||||||
|
inactive-color="#DCDFE6"
|
||||||
|
active-value="true"
|
||||||
|
inactive-value="false"
|
||||||
|
:disabled="threadGroupDisable(row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="ThreadGroup">
|
||||||
|
<template v-slot:default="{row}">
|
||||||
|
{{ row.name.substring(row.name.lastIndexOf(".") + 1) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('commons.operating')">
|
||||||
|
<template v-slot:default="{row}">
|
||||||
|
<el-button :disabled="isReadOnly || threadGroupDisable(row)"
|
||||||
|
@click="handleDeleteThreadGroup(row)"
|
||||||
|
type="danger"
|
||||||
|
icon="el-icon-delete" size="mini"
|
||||||
|
circle/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
<el-table class="basic-config" :data="tableData">
|
<el-row type="flex" justify="space-between" align="middle">
|
||||||
|
<h4>{{ $t('load_test.other_resource') }}</h4>
|
||||||
|
</el-row>
|
||||||
|
<el-row type="flex" justify="start" align="middle">
|
||||||
|
<el-upload
|
||||||
|
style="padding-right: 10px;"
|
||||||
|
accept=".jar,.csv"
|
||||||
|
action=""
|
||||||
|
:limit="fileNumLimit"
|
||||||
|
multiple
|
||||||
|
:show-file-list="false"
|
||||||
|
:before-upload="beforeUploadFile"
|
||||||
|
:http-request="handleUpload"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
:disabled="isReadOnly"
|
||||||
|
:file-list="fileList">
|
||||||
|
<ms-table-button :is-tester-permission="true" icon="el-icon-upload2"
|
||||||
|
:content="$t('load_test.upload_file')"/>
|
||||||
|
</el-upload>
|
||||||
|
|
||||||
|
<ms-table-button :is-tester-permission="true" icon="el-icon-circle-plus-outline"
|
||||||
|
:content="$t('load_test.load_exist_file')" @click="loadFile()"/>
|
||||||
|
</el-row>
|
||||||
|
<el-table class="basic-config" :data="tableData.filter(f => !f.name.toUpperCase().endsWith('.JMX'))">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="name"
|
prop="name"
|
||||||
:label="$t('load_test.file_name')">
|
:label="$t('load_test.file_name')">
|
||||||
|
@ -51,15 +115,80 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog :title="$t('load_test.exist_jmx')" width="70%" :visible.sync="loadFileVisible">
|
||||||
|
|
||||||
|
<el-table class="basic-config" :data="existFiles" v-loading="projectLoadingResult.loading">
|
||||||
|
<el-table-column
|
||||||
|
prop="testName"
|
||||||
|
:label="$t('load_test.test')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
:label="$t('load_test.file_name')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="type"
|
||||||
|
:label="$t('load_test.file_type')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('load_test.last_modify_time')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<i class="el-icon-time"/>
|
||||||
|
<span class="last-modified">{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('commons.operating')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<ms-table-operator-button :is-tester-permission="true"
|
||||||
|
:tip="$t('api_test.api_import.label')"
|
||||||
|
icon="el-icon-upload"
|
||||||
|
@exec="handleImport(scope.row)"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<ms-table-pagination :change="getProjectFiles" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||||
|
:total="total"/>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog :title="$t('load_test.scenario_list')" width="60%" :visible.sync="loadApiAutomationVisible">
|
||||||
|
|
||||||
|
<el-table class="basic-config" :data="apiScenarios" v-loading="projectLoadingResult.loading">
|
||||||
|
<el-table-column
|
||||||
|
prop="num"
|
||||||
|
label="ID">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
:label="$t('load_test.scenario_name')">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('commons.operating')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<ms-table-operator-button :is-tester-permission="true"
|
||||||
|
:tip="$t('api_test.api_import.label')"
|
||||||
|
icon="el-icon-upload"
|
||||||
|
@exec="handleImportApi(scope.row)"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<ms-table-pagination :change="getProjectFiles" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||||
|
:total="total"/>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {Message} from "element-ui";
|
import {Message} from "element-ui";
|
||||||
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
|
import {findTestPlan, findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
|
||||||
|
import MsTableButton from "@/business/components/common/components/MsTableButton";
|
||||||
|
import {getCurrentProjectID} from "@/common/js/utils";
|
||||||
|
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
|
||||||
|
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PerformanceBasicConfig",
|
name: "PerformanceBasicConfig",
|
||||||
|
components: {MsTableOperatorButton, MsTablePagination, MsTableButton},
|
||||||
props: {
|
props: {
|
||||||
test: {
|
test: {
|
||||||
type: Object
|
type: Object
|
||||||
|
@ -72,6 +201,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
result: {},
|
result: {},
|
||||||
|
projectLoadingResult: {},
|
||||||
getFileMetadataPath: "/performance/file/metadata",
|
getFileMetadataPath: "/performance/file/metadata",
|
||||||
jmxDownloadPath: '/performance/file/download',
|
jmxDownloadPath: '/performance/file/download',
|
||||||
jmxDeletePath: '/performance/file/delete',
|
jmxDeletePath: '/performance/file/delete',
|
||||||
|
@ -79,6 +209,15 @@ export default {
|
||||||
tableData: [],
|
tableData: [],
|
||||||
uploadList: [],
|
uploadList: [],
|
||||||
fileNumLimit: 10,
|
fileNumLimit: 10,
|
||||||
|
threadGroups: [],
|
||||||
|
loadFileVisible: false,
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
total: 0,
|
||||||
|
existFiles: [],
|
||||||
|
loadType: 'jmx',
|
||||||
|
apiScenarios: [],
|
||||||
|
loadApiAutomationVisible: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -98,9 +237,9 @@ export default {
|
||||||
if (fileList.length > 0) {
|
if (fileList.length > 0) {
|
||||||
let file = fileList[0];
|
let file = fileList[0];
|
||||||
let jmxReader = new FileReader();
|
let jmxReader = new FileReader();
|
||||||
jmxReader.onload = function (event) {
|
jmxReader.onload = (event) => {
|
||||||
let threadGroups = findThreadGroup(event.target.result);
|
self.threadGroups = findThreadGroup(event.target.result);
|
||||||
self.$emit('fileChange', threadGroups);
|
self.$emit('fileChange', self.threadGroups);
|
||||||
};
|
};
|
||||||
jmxReader.readAsText(file);
|
jmxReader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
@ -113,11 +252,11 @@ export default {
|
||||||
this.uploadList = [];
|
this.uploadList = [];
|
||||||
this.result = this.$get(this.getFileMetadataPath + "/" + test.id, response => {
|
this.result = this.$get(this.getFileMetadataPath + "/" + test.id, response => {
|
||||||
let files = response.data;
|
let files = response.data;
|
||||||
|
|
||||||
if (!files) {
|
if (!files) {
|
||||||
Message.error({message: this.$t('load_test.related_file_not_found'), showClose: true});
|
Message.error({message: this.$t('load_test.related_file_not_found'), showClose: true});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log(files);
|
||||||
// deep copy
|
// deep copy
|
||||||
this.fileList = JSON.parse(JSON.stringify(files));
|
this.fileList = JSON.parse(JSON.stringify(files));
|
||||||
this.tableData = JSON.parse(JSON.stringify(files));
|
this.tableData = JSON.parse(JSON.stringify(files));
|
||||||
|
@ -126,12 +265,40 @@ export default {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
beforeUpload(file) {
|
deleteExistJmx: function () {
|
||||||
|
// 只能上传一个jmx
|
||||||
|
let jmxs = this.tableData.filter(f => {
|
||||||
|
let type = f.name.substring(f.name.lastIndexOf(".") + 1);
|
||||||
|
return type.toUpperCase() === 'JMX';
|
||||||
|
});
|
||||||
|
for (let i = 0; i < jmxs.length; i++) {
|
||||||
|
let index = this.tableData.indexOf(jmxs[i]);
|
||||||
|
if (index > -1) {
|
||||||
|
this.tableData.splice(index, 1);
|
||||||
|
}
|
||||||
|
let index2 = this.uploadList.indexOf(jmxs[i]);
|
||||||
|
if (index2 > -1) {
|
||||||
|
this.uploadList.splice(index2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jmxs = this.fileList.filter(f => {
|
||||||
|
let type = f.name.substring(f.name.lastIndexOf(".") + 1);
|
||||||
|
return type.toUpperCase() === 'JMX';
|
||||||
|
});
|
||||||
|
for (let i = 0; i < jmxs.length; i++) {
|
||||||
|
let index3 = this.fileList.indexOf(jmxs[i]);
|
||||||
|
if (index3 > -1) {
|
||||||
|
this.fileList.splice(index3, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUploadJmx(file) {
|
||||||
if (!this.fileValidator(file)) {
|
if (!this.fileValidator(file)) {
|
||||||
/// todo: 显示错误信息
|
/// todo: 显示错误信息
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
this.deleteExistJmx();
|
||||||
if (this.tableData.filter(f => f.name === file.name).length > 0) {
|
if (this.tableData.filter(f => f.name === file.name).length > 0) {
|
||||||
this.$error(this.$t('load_test.delete_file'));
|
this.$error(this.$t('load_test.delete_file'));
|
||||||
return false;
|
return false;
|
||||||
|
@ -141,7 +308,28 @@ export default {
|
||||||
|
|
||||||
this.tableData.push({
|
this.tableData.push({
|
||||||
name: file.name,
|
name: file.name,
|
||||||
size: file.size + ' Bytes', /// todo: 按照大小显示Byte、KB、MB等
|
size: (file.size / 1024).toFixed(2) + ' KB',
|
||||||
|
type: type.toUpperCase(),
|
||||||
|
updateTime: file.lastModified,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
beforeUploadFile(file) {
|
||||||
|
if (!this.fileValidator(file)) {
|
||||||
|
/// todo: 显示错误信息
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.tableData.filter(f => f.name === file.name).length > 0) {
|
||||||
|
this.$error(this.$t('load_test.delete_file'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let type = file.name.substring(file.name.lastIndexOf(".") + 1);
|
||||||
|
|
||||||
|
this.tableData.push({
|
||||||
|
name: file.name,
|
||||||
|
size: (file.size / 1024).toFixed(2) + ' KB',
|
||||||
type: type.toUpperCase(),
|
type: type.toUpperCase(),
|
||||||
updateTime: file.lastModified,
|
updateTime: file.lastModified,
|
||||||
});
|
});
|
||||||
|
@ -181,25 +369,116 @@ export default {
|
||||||
Message.error({message: e.message, showClose: true});
|
Message.error({message: e.message, showClose: true});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleDelete(file, index) {
|
handleImport(row) {
|
||||||
|
if (this.tableData.filter(f => f.name === row.name).length > 0) {
|
||||||
|
this.$error(this.$t('load_test.delete_file'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.loadType === 'resource') {
|
||||||
|
this.fileList.push(row);
|
||||||
|
this.tableData.push(row);
|
||||||
|
this.$success(this.$t('test_track.case.import.success'));
|
||||||
|
this.loadFileVisible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.result = this.$get('/performance/get-jmx-content/' + row.testId, (response) => {
|
||||||
|
if (response.data) {
|
||||||
|
let testPlan = findTestPlan(response.data);
|
||||||
|
testPlan.elements.forEach(e => {
|
||||||
|
if (e.attributes.name === 'TestPlan.serialize_threadgroups') {
|
||||||
|
this.serializeThreadgroups = Boolean(e.elements[0].text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.threadGroups = findThreadGroup(response.data);
|
||||||
|
this.threadGroups.forEach(tg => {
|
||||||
|
tg.options = {};
|
||||||
|
});
|
||||||
|
this.$emit('fileChange', this.threadGroups);
|
||||||
|
}
|
||||||
|
this.deleteExistJmx();
|
||||||
|
this.fileList.push(row);
|
||||||
|
this.tableData.push(row);
|
||||||
|
this.$success(this.$t('test_track.case.import.success'));
|
||||||
|
this.loadFileVisible = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
countStrToBit(str) {
|
||||||
|
let count = 0
|
||||||
|
const arr = str.split('')
|
||||||
|
arr.forEach(item => {
|
||||||
|
count += Math.ceil(item.charCodeAt().toString(2).length / 8)
|
||||||
|
})
|
||||||
|
return count
|
||||||
|
},
|
||||||
|
handleImportApi(row) {
|
||||||
|
let condition = {
|
||||||
|
projectId: getCurrentProjectID(),
|
||||||
|
ids: [row.id]
|
||||||
|
};
|
||||||
|
this.projectLoadingResult = this.$post('api/automation/export/jmx', condition, response => {
|
||||||
|
let data = response.data[0];
|
||||||
|
this.threadGroups = findThreadGroup(data.jmx);
|
||||||
|
this.threadGroups.forEach(tg => {
|
||||||
|
tg.options = {};
|
||||||
|
});
|
||||||
|
this.$emit('fileChange', this.threadGroups);
|
||||||
|
this.deleteExistJmx();
|
||||||
|
let bytes = this.countStrToBit(data.jmx);
|
||||||
|
this.fileList.push({
|
||||||
|
name: this.test.name + ".jmx",
|
||||||
|
size: bytes,
|
||||||
|
type: "JMX",
|
||||||
|
updateTime: new Date().getTime(),
|
||||||
|
});
|
||||||
|
this.tableData.push({
|
||||||
|
name: this.test.name + ".jmx",
|
||||||
|
size: (bytes / 1024).toFixed(2) + ' KB',
|
||||||
|
type: "JMX",
|
||||||
|
updateTime: new Date().getTime(),
|
||||||
|
});
|
||||||
|
this.test.jmx = data.jmx;
|
||||||
|
this.$success(this.$t('test_track.case.import.success'));
|
||||||
|
this.loadApiAutomationVisible = false;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDelete(file) {
|
||||||
this.$alert(this.$t('load_test.delete_file_confirm') + file.name + "?", '', {
|
this.$alert(this.$t('load_test.delete_file_confirm') + file.name + "?", '', {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
callback: (action) => {
|
callback: (action) => {
|
||||||
if (action === 'confirm') {
|
if (action === 'confirm') {
|
||||||
this._handleDelete(file, index);
|
this._handleDelete(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_handleDelete(file, index) {
|
_handleDelete(file) {
|
||||||
this.fileList.splice(index, 1);
|
let index = this.fileList.findIndex(f => f.name === file.name);
|
||||||
this.tableData.splice(index, 1);
|
if (index > -1) {
|
||||||
|
this.fileList.splice(index, 1);
|
||||||
|
}
|
||||||
|
index = this.tableData.findIndex(f => f.name === file.name);
|
||||||
|
if (index > -1) {
|
||||||
|
this.tableData.splice(index, 1);
|
||||||
|
}
|
||||||
//
|
//
|
||||||
let i = this.uploadList.findIndex(upLoadFile => upLoadFile.name === file.name);
|
let i = this.uploadList.findIndex(upLoadFile => upLoadFile.name === file.name);
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
this.uploadList.splice(i, 1);
|
this.uploadList.splice(i, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
handleDeleteThreadGroup(tg) {
|
||||||
|
this.$alert(this.$t('load_test.delete_threadgroup_confirm') + tg.attributes.testname + "?", '', {
|
||||||
|
confirmButtonText: this.$t('commons.confirm'),
|
||||||
|
callback: (action) => {
|
||||||
|
if (action === 'confirm') {
|
||||||
|
tg.deleted = 'true';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
threadGroupDisable(row) {
|
||||||
|
return this.threadGroups.filter(tg => tg.enabled == 'true').length === 1 && row.enabled == 'true';
|
||||||
|
},
|
||||||
handleExceed() {
|
handleExceed() {
|
||||||
this.$error(this.$t('load_test.file_size_limit'));
|
this.$error(this.$t('load_test.file_size_limit'));
|
||||||
},
|
},
|
||||||
|
@ -210,6 +489,39 @@ export default {
|
||||||
updatedFileList() {
|
updatedFileList() {
|
||||||
return this.fileList;// 表示修改了已经上传的文件列表
|
return this.fileList;// 表示修改了已经上传的文件列表
|
||||||
},
|
},
|
||||||
|
loadJMX() {
|
||||||
|
this.loadFileVisible = true;
|
||||||
|
this.loadType = "jmx";
|
||||||
|
this.getProjectFiles();
|
||||||
|
},
|
||||||
|
loadFile() {
|
||||||
|
this.loadFileVisible = true;
|
||||||
|
this.loadType = "resource";
|
||||||
|
this.getProjectFiles();
|
||||||
|
},
|
||||||
|
loadApiAutomation() {
|
||||||
|
this.loadApiAutomationVisible = true;
|
||||||
|
this.getProjectScenarios();
|
||||||
|
},
|
||||||
|
getProjectFiles() {
|
||||||
|
this.projectLoadingResult = this.$get('/performance/project/' + this.loadType + '/' + getCurrentProjectID() + "/" + this.currentPage + "/" + this.pageSize, res => {
|
||||||
|
let data = res.data;
|
||||||
|
this.total = data.itemCount;
|
||||||
|
this.existFiles = data.listObject;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getProjectScenarios() {
|
||||||
|
let condition = {
|
||||||
|
projectId: getCurrentProjectID(),
|
||||||
|
filters: {status: ["Prepare", "Underway", "Completed"]}
|
||||||
|
}
|
||||||
|
this.projectLoadingResult = this.$post('/api/automation/list/' + this.currentPage + "/" + this.pageSize, condition, res => {
|
||||||
|
let data = res.data;
|
||||||
|
this.total = data.itemCount;
|
||||||
|
this.apiScenarios = data.listObject;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
validConfig() {
|
validConfig() {
|
||||||
let newJmxNum = 0, oldJmxNum = 0, newCsvNum = 0, oldCsvNum = 0, newJarNum = 0, oldJarNum = 0;
|
let newJmxNum = 0, oldJmxNum = 0, newCsvNum = 0, oldCsvNum = 0, newJarNum = 0, oldJarNum = 0;
|
||||||
if (this.uploadList.length > 0) {
|
if (this.uploadList.length > 0) {
|
||||||
|
@ -246,6 +558,10 @@ export default {
|
||||||
this.$error(this.$t('load_test.jmx_is_null'));
|
this.$error(this.$t('load_test.jmx_is_null'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (this.threadGroups.filter(tg => tg.attributes.enabled == 'true').length === 0) {
|
||||||
|
this.$error(this.$t('load_test.threadgroup_at_least_one'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -260,4 +576,8 @@ export default {
|
||||||
.last-modified {
|
.last-modified {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-dialog >>> .el-dialog__body {
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-collapse v-model="activeNames">
|
<el-collapse v-model="activeNames">
|
||||||
<el-collapse-item :title="threadGroup.attributes.testname" :name="index"
|
<el-collapse-item :title="threadGroup.attributes.testname" :name="index"
|
||||||
v-for="(threadGroup, index) in threadGroups"
|
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
||||||
:key="index">
|
:key="index">
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-form :inline="true">
|
<el-form :inline="true">
|
||||||
|
@ -140,6 +140,8 @@ const RPS_LIMIT_ENABLE = "rpsLimitEnable";
|
||||||
const HOLD = "Hold";
|
const HOLD = "Hold";
|
||||||
const THREAD_TYPE = "threadType";
|
const THREAD_TYPE = "threadType";
|
||||||
const ITERATE_NUM = "iterateNum";
|
const ITERATE_NUM = "iterateNum";
|
||||||
|
const ENABLED = "enabled";
|
||||||
|
const DELETED = "deleted";
|
||||||
|
|
||||||
const hexToRgba = function (hex, opacity) {
|
const hexToRgba = function (hex, opacity) {
|
||||||
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
|
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
|
||||||
|
@ -221,90 +223,57 @@ export default {
|
||||||
let data = JSON.parse(response.data);
|
let data = JSON.parse(response.data);
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
let d = data[i];
|
let d = data[i];
|
||||||
if (d instanceof Array) {
|
d.forEach(item => {
|
||||||
d.forEach(item => {
|
switch (item.key) {
|
||||||
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:
|
|
||||||
if (item.unit) {
|
|
||||||
this.threadGroups[i].duration = item.value;
|
|
||||||
} else {
|
|
||||||
this.threadGroups[i].duration = item.value * 60;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
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 {
|
|
||||||
switch (d.key) {
|
|
||||||
case TARGET_LEVEL:
|
case TARGET_LEVEL:
|
||||||
this.threadGroups[0].threadNumber = d.value;
|
this.threadGroups[i].threadNumber = item.value;
|
||||||
break;
|
break;
|
||||||
case RAMP_UP:
|
case RAMP_UP:
|
||||||
this.threadGroups[0].rampUpTime = d.value;
|
this.threadGroups[i].rampUpTime = item.value;
|
||||||
break;
|
break;
|
||||||
case ITERATE_RAMP_UP:
|
case ITERATE_RAMP_UP:
|
||||||
this.threadGroups[0].iterateRampUp = d.value;
|
this.threadGroups[i].iterateRampUp = item.value;
|
||||||
break;
|
break;
|
||||||
case DURATION:
|
case DURATION:
|
||||||
if (d.unit) {
|
if (item.unit) {
|
||||||
this.threadGroups[0].duration = d.value;
|
this.threadGroups[i].duration = item.value;
|
||||||
} else {
|
} else {
|
||||||
this.threadGroups[0].duration = d.value * 60;
|
this.threadGroups[i].duration = item.value * 60;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STEPS:
|
case STEPS:
|
||||||
this.threadGroups[0].step = d.value;
|
this.threadGroups[i].step = item.value;
|
||||||
break;
|
break;
|
||||||
case RPS_LIMIT:
|
case RPS_LIMIT:
|
||||||
this.threadGroups[0].rpsLimit = d.value;
|
this.threadGroups[i].rpsLimit = item.value;
|
||||||
break;
|
break;
|
||||||
case RPS_LIMIT_ENABLE:
|
case RPS_LIMIT_ENABLE:
|
||||||
this.threadGroups[0].rpsLimitEnable = d.value;
|
this.threadGroups[i].rpsLimitEnable = item.value;
|
||||||
break;
|
break;
|
||||||
case THREAD_TYPE:
|
case THREAD_TYPE:
|
||||||
this.threadGroups[0].threadType = d.value;
|
this.threadGroups[i].threadType = item.value;
|
||||||
break;
|
break;
|
||||||
case ITERATE_NUM:
|
case ITERATE_NUM:
|
||||||
this.threadGroups[0].iterateNum = d.value;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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[i], "threadType", this.threadGroups[i].threadType || 'DURATION');
|
||||||
this.$set(this.threadGroups[0], "iterateRampUp", this.threadGroups[0].iterateRampUp || 10);
|
this.$set(this.threadGroups[i], "iterateNum", this.threadGroups[i].iterateNum || 1);
|
||||||
this.calculateChart(this.threadGroups[0]);
|
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.calculateChart(this.threadGroups[i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
this.calculateTotalChart();
|
this.calculateTotalChart();
|
||||||
}
|
}
|
||||||
|
@ -324,6 +293,7 @@ export default {
|
||||||
this.threadGroups.forEach(tg => {
|
this.threadGroups.forEach(tg => {
|
||||||
tg.options = {};
|
tg.options = {};
|
||||||
});
|
});
|
||||||
|
this.$emit('fileChange', this.threadGroups);
|
||||||
this.getLoadConfig();
|
this.getLoadConfig();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -355,6 +325,9 @@ export default {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let i = 0; i < handler.threadGroups.length; i++) {
|
for (let i = 0; i < handler.threadGroups.length; i++) {
|
||||||
|
if (handler.threadGroups[i].enabled === 'false' || handler.threadGroups[i].deleted === 'true') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let seriesData = {
|
let seriesData = {
|
||||||
name: handler.threadGroups[i].attributes.testname,
|
name: handler.threadGroups[i].attributes.testname,
|
||||||
data: [],
|
data: [],
|
||||||
|
@ -560,6 +533,8 @@ export default {
|
||||||
{key: THREAD_TYPE, value: this.threadGroups[i].threadType},
|
{key: THREAD_TYPE, value: this.threadGroups[i].threadType},
|
||||||
{key: ITERATE_NUM, value: this.threadGroups[i].iterateNum},
|
{key: ITERATE_NUM, value: this.threadGroups[i].iterateNum},
|
||||||
{key: ITERATE_RAMP_UP, value: this.threadGroups[i].iterateRampUp},
|
{key: ITERATE_RAMP_UP, value: this.threadGroups[i].iterateRampUp},
|
||||||
|
{key: ENABLED, value: this.threadGroups[i].enabled},
|
||||||
|
{key: DELETED, value: this.threadGroups[i].deleted},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -5,8 +5,17 @@ let travel = function (elements, threadGroups) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let element of elements) {
|
for (let element of elements) {
|
||||||
if (element.name === 'ThreadGroup') {
|
switch (element.name) {
|
||||||
threadGroups.push(element);
|
case "ThreadGroup":
|
||||||
|
case "kg.apc.jmeter.threads.UltimateThreadGroup":
|
||||||
|
case "com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup":
|
||||||
|
case "com.blazemeter.jmeter.threads.arrivals.FreeFormArrivalsThreadGroup":
|
||||||
|
case "com.blazemeter.jmeter.threads.arrivals.ArrivalsThreadGroup":
|
||||||
|
case "com.octoperf.jmeter.OctoPerfThreadGroup":
|
||||||
|
threadGroups.push(element);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
travel(element.elements, threadGroups)
|
travel(element.elements, threadGroups)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +25,10 @@ export function findThreadGroup(jmxContent) {
|
||||||
let jmxJson = JSON.parse(xml2json(jmxContent));
|
let jmxJson = JSON.parse(xml2json(jmxContent));
|
||||||
let threadGroups = [];
|
let threadGroups = [];
|
||||||
travel(jmxJson.elements, threadGroups);
|
travel(jmxJson.elements, threadGroups);
|
||||||
|
threadGroups.forEach(tg => {
|
||||||
|
tg.deleted = 'false';
|
||||||
|
tg.enabled = tg.attributes.enabled;
|
||||||
|
})
|
||||||
return threadGroups;
|
return threadGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -420,6 +420,8 @@ export default {
|
||||||
delete_batch_confirm: 'Confirm batch delete report',
|
delete_batch_confirm: 'Confirm batch delete report',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
|
test: 'Test',
|
||||||
|
name: 'Test Name',
|
||||||
same_project_test: 'Only tests within the same project can be run',
|
same_project_test: 'Only tests within the same project can be run',
|
||||||
run: 'One click operation',
|
run: 'One click operation',
|
||||||
operating: 'Operating',
|
operating: 'Operating',
|
||||||
|
@ -488,7 +490,18 @@ export default {
|
||||||
user_name: 'Creator',
|
user_name: 'Creator',
|
||||||
special_characters_are_not_supported: 'Test name does not support special characters',
|
special_characters_are_not_supported: 'Test name does not support special characters',
|
||||||
pressure_config_params_is_empty: 'Pressure configuration parameters cannot be empty!',
|
pressure_config_params_is_empty: 'Pressure configuration parameters cannot be empty!',
|
||||||
schedule_tip: 'The interval must not be less than the pressure measuring time'
|
schedule_tip: 'The interval must not be less than the pressure measuring time',
|
||||||
|
delete_threadgroup_confirm: 'Confirm delete scenario: ',
|
||||||
|
scenario_list: 'Scenario List',
|
||||||
|
scenario_name: 'Scenario Name',
|
||||||
|
upload_jmx: 'Upload JMX',
|
||||||
|
exist_jmx: 'Existed Files',
|
||||||
|
other_resource: 'Other Files',
|
||||||
|
upload_file: 'Upload Files',
|
||||||
|
load_exist_file: 'Load Project Files',
|
||||||
|
load_exist_jmx: 'Load Project JMX',
|
||||||
|
threadgroup_at_least_one: 'At least one ThreadGroup is enabled',
|
||||||
|
load_api_automation_jmx: 'Import API automation scenario',
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
creator: "Creator",
|
creator: "Creator",
|
||||||
|
@ -605,7 +618,7 @@ export default {
|
||||||
edit_time_Reverse_order: "From back to front by update time",
|
edit_time_Reverse_order: "From back to front by update time",
|
||||||
request_method: "Request method",
|
request_method: "Request method",
|
||||||
request_interface: "Request interface",
|
request_interface: "Request interface",
|
||||||
search_by_api_name : "Search by api name",
|
search_by_api_name: "Search by api name",
|
||||||
request_info: "Request info",
|
request_info: "Request info",
|
||||||
request_head: "Request head",
|
request_head: "Request head",
|
||||||
request_param: "Param",
|
request_param: "Param",
|
||||||
|
@ -615,7 +628,7 @@ export default {
|
||||||
response_head: "Response head",
|
response_head: "Response head",
|
||||||
response_body: "Response body",
|
response_body: "Response body",
|
||||||
response_code: "Response code",
|
response_code: "Response code",
|
||||||
table_coloum:{
|
table_coloum: {
|
||||||
name: "name",
|
name: "name",
|
||||||
value: "value",
|
value: "value",
|
||||||
is_required: "Is it required",
|
is_required: "Is it required",
|
||||||
|
|
|
@ -418,6 +418,8 @@ export default {
|
||||||
delete_batch_confirm: '确认批量删除报告',
|
delete_batch_confirm: '确认批量删除报告',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
|
test: '测试',
|
||||||
|
name: '测试名称',
|
||||||
same_project_test: '只能运行同一项目内的测试',
|
same_project_test: '只能运行同一项目内的测试',
|
||||||
already_exists: '测试名称不能重复',
|
already_exists: '测试名称不能重复',
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
|
@ -487,7 +489,18 @@ export default {
|
||||||
user_name: '创建人',
|
user_name: '创建人',
|
||||||
special_characters_are_not_supported: '测试名称不支持特殊字符',
|
special_characters_are_not_supported: '测试名称不支持特殊字符',
|
||||||
pressure_config_params_is_empty: '压力配置参数不能为空!',
|
pressure_config_params_is_empty: '压力配置参数不能为空!',
|
||||||
schedule_tip: '间隔时间不能小于压测时长'
|
schedule_tip: '间隔时间不能小于压测时长',
|
||||||
|
delete_threadgroup_confirm: '确认删除场景',
|
||||||
|
scenario_list: '场景列表',
|
||||||
|
scenario_name: "场景名称",
|
||||||
|
upload_jmx: '上传 JMX 文件',
|
||||||
|
exist_jmx: '已存在的文件',
|
||||||
|
other_resource: '其他资源',
|
||||||
|
upload_file: '上传新文件',
|
||||||
|
load_exist_file: '加载已有文件',
|
||||||
|
load_exist_jmx: '加载已有 JMX 文件',
|
||||||
|
threadgroup_at_least_one: '至少启用一个线程组',
|
||||||
|
load_api_automation_jmx: '引用接口自动化场景',
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
creator: "创建人",
|
creator: "创建人",
|
||||||
|
@ -606,7 +619,7 @@ export default {
|
||||||
edit_time_Reverse_order: "按更新时间从后到前",
|
edit_time_Reverse_order: "按更新时间从后到前",
|
||||||
request_method: "请求方式",
|
request_method: "请求方式",
|
||||||
request_interface: "请求接口",
|
request_interface: "请求接口",
|
||||||
search_by_api_name : "名称搜索",
|
search_by_api_name: "名称搜索",
|
||||||
request_info: "请求信息",
|
request_info: "请求信息",
|
||||||
request_head: "请求头",
|
request_head: "请求头",
|
||||||
request_param: "参数",
|
request_param: "参数",
|
||||||
|
@ -616,7 +629,7 @@ export default {
|
||||||
response_head: "响应头",
|
response_head: "响应头",
|
||||||
response_body: "响应体",
|
response_body: "响应体",
|
||||||
response_code: "响应码",
|
response_code: "响应码",
|
||||||
table_coloum:{
|
table_coloum: {
|
||||||
name: "名称",
|
name: "名称",
|
||||||
value: "值",
|
value: "值",
|
||||||
is_required: "是否必填",
|
is_required: "是否必填",
|
||||||
|
|
|
@ -418,6 +418,8 @@ export default {
|
||||||
delete_batch_confirm: '確認批量刪除報告',
|
delete_batch_confirm: '確認批量刪除報告',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
|
test: '測試',
|
||||||
|
name: '測試名稱',
|
||||||
same_project_test: '只能運行同壹項目內的測試',
|
same_project_test: '只能運行同壹項目內的測試',
|
||||||
already_exists: '測試名稱不能重復',
|
already_exists: '測試名稱不能重復',
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
|
@ -487,7 +489,18 @@ export default {
|
||||||
user_name: '創建人',
|
user_name: '創建人',
|
||||||
special_characters_are_not_supported: '測試名稱不支持特殊字符',
|
special_characters_are_not_supported: '測試名稱不支持特殊字符',
|
||||||
pressure_config_params_is_empty: '壓力配置參數不能為空!',
|
pressure_config_params_is_empty: '壓力配置參數不能為空!',
|
||||||
schedule_tip: '間隔時間不能小於壓測時長'
|
schedule_tip: '間隔時間不能小於壓測時長',
|
||||||
|
delete_threadgroup_confirm: '確認刪除場景: ',
|
||||||
|
scenario_list: '場景列表',
|
||||||
|
scenario_name: '場景名稱',
|
||||||
|
upload_jmx: '上傳 JMX文件',
|
||||||
|
exist_jmx: '已存在的文件',
|
||||||
|
other_resource: '其他資源',
|
||||||
|
upload_file: '上傳新文件',
|
||||||
|
load_exist_file: '加載已有文件',
|
||||||
|
load_exist_jmx: '加載已有 JMX 文件',
|
||||||
|
threadgroup_at_least_one: '至少啟用一個線程組',
|
||||||
|
load_api_automation_jmx: '引用接口自動化場景',
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
creator: "創建人",
|
creator: "創建人",
|
||||||
|
@ -605,7 +618,7 @@ export default {
|
||||||
edit_time_Reverse_order: "按更新時間從後到前",
|
edit_time_Reverse_order: "按更新時間從後到前",
|
||||||
request_method: "請求方式",
|
request_method: "請求方式",
|
||||||
request_interface: "請求接口e",
|
request_interface: "請求接口e",
|
||||||
search_by_api_name : "API名稱搜索",
|
search_by_api_name: "API名稱搜索",
|
||||||
request_info: "請求信息",
|
request_info: "請求信息",
|
||||||
request_head: "請求頭",
|
request_head: "請求頭",
|
||||||
request_param: "參數",
|
request_param: "參數",
|
||||||
|
@ -615,7 +628,7 @@ export default {
|
||||||
response_head: "響應頭",
|
response_head: "響應頭",
|
||||||
response_body: "響應體",
|
response_body: "響應體",
|
||||||
response_code: "響應碼",
|
response_code: "響應碼",
|
||||||
table_coloum:{
|
table_coloum: {
|
||||||
name: "名稱",
|
name: "名稱",
|
||||||
value: "值",
|
value: "值",
|
||||||
is_required: "是否必填",
|
is_required: "是否必填",
|
||||||
|
|
Loading…
Reference in New Issue