fix(接口测试): 修复分布式执行相关缺陷

This commit is contained in:
fit2-zhao 2021-12-21 19:53:21 +08:00 committed by fit2-zhao
parent 78e23135df
commit eb80bb6f1e
20 changed files with 191 additions and 105 deletions

View File

@ -7,7 +7,6 @@ import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.automation.parse.ScenarioImport;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.ApiScenario;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
@ -330,7 +329,6 @@ public class ApiAutomationController {
@GetMapping(value = "/stop/{reportId}")
public void stop(@PathVariable String reportId) {
if (StringUtils.isNotEmpty(reportId)) {
MessageCache.caseExecResourceLock.remove(reportId);
execThreadPoolExecutor.removeQueue(reportId);
new LocalRunner().stop(reportId);
}

View File

@ -47,8 +47,8 @@ public class ApiJmeterFileController {
}
@GetMapping("download")
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode) {
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode, testId, reportId);
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode, @RequestParam("reportType") String reportType) {
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode, testId, reportId, reportType);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + "_" + testId + ".zip\"")

View File

@ -24,6 +24,7 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.EnvironmentGroupProjectService;
@ -270,6 +271,24 @@ public class ElementUtil {
}
};
public final static List<String> requests = new ArrayList<String>() {{
this.add("HTTPSamplerProxy");
this.add("DubboSampler");
this.add("JDBCSampler");
this.add("TCPSampler");
this.add("JSR223Processor");
this.add("JSR223PreProcessor");
this.add("JSR223PostProcessor");
this.add("JDBCPreProcessor");
this.add("JDBCPostProcessor");
this.add("JmeterElement");
this.add("TestPlan");
this.add("ThreadGroup");
this.add("DNSCacheManager");
this.add("DebugSampler");
this.add("AuthManager");
}};
private static void formatSampler(JSONObject element) {
if (element == null || StringUtils.isEmpty(element.getString("type"))) {
return;
@ -340,6 +359,41 @@ public class ElementUtil {
}
}
public static void dataFormatting(JSONArray hashTree, String id, String reportType) {
for (int i = 0; i < hashTree.size(); i++) {
JSONObject element = hashTree.getJSONObject(i);
formatSampler(element);
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
if (element != null && requests.contains(element.getString("type")) && !element.getString("resourceId").contains(id)) {
element.fluentPut("resourceId", id + "=" + element.getString("resourceId"));
}
}
if (element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray, id, reportType);
}
}
}
public static void dataFormatting(JSONObject element, String id, String reportType) {
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
if (element != null && requests.contains(element.getString("type")) && !element.getString("resourceId").contains(id)) {
element.fluentPut("resourceId", id + "=" + element.getString("resourceId"));
}
}
formatSampler(element);
if (element != null && element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray, id, reportType);
}
}
public static void dataSetDomain(JSONArray hashTree, MsParameter msParameter) {
try {
ObjectMapper mapper = new ObjectMapper();

View File

@ -18,7 +18,6 @@ import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.TcpApiParamService;
import io.metersphere.base.domain.*;
@ -120,7 +119,6 @@ public class ApiExecuteService {
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
for (RunCaseRequest runCaseRequest : executeQueue) {
MessageCache.caseExecResourceLock.put(runCaseRequest.getReportId(), runCaseRequest.getReport());
responseDTOS.add(exec(runCaseRequest));
}
return responseDTOS;
@ -153,13 +151,14 @@ public class ApiExecuteService {
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testCaseWithBLOBs.getId(), StringUtils.isEmpty(request.getReportId()) ? request.getId() : request.getReportId(), request.getRunMode(), jmeterHashTree);
jMeterService.run(runRequest);
} catch (Exception ex) {
ApiDefinitionExecResult result = MessageCache.caseExecResourceLock.get(request.getReportId());
result.setStatus("error");
apiDefinitionExecResultMapper.updateByPrimaryKey(result);
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
caseWithBLOBs.setStatus("error");
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
MessageCache.caseExecResourceLock.remove(request.getReportId());
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(request.getReportId());
if (result != null) {
result.setStatus("error");
apiDefinitionExecResultMapper.updateByPrimaryKey(result);
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
caseWithBLOBs.setStatus("error");
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
}
LogUtil.error(ex.getMessage(), ex);
}
}

View File

@ -7,7 +7,6 @@ import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiExecutionQueue;
@ -102,7 +101,6 @@ public class TestPlanApiExecuteService {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, APITestStatus.Running.name(), batchMapper);
executeQueue.put(report.getId(), testPlanApiCase);
executeThreadIdMap.put(testPlanApiCase.getId(), report.getId());
MessageCache.caseExecResourceLock.put(report.getId(), report);
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
});
sqlSession.flushStatements();

View File

@ -225,7 +225,7 @@ public class ApiScenarioEnvService {
}
String definition = apiScenarioWithBLOBs.getScenarioDefinition();
MsScenario scenario = JSONObject.parseObject(definition, MsScenario.class);
GenerateHashTreeUtil.parse(definition, scenario);
GenerateHashTreeUtil.parse(definition, scenario, apiScenarioWithBLOBs.getId(), null);
if (StringUtils.equals(environmentType, EnvironmentType.JSON.toString())) {
scenario.setEnvironmentMap(JSON.parseObject(environmentJson, Map.class));
} else if (StringUtils.equals(environmentType, EnvironmentType.GROUP.toString())) {
@ -428,4 +428,18 @@ public class ApiScenarioEnvService {
config.setConfig(envConfig);
}
}
public Map<String, String> planEnvMap(String testPlanScenarioId) {
Map<String, String> planEnvMap = new HashMap<>();
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
String envJson = planApiScenario.getEnvironment();
String envType = planApiScenario.getEnvironmentType();
String envGroupId = planApiScenario.getEnvironmentGroupId();
if (StringUtils.equals(envType, EnvironmentType.JSON.toString()) && StringUtils.isNotBlank(envJson)) {
planEnvMap = JSON.parseObject(envJson, Map.class);
} else if (StringUtils.equals(envType, EnvironmentType.GROUP.toString()) && StringUtils.isNotBlank(envGroupId)) {
planEnvMap = environmentGroupProjectService.getEnvMap(envGroupId);
}
return planEnvMap;
}
}

View File

@ -150,7 +150,7 @@ public class ApiScenarioExecuteService {
responseDTOS.add(new MsExecResponseDTO(JSON.toJSONString(scenarioIds), serialReportId, request.getRunMode()));
// 增加并行集合报告
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.PARALLEL.toString())) {
apiScenarioReportStructureService.save(apiScenarios, serialReportId);
apiScenarioReportStructureService.save(apiScenarios, serialReportId, request.getConfig() != null ? request.getConfig().getReportType() : null);
}
}
// 开始执行
@ -160,7 +160,7 @@ public class ApiScenarioExecuteService {
DBTestQueue executionQueue = apiExecutionQueueService.add(executeQueue, request.getConfig().getResourcePoolId(), ApiRunMode.SCENARIO.name(), serialReportId, reportType, request.getRunMode());
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (StringUtils.isNotEmpty(serialReportId)) {
apiScenarioReportStructureService.save(apiScenarios, serialReportId);
apiScenarioReportStructureService.save(apiScenarios, serialReportId, request.getConfig() != null ? request.getConfig().getReportType() : null);
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
@ -267,7 +267,7 @@ public class ApiScenarioExecuteService {
// 生成并行报告和HashTree
RunModeDataDTO runModeDataDTO = new RunModeDataDTO(report, testPlanScenarioId);
if (request.getConfig() != null && !request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
runModeDataDTO.setHashTree(GenerateHashTreeUtil.generateHashTree(scenario, reportId, planEnvMap));
runModeDataDTO.setHashTree(GenerateHashTreeUtil.generateHashTree(scenario, reportId, planEnvMap, request.getConfig().getReportType()));
}
executeQueue.put(report.getId(), runModeDataDTO);
} catch (Exception ex) {
@ -284,7 +284,7 @@ public class ApiScenarioExecuteService {
// 生成文档结构
if (request.getConfig() == null || !StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportStructureService.save(scenario, report.getId());
apiScenarioReportStructureService.save(scenario, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);
}
// 重置报告ID
reportId = UUID.randomUUID().toString();
@ -317,7 +317,7 @@ public class ApiScenarioExecuteService {
try {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO(report, item.getId());
if (request.getConfig() != null && !request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
HashTree hashTree = GenerateHashTreeUtil.generateHashTree(item, StringUtils.isNotEmpty(serialReportId) ? serialReportId + "-" + i : reportId, new HashMap<>());
HashTree hashTree = GenerateHashTreeUtil.generateHashTree(item, StringUtils.isNotEmpty(serialReportId) ? serialReportId + "-" + i : reportId, new HashMap<>(), request.getConfig().getReportType());
runModeDataDTO.setHashTree(hashTree);
}
executeQueue.put(report.getId(), runModeDataDTO);
@ -332,7 +332,7 @@ public class ApiScenarioExecuteService {
}
// 生成报告结构
if (request.getConfig() == null || !StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportStructureService.save(item, report.getId());
apiScenarioReportStructureService.save(item, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);
}
// 重置报告ID
reportId = UUID.randomUUID().toString();
@ -370,7 +370,7 @@ public class ApiScenarioExecuteService {
apiScenarioReportMapper.insert(report);
if (request.isSaved()) {
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(request.getScenarioId());
apiScenarioReportStructureService.save(scenario, report.getId());
apiScenarioReportStructureService.save(scenario, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);
}
uploadBodyFiles(request.getBodyFileRequestIds(), bodyFiles);
FileUtils.createBodyFiles(request.getScenarioFileIds(), scenarioFiles);

View File

@ -15,17 +15,21 @@ import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.TestResultService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.HashTreeUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.ResultDTO;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.lang3.StringUtils;
@ -51,6 +55,10 @@ public class ApiScenarioSerialService {
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
private ApiScenarioEnvService apiScenarioEnvService;
public void serial(ApiExecutionQueue executionQueue, ApiExecutionQueueDetail queue) {
LoggerUtil.debug("Scenario run-执行脚本装载-进入串行准备");
@ -73,12 +81,22 @@ public class ApiScenarioSerialService {
HashTree hashTree = null;
if (StringUtils.isEmpty(executionQueue.getPoolId())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(queue.getTestId());
ApiScenarioWithBLOBs scenario = null;
Map<String, String> planEnvMap = new LinkedHashMap<>();
if (StringUtils.isNotEmpty(queue.getEvnMap())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
scenario = apiScenarioMapper.selectByPrimaryKey(queue.getTestId());
} else {
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(queue.getTestId());
if (planApiScenario != null) {
planEnvMap = apiScenarioEnvService.planEnvMap(queue.getTestId());
queue.setEvnMap(JSON.toJSONString(planEnvMap));
scenario = apiScenarioMapper.selectByPrimaryKey(planApiScenario.getApiScenarioId());
}
}
if ((planEnvMap == null || planEnvMap.isEmpty()) && StringUtils.isNotEmpty(queue.getEvnMap())) {
planEnvMap = JSON.parseObject(queue.getEvnMap(), Map.class);
}
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, queue.getReportId(), planEnvMap);
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, queue.getReportId(), planEnvMap, executionQueue.getReportType());
} else {
hashTree = generateHashTree(queue.getTestId());
}
@ -86,6 +104,9 @@ public class ApiScenarioSerialService {
this.initEnv(hashTree);
}
String reportId = StringUtils.isNotEmpty(executionQueue.getReportId()) ? executionQueue.getReportId() : queue.getReportId();
if (!StringUtils.equals(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
reportId = queue.getReportId();
}
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(queue.getTestId(), reportId, executionQueue.getRunMode(), hashTree);
runRequest.setReportType(executionQueue.getReportType());
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(executionQueue.getPoolId()));
@ -96,11 +117,14 @@ public class ApiScenarioSerialService {
// 开始执行
jMeterService.run(runRequest);
} catch (Exception e) {
LogUtil.error("执行终止:" + e.getMessage());
LoggerUtil.error("执行终止:" + e.getMessage());
ResultDTO dto = new ResultDTO();
BeanUtils.copyBean(dto, queue);
dto.setRunType(RunModeConstants.SERIAL.toString());
dto.setReportType(executionQueue.getReportType());
dto.setRunMode(executionQueue.getRunMode());
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(queue.getReportId());
report.setStatus(APITestStatus.Error.name());
apiScenarioReportMapper.updateByPrimaryKey(report);
CommonBeanFactory.getBean(TestResultService.class).testEnded(dto);
} else {
ApiDefinitionExecResult apiDefinitionExecResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
if (apiDefinitionExecResult != null) {
@ -108,6 +132,7 @@ public class ApiScenarioSerialService {
apiDefinitionExecResultMapper.updateByPrimaryKey(apiDefinitionExecResult);
}
}
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
}
}

View File

@ -32,16 +32,16 @@ public class GenerateHashTreeUtil {
public static MsScenario parseScenarioDefinition(String scenarioDefinition) {
MsScenario scenario = JSONObject.parseObject(scenarioDefinition, MsScenario.class);
parse(scenarioDefinition, scenario);
parse(scenarioDefinition, scenario, scenario.getId(), null);
return scenario;
}
public static void parse(String scenarioDefinition, MsScenario scenario) {
public static void parse(String scenarioDefinition, MsScenario scenario, String id, String reportType) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
JSONObject element = JSON.parseObject(scenarioDefinition);
ElementUtil.dataFormatting(element);
ElementUtil.dataFormatting(element, id, reportType);
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
@ -99,7 +99,7 @@ public class GenerateHashTreeUtil {
return null;
}
public static HashTree generateHashTree(ApiScenarioWithBLOBs item, String reportId, Map<String, String> planEnvMap) {
public static HashTree generateHashTree(ApiScenarioWithBLOBs item, String reportId, Map<String, String> planEnvMap, String reportType) {
HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
@ -112,7 +112,7 @@ public class GenerateHashTreeUtil {
if (planEnvMap != null && planEnvMap.size() > 0) {
scenario.setEnvironmentMap(planEnvMap);
}
GenerateHashTreeUtil.parse(item.getScenarioDefinition(), scenario);
GenerateHashTreeUtil.parse(item.getScenarioDefinition(), scenario, item.getId(), reportType);
group.setEnableCookieShare(scenario.isEnableCookieShare());
LinkedList<MsTestElement> scenarios = new LinkedList<>();

View File

@ -12,9 +12,6 @@ public class FixedTask {
@Scheduled(cron = "0 */5 * * * ?")
public void execute() {
if (MessageCache.caseExecResourceLock.size() > 10000) {
MessageCache.caseExecResourceLock.clear();
}
if (queueService == null) {
queueService = CommonBeanFactory.getBean(ApiExecutionQueueService.class);
}

View File

@ -107,7 +107,11 @@ public class JMeterService {
if (baseInfo != null) {
platformUrl = baseInfo.getUrl();
}
platformUrl += "/api/jmeter/download?testId=" + request.getTestId() + "&reportId=" + request.getReportId() + "&runMode=" + request.getRunMode();
platformUrl += "/api/jmeter/download?testId="
+ request.getTestId()
+ "&reportId=" + request.getReportId()
+ "&runMode=" + request.getRunMode()
+ "&reportType=" + request.getReportType();
request.setPlatformUrl(platformUrl);
request.setKafkaConfig(KafkaConfig.getKafka());

View File

@ -1,7 +1,5 @@
package io.metersphere.api.jmeter;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import javax.websocket.Session;
import java.util.HashMap;
import java.util.LinkedList;
@ -11,8 +9,6 @@ import java.util.concurrent.ConcurrentHashMap;
public class MessageCache {
public final static ConcurrentHashMap<String, Session> reportCache = new ConcurrentHashMap<>();
// 用例并发锁
public final static ConcurrentHashMap<String, ApiDefinitionExecResult> caseExecResourceLock = new ConcurrentHashMap<>();
public final static Map<String, Long> jmeterLogTask = new HashMap<>();

View File

@ -721,7 +721,7 @@ public class ApiAutomationService {
if (scenario == null) {
return null;
}
GenerateHashTreeUtil.parse(apiScenario.getScenarioDefinition(), scenario);
GenerateHashTreeUtil.parse(apiScenario.getScenarioDefinition(), scenario, apiScenario.getId(), null);
String environmentType = apiScenario.getEnvironmentType();
String environmentJson = apiScenario.getEnvironmentJson();
String environmentGroupId = apiScenario.getEnvironmentGroupId();

View File

@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiDefinitionMapper;
@ -320,34 +319,22 @@ public class ApiDefinitionExecResultService {
private ApiDefinitionExecResult save(RequestResult item, String reportId, String console, int expectProcessResultCount, String type, String testId, boolean isFirst) {
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
ApiDefinitionExecResult saveResult = MessageCache.caseExecResourceLock.get(reportId);
if (saveResult == null) {
saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(reportId);
}
ApiDefinitionExecResult saveResult = new ApiDefinitionExecResult();
item.getResponseResult().setConsole(console);
boolean saved = true;
if (saveResult == null || expectProcessResultCount > 1) {
saveResult = new ApiDefinitionExecResult();
if (isFirst) {
saveResult.setId(reportId);
} else {
saveResult.setId(UUID.randomUUID().toString());
}
saveResult.setActuator("LOCAL");
saveResult.setName(item.getName());
if (StringUtils.equals(type, ApiRunMode.JENKINS_API_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.API.name());
} else if (StringUtils.equals(type, ApiRunMode.MANUAL_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
} else {
saveResult.setTriggerMode(TriggerMode.SCHEDULE.name());
}
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (SessionUtils.getUser() != null) {
saveResult.setUserId(SessionUtils.getUser().getId());
}
saved = false;
saveResult.setId(reportId);
saveResult.setActuator("LOCAL");
saveResult.setName(item.getName());
if (StringUtils.equals(type, ApiRunMode.JENKINS_API_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.API.name());
} else if (StringUtils.equals(type, ApiRunMode.MANUAL_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
} else {
saveResult.setTriggerMode(TriggerMode.SCHEDULE.name());
}
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (SessionUtils.getUser() != null) {
saveResult.setUserId(SessionUtils.getUser().getId());
}
String status = item.isSuccess() ? "success" : "error";
@ -367,14 +354,7 @@ public class ApiDefinitionExecResultService {
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
}
if (!saved) {
apiDefinitionExecResultMapper.insert(saveResult);
} else {
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
}
if (StringUtils.isNotEmpty(reportId)) {
MessageCache.caseExecResourceLock.remove(reportId);
}
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
return saveResult;
}
return null;

View File

@ -58,7 +58,7 @@ public class ApiJmeterFileService {
return listBytesToZip(files);
}
public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId) {
public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String reportType) {
Map<String, String> planEnvMap = new HashMap<>();
ApiScenarioWithBLOBs scenario = null;
if (StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
@ -96,7 +96,7 @@ public class ApiJmeterFileService {
planEnvMap = environmentGroupProjectService.getEnvMap(envGroupId);
}
}
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, reportId, planEnvMap);
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, reportId, planEnvMap, reportType);
}
return zipFilesToByteArray((reportId + "_" + remoteTestId), hashTree);
}

View File

@ -43,7 +43,12 @@ public class ApiScenarioReportResultService {
report.setId(UUID.randomUUID().toString());
result.setEndTime(System.currentTimeMillis());
if (result.getResponseResult() != null) {
result.getResponseResult().setResponseTime((result.getEndTime() - result.getStartTime()));
long time = result.getEndTime() - result.getStartTime();
if (time > 0) {
result.getResponseResult().setResponseTime(time);
} else {
result.setEndTime(result.getEndTime());
}
}
String resourceId = result.getResourceId();
if (StringUtils.isNotEmpty(resourceId) && resourceId.contains("_")) {

View File

@ -8,6 +8,7 @@ import io.metersphere.api.dto.StepTreeDTO;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioReportResultMapper;
import io.metersphere.base.mapper.ApiScenarioReportStructureMapper;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RequestResult;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
@ -32,10 +33,10 @@ public class ApiScenarioReportStructureService {
private static final List<String> requests = Arrays.asList("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor", "AbstractSampler");
public void save(List<ApiScenarioWithBLOBs> apiScenarios, String reportId) {
public void save(List<ApiScenarioWithBLOBs> apiScenarios, String reportId, String reportType) {
List<StepTreeDTO> dtoList = new LinkedList<>();
for (ApiScenarioWithBLOBs bos : apiScenarios) {
StepTreeDTO dto = dataFormatting(bos);
StepTreeDTO dto = dataFormatting(bos, reportType);
dtoList.add(dto);
}
if (LoggerUtil.getLogger().isDebugEnabled()) {
@ -44,9 +45,9 @@ public class ApiScenarioReportStructureService {
this.save(reportId, dtoList);
}
public void save(ApiScenarioWithBLOBs apiScenario, String reportId) {
public void save(ApiScenarioWithBLOBs apiScenario, String reportId, String reportType) {
List<StepTreeDTO> dtoList = new LinkedList<>();
StepTreeDTO dto = dataFormatting(apiScenario);
StepTreeDTO dto = dataFormatting(apiScenario, reportType);
dtoList.add(dto);
this.save(reportId, dtoList);
}
@ -70,28 +71,40 @@ public class ApiScenarioReportStructureService {
}
}
public static StepTreeDTO dataFormatting(ApiScenarioWithBLOBs apiScenario) {
public static StepTreeDTO dataFormatting(ApiScenarioWithBLOBs apiScenario, String reportType) {
JSONObject element = JSON.parseObject(apiScenario.getScenarioDefinition());
StepTreeDTO dto = null;
if (element != null && element.getBoolean("enable")) {
dto = new StepTreeDTO(apiScenario.getName(), element.getString("resourceId"), element.getString("type"), element.getIntValue("index"));
String resourceId = element.getString("resourceId");
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
if (StringUtils.isNotEmpty(resourceId) && StringUtils.isNotEmpty(apiScenario.getId()) && !resourceId.contains(apiScenario.getId())) {
resourceId = apiScenario.getId() + "=" + element.getString("resourceId");
}
}
dto = new StepTreeDTO(apiScenario.getName(), resourceId, element.getString("type"), element.getIntValue("index"));
if (element.containsKey("hashTree") && !requests.contains(dto.getType())) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray, dto);
dataFormatting(elementJSONArray, dto, apiScenario.getId(), reportType);
}
}
return dto;
}
public static void dataFormatting(JSONArray hashTree, StepTreeDTO dto) {
public static void dataFormatting(JSONArray hashTree, StepTreeDTO dto, String id, String reportType) {
for (int i = 0; i < hashTree.size(); i++) {
JSONObject element = hashTree.getJSONObject(i);
if (element != null && element.getBoolean("enable")) {
StepTreeDTO children = new StepTreeDTO(element.getString("name"), element.getString("resourceId"), element.getString("type"), element.getIntValue("index"));
String resourceId = element.getString("resourceId");
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
if (StringUtils.isNotEmpty(resourceId) && StringUtils.isNotEmpty(id) && !resourceId.contains(id)) {
resourceId = id + "=" + element.getString("resourceId");
}
}
StepTreeDTO children = new StepTreeDTO(element.getString("name"), resourceId, element.getString("type"), element.getIntValue("index"));
dto.getChildren().add(children);
if (element.containsKey("hashTree") && !requests.contains(children.getType())) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray, children);
dataFormatting(elementJSONArray, children, id, reportType);
}
}
}
@ -127,7 +140,7 @@ public class ApiScenarioReportStructureService {
}
}
private void calculateStep(List<StepTreeDTO> dtoList, AtomicLong stepError) {
private void calculateStep(List<StepTreeDTO> dtoList, AtomicLong stepError, AtomicLong stepTotal) {
for (StepTreeDTO step : dtoList) {
// 失败结果数量
AtomicLong error = new AtomicLong();
@ -135,6 +148,9 @@ public class ApiScenarioReportStructureService {
if (error.longValue() > 0) {
stepError.set((stepError.longValue() + 1));
}
if (CollectionUtils.isNotEmpty(step.getChildren())) {
stepTotal.set((stepTotal.longValue() + step.getChildren().size()));
}
}
}
@ -194,8 +210,6 @@ public class ApiScenarioReportStructureService {
ApiScenarioReportStructureWithBLOBs scenarioReportStructure = reportStructureWithBLOBs.get(0);
List<StepTreeDTO> stepList = JSONArray.parseArray(new String(scenarioReportStructure.getResourceTree(), StandardCharsets.UTF_8), StepTreeDTO.class);
reportDTO.setScenarioStepTotal(stepList.size());
// 匹配结果
Map<String, List<ApiScenarioReportResult>> maps = reportResults.stream().collect(Collectors.groupingBy(ApiScenarioReportResult::getResourceId));
this.reportFormatting(stepList, maps);
@ -213,7 +227,9 @@ public class ApiScenarioReportStructureService {
reportDTO.setScenarioSuccess((totalScenario.longValue() - scenarioError.longValue()));
AtomicLong stepError = new AtomicLong();
calculateStep(stepList, stepError);
AtomicLong stepTotal = new AtomicLong();
calculateStep(stepList, stepError, stepTotal);
reportDTO.setScenarioStepTotal(stepTotal.longValue());
reportDTO.setScenarioStepError(stepError.longValue());
reportDTO.setScenarioStepSuccess((stepList.size() - stepError.longValue()));

View File

@ -114,7 +114,6 @@ public class RemakeReportService {
}
}
}
MessageCache.caseExecResourceLock.remove(request.getReportId());
} catch (Exception e) {
LogUtil.error(e);
}
@ -143,6 +142,5 @@ public class RemakeReportService {
}
report.setStatus(APITestStatus.Error.name());
apiScenarioReportMapper.insert(report);
MessageCache.caseExecResourceLock.remove(report.getId());
}
}

View File

@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.automation.TaskRequest;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
@ -124,7 +123,6 @@ public class TaskService {
result.setStatus("STOP");
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(result);
actuator = result.getActuator();
MessageCache.caseExecResourceLock.remove(result.getId());
}
} else if (StringUtils.equals(request.getType(), "SCENARIO")) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
@ -145,7 +143,6 @@ public class TaskService {
item.setStatus("STOP");
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(item);
actuator = item.getActuator();
MessageCache.caseExecResourceLock.remove(item.getId());
request.setReportId(item.getId());
extracted(poolMap, request, actuator);
}

View File

@ -21,7 +21,7 @@
<template slot="label">
<span class="console">{{ $t('api_test.definition.request.console') }}</span>
</template>
<pre>{{ content.console }}</pre>
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="content.console" height="calc(100vh - 500px)"/>
</el-tab-pane>
</el-tabs>
@ -50,6 +50,7 @@ import {RequestFactory} from "../../definition/model/ApiTestModel";
import {windowPrint, getUUID, getCurrentProjectID} from "@/common/js/utils";
import {getScenarioReport, getShareScenarioReport} from "@/network/api";
import {STEP} from "@/business/components/api/automation/scenario/Setting";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
export default {
name: "MsApiReport",
@ -57,6 +58,7 @@ export default {
MsApiReportViewHeader,
MsApiReportExport,
MsMainContainer,
MsCodeEdit,
MsContainer, MsScenarioResults, MsRequestResultTail, MsMetricChart, MsScenarioResult, MsRequestResult
},
data() {
@ -526,7 +528,10 @@ export default {
.report-container .is-active .fail {
color: inherit;
}
.report-console {
height: calc(100vh - 270px);
overflow-y: auto;
}
.export-button {
float: right;
}