feat(接口自动化): 修改资源池执行方式,由主动推送数据改为被动拉取。
This commit is contained in:
parent
5bbee94e00
commit
b75e52122a
|
@ -0,0 +1,39 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.service.ApiJmeterFileService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/jmeter")
|
||||
public class ApiJmeterFileController {
|
||||
|
||||
@Resource
|
||||
private ApiJmeterFileService apiJmeterFileService;
|
||||
|
||||
@GetMapping("download")
|
||||
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode, @RequestParam("testPlanScenarioId") String testPlanScenarioId) {
|
||||
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode,testId, reportId, testPlanScenarioId);
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + testId + ".zip\"")
|
||||
.body(bytes);
|
||||
}
|
||||
|
||||
@GetMapping("download/jar")
|
||||
public ResponseEntity<byte[]> downloadJmeterFiles() {
|
||||
byte[] bytes = apiJmeterFileService.downloadJmeterJar();
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + UUID.randomUUID().toString() + ".zip\"")
|
||||
.body(bytes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.api.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class RunModeDataDTO {
|
||||
// 执行HashTree
|
||||
private HashTree hashTree;
|
||||
// 测试场景/测试用例
|
||||
private String testId;
|
||||
// 报告id
|
||||
private String reportId;
|
||||
public RunModeDataDTO(String testId,String reportId) {
|
||||
this.testId = testId;
|
||||
this.reportId = reportId;
|
||||
}
|
||||
|
||||
public RunModeDataDTO(HashTree hashTree,String reportId) {
|
||||
this.hashTree = hashTree;
|
||||
this.reportId = reportId;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import lombok.Setter;
|
|||
@Setter
|
||||
public class RunRequest {
|
||||
private String testId;
|
||||
private String url;
|
||||
private String userId;
|
||||
private boolean isDebug;
|
||||
private String runMode;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package io.metersphere.api.dto.definition;
|
||||
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class BatchRunDefinitionRequest {
|
||||
private String id;
|
||||
|
||||
private List<String> planIds;
|
||||
|
||||
private RunModeConfig config;
|
||||
|
||||
}
|
|
@ -40,8 +40,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
|
||||
public final static String TEST_ID = "ms.test.id";
|
||||
|
||||
public final static String TEST_REPORT_ID = "ms.test.report.name";
|
||||
|
||||
private final static String THREAD_SPLIT = " ";
|
||||
|
||||
private final static String ID_SPLIT = "-";
|
||||
|
@ -76,8 +74,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
private String testId;
|
||||
|
||||
private String debugReportId;
|
||||
// 只有合并报告是这个有值
|
||||
private String setReportId;
|
||||
|
||||
//获得控制台内容
|
||||
private PrintStream oldPrintStream = System.out;
|
||||
|
@ -156,8 +152,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
TestResult testResult = new TestResult();
|
||||
testResult.setTestId(testId);
|
||||
testResult.setTotal(queue.size());
|
||||
testResult.setSetReportId(this.setReportId);
|
||||
testResult.setConsole(getConsole());
|
||||
testResult.setConsole(getConsole());
|
||||
|
||||
// 一个脚本里可能包含多个场景(ThreadGroup),所以要区分开,key: 场景Id
|
||||
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
||||
|
@ -506,7 +501,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
|
||||
private void setParam(BackendListenerContext context) {
|
||||
this.testId = context.getParameter(TEST_ID);
|
||||
this.setReportId = context.getParameter(TEST_REPORT_ID);
|
||||
this.runMode = context.getParameter("runMode");
|
||||
this.debugReportId = context.getParameter("debugReportId");
|
||||
if (StringUtils.isBlank(this.runMode)) {
|
||||
|
|
|
@ -3,13 +3,11 @@ package io.metersphere.api.jmeter;
|
|||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.RunRequest;
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import io.metersphere.api.service.ApiScenarioReportService;
|
||||
import io.metersphere.base.domain.JarConfig;
|
||||
import io.metersphere.base.domain.TestResource;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.RunModeConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.*;
|
||||
import io.metersphere.config.JmeterProperties;
|
||||
|
@ -31,13 +29,8 @@ import org.apache.jorphan.collections.HashTree;
|
|||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
@ -47,7 +40,10 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class JMeterService {
|
||||
|
@ -125,10 +121,6 @@ public class JMeterService {
|
|||
BackendListener backendListener = new BackendListener();
|
||||
backendListener.setName(testId);
|
||||
Arguments arguments = new Arguments();
|
||||
if (config != null && config.getMode().equals(RunModeConstants.SERIAL.toString()) && config.getReportType().equals(RunModeConstants.SET_REPORT.toString())) {
|
||||
arguments.addArgument(APIBackendListenerClient.TEST_REPORT_ID, config.getReportId());
|
||||
|
||||
}
|
||||
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
|
||||
if (StringUtils.isNotBlank(runMode)) {
|
||||
arguments.addArgument("runMode", runMode);
|
||||
|
@ -141,6 +133,16 @@ public class JMeterService {
|
|||
testPlan.add(testPlan.getArray()[0], backendListener);
|
||||
}
|
||||
|
||||
public void addBackendListener(String testId, HashTree testPlan) {
|
||||
BackendListener backendListener = new BackendListener();
|
||||
backendListener.setName(testId);
|
||||
Arguments arguments = new Arguments();
|
||||
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
|
||||
backendListener.setArguments(arguments);
|
||||
backendListener.setClassname(APIBackendListenerClient.class.getCanonicalName());
|
||||
testPlan.add(testPlan.getArray()[0], backendListener);
|
||||
}
|
||||
|
||||
public void runDefinition(String testId, HashTree testPlan, String debugReportId, String runMode) {
|
||||
try {
|
||||
init();
|
||||
|
@ -198,7 +200,7 @@ public class JMeterService {
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] fileToByte(File tradeFile) {
|
||||
public byte[] fileToByte(File tradeFile) {
|
||||
byte[] buffer = null;
|
||||
try (FileInputStream fis = new FileInputStream(tradeFile);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();) {
|
||||
|
@ -213,7 +215,7 @@ public class JMeterService {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
private List<Object> getZipJar() {
|
||||
public List<Object> getZipJar() {
|
||||
List<Object> jarFiles = new LinkedList<>();
|
||||
// jar 包
|
||||
JarConfigService jarConfigService = CommonBeanFactory.getBean(JarConfigService.class);
|
||||
|
@ -249,7 +251,7 @@ public class JMeterService {
|
|||
return jarFiles;
|
||||
}
|
||||
|
||||
private List<Object> getJar() {
|
||||
public List<Object> getJar() {
|
||||
List<Object> jarFiles = new LinkedList<>();
|
||||
// jar 包
|
||||
JarConfigService jarConfigService = CommonBeanFactory.getBean(JarConfigService.class);
|
||||
|
@ -280,7 +282,7 @@ public class JMeterService {
|
|||
return jarFiles;
|
||||
}
|
||||
|
||||
private List<Object> getMultipartFiles(HashTree hashTree) {
|
||||
public List<Object> getMultipartFiles(HashTree hashTree) {
|
||||
List<Object> multipartFiles = new LinkedList<>();
|
||||
// 获取附件
|
||||
List<BodyFile> files = new LinkedList<>();
|
||||
|
@ -306,12 +308,7 @@ public class JMeterService {
|
|||
return multipartFiles;
|
||||
}
|
||||
|
||||
public void runTest(String testId, HashTree hashTree, String runMode, boolean isDebug, RunModeConfig config) {
|
||||
// 获取JMX使用到的附件
|
||||
List<Object> multipartFiles = getMultipartFiles(hashTree);
|
||||
// 获取JAR
|
||||
List<Object> jarFiles = getJar();
|
||||
|
||||
public void runTest(String testId, String reportId, String runMode, String testPlanScenarioId, RunModeConfig config) {
|
||||
// 获取可以执行的资源池
|
||||
String resourcePoolId = config.getResourcePoolId();
|
||||
TestResource testResource = resourcePoolCalculation.getPool(resourcePoolId);
|
||||
|
@ -327,54 +324,26 @@ public class JMeterService {
|
|||
if (baseInfo != null) {
|
||||
metersphereUrl = baseInfo.getUrl();
|
||||
}
|
||||
// 检查≈地址是否正确
|
||||
String jmeterPingUrl = metersphereUrl + "/jmeter/ping";
|
||||
// docker 不能从 localhost 中下载文件
|
||||
if (StringUtils.contains(metersphereUrl, "http://localhost")
|
||||
|| !UrlTestUtils.testUrlWithTimeOut(jmeterPingUrl, 1000)) {
|
||||
MSException.throwException(Translator.get("run_load_test_file_init_error"));
|
||||
}
|
||||
|
||||
String uri = String.format(BASE_URL + "/jmeter/api/run", nodeIp, port);
|
||||
try {
|
||||
File file = new File(FileUtils.BODY_FILE_DIR + "/tmp");
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
RunRequest runRequest = new RunRequest();
|
||||
runRequest.setTestId(testId);
|
||||
runRequest.setDebug(isDebug);
|
||||
metersphereUrl += "/api/jmeter/download?testId=" + testId + "&reportId=" + reportId + "&testPlanScenarioId" + "&runMode=" + runMode;
|
||||
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
|
||||
metersphereUrl += "=" + testPlanScenarioId;
|
||||
}
|
||||
runRequest.setUrl(metersphereUrl);
|
||||
runRequest.setRunMode(runMode);
|
||||
runRequest.setConfig(config);
|
||||
runRequest.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
|
||||
runRequest.setJmx(new MsTestPlan().getJmx(hashTree));
|
||||
MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>();
|
||||
if (CollectionUtils.isEmpty(multipartFiles)) {
|
||||
multipartFiles.add(new FileSystemResource(file));
|
||||
}
|
||||
if (CollectionUtils.isEmpty(jarFiles)) {
|
||||
jarFiles.add(new FileSystemResource(file));
|
||||
}
|
||||
postParameters.put("files", multipartFiles);
|
||||
postParameters.put("jarFiles", jarFiles);
|
||||
postParameters.add("request", JSON.toJSONString(runRequest));
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN));
|
||||
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(postParameters, headers);
|
||||
|
||||
ResponseEntity<String> result = restTemplate.postForEntity(uri, request, String.class);
|
||||
String uri = String.format(BASE_URL + "/jmeter/api/start", nodeIp, port);
|
||||
ResponseEntity<String> result = restTemplate.postForEntity(uri, runRequest, String.class);
|
||||
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
|
||||
// 清理零时报告
|
||||
ApiScenarioReportService apiScenarioReportService = CommonBeanFactory.getBean(ApiScenarioReportService.class);
|
||||
apiScenarioReportService.delete(testId);
|
||||
apiScenarioReportService.delete(reportId);
|
||||
MSException.throwException("执行失败:" + result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
MSException.throwException("Please check node-controller status.");
|
||||
MSException.throwException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@ public class TestResult {
|
|||
|
||||
private String testId;
|
||||
|
||||
private String setReportId;
|
||||
|
||||
private int scenarioTotal;
|
||||
|
||||
private int scenarioSuccess;
|
||||
|
|
|
@ -776,7 +776,7 @@ public class ApiAutomationService {
|
|||
}
|
||||
}
|
||||
|
||||
private HashTree generateHashTree(ApiScenarioWithBLOBs item, String reportId, Map<String, String> planEnvMap) {
|
||||
public HashTree generateHashTree(ApiScenarioWithBLOBs item, String reportId, Map<String, String> planEnvMap) {
|
||||
HashTree jmeterHashTree = new HashTree();
|
||||
MsTestPlan testPlan = new MsTestPlan();
|
||||
testPlan.setHashTree(new LinkedList<>());
|
||||
|
@ -903,7 +903,7 @@ public class ApiAutomationService {
|
|||
request.setTriggerMode(ReportTriggerMode.MANUAL.name());
|
||||
}
|
||||
String reportId = request.getId();
|
||||
Map<APIScenarioReportResult, HashTree> map = new LinkedHashMap<>();
|
||||
Map<APIScenarioReportResult, RunModeDataDTO> map = new LinkedHashMap<>();
|
||||
List<String> scenarioIds = new ArrayList<>();
|
||||
StringBuilder scenarioNames = new StringBuilder();
|
||||
// 按照场景执行
|
||||
|
@ -928,19 +928,23 @@ public class ApiAutomationService {
|
|||
if (request.isTestPlanScheduleJob()) {
|
||||
String savedScenarioId = testPlanScenarioId + ":" + request.getTestPlanReportId();
|
||||
report = createScenarioReport(reportId, savedScenarioId, item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
} else {
|
||||
report = createScenarioReport(reportId, testPlanScenarioId, item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
}
|
||||
} else {
|
||||
report = createScenarioReport(reportId, ExecuteType.Marge.name().equals(request.getExecuteType()) ? serialReportId : item.getId(), item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
}
|
||||
try {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(item, reportId, planEnvMap);
|
||||
map.put(report, hashTree);
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
map.put(report, new RunModeDataDTO(item.getId(), report.getId()));
|
||||
} else {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(item, reportId, planEnvMap);
|
||||
map.put(report, new RunModeDataDTO(hashTree, report.getId()));
|
||||
}
|
||||
scenarioIds.add(item.getId());
|
||||
scenarioNames.append(item.getName()).append(",");
|
||||
// 重置报告ID
|
||||
|
@ -953,7 +957,7 @@ public class ApiAutomationService {
|
|||
if (request.getConfig() != null && StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString()) && StringUtils.isNotEmpty(request.getConfig().getReportName())) {
|
||||
request.getConfig().setReportId(UUID.randomUUID().toString());
|
||||
APIScenarioReportResult report = createScenarioReport(request.getConfig().getReportId(), JSON.toJSONString(scenarioIds), scenarioNames.deleteCharAt(scenarioNames.toString().length() - 1).toString(), ReportTriggerMode.MANUAL.name(),
|
||||
ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
report.setName(request.getConfig().getReportName());
|
||||
report.setId(serialReportId);
|
||||
apiScenarioReportMapper.insert(report);
|
||||
|
@ -974,7 +978,7 @@ public class ApiAutomationService {
|
|||
return request.getId();
|
||||
}
|
||||
|
||||
private void run(Map<APIScenarioReportResult, HashTree> map, RunScenarioRequest request, String serialReportId) {
|
||||
private void run(Map<APIScenarioReportResult, RunModeDataDTO> map, RunScenarioRequest request, String serialReportId) {
|
||||
// 开始选择执行模式
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(map.size());
|
||||
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
|
||||
|
@ -987,7 +991,7 @@ public class ApiAutomationService {
|
|||
apiScenarioReportMapper.insert(key);
|
||||
reportIds.add(key.getId());
|
||||
try {
|
||||
Future<ApiScenarioReport> future = executorService.submit(new SerialScenarioExecTask(jMeterService, apiScenarioReportMapper, key.getId(), map.get(key), request));
|
||||
Future<ApiScenarioReport> future = executorService.submit(new SerialScenarioExecTask(jMeterService, apiScenarioReportMapper, map.get(key), request));
|
||||
ApiScenarioReport report = future.get();
|
||||
// 如果开启失败结束执行,则判断返回结果状态
|
||||
if (request.getConfig().isOnSampleError()) {
|
||||
|
@ -1015,7 +1019,7 @@ public class ApiAutomationService {
|
|||
for (APIScenarioReportResult report : map.keySet()) {
|
||||
//存储报告
|
||||
batchMapper.insert(report);
|
||||
executorService.submit(new ParallelScenarioExecTask(jMeterService, report.getId(), map.get(report), request));
|
||||
executorService.submit(new ParallelScenarioExecTask(jMeterService, map.get(report), request));
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
|
@ -1095,14 +1099,14 @@ public class ApiAutomationService {
|
|||
if (request.isTestPlanScheduleJob()) {
|
||||
String savedScenarioId = testPlanScenarioId + ":" + request.getTestPlanReportId();
|
||||
report = createScenarioReport(group.getName(), savedScenarioId, item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
} else {
|
||||
report = createScenarioReport(group.getName(), testPlanScenarioId, item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
}
|
||||
} else {
|
||||
report = createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(),request.getConfig());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig());
|
||||
}
|
||||
batchMapper.insert(report);
|
||||
reportIds.add(group.getName());
|
||||
|
@ -1223,12 +1227,7 @@ public class ApiAutomationService {
|
|||
List<String> reportIds = new LinkedList<>();
|
||||
try {
|
||||
HashTree hashTree = generateHashTree(apiScenarios, request, reportIds);
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(JSON.toJSONString(reportIds), hashTree, runMode, false, request.getConfig());
|
||||
} else {
|
||||
jMeterService.runSerial(JSON.toJSONString(reportIds), hashTree, request.getReportId(), runMode, request.getConfig());
|
||||
}
|
||||
|
||||
jMeterService.runSerial(JSON.toJSONString(reportIds), hashTree, request.getReportId(), runMode, request.getConfig());
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage());
|
||||
MSException.throwException(e.getMessage());
|
||||
|
@ -1322,7 +1321,7 @@ public class ApiAutomationService {
|
|||
}
|
||||
|
||||
APIScenarioReportResult report = createScenarioReport(request.getId(), request.getScenarioId(), request.getScenarioName(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
|
||||
SessionUtils.getUserId(),request.getConfig());
|
||||
SessionUtils.getUserId(), request.getConfig());
|
||||
apiScenarioReportMapper.insert(report);
|
||||
|
||||
uploadBodyFiles(request.getBodyFileRequestIds(), bodyFiles);
|
||||
|
|
|
@ -589,7 +589,7 @@ public class ApiDefinitionService {
|
|||
|
||||
// 调用执行方法
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(request.getId(), hashTree, runMode, request.getReportId() != null, request.getConfig());
|
||||
jMeterService.runTest(request.getId(), request.getId(), runMode, null, request.getConfig());
|
||||
} else {
|
||||
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), runMode);
|
||||
}
|
||||
|
@ -637,6 +637,7 @@ public class ApiDefinitionService {
|
|||
ApiDefinitionExecResult result = extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId);
|
||||
return buildAPIReportResult(result);
|
||||
}
|
||||
|
||||
public APIReportResult getReportById(String testId) {
|
||||
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(testId);
|
||||
return buildAPIReportResult(result);
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.JarConfig;
|
||||
import io.metersphere.base.domain.TestPlanApiScenario;
|
||||
import io.metersphere.base.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.service.JarConfigService;
|
||||
import io.metersphere.track.service.TestPlanApiCaseService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@Service
|
||||
public class ApiJmeterFileService {
|
||||
|
||||
@Resource
|
||||
private ApiAutomationService apiAutomationService;
|
||||
@Resource
|
||||
private TestPlanApiCaseService testPlanApiCaseService;
|
||||
@Resource
|
||||
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
|
||||
@Resource
|
||||
private ApiScenarioMapper apiScenarioMapper;
|
||||
@Resource
|
||||
private JMeterService jMeterService;
|
||||
|
||||
public byte[] downloadJmeterFiles(String runMode, String testId, String reportId, String testPlanScenarioId) {
|
||||
Map<String, String> planEnvMap = new HashMap<>();
|
||||
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
|
||||
// 获取场景用例单独的执行环境
|
||||
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
|
||||
String environment = planApiScenario.getEnvironment();
|
||||
if (StringUtils.isNotBlank(environment)) {
|
||||
planEnvMap = JSON.parseObject(environment, Map.class);
|
||||
}
|
||||
}
|
||||
HashTree hashTree = null;
|
||||
if (ApiRunMode.DEFINITION.name().equals(runMode) || ApiRunMode.API_PLAN.name().equals(runMode)) {
|
||||
hashTree = testPlanApiCaseService.generateHashTree(testId);
|
||||
} else {
|
||||
ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(testId);
|
||||
if (item == null) {
|
||||
MSException.throwException("未找到执行场景。");
|
||||
}
|
||||
hashTree = apiAutomationService.generateHashTree(item, reportId, planEnvMap);
|
||||
}
|
||||
//jMeterService.addBackendListener(reportId, hashTree);
|
||||
return zipFilesToByteArray(testId, hashTree);
|
||||
}
|
||||
|
||||
public byte[] downloadJmeterJar() {
|
||||
Map<String, byte[]> files = new HashMap<>();
|
||||
// 获取JAR
|
||||
Map<String, byte[]> jarFiles = this.getJar();
|
||||
if (!com.alibaba.excel.util.CollectionUtils.isEmpty(jarFiles)) {
|
||||
for (String k : jarFiles.keySet()) {
|
||||
byte[] v = jarFiles.get(k);
|
||||
files.put(k, v);
|
||||
}
|
||||
}
|
||||
return listBytesToZip(files);
|
||||
}
|
||||
|
||||
private Map<String, byte[]> getJar() {
|
||||
Map<String, byte[]> jarFiles = new LinkedHashMap<>();
|
||||
// jar 包
|
||||
JarConfigService jarConfigService = CommonBeanFactory.getBean(JarConfigService.class);
|
||||
List<JarConfig> jars = jarConfigService.list();
|
||||
jars.forEach(jarConfig -> {
|
||||
try {
|
||||
String path = jarConfig.getPath();
|
||||
File file = new File(path);
|
||||
if (file.isDirectory() && !path.endsWith("/")) {
|
||||
file = new File(path + "/");
|
||||
}
|
||||
byte[] fileByte = jMeterService.fileToByte(file);
|
||||
if (fileByte != null) {
|
||||
jarFiles.put(file.getName(), fileByte);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
return jarFiles;
|
||||
}
|
||||
|
||||
private Map<String, byte[]> getMultipartFiles(HashTree hashTree) {
|
||||
Map<String, byte[]> multipartFiles = new LinkedHashMap<>();
|
||||
// 获取附件
|
||||
List<BodyFile> files = new LinkedList<>();
|
||||
jMeterService.getFiles(hashTree, files);
|
||||
if (CollectionUtils.isNotEmpty(files)) {
|
||||
for (BodyFile bodyFile : files) {
|
||||
File file = new File(bodyFile.getName());
|
||||
if (file != null && !file.exists()) {
|
||||
byte[] fileByte = jMeterService.fileToByte(file);
|
||||
if (fileByte != null) {
|
||||
multipartFiles.put(file.getName(), fileByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return multipartFiles;
|
||||
}
|
||||
|
||||
private byte[] zipFilesToByteArray(String testId, HashTree hashTree) {
|
||||
String fileName = testId + ".jmx";
|
||||
String jmx = new MsTestPlan().getJmx(hashTree);
|
||||
Map<String, byte[]> files = new HashMap<>();
|
||||
// 每个测试生成一个文件夹
|
||||
files.put(fileName, jmx.getBytes(StandardCharsets.UTF_8));
|
||||
// 获取JMX使用到的附件
|
||||
Map<String, byte[]> multipartFiles = this.getMultipartFiles(hashTree);
|
||||
if (!com.alibaba.excel.util.CollectionUtils.isEmpty(multipartFiles)) {
|
||||
for (String k : multipartFiles.keySet()) {
|
||||
byte[] v = multipartFiles.get(k);
|
||||
files.put(k, v);
|
||||
}
|
||||
}
|
||||
return listBytesToZip(files);
|
||||
}
|
||||
|
||||
private byte[] listBytesToZip(Map<String, byte[]> mapReport) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos);
|
||||
for (Map.Entry<String, byte[]> report : mapReport.entrySet()) {
|
||||
ZipEntry entry = new ZipEntry(report.getKey());
|
||||
entry.setSize(report.getValue().length);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(report.getValue());
|
||||
}
|
||||
zos.closeEntry();
|
||||
zos.close();
|
||||
return baos.toByteArray();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -358,33 +358,6 @@ public class ApiScenarioReportService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void margeReport(TestResult result, StringBuilder scenarioIds, StringBuilder scenarioNames, String runMode, String projectId, String userId, List<String> reportIds) {
|
||||
// 合并生成一份报告
|
||||
if (StringUtils.isNotEmpty(result.getSetReportId())) {
|
||||
// 清理其他报告保留一份合并后的报告
|
||||
this.deleteByIds(reportIds);
|
||||
|
||||
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(result.getSetReportId());
|
||||
report.setStatus(result.getError() > 0 ? "Error" : "Success");
|
||||
if (StringUtils.isNotEmpty(userId)) {
|
||||
report.setUserId(userId);
|
||||
} else {
|
||||
report.setUserId(SessionUtils.getUserId());
|
||||
}
|
||||
report.setExecuteType(ExecuteType.Saved.name());
|
||||
report.setProjectId(projectId);
|
||||
report.setScenarioName(scenarioNames.toString().substring(0, scenarioNames.toString().length() - 1));
|
||||
report.setScenarioId(scenarioIds.toString());
|
||||
apiScenarioReportMapper.updateByPrimaryKey(report);
|
||||
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
|
||||
detail.setContent(JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8));
|
||||
detail.setReportId(report.getId());
|
||||
detail.setProjectId(report.getProjectId());
|
||||
apiScenarioReportDetailMapper.insert(detail);
|
||||
}
|
||||
}
|
||||
|
||||
public void margeReport(String reportId, List<String> reportIds) {
|
||||
// 合并生成一份报告
|
||||
if (CollectionUtils.isNotEmpty(reportIds)) {
|
||||
|
|
|
@ -3,35 +3,33 @@
|
|||
*/
|
||||
package io.metersphere.api.service.task;
|
||||
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.RunScenarioRequest;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ParallelScenarioExecTask<T> implements Callable<T> {
|
||||
private RunScenarioRequest request;
|
||||
private JMeterService jMeterService;
|
||||
private HashTree hashTree;
|
||||
private String id;
|
||||
private RunModeDataDTO runModeDataDTO;
|
||||
|
||||
public ParallelScenarioExecTask(JMeterService jMeterService, String id, HashTree hashTree, RunScenarioRequest request) {
|
||||
public ParallelScenarioExecTask(JMeterService jMeterService, RunModeDataDTO runModeDataDTO, RunScenarioRequest request) {
|
||||
this.jMeterService = jMeterService;
|
||||
this.request = request;
|
||||
this.hashTree = hashTree;
|
||||
this.id = id;
|
||||
this.runModeDataDTO = runModeDataDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() {
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(id, hashTree, request.getRunMode(), false, request.getConfig());
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReportId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig());
|
||||
} else {
|
||||
jMeterService.runSerial(id, hashTree, request.getReportId(), request.getRunMode(), request.getConfig());
|
||||
jMeterService.runSerial(runModeDataDTO.getReportId(), runModeDataDTO.getHashTree(), request.getReportId(), request.getRunMode(), request.getConfig());
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
package io.metersphere.api.service.task;
|
||||
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.RunScenarioRequest;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.ApiScenarioReport;
|
||||
|
@ -11,7 +12,6 @@ import io.metersphere.commons.constants.APITestStatus;
|
|||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
@ -19,32 +19,30 @@ public class SerialScenarioExecTask<T> implements Callable<T> {
|
|||
private RunScenarioRequest request;
|
||||
private JMeterService jMeterService;
|
||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||
private HashTree hashTree;
|
||||
private RunModeDataDTO runModeDataDTO;
|
||||
ApiScenarioReport report = null;
|
||||
private String id;
|
||||
|
||||
public SerialScenarioExecTask(JMeterService jMeterService, ApiScenarioReportMapper apiScenarioReportMapper, String id, HashTree hashTree, RunScenarioRequest request) {
|
||||
public SerialScenarioExecTask(JMeterService jMeterService, ApiScenarioReportMapper apiScenarioReportMapper, RunModeDataDTO runModeDataDTO, RunScenarioRequest request) {
|
||||
this.jMeterService = jMeterService;
|
||||
this.apiScenarioReportMapper = apiScenarioReportMapper;
|
||||
this.request = request;
|
||||
this.hashTree = hashTree;
|
||||
this.id = id;
|
||||
this.runModeDataDTO = runModeDataDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() {
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(id, hashTree, request.getRunMode(), false, request.getConfig());
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReportId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig());
|
||||
} else {
|
||||
jMeterService.runSerial(id, hashTree, request.getReportId(), request.getRunMode(), request.getConfig());
|
||||
jMeterService.runSerial(runModeDataDTO.getReportId(), runModeDataDTO.getHashTree(), request.getReportId(), request.getRunMode(), request.getConfig());
|
||||
}
|
||||
// 轮询查看报告状态,最多200次,防止死循环
|
||||
int index = 1;
|
||||
while (index < 200) {
|
||||
Thread.sleep(3000);
|
||||
index++;
|
||||
report = apiScenarioReportMapper.selectByPrimaryKey(id);
|
||||
report = apiScenarioReportMapper.selectByPrimaryKey(runModeDataDTO.getReportId());
|
||||
if (report != null && !report.getStatus().equals(APITestStatus.Running.name())) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ public class ShiroUtils {
|
|||
filterChainDefinitionMap.put("/sso/signin", "anon");
|
||||
filterChainDefinitionMap.put("/sso/callback", "anon");
|
||||
filterChainDefinitionMap.put("/license/valid", "anon");
|
||||
filterChainDefinitionMap.put("/api/jmeter/download", "anon");
|
||||
filterChainDefinitionMap.put("/api/jmeter/download/jar", "anon");
|
||||
|
||||
// for swagger
|
||||
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
||||
|
|
|
@ -4,18 +4,16 @@ import com.github.pagehelper.Page;
|
|||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
||||
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
||||
import io.metersphere.commons.constants.OperLogConstants;
|
||||
import io.metersphere.commons.constants.PermissionConstants;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.log.annotation.MsAuditLog;
|
||||
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
|
||||
import io.metersphere.track.service.TestPlanApiCaseService;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -66,4 +64,8 @@ public class TestPlanApiCaseController {
|
|||
testPlanApiCaseService.batchUpdateEnv(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run")
|
||||
public String run(@RequestPart("request") BatchRunDefinitionRequest request) {
|
||||
return testPlanApiCaseService.run(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,46 @@
|
|||
package io.metersphere.track.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
||||
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.dto.definition.request.MsThreadGroup;
|
||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.service.ApiDefinitionExecResultService;
|
||||
import io.metersphere.api.service.ApiTestCaseService;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
|
||||
import io.metersphere.base.mapper.ApiTestCaseMapper;
|
||||
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
|
||||
import io.metersphere.base.mapper.TestPlanMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestPlanApiCaseMapper;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.commons.utils.ServiceUtils;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.RunModeConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.*;
|
||||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import io.metersphere.log.vo.OperatingLogDetails;
|
||||
import io.metersphere.service.SystemParameterService;
|
||||
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
|
||||
import io.metersphere.track.service.task.ParallelApiExecTask;
|
||||
import io.metersphere.track.service.task.SerialApiExecTask;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
@ -26,6 +48,9 @@ import org.springframework.util.CollectionUtils;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
|
@ -45,6 +70,12 @@ public class TestPlanApiCaseService {
|
|||
private TestPlanMapper testPlanMapper;
|
||||
@Resource
|
||||
ApiTestCaseMapper apiTestCaseMapper;
|
||||
@Resource
|
||||
private SystemParameterService systemParameterService;
|
||||
@Resource
|
||||
private JMeterService jMeterService;
|
||||
@Resource
|
||||
private ApiDefinitionExecResultMapper mapper;
|
||||
|
||||
public TestPlanApiCase getInfo(String caseId, String testPlanId) {
|
||||
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||
|
@ -219,4 +250,169 @@ public class TestPlanApiCaseService {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private MsTestElement parse(String api, String planId) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
try {
|
||||
JSONObject element = JSON.parseObject(api);
|
||||
LinkedList<MsTestElement> list = new LinkedList<>();
|
||||
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
|
||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
|
||||
new TypeReference<LinkedList<MsTestElement>>() {
|
||||
});
|
||||
list.addAll(elements);
|
||||
}
|
||||
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(planId);
|
||||
Map<String, String> envMap = null;
|
||||
if (apiCase != null) {
|
||||
envMap = JSON.parseObject(apiCase.getEnvironmentId(), Map.class);
|
||||
}
|
||||
if (element.getString("type").equals("HTTPSamplerProxy")) {
|
||||
MsHTTPSamplerProxy httpSamplerProxy = JSON.parseObject(api, MsHTTPSamplerProxy.class);
|
||||
httpSamplerProxy.setHashTree(list);
|
||||
if (envMap != null && envMap.containsKey(httpSamplerProxy.getProjectId())) {
|
||||
httpSamplerProxy.setUseEnvironment(envMap.get(httpSamplerProxy.getProjectId()));
|
||||
}
|
||||
return httpSamplerProxy;
|
||||
}
|
||||
if (element.getString("type").equals("TCPSampler")) {
|
||||
MsTCPSampler msTCPSampler = JSON.parseObject(api, MsTCPSampler.class);
|
||||
if (envMap != null && envMap.containsKey(msTCPSampler.getProjectId())) {
|
||||
msTCPSampler.setUseEnvironment(envMap.get(msTCPSampler.getProjectId()));
|
||||
}
|
||||
msTCPSampler.setHashTree(list);
|
||||
return msTCPSampler;
|
||||
}
|
||||
if (element.getString("type").equals("DubboSampler")) {
|
||||
MsDubboSampler dubboSampler = JSON.parseObject(api, MsDubboSampler.class);
|
||||
if (envMap != null && envMap.containsKey(dubboSampler.getProjectId())) {
|
||||
dubboSampler.setUseEnvironment(envMap.get(dubboSampler.getProjectId()));
|
||||
}
|
||||
dubboSampler.setHashTree(list);
|
||||
return dubboSampler;
|
||||
}
|
||||
if (element.getString("type").equals("JDBCSampler")) {
|
||||
MsJDBCSampler jDBCSampler = JSON.parseObject(api, MsJDBCSampler.class);
|
||||
if (envMap != null && envMap.containsKey(jDBCSampler.getProjectId())) {
|
||||
jDBCSampler.setUseEnvironment(envMap.get(jDBCSampler.getProjectId()));
|
||||
}
|
||||
jDBCSampler.setHashTree(list);
|
||||
return jDBCSampler;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public HashTree generateHashTree(String testId) {
|
||||
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(testId);
|
||||
if (apiCase != null) {
|
||||
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(apiCase.getApiCaseId());
|
||||
HashTree jmeterHashTree = new HashTree();
|
||||
MsTestPlan testPlan = new MsTestPlan();
|
||||
testPlan.setHashTree(new LinkedList<>());
|
||||
if (caseWithBLOBs != null) {
|
||||
try {
|
||||
MsThreadGroup group = new MsThreadGroup();
|
||||
group.setLabel(caseWithBLOBs.getName());
|
||||
group.setName(testId);
|
||||
MsTestElement testElement = parse(caseWithBLOBs.getRequest(), testId);
|
||||
group.setHashTree(new LinkedList<>());
|
||||
group.getHashTree().add(testElement);
|
||||
testPlan.getHashTree().add(group);
|
||||
} catch (Exception ex) {
|
||||
MSException.throwException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
|
||||
return jmeterHashTree;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String modeRun(BatchRunDefinitionRequest request) {
|
||||
List<String> ids = request.getPlanIds();
|
||||
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||
example.createCriteria().andIdIn(ids);
|
||||
List<TestPlanApiCase> planApiCases = testPlanApiCaseMapper.selectByExample(example);
|
||||
|
||||
// 开始选择执行模式
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(planApiCases.size());
|
||||
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
|
||||
// 开始串行执行
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (TestPlanApiCase key : planApiCases) {
|
||||
try {
|
||||
RunModeDataDTO modeDataDTO = null;
|
||||
if (StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
modeDataDTO = new RunModeDataDTO(key.getId(), UUID.randomUUID().toString());
|
||||
} else {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(key.getId());
|
||||
modeDataDTO = new RunModeDataDTO(hashTree, UUID.randomUUID().toString());
|
||||
}
|
||||
Future<ApiDefinitionExecResult> future = executorService.submit(new SerialApiExecTask(jMeterService, mapper, modeDataDTO, request.getConfig(), ApiRunMode.API_PLAN.name()));
|
||||
ApiDefinitionExecResult report = future.get();
|
||||
// 如果开启失败结束执行,则判断返回结果状态
|
||||
if (request.getConfig().isOnSampleError()) {
|
||||
if (report == null || !report.getStatus().equals("Success")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error("执行终止:" + e.getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
} else {
|
||||
// 开始并发执行
|
||||
for (TestPlanApiCase key : planApiCases) {
|
||||
RunModeDataDTO modeDataDTO = null;
|
||||
if (StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
modeDataDTO = new RunModeDataDTO(key.getId(), UUID.randomUUID().toString());
|
||||
} else {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(key.getId());
|
||||
modeDataDTO = new RunModeDataDTO(hashTree, UUID.randomUUID().toString());
|
||||
}
|
||||
executorService.submit(new ParallelApiExecTask(jMeterService, mapper, modeDataDTO, request.getConfig(), ApiRunMode.API_PLAN.name()));
|
||||
}
|
||||
}
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试执行
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public String run(BatchRunDefinitionRequest request) {
|
||||
if (request.getConfig() != null) {
|
||||
if (request.getConfig().getMode().equals(RunModeConstants.PARALLEL.toString())) {
|
||||
// 校验并发数量
|
||||
int count = 50;
|
||||
BaseSystemConfigDTO dto = systemParameterService.getBaseInfo();
|
||||
if (StringUtils.isNotEmpty(dto.getConcurrency())) {
|
||||
count = Integer.parseInt(dto.getConcurrency());
|
||||
}
|
||||
if (request.getPlanIds().size() > count) {
|
||||
MSException.throwException("并发数量过大,请重新选择!");
|
||||
}
|
||||
return this.modeRun(request);
|
||||
} else {
|
||||
return this.modeRun(request);
|
||||
}
|
||||
}
|
||||
return request.getId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package io.metersphere.track.service.task;
|
||||
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ParallelApiExecTask<T> implements Callable<T> {
|
||||
private RunModeConfig config;
|
||||
private JMeterService jMeterService;
|
||||
private RunModeDataDTO runModeDataDTO;
|
||||
private String runMode;
|
||||
private ApiDefinitionExecResultMapper mapper;
|
||||
|
||||
public ParallelApiExecTask(JMeterService jMeterService, ApiDefinitionExecResultMapper mapper, RunModeDataDTO runModeDataDTO, RunModeConfig config, String runMode) {
|
||||
this.jMeterService = jMeterService;
|
||||
this.config = config;
|
||||
this.runModeDataDTO = runModeDataDTO;
|
||||
this.runMode = runMode;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() {
|
||||
try {
|
||||
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReportId(), runMode, null, config);
|
||||
} else {
|
||||
jMeterService.runDefinition(runModeDataDTO.getReportId(), runModeDataDTO.getHashTree(), null, runMode);
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
LogUtil.error(ex.getMessage());
|
||||
MSException.throwException(ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package io.metersphere.track.service.task;
|
||||
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
||||
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class SerialApiExecTask<T> implements Callable<T> {
|
||||
private RunModeConfig config;
|
||||
private JMeterService jMeterService;
|
||||
private RunModeDataDTO runModeDataDTO;
|
||||
private String runMode;
|
||||
private ApiDefinitionExecResultMapper mapper;
|
||||
|
||||
public SerialApiExecTask(JMeterService jMeterService, ApiDefinitionExecResultMapper mapper, RunModeDataDTO runModeDataDTO, RunModeConfig config, String runMode) {
|
||||
this.jMeterService = jMeterService;
|
||||
this.config = config;
|
||||
this.runModeDataDTO = runModeDataDTO;
|
||||
this.runMode = runMode;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() {
|
||||
try {
|
||||
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReportId(), runMode, null, config);
|
||||
} else {
|
||||
jMeterService.runDefinition(runModeDataDTO.getReportId(), runModeDataDTO.getHashTree(), null, runMode);
|
||||
}
|
||||
// 轮询查看报告状态,最多200次,防止死循环
|
||||
ApiDefinitionExecResult report = null;
|
||||
int index = 1;
|
||||
while (index < 200) {
|
||||
Thread.sleep(3000);
|
||||
index++;
|
||||
report = mapper.selectByPrimaryKey(runModeDataDTO.getReportId());
|
||||
if (report != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (T) report;
|
||||
} catch (Exception ex) {
|
||||
LogUtil.error(ex.getMessage());
|
||||
MSException.throwException(ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue