From 2b586710db4c6e9a67b7444d3013e92672c82729 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Wed, 26 Apr 2023 10:14:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):?= =?UTF-8?q?=20=E4=BC=98=E5=8C=96=E8=AF=AF=E6=8A=A5=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fit2-zhao --- .../api/ApiCaseParallelExecuteService.java | 15 +- .../api/exec/api/ApiCaseSerialService.java | 3 + .../api/exec/api/ApiExecuteService.java | 34 ++-- .../scenario/ApiScenarioExecuteService.java | 3 + .../scenario/ApiScenarioParallelService.java | 4 + .../scenario/ApiScenarioSerialService.java | 3 + .../metersphere/api/jmeter/JMeterService.java | 27 +-- .../api/jmeter/KafkaListenerTask.java | 10 +- .../api/jmeter/MsApiBackendListener.java | 19 +- .../api/jmeter/MsDebugListener.java | 9 +- .../api/jmeter/NewDriverManager.java | 16 +- .../api/jmeter/utils/ApiFakeErrorUtil.java | 57 ++++++ .../commons/constants/ExtendedParameter.java | 1 - .../commons/utils/FakeErrorParse.java | 108 ----------- .../commons/utils/GenerateHashTreeUtil.java | 2 +- .../commons/utils/ResponseUtil.java | 23 +-- .../commons/utils/ResultConversionUtil.java | 22 +-- .../listener/ApiExecutionQueueListener.java | 2 +- .../service/ApiExecutionQueueService.java | 175 ++++++++++-------- .../service/ApiJMeterFileService.java | 2 +- .../service/RedisTemplateService.java | 22 +-- .../service/RemakeReportService.java | 9 +- .../service/TestResultService.java | 9 +- .../scenario/ApiScenarioReportService.java | 4 +- .../constants/BackendListenerConstants.java | 4 +- .../java/io/metersphere/dto/FakeErrorDTO.java | 11 ++ .../metersphere}/dto/FakeErrorLibraryDTO.java | 3 +- .../metersphere/dto/JmeterRunRequestDTO.java | 3 + .../java/io/metersphere/dto}/MsRegexDTO.java | 2 +- .../io/metersphere/dto/RequestResult.java | 3 +- .../java/io/metersphere/dto/ResultDTO.java | 4 + .../io/metersphere/enums/ApiReportStatus.java | 5 + .../io/metersphere/jmeter/JMeterBase.java | 43 +++-- .../io/metersphere/utils/FakeErrorUtils.java | 84 +++++++++ .../java/io/metersphere/utils/JsonUtils.java | 9 + .../metersphere}/utils/ReportStatusUtil.java | 25 ++- .../java/io/metersphere}/vo/ResultVO.java | 2 +- .../snippet/listener/MsDebugListener.java | 3 +- 38 files changed, 436 insertions(+), 344 deletions(-) create mode 100644 api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ApiFakeErrorUtil.java delete mode 100644 api-test/backend/src/main/java/io/metersphere/commons/utils/FakeErrorParse.java create mode 100644 framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorDTO.java rename {api-test/backend/src/main/java/io/metersphere/api => framework/sdk-parent/jmeter/src/main/java/io/metersphere}/dto/FakeErrorLibraryDTO.java (90%) rename {api-test/backend/src/main/java/io/metersphere/api/dto/definition => framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto}/MsRegexDTO.java (82%) create mode 100644 framework/sdk-parent/jmeter/src/main/java/io/metersphere/enums/ApiReportStatus.java create mode 100644 framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/FakeErrorUtils.java rename {api-test/backend/src/main/java/io/metersphere/api/jmeter => framework/sdk-parent/jmeter/src/main/java/io/metersphere}/utils/ReportStatusUtil.java (82%) rename {api-test/backend/src/main/java/io/metersphere/commons => framework/sdk-parent/jmeter/src/main/java/io/metersphere}/vo/ResultVO.java (93%) diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseParallelExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseParallelExecuteService.java index 6ba97d4051..26adffa8b1 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseParallelExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseParallelExecuteService.java @@ -2,11 +2,13 @@ package io.metersphere.api.exec.api; import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.api.jmeter.utils.ApiFakeErrorUtil; import io.metersphere.api.jmeter.utils.SmoothWeighted; import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs; import io.metersphere.commons.constants.CommonConstants; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.GenerateHashTreeUtil; +import io.metersphere.commons.utils.JSON; import io.metersphere.constants.RunModeConstants; import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.dto.JmeterRunRequestDTO; @@ -15,15 +17,13 @@ import io.metersphere.service.RemakeReportService; import io.metersphere.service.SystemParameterService; import io.metersphere.utils.LoggerUtil; import io.metersphere.vo.BooleanPool; +import jakarta.annotation.Resource; import org.apache.commons.collections4.MapUtils; import org.apache.jorphan.collections.HashTree; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; - -import java.util.HashMap; -import java.util.Map; +import java.util.*; @Service public class ApiCaseParallelExecuteService { @@ -34,7 +34,8 @@ public class ApiCaseParallelExecuteService { @Resource private RedisTemplate redisTemplate; @Resource - private RemakeReportService remakeReportService; + private RemakeReportService remakeReportService; + public void parallel(Map executeQueue, RunModeConfigDTO config, DBTestQueue executionQueue, String runMode) { BooleanPool pool = GenerateHashTreeUtil.isResourcePool(config.getResourcePoolId()); // 初始化分配策略 @@ -73,13 +74,15 @@ public class ApiCaseParallelExecuteService { } // 开始执行 runRequest.getExtendedParameters().put("projectId", executionQueue.getDetail().getProjectIds()); - + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get( + JSON.parseArray(executionQueue.getDetail().getProjectIds()))); LoggerUtil.info("进入并行模式,开始执行用例:[" + result.getName() + "] 报告ID [" + reportId + "]"); } catch (Exception e) { remakeReportService.testEnded(runRequest, e.getMessage()); LoggerUtil.error("脚本处理失败", runRequest.getReportId(), e); continue; } + // 误报规则 jMeterService.run(runRequest); } } diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseSerialService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseSerialService.java index e5d3d2dfa1..f444b3eea8 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseSerialService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseSerialService.java @@ -8,6 +8,7 @@ import io.metersphere.api.dto.definition.request.ParameterConfig; import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.NewDriverManager; +import io.metersphere.api.jmeter.utils.ApiFakeErrorUtil; import io.metersphere.api.jmeter.utils.SmoothWeighted; import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs; import io.metersphere.base.domain.ApiExecutionQueueDetail; @@ -77,6 +78,8 @@ public class ApiCaseSerialService { if (runRequest.getPool().isPool()) { SmoothWeighted.setServerConfig(runRequest.getPoolId(), redisTemplate); } + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get( + JSON.parseArray(queue.getProjectIds()))); // 开始执行 runRequest.getExtendedParameters().put(PROJECT_ID, queue.getProjectIds()); } catch (Exception e) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java index ad3862f360..0a07cd7c53 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java @@ -14,6 +14,7 @@ import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.NewDriverManager; +import io.metersphere.api.jmeter.utils.ApiFakeErrorUtil; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiDefinitionExecResultMapper; import io.metersphere.base.mapper.ApiDefinitionMapper; @@ -115,27 +116,24 @@ public class ApiExecuteService { } public MsExecResponseDTO exec(RunCaseRequest request, Map extendedParameters) { - ApiTestCaseWithBLOBs testCaseWithBLOBs = request.getBloBs(); - PerformInspectionUtil.countMatches(testCaseWithBLOBs.getRequest(), testCaseWithBLOBs.getId()); + ApiTestCaseWithBLOBs testCase = request.getBloBs(); + PerformInspectionUtil.countMatches(testCase.getRequest(), testCase.getId()); if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) { - testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getReportId()); + testCase = apiTestCaseMapper.selectByPrimaryKey(request.getReportId()); request.setCaseId(request.getReportId()); //通过测试计划id查询环境 request.setReportId(request.getTestPlanId()); } - LoggerUtil.info("开始执行单条用例【 " + testCaseWithBLOBs.getId() + " 】", request.getReportId()); + LoggerUtil.info("开始执行单条用例【 " + testCase.getId() + " 】", request.getReportId()); RunModeConfigDTO runModeConfigDTO = new RunModeConfigDTO(); - jMeterService.verifyPool(testCaseWithBLOBs.getProjectId(), runModeConfigDTO); + jMeterService.verifyPool(testCase.getProjectId(), runModeConfigDTO); - // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 - JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testCaseWithBLOBs.getId(), StringUtils.isEmpty(request.getReportId()) ? request.getId() : request.getReportId(), request.getRunMode(), null, null); - if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) { + JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testCase.getId(), + StringUtils.isEmpty(request.getReportId()) ? request.getId() + : request.getReportId(), request.getRunMode(), null,null); + if (testCase != null && StringUtils.isNotEmpty(testCase.getRequest())) { try { - HashTree jmeterHashTree = this.generateHashTree(request, testCaseWithBLOBs, runModeConfigDTO); - if (LoggerUtil.getLogger().isDebugEnabled()) { - LoggerUtil.debug("生成jmx文件:" + ElementUtil.hashTreeToString(jmeterHashTree)); - } - + HashTree jmeterHashTree = this.generateHashTree(request, testCase, runModeConfigDTO); // 调用执行方法 runRequest.setHashTree(jmeterHashTree); if (MapUtils.isNotEmpty(extendedParameters)) { @@ -148,11 +146,16 @@ public class ApiExecuteService { BaseSystemConfigDTO baseInfo = systemParameterService.getBaseInfo(); runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, null)); } - jMeterService.run(runRequest); + String projectId = testCase.getProjectId(); + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get(new ArrayList<>() {{ + this.add(projectId); + }})); } catch (Exception ex) { remakeReportService.updateReport(runRequest, ex.getMessage()); LogUtil.error(ex.getMessage(), ex); + return new MsExecResponseDTO(request.getCaseId(), request.getReport().getId(), request.getRunMode()); } + jMeterService.run(runRequest); } return new MsExecResponseDTO(request.getCaseId(), request.getReport().getId(), request.getRunMode()); } @@ -165,6 +168,9 @@ public class ApiExecuteService { request.getTestElement().getHashTree().get(0).setName(request.getId()); } JmeterRunRequestDTO runRequest = this.initRunRequest(request, bodyFiles); + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get(new ArrayList<>() {{ + this.add(request.getProjectId()); + }})); // 开始执行 jMeterService.run(runRequest); return new MsExecResponseDTO(runRequest.getTestId(), runRequest.getReportId(), runRequest.getRunMode()); diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java index e8144006fe..f4cb9b52ec 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java @@ -13,6 +13,7 @@ import io.metersphere.api.exec.api.ApiCaseExecuteService; import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.NewDriverManager; +import io.metersphere.api.jmeter.utils.ApiFakeErrorUtil; import io.metersphere.base.domain.ApiScenario; import io.metersphere.base.domain.ApiScenarioExample; import io.metersphere.base.domain.ApiScenarioReportWithBLOBs; @@ -466,6 +467,8 @@ public class ApiScenarioExecuteService { test.setProperty(ApiTestConstants.JAR_PATH, JSON.toJSONString(loadJar.keySet().stream().toList())); runRequest.setCustomJarInfo(loadJar); } + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get( + NewDriverManager.getProjectIds(request))); jMeterService.run(runRequest); return request.getId(); } diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioParallelService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioParallelService.java index 7bd28bb9ff..98a1f3e70c 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioParallelService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioParallelService.java @@ -4,8 +4,10 @@ import io.metersphere.api.dto.RunModeDataDTO; import io.metersphere.api.dto.automation.RunScenarioRequest; import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.api.jmeter.utils.ApiFakeErrorUtil; import io.metersphere.api.jmeter.utils.SmoothWeighted; import io.metersphere.commons.utils.GenerateHashTreeUtil; +import io.metersphere.commons.utils.JSON; import io.metersphere.constants.RunModeConstants; import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.dto.JmeterRunRequestDTO; @@ -57,6 +59,8 @@ public class ApiScenarioParallelService { dataDTO.getPlanEnvMap(), runRequest)); } runRequest.getExtendedParameters().put("projectId", executionQueue.getDetail().getProjectIds()); + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get( + JSON.parseArray(executionQueue.getDetail().getProjectIds()))); LoggerUtil.info("进入并行模式,准备执行场景:[ " + executeQueue.get(reportId).getReport().getName() + " ]", reportId); } catch (Exception e) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioSerialService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioSerialService.java index 55f1dd4733..c0ab2eda78 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioSerialService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioSerialService.java @@ -3,6 +3,7 @@ package io.metersphere.api.exec.scenario; import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.api.jmeter.utils.ApiFakeErrorUtil; import io.metersphere.api.jmeter.utils.SmoothWeighted; import io.metersphere.base.domain.ApiExecutionQueueDetail; import io.metersphere.base.domain.ApiScenarioReport; @@ -99,6 +100,8 @@ public class ApiScenarioSerialService { } // 开始执行 runRequest.getExtendedParameters().put("projectId", queue.getProjectIds()); + runRequest.setFakeErrorMap(ApiFakeErrorUtil.get( + JSON.parseArray(queue.getProjectIds()))); } catch (Exception e) { remakeReportService.testEnded(runRequest, e.getMessage()); LoggerUtil.error("脚本处理失败", runRequest.getReportId(), e); diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java index 9e7dfd9a3e..9a2ad0f239 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java @@ -90,25 +90,25 @@ public class JMeterService { /** * 添加调试监听 - * - * @param testId - * @param testPlan */ - private void addDebugListener(String testId, HashTree testPlan, String runMode) { + private void addDebugListener(JmeterRunRequestDTO request) { MsDebugListener resultCollector = new MsDebugListener(); - resultCollector.setName(testId); + resultCollector.setName(request.getReportId()); resultCollector.setProperty(TestElement.TEST_CLASS, MsDebugListener.class.getName()); resultCollector.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ViewResultsFullVisualizer")); resultCollector.setEnabled(true); - resultCollector.setRunMode(runMode); - + resultCollector.setRunMode(request.getRunMode()); + resultCollector.setFakeErrorMap(request.getFakeErrorMap()); // 添加DEBUG标示 - HashTree test = ArrayUtils.isNotEmpty(testPlan.getArray()) ? testPlan.getTree(testPlan.getArray()[0]) : null; - if (test != null && ArrayUtils.isNotEmpty(test.getArray()) && test.getArray()[0] instanceof ThreadGroup) { + HashTree test = ArrayUtils.isNotEmpty(request.getHashTree().getArray()) + ? request.getHashTree().getTree(request.getHashTree().getArray()[0]) : null; + + if (test != null && ArrayUtils.isNotEmpty(test.getArray()) + && test.getArray()[0] instanceof ThreadGroup) { ThreadGroup group = (ThreadGroup) test.getArray()[0]; group.setProperty(BackendListenerConstants.MS_DEBUG.name(), true); } - testPlan.add(testPlan.getArray()[0], resultCollector); + request.getHashTree().add(request.getHashTree().getArray()[0], resultCollector); } private void runLocal(JmeterRunRequestDTO request) { @@ -131,12 +131,12 @@ public class JMeterService { && request.getExtendedParameters().containsKey(ExtendedParameter.SYNC_STATUS) && (Boolean) request.getExtendedParameters().get(ExtendedParameter.SYNC_STATUS)) { LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加Debug Listener"); - addDebugListener(request.getReportId(), request.getHashTree(), request.getRunMode()); + addDebugListener(request); } if (request.isDebug()) { LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加Debug Listener"); - addDebugListener(request.getReportId(), request.getHashTree(), request.getRunMode()); + addDebugListener(request); } else { LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加同步接收结果 Listener"); JMeterBase.addBackendListener(request, request.getHashTree(), MsApiBackendListener.class.getCanonicalName()); @@ -178,6 +178,7 @@ public class JMeterService { engine.start(); } catch (Exception e) { remakeReportService.testEnded(request, e.getMessage()); + redisTemplateService.delFilePathAndScript(request.getReportId(), request.getTestId()); LoggerUtil.error("调用K8S执行请求[ " + request.getTestId() + " ]失败:", request.getReportId(), e); } } else if ((MapUtils.isNotEmpty(request.getExtendedParameters()) @@ -203,6 +204,7 @@ public class JMeterService { apiPoolDebugService.run(request, resources); } catch (Exception e) { remakeReportService.updateReport(request, e.getMessage()); + redisTemplateService.delFilePathAndScript(request.getReportId(), request.getTestId()); LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e); MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常"); } @@ -231,6 +233,7 @@ public class JMeterService { } } catch (Exception e) { remakeReportService.testEnded(request, e.getMessage()); + redisTemplateService.delFilePath(request.getReportId()); LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e); } } diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java index 1c9b7ba39c..2d6a96df45 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java @@ -2,9 +2,7 @@ package io.metersphere.api.jmeter; import com.fasterxml.jackson.core.type.TypeReference; import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil; -import io.metersphere.api.jmeter.utils.JmxFileUtil; import io.metersphere.commons.constants.ApiRunMode; -import io.metersphere.commons.constants.ExtendedParameter; import io.metersphere.commons.utils.JSON; import io.metersphere.dto.ResultDTO; import io.metersphere.service.ApiExecutionQueueService; @@ -14,6 +12,7 @@ import io.metersphere.utils.LoggerUtil; import lombok.Data; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.consumer.ConsumerRecord; @@ -60,13 +59,12 @@ public class KafkaListenerTask implements Runnable { return; } - if (dto.getArbitraryData() != null && dto.getArbitraryData().containsKey(ExtendedParameter.TEST_END) - && (Boolean) dto.getArbitraryData().get(ExtendedParameter.TEST_END)) { - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(dto.getReportId())); + if (BooleanUtils.isTrue(dto.getHasEnded())) { + redisTemplateService.delFilePath(dto.getReportId()); resultDTOS.add(dto); // 全局并发队列 PoolExecBlockingQueueUtil.offer(dto.getReportId()); - LoggerUtil.info("KAFKA消费结果处理状态:" + dto.getArbitraryData().get(ExtendedParameter.TEST_END), String.valueOf(record.key())); + LoggerUtil.info("KAFKA消费结束:", record.key()); } // 携带结果 if (CollectionUtils.isNotEmpty(dto.getRequestResults())) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java index 27bbe87f39..0ed08c13df 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java @@ -1,14 +1,15 @@ package io.metersphere.api.jmeter; +import com.fasterxml.jackson.core.type.TypeReference; import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil; -import io.metersphere.api.jmeter.utils.JmxFileUtil; -import io.metersphere.api.jmeter.utils.ReportStatusUtil; +import io.metersphere.utils.ReportStatusUtil; import io.metersphere.commons.constants.CommonConstants; import io.metersphere.commons.utils.*; -import io.metersphere.commons.vo.ResultVO; +import io.metersphere.vo.ResultVO; import io.metersphere.constants.BackendListenerConstants; import io.metersphere.constants.RunModeConstants; +import io.metersphere.dto.MsRegexDTO; import io.metersphere.dto.ResultDTO; import io.metersphere.jmeter.JMeterBase; import io.metersphere.service.ApiExecutionQueueService; @@ -65,8 +66,6 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen if (dto.isRetryEnable()) { queues.addAll(sampleResults); } else { - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(dto.getReportId())); - if (!StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) { dto.setConsole(FixedCapacityUtil.getJmeterLogger(getReportId(), false)); } @@ -84,9 +83,6 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen public void teardownTest(BackendListenerContext context) { try { LoggerUtil.info("进入TEST-END处理报告" + dto.getRunMode(), dto.getReportId()); - - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(dto.getReportId())); - super.teardownTest(context); // 获取执行日志 if (!StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) { @@ -125,6 +121,7 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen LoggerUtil.error("结果集处理异常", dto.getReportId(), e); } finally { queues.clear(); + redisTemplateService.delFilePath(dto.getReportId()); FileUtils.deleteBodyFiles(dto.getReportId()); if (FileServer.getFileServer() != null) { LoggerUtil.info("进入监听,开始关闭CSV", dto.getReportId()); @@ -158,6 +155,12 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen if (StringUtils.isNotEmpty(ept)) { dto.setExtendedParameters(JSON.parseObject(context.getParameter(BackendListenerConstants.EPT.name()), Map.class)); } + if (StringUtils.isNotBlank(context.getParameter(BackendListenerConstants.FAKE_ERROR.name()))) { + Map> fakeErrorMap = JSON.parseObject( + context.getParameter(BackendListenerConstants.FAKE_ERROR.name()), + new TypeReference>>() {}); + dto.setFakeErrorMap(fakeErrorMap); + } } private String getReportId() { diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsDebugListener.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsDebugListener.java index 1722bd6748..044cf20269 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsDebugListener.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsDebugListener.java @@ -23,6 +23,7 @@ import io.metersphere.api.dto.RunningParamKeys; import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.utils.*; +import io.metersphere.dto.MsRegexDTO; import io.metersphere.dto.RequestResult; import io.metersphere.jmeter.JMeterBase; import io.metersphere.service.definition.ApiDefinitionEnvService; @@ -38,6 +39,7 @@ import org.apache.jmeter.testelement.property.BooleanProperty; import org.apache.jmeter.threads.JMeterVariables; import java.io.Serializable; +import java.util.List; import java.util.Map; /** @@ -57,6 +59,7 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi private String runMode; private ApiDefinitionEnvService apiDefinitionEnvService; + private Map> fakeErrorMap; @Override public Object clone() { @@ -64,6 +67,10 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi return clone; } + public void setFakeErrorMap(Map> fakeErrorMap) { + this.fakeErrorMap = fakeErrorMap; + } + public boolean isErrorLogging() { return getPropertyAsBoolean(ERROR_LOGGING); } @@ -160,7 +167,7 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi SampleResult result = event.getResult(); this.setVars(result); if (isSampleWanted(result.isSuccessful(), result) && !StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) { - RequestResult requestResult = JMeterBase.getRequestResult(result); + RequestResult requestResult = JMeterBase.getRequestResult(result, fakeErrorMap); if (requestResult != null && ResultParseUtil.isNotAutoGenerateSampler(requestResult)) { MsgDTO dto = new MsgDTO(); dto.setExecEnd(false); diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java index 03673d72ad..91b7bed56a 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/NewDriverManager.java @@ -97,6 +97,14 @@ public class NewDriverManager { public static Map> loadJar(RunDefinitionRequest request, BooleanPool pool) { // 加载自定义JAR MsTestPlan testPlan = (MsTestPlan) request.getTestElement(); + List projectIds = getProjectIds(request); + Map> jars = getJars(projectIds, pool); + testPlan.setProjectJarIds(projectIds); + + return jars; + } + + public static List getProjectIds(RunDefinitionRequest request) { List projectIds = new ArrayList<>(); projectIds.add(request.getProjectId()); if (MapUtils.isNotEmpty(request.getEnvironmentMap())) { @@ -106,10 +114,6 @@ public class NewDriverManager { } }); } - Map> jars = getJars(projectIds, pool); - testPlan.setProjectJarIds(projectIds); - - return jars; + return projectIds; } - -} \ No newline at end of file +} diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ApiFakeErrorUtil.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ApiFakeErrorUtil.java new file mode 100644 index 0000000000..939c67349b --- /dev/null +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ApiFakeErrorUtil.java @@ -0,0 +1,57 @@ +package io.metersphere.api.jmeter.utils; + +import io.metersphere.base.domain.ErrorReportLibraryExample; +import io.metersphere.base.domain.ErrorReportLibraryWithBLOBs; +import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.commons.utils.JSON; +import io.metersphere.commons.utils.JSONUtil; +import io.metersphere.commons.utils.LogUtil; +import io.metersphere.dto.MsRegexDTO; +import io.metersphere.xpack.fake.error.ErrorReportLibraryService; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ApiFakeErrorUtil { + + private static final String REGEX_CONFIG = "regexConfig"; + + public static Map> get(List projectIds) { + Map> fakeErrorMap = new HashMap<>(); + if (CollectionUtils.isEmpty(projectIds)) { + return fakeErrorMap; + } + ErrorReportLibraryService service = CommonBeanFactory.getBean(ErrorReportLibraryService.class); + if (service != null) { + ErrorReportLibraryExample example = new ErrorReportLibraryExample(); + example.createCriteria().andProjectIdIn(projectIds).andStatusEqualTo(true); + List bloBs = service.selectByExampleWithBLOBs(example); + bloBs.forEach(item -> { + if (StringUtils.isNotEmpty(item.getContent())) { + try { + Map assertionMap = JSON.parseObject(item.getContent(), Map.class); + if (assertionMap != null) { + MsRegexDTO regexConfig = JSON.parseObject( + JSONUtil.toJSONString(assertionMap.get(REGEX_CONFIG)), MsRegexDTO.class); + regexConfig.setErrorCode(item.getErrorCode()); + if (fakeErrorMap.containsKey(item.getProjectId())) { + fakeErrorMap.get(item.getProjectId()).add(regexConfig); + } else { + fakeErrorMap.put(item.getProjectId(), new LinkedList<>() {{ + this.add(regexConfig); + }}); + } + } + } catch (Exception e) { + LogUtil.error(e); + } + } + }); + } + return fakeErrorMap; + } +} diff --git a/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java b/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java index 19be0417a1..dbd7dba72f 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java @@ -3,5 +3,4 @@ package io.metersphere.commons.constants; public class ExtendedParameter { public static final String SYNC_STATUS = "SYN_RES"; public static final String SAVE_RESULT = "SAVE_RESULT"; - public static final String TEST_END = "TEST_END"; } diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/FakeErrorParse.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/FakeErrorParse.java deleted file mode 100644 index 7710a961ba..0000000000 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/FakeErrorParse.java +++ /dev/null @@ -1,108 +0,0 @@ -package io.metersphere.commons.utils; - -import io.metersphere.api.dto.FakeErrorLibraryDTO; -import io.metersphere.api.dto.definition.FakeError; -import io.metersphere.api.dto.definition.MsRegexDTO; -import io.metersphere.base.domain.ErrorReportLibraryExample; -import io.metersphere.base.domain.ErrorReportLibraryWithBLOBs; -import io.metersphere.commons.enums.ApiReportStatus; -import io.metersphere.dto.RequestResult; -import io.metersphere.utils.JsonUtils; -import io.metersphere.xpack.fake.error.ErrorReportLibraryService; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * 误报解析类 - * - * @author xiaogang - */ -public class FakeErrorParse { - - public static FakeErrorLibraryDTO parseAssertions(RequestResult result) { - FakeErrorLibraryDTO fakeError = new FakeErrorLibraryDTO(); - if (StringUtils.isNotBlank(result.getFakeErrorMessage())) { - FakeError errorReportDTO = JsonUtils.parseObject(result.getFakeErrorMessage(), FakeError.class); - ErrorReportLibraryService service = CommonBeanFactory.getBean(ErrorReportLibraryService.class); - if (service != null) { - ErrorReportLibraryExample example = new ErrorReportLibraryExample(); - example.createCriteria().andProjectIdEqualTo(errorReportDTO.getProjectId()).andStatusEqualTo(true); - List bloBs = service.selectByExampleWithBLOBs(example); - List regexList = new ArrayList<>(); - bloBs.forEach(item -> { - if (StringUtils.isNotEmpty(item.getContent())) { - try { - Map assertionMap = JSON.parseObject(item.getContent(), Map.class); - if (assertionMap != null) { - MsRegexDTO regexConfig = JSON.parseObject(JSONUtil.toJSONString(assertionMap.get("regexConfig")), MsRegexDTO.class); - regexConfig.setErrorCode(item.getErrorCode()); - regexList.add(regexConfig); - } - } catch (Exception e) { - LogUtil.error(e); - } - } - }); - //根据配置来筛选断言、获取误报编码、获取接口状态是否是误报 - List errorCodeList = new ArrayList<>(); - regexList.forEach(item -> { - if (StringUtils.isNotEmpty(item.getSubject())) { - switch (item.getSubject()) { - case "Response Code" -> - item.setPass(parseResponseCode(result.getResponseResult().getResponseCode(), item.getValue(), item.getCondition())); - - case "Response Headers" -> - item.setPass(parseResponseCode(result.getResponseResult().getHeaders(), item.getValue(), item.getCondition())); - - case "Response Data" -> - item.setPass(parseResponseCode(result.getResponseResult().getBody(), item.getValue(), item.getCondition())); - default -> item.setPass(false); - } - } - if (item.isPass()) { - errorCodeList.add(item.getErrorCode()); - } - }); - boolean higherThanError = errorReportDTO.isHigherThanError(); - boolean higherThanSuccess = errorReportDTO.isHigherThanSuccess(); - if (CollectionUtils.isNotEmpty(errorCodeList)) { - if ((higherThanError && !result.isSuccess()) || (higherThanSuccess && result.isSuccess())) { - fakeError.setRequestStatus(ApiReportStatus.FAKE_ERROR.name()); - } - fakeError.setErrorCodeList(errorCodeList); - } - LogUtil.info(" FAKE_ERROR result: config-higherThanError:" + higherThanError - + ", config-higherThanSuccess:" + higherThanSuccess - + ", resultIsSuccess: " + result.isSuccess() - + ", isFakeError: " + ((higherThanError && !result.isSuccess()) || (higherThanSuccess && result.isSuccess())) - + "; status:" + fakeError.getRequestStatus()); - } - } - fakeError.setResult(result); - return fakeError; - } - - private static boolean parseResponseCode(String result, String regexDTO, String condition) { - return switch (condition.toUpperCase()) { - case "CONTAINS" -> result.contains(regexDTO); - - case "NOT_CONTAINS" -> notContains(result, regexDTO); - - case "EQUALS" -> StringUtils.equals(result, regexDTO); - - case "START_WITH" -> result.startsWith(regexDTO); - - case "END_WITH" -> result.endsWith(regexDTO); - - default -> false; - }; - } - - private static boolean notContains(String result, String regexDTO) { - return !result.contains(regexDTO); - } -} \ No newline at end of file diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java index 4c72a1ef29..b749f942f9 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java @@ -165,7 +165,7 @@ public class GenerateHashTreeUtil { } catch (Exception ex) { LoggerUtil.error("场景资源:" + item.getName() + ", 生成执行脚本失败", runRequest.getReportId(), ex); - MSException.throwException("场景资源:" + item.getName() + ", 生成执行脚本失败"); + MSException.throwException("场景资源:" + item.getName() + ", 生成执行脚本失败" + ex.getMessage()); } LogUtil.info(testPlan.getJmx(jmeterHashTree)); diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/ResponseUtil.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/ResponseUtil.java index a62d9f3087..d553cb0321 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/ResponseUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/utils/ResponseUtil.java @@ -3,13 +3,11 @@ package io.metersphere.commons.utils; import com.fasterxml.jackson.core.util.DefaultIndenter; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; -import io.metersphere.api.dto.FakeErrorLibraryDTO; import io.metersphere.api.dto.RequestResultExpandDTO; import io.metersphere.commons.enums.ApiReportStatus; import io.metersphere.commons.enums.ResponseFormatType; import io.metersphere.dto.RequestResult; import io.metersphere.dto.ResponseResult; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import java.util.HashMap; @@ -20,29 +18,22 @@ import java.util.Map; */ public class ResponseUtil { - public static RequestResultExpandDTO parseByRequestResult(RequestResult baseResult) { - //根据responseheader的信息来处理返回数据 - baseResult = ResponseUtil.parseResponseBodyByHeader(baseResult); + public static RequestResultExpandDTO parseByRequestResult(RequestResult requestResult) { + requestResult = ResponseUtil.parseResponseBodyByHeader(requestResult); //解析是否含有误报库信息 - FakeErrorLibraryDTO errorCodeDTO = FakeErrorParse.parseAssertions(baseResult); - RequestResult requestResult = errorCodeDTO.getResult(); RequestResultExpandDTO expandDTO = new RequestResultExpandDTO(); BeanUtils.copyBean(expandDTO, requestResult); - if (CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())) { + if (StringUtils.isNotBlank(requestResult.getFakeErrorCode())) { Map expandMap = new HashMap<>(); - expandMap.put(ApiReportStatus.FAKE_ERROR.name(), errorCodeDTO.getErrorCodeStr()); - if (StringUtils.equalsIgnoreCase(errorCodeDTO.getRequestStatus(), ApiReportStatus.FAKE_ERROR.name())) { + expandMap.put(ApiReportStatus.FAKE_ERROR.name(), requestResult.getFakeErrorCode()); + if (StringUtils.equalsIgnoreCase(requestResult.getStatus(), ApiReportStatus.FAKE_ERROR.name())) { expandMap.put("status", ApiReportStatus.FAKE_ERROR.name()); } expandDTO.setAttachInfoMap(expandMap); - LogUtil.info(" FAKE_ERROR result.id:" + errorCodeDTO.getRequestStatus() + "; AttachInfoMap:" + JSON.toJSONString(expandDTO.getAttachInfoMap())); } - if (StringUtils.equalsIgnoreCase(errorCodeDTO.getRequestStatus(), ApiReportStatus.FAKE_ERROR.name())) { - expandDTO.setStatus(errorCodeDTO.getRequestStatus()); + if (StringUtils.equalsIgnoreCase(requestResult.getStatus(), ApiReportStatus.FAKE_ERROR.name())) { + expandDTO.setStatus(requestResult.getStatus()); } - LogUtil.info(" FAKE_ERROR result.id:" + errorCodeDTO.getRequestStatus() - + ";status:" + expandDTO.getStatus() - + " AttachInfoMap:" + (expandDTO.getAttachInfoMap() == null ? "null" : JSON.toJSONString(expandDTO.getAttachInfoMap()))); return expandDTO; } diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/ResultConversionUtil.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/ResultConversionUtil.java index fbf98b144c..3bc0e91f10 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/ResultConversionUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/utils/ResultConversionUtil.java @@ -2,12 +2,9 @@ package io.metersphere.commons.utils; import io.metersphere.api.dto.ApiScenarioReportBaseInfoDTO; -import io.metersphere.api.dto.FakeErrorLibraryDTO; import io.metersphere.base.domain.ApiScenarioReportResultWithBLOBs; -import io.metersphere.commons.enums.ApiReportStatus; import io.metersphere.dto.RequestResult; import io.metersphere.utils.LoggerUtil; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import java.nio.charset.StandardCharsets; @@ -15,26 +12,15 @@ import java.util.UUID; public class ResultConversionUtil { - public static ApiScenarioReportResultWithBLOBs getApiScenarioReportResult(String reportId, RequestResult requestResult) { - //解析误报内容 - FakeErrorLibraryDTO errorCodeDTO = FakeErrorParse.parseAssertions(requestResult); - RequestResult result = errorCodeDTO.getResult(); + public static ApiScenarioReportResultWithBLOBs getApiScenarioReportResult(String reportId, RequestResult result) { String resourceId = result.getResourceId(); - ApiScenarioReportResultWithBLOBs report = newScenarioReportResult(reportId, resourceId); report.setTotalAssertions(Long.parseLong(result.getTotalAssertions() + StringUtils.EMPTY)); report.setPassAssertions(Long.parseLong(result.getPassAssertions() + StringUtils.EMPTY)); - String status = result.getError() == 0 ? ApiReportStatus.SUCCESS.name() : ApiReportStatus.ERROR.name(); - if (CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())) { - report.setErrorCode(errorCodeDTO.getErrorCodeStr()); - } - if (StringUtils.equalsIgnoreCase(errorCodeDTO.getRequestStatus(), ApiReportStatus.FAKE_ERROR.name())) { - status = errorCodeDTO.getRequestStatus(); - } - requestResult.setStatus(status); - report.setStatus(status); + report.setErrorCode(result.getFakeErrorCode()); + report.setStatus(result.getStatus()); report.setRequestTime(result.getEndTime() - result.getStartTime()); - LoggerUtil.info("报告ID [ " + reportId + " ] 执行请求:【 " + requestResult.getName() + "】 入库存储"); + LoggerUtil.info("报告ID [ " + reportId + " ] 执行请求:【 " + result.getName() + "】 入库存储"); return report; } diff --git a/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java b/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java index 686fac0e91..71cd1724d6 100644 --- a/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java +++ b/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Component; public class ApiExecutionQueueListener { private ApiExecutionQueueService queueService; - @QuartzScheduled(cron = "0 0/10 0/1 * * ?") + @QuartzScheduled(cron = "0 0/30 0/1 * * ?") public void execute() { if (queueService == null) { queueService = CommonBeanFactory.getBean(ApiExecutionQueueService.class); diff --git a/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java b/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java index ef6cc1f877..e304b58dec 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java @@ -6,7 +6,6 @@ import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.exec.scenario.ApiScenarioSerialService; import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterThreadUtils; -import io.metersphere.api.jmeter.utils.JmxFileUtil; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.ext.BaseApiExecutionQueueMapper; @@ -46,8 +45,6 @@ public class ApiExecutionQueueService { @Resource private ApiExecutionQueueDetailMapper executionQueueDetailMapper; @Resource - private RedisTemplateService redisTemplateService; - @Resource private ApiScenarioSerialService apiScenarioSerialService; @Resource private ApiScenarioReportService apiScenarioReportService; @@ -227,37 +224,39 @@ public class ApiExecutionQueueService { public DBTestQueue handleQueue(String id, String testId) { ApiExecutionQueue executionQueue = queueMapper.selectByPrimaryKey(id); DBTestQueue queue = new DBTestQueue(); - if (executionQueue != null) { - BeanUtils.copyBean(queue, executionQueue); - LoggerUtil.info("Get the next execution point:【" + id + "】"); + if (executionQueue == null) { + LoggerUtil.info("The queue was accidentally deleted:【" + id + "】"); + return queue; + } + BeanUtils.copyBean(queue, executionQueue); + LoggerUtil.info("Get the next execution point:【" + id + "】"); - ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample(); - example.setOrderByClause("sort asc"); - example.createCriteria().andQueueIdEqualTo(id); - List queues = executionQueueDetailMapper.selectByExampleWithBLOBs(example); + ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample(); + example.setOrderByClause("sort asc"); + example.createCriteria().andQueueIdEqualTo(id); + List queues = executionQueueDetailMapper.selectByExampleWithBLOBs(example); + if (CollectionUtils.isNotEmpty(queues)) { + // 处理掉当前已经执行完成的资源 + List completedQueues = queues.stream() + .filter(item -> StringUtils.equals(item.getTestId(), testId)) + .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(completedQueues)) { + ApiExecutionQueueDetail completed = completedQueues.get(0); + queue.setCompletedReportId(completed.getReportId()); + executionQueueDetailMapper.deleteByPrimaryKey(completed.getId()); + queues.remove(completed); + } + // 取出下一个要执行的节点 if (CollectionUtils.isNotEmpty(queues)) { - // 处理掉当前已经执行完成的资源 - List completedQueues = queues.stream().filter(item -> StringUtils.equals(item.getTestId(), testId)).collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(completedQueues)) { - ApiExecutionQueueDetail completed = completedQueues.get(0); - queue.setCompletedReportId(completed.getReportId()); - executionQueueDetailMapper.deleteByPrimaryKey(completed.getId()); - queues.remove(completed); - } - // 取出下一个要执行的节点 - if (CollectionUtils.isNotEmpty(queues)) { - queue.setDetail(queues.get(0)); - } else { - LoggerUtil.info("execution complete,clear queue:【" + id + "】"); - queueMapper.deleteByPrimaryKey(id); - } + queue.setDetail(queues.get(0)); } else { LoggerUtil.info("execution complete,clear queue:【" + id + "】"); queueMapper.deleteByPrimaryKey(id); } } else { - LoggerUtil.info("The queue was accidentally deleted:【" + id + "】"); + LoggerUtil.info("execution complete,clear queue:【" + id + "】"); + queueMapper.deleteByPrimaryKey(id); } return queue; } @@ -312,50 +311,37 @@ public class ApiExecutionQueueService { } return; } - // 获取串行下一个执行节点 + // 清理当前节点并获取下一个要执行的资源 DBTestQueue executionQueue = this.handleQueue(dto.getQueueId(), dto.getTestId()); - if (executionQueue != null) { - // 串行失败停止 - if (BooleanUtils.isTrue(executionQueue.getFailure()) && StringUtils.isNotEmpty(executionQueue.getCompletedReportId())) { - boolean isNext = failure(executionQueue, dto); - if (!isNext) { - return; - } + // 串行失败停止 + if (BooleanUtils.isTrue(executionQueue.getFailure()) && StringUtils.isNotEmpty(executionQueue.getCompletedReportId())) { + boolean isNext = failure(executionQueue, dto); + if (!isNext) { + return; } - LoggerUtil.info("开始处理执行队列:" + executionQueue.getId() + " 当前资源是:" + dto.getTestId() + "报告ID:" + dto.getReportId()); - if (executionQueue.getDetail() != null && StringUtils.isNotEmpty(executionQueue.getDetail().getTestId())) { - if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) { - LoggerUtil.info("当前执行队列是:" + JSON.toJSONString(executionQueue.getDetail())); - // 防止重复执行 - String key = StringUtils.join(RunModeConstants.SERIAL.name(), "_", executionQueue.getDetail().getReportId()); - boolean isNext = redisTemplateService.setIfAbsent(key, executionQueue.getDetail().getQueueId()); - if (!isNext) { - return; - } - redisTemplateService.expire(key); - 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())) { - apiScenarioSerialService.serial(executionQueue); - } else { - apiCaseSerialService.serial(executionQueue); - } - } - } else { - // 集合报告合并 - this.margeReport(dto); - queueMapper.deleteByPrimaryKey(dto.getQueueId()); - LoggerUtil.info("Queue execution ends:" + dto.getQueueId()); - } - - ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample(); - example.createCriteria().andQueueIdEqualTo(dto.getQueueId()).andTestIdEqualTo(dto.getTestId()); - executionQueueDetailMapper.deleteByExample(example); } - LoggerUtil.info("处理队列结束:" + dto.getReportId() + "QID:" + dto.getQueueId()); + LoggerUtil.info("开始处理执行队列:" + executionQueue.getId() + " 当前资源是:" + dto.getTestId() + "报告ID:" + dto.getReportId()); + if (executionQueue.getDetail() != null && StringUtils.isNotEmpty(executionQueue.getDetail().getTestId())) { + if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) { + 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())) { + // 场景执行 + apiScenarioSerialService.serial(executionQueue); + } else { + // 接口用例执行 + apiCaseSerialService.serial(executionQueue); + } + } + } else { + // 集合报告合并 + this.margeReport(dto); + queueMapper.deleteByPrimaryKey(dto.getQueueId()); + LoggerUtil.info("Queue execution ends:" + dto.getQueueId()); + } } private void margeReport(ResultDTO dto) { @@ -396,7 +382,6 @@ public class ApiExecutionQueueService { dto.setQueueId(item.getQueueId()); dto.setTestId(item.getTestId()); if (StringUtils.equalsAnyIgnoreCase(queue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) { - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(item.getReportId())); ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId()); // 报告已经被删除则队列也删除 if (report == null) { @@ -408,10 +393,6 @@ public class ApiExecutionQueueService { apiScenarioReportMapper.updateByPrimaryKeySelective(report); LoggerUtil.info("超时处理报告:" + report.getId()); if (queue != null && StringUtils.equalsIgnoreCase(item.getType(), RunModeConstants.SERIAL.toString())) { - // 删除串行资源锁 - String key = StringUtils.join(RunModeConstants.SERIAL.name(), "_", dto.getReportId()); - redisTemplateService.delete(key); - LoggerUtil.info("超时处理报告:【" + report.getId() + "】进入下一个执行"); dto.setTestPlanReportId(queue.getReportId()); dto.setReportId(queue.getReportId()); @@ -424,7 +405,6 @@ public class ApiExecutionQueueService { } } } else { - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(item.getReportId())); // 用例/接口超时结果处理 ApiDefinitionExecResultWithBLOBs result = apiDefinitionExecResultMapper.selectByPrimaryKey(item.getReportId()); if (result != null && StringUtils.equalsAnyIgnoreCase(result.getStatus(), TestPlanReportStatus.RUNNING.name())) { @@ -476,8 +456,6 @@ public class ApiExecutionQueueService { checkTestPlanCaseTestEnd(null, null, reportId); }); } - // 清除异常队列/一般是服务突然停止产生 - extApiExecutionQueueMapper.delete(); } public void stop(String reportId) { @@ -539,11 +517,46 @@ public class ApiExecutionQueueService { * 服务异常重启处理 */ public void exceptionHandling() { - LogUtil.info("开始处理服务重启导致执行未完成的报告状态"); - // 更新报告状态 - extApiScenarioReportMapper.updateAllStatus(); - // 更新用例报告状态 - extApiDefinitionExecResultMapper.updateAllStatus(); - LogUtil.info("处理服务重启导致执行未完成的报告状态完成"); + try { + LogUtil.info("开始处理服务重启导致执行未完成的报告状态"); + // 更新报告状态 + extApiScenarioReportMapper.updateAllStatus(); + // 更新用例报告状态 + extApiDefinitionExecResultMapper.updateAllStatus(); + LogUtil.info("处理服务重启导致执行未完成的报告状态完成"); + // 清理队列 + final List apiModes = new ArrayList<>() {{ + this.add(ApiRunMode.SCENARIO.name()); + this.add(ApiRunMode.SCHEDULE_SCENARIO.name()); + this.add(ApiRunMode.SCENARIO_PLAN.name()); + this.add(ApiRunMode.SCHEDULE_SCENARIO_PLAN.name()); + this.add(ApiRunMode.JENKINS_SCENARIO_PLAN.name()); + this.add(ApiRunMode.DEFINITION.name()); + this.add(ApiRunMode.JENKINS.name()); + this.add(ApiRunMode.API_PLAN.name()); + this.add(ApiRunMode.SCHEDULE_API_PLAN.name()); + this.add(ApiRunMode.JENKINS_API_PLAN.name()); + this.add(ApiRunMode.MANUAL_PLAN.name()); + }}; + + ApiExecutionQueueExample queueExample = new ApiExecutionQueueExample(); + queueExample.createCriteria().andRunModeIn(apiModes); + List queues = apiExecutionQueueMapper.selectByExample(queueExample); + if (CollectionUtils.isNotEmpty(queues)) { + List ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList()); + ApiExecutionQueueDetailExample queueDetailExample = new ApiExecutionQueueDetailExample(); + queueDetailExample.createCriteria().andQueueIdIn(ids); + apiExecutionQueueDetailMapper.deleteByExample(queueDetailExample); + // 通知测试计划 + queues.forEach(item -> { + if (StringUtils.endsWith(item.getRunMode(), "PLAN")) { + checkTestPlanCaseTestEnd(null, null, item.getReportId()); + } + }); + apiExecutionQueueMapper.deleteByExample(queueExample); + } + } catch (Exception e) { + LoggerUtil.error(e); + } } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java b/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java index b492803e0c..44cc1a242e 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java @@ -374,7 +374,7 @@ public class ApiJMeterFileService { Object jmxFileInfoObj = redisTemplateService.get(JmxFileUtil.getExecuteFileKeyInRedis(request.getReportId())); List fileInJmx = JmxFileUtil.formatRedisJmxFileString(jmxFileInfoObj); - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(request.getReportId())); + redisTemplateService.delFilePath(request.getReportId()); if (CollectionUtils.isNotEmpty(request.getBodyFiles())) { request.getBodyFiles().forEach(attachmentBodyFile -> { diff --git a/api-test/backend/src/main/java/io/metersphere/service/RedisTemplateService.java b/api-test/backend/src/main/java/io/metersphere/service/RedisTemplateService.java index f22c2d8226..25ced0fa31 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/RedisTemplateService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/RedisTemplateService.java @@ -1,17 +1,15 @@ package io.metersphere.service; +import io.metersphere.api.jmeter.utils.JmxFileUtil; import io.metersphere.utils.LoggerUtil; import jakarta.annotation.Resource; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import java.util.concurrent.TimeUnit; - @Service public class RedisTemplateService { @Resource private RedisTemplate redisTemplate; - public static final long TIME_OUT = 30; public boolean setIfAbsent(String key, String value) { try { @@ -22,15 +20,6 @@ public class RedisTemplateService { } } - public boolean expire(String key) { - try { - return redisTemplate.expire(key, TIME_OUT, TimeUnit.MINUTES); - } catch (Exception e) { - LoggerUtil.error(key, e); - return false; - } - } - public Object get(String key) { try { return redisTemplate.opsForValue().get(key); @@ -48,4 +37,13 @@ public class RedisTemplateService { return false; } } + + public void delFilePathAndScript(String reportId, String testId) { + delete(JmxFileUtil.getExecuteScriptKey(reportId, testId)); + delete(JmxFileUtil.getExecuteFileKeyInRedis(reportId)); + } + + public void delFilePath(String reportId) { + delete(JmxFileUtil.getExecuteFileKeyInRedis(reportId)); + } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java b/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java index 52e83ab2b1..0e92fa155e 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java @@ -9,15 +9,11 @@ import io.metersphere.commons.utils.FixedCapacityUtil; import io.metersphere.dto.JmeterRunRequestDTO; import io.metersphere.dto.ResultDTO; import io.metersphere.utils.LoggerUtil; -import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @Service public class RemakeReportService { - @Resource - private RedisTemplateService redisTemplateService; - public void queueNext(JmeterRunRequestDTO request, String errorMsg) { try { ResultDTO dto = new ResultDTO(); @@ -35,11 +31,8 @@ public class RemakeReportService { LoggerUtil.info("Check Processing Test Plan report status.queueId:" + dto.getQueueId() + ",runMode:" + dto.getRunMode() + ",testId:" + dto.getTestId(), dto.getReportId()); CommonBeanFactory.getBean(ApiExecutionQueueService.class).checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId()); } catch (Exception e) { - LoggerUtil.error("回退报告异常", request.getReportId(), e); - } finally { ApiLocalRunner.clearCache(request.getReportId()); - redisTemplateService.delete(JmxFileUtil.getExecuteScriptKey(request.getReportId(), request.getTestId())); - redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(request.getReportId())); + LoggerUtil.error("回退报告异常", request.getReportId(), e); } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/TestResultService.java b/api-test/backend/src/main/java/io/metersphere/service/TestResultService.java index ba7fbf2fd5..367e91aa7e 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/TestResultService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/TestResultService.java @@ -2,7 +2,7 @@ package io.metersphere.service; import io.metersphere.api.dto.automation.ApiTestReportVariable; import io.metersphere.api.exec.scenario.ApiEnvironmentRunningParamService; -import io.metersphere.api.jmeter.utils.ReportStatusUtil; +import io.metersphere.utils.ReportStatusUtil; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiDefinitionExecResultMapper; import io.metersphere.base.mapper.ApiScenarioMapper; @@ -13,7 +13,7 @@ import io.metersphere.commons.enums.ApiReportStatus; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.JSON; -import io.metersphere.commons.vo.ResultVO; +import io.metersphere.vo.ResultVO; import io.metersphere.constants.RunModeConstants; import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.dto.RequestResult; @@ -204,11 +204,6 @@ public class TestResultService { } public void testEnded(ResultDTO dto) { - // 删除串行资源锁 - if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) { - String key = StringUtils.join(RunModeConstants.SERIAL.name(), "_", dto.getReportId()); - redisTemplateService.delete(key); - } if (dto.getRequestResults() == null) { dto.setRequestResults(new LinkedList<>()); } diff --git a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java index b5328c5f9e..7ab168434e 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java @@ -7,7 +7,7 @@ import io.metersphere.api.dto.automation.ExecuteType; import io.metersphere.api.dto.automation.RunScenarioRequest; import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.api.dto.definition.RunDefinitionRequest; -import io.metersphere.api.jmeter.utils.ReportStatusUtil; +import io.metersphere.utils.ReportStatusUtil; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper; @@ -20,7 +20,7 @@ import io.metersphere.commons.enums.ApiReportStatus; import io.metersphere.commons.enums.ExecutionExecuteTypeEnum; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.*; -import io.metersphere.commons.vo.ResultVO; +import io.metersphere.vo.ResultVO; import io.metersphere.constants.RunModeConstants; import io.metersphere.dto.*; import io.metersphere.i18n.Translator; diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/constants/BackendListenerConstants.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/constants/BackendListenerConstants.java index add7663694..83903ce845 100644 --- a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/constants/BackendListenerConstants.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/constants/BackendListenerConstants.java @@ -1,5 +1,7 @@ package io.metersphere.constants; public enum BackendListenerConstants { - RETRY_ENABLE, TEST_ID, NAME, REPORT_ID, RUN_MODE, REPORT_TYPE, CLASS_NAME, MS_TEST_PLAN_REPORT_ID, RUN, KAFKA_CONFIG, QUEUE_ID, RUN_TYPE, EPT, MS_DEBUG + RETRY_ENABLE, TEST_ID, NAME, REPORT_ID, RUN_MODE, REPORT_TYPE, + CLASS_NAME, MS_TEST_PLAN_REPORT_ID, RUN, KAFKA_CONFIG, QUEUE_ID, + RUN_TYPE, EPT, MS_DEBUG, FAKE_ERROR } diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorDTO.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorDTO.java new file mode 100644 index 0000000000..5c919ba6f2 --- /dev/null +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorDTO.java @@ -0,0 +1,11 @@ +package io.metersphere.dto; + +import lombok.Data; + +@Data +public class FakeErrorDTO { + private String projectId; + private boolean higherThanSuccess; + private boolean higherThanError; +} + diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/FakeErrorLibraryDTO.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorLibraryDTO.java similarity index 90% rename from api-test/backend/src/main/java/io/metersphere/api/dto/FakeErrorLibraryDTO.java rename to framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorLibraryDTO.java index c83cceebd9..efcf144742 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/FakeErrorLibraryDTO.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/FakeErrorLibraryDTO.java @@ -1,6 +1,5 @@ -package io.metersphere.api.dto; +package io.metersphere.dto; -import io.metersphere.dto.RequestResult; import lombok.Getter; import lombok.Setter; import org.apache.commons.collections.CollectionUtils; diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/JmeterRunRequestDTO.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/JmeterRunRequestDTO.java index 13403a9e76..5671fb70ef 100644 --- a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/JmeterRunRequestDTO.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/JmeterRunRequestDTO.java @@ -97,6 +97,9 @@ public class JmeterRunRequestDTO { //自定义jar信息 private Map> customJarInfo; + // 自定义误报库 + private Map> fakeErrorMap; + private String triggerMode; public JmeterRunRequestDTO() { diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/MsRegexDTO.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/MsRegexDTO.java similarity index 82% rename from api-test/backend/src/main/java/io/metersphere/api/dto/definition/MsRegexDTO.java rename to framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/MsRegexDTO.java index b33fbab29e..7ff9de4b65 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/MsRegexDTO.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/MsRegexDTO.java @@ -1,4 +1,4 @@ -package io.metersphere.api.dto.definition; +package io.metersphere.dto; import lombok.Data; diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/RequestResult.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/RequestResult.java index d886698de7..db9da1861c 100644 --- a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/RequestResult.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/RequestResult.java @@ -54,5 +54,6 @@ public class RequestResult { } private String fakeErrorMessage; - + // 误报编码名称 + private String fakeErrorCode; } diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/ResultDTO.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/ResultDTO.java index 5a3cac5076..5398d0f979 100644 --- a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/ResultDTO.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/dto/ResultDTO.java @@ -17,6 +17,8 @@ public class ResultDTO { private String runType; private String console; private String runningDebugSampler; + // 是否是结束操作 + private Boolean hasEnded; // 失败重试 private boolean retryEnable; /** @@ -26,5 +28,7 @@ public class ResultDTO { // 预留一个参数,可以放任何数据 private Map arbitraryData; + // 误报规则 + Map> fakeErrorMap; } diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/enums/ApiReportStatus.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/enums/ApiReportStatus.java new file mode 100644 index 0000000000..faf7f17708 --- /dev/null +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/enums/ApiReportStatus.java @@ -0,0 +1,5 @@ +package io.metersphere.enums; + +public enum ApiReportStatus { + PENDING, RUNNING, RERUNNING, ERROR, SUCCESS, FAKE_ERROR, STOPPED, TIMEOUT +} diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/jmeter/JMeterBase.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/jmeter/JMeterBase.java index f82cfd176a..c985b3de24 100644 --- a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/jmeter/JMeterBase.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/jmeter/JMeterBase.java @@ -1,12 +1,11 @@ package io.metersphere.jmeter; +import com.alibaba.fastjson.JSON; import io.metersphere.constants.BackendListenerConstants; import io.metersphere.constants.HttpMethodConstants; import io.metersphere.dto.*; -import io.metersphere.utils.JMeterVars; -import io.metersphere.utils.JsonUtils; -import io.metersphere.utils.ListenerUtil; -import io.metersphere.utils.LoggerUtil; +import io.metersphere.enums.ApiReportStatus; +import io.metersphere.utils.*; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -26,8 +25,10 @@ import java.util.List; import java.util.Map; public class JMeterBase { - private final static String THREAD_SPLIT = " "; + private final static String TRANSACTION = "Transaction="; + private final static String SPLIT_EQ = "split=="; + private final static String SPLIT_AND = "split&&"; public static HashTree getHashTree(Object scriptWrapper) throws Exception { Field field = scriptWrapper.getClass().getDeclaredField("testPlan"); @@ -51,6 +52,9 @@ public class JMeterBase { arguments.addArgument(BackendListenerConstants.QUEUE_ID.name(), request.getQueueId()); arguments.addArgument(BackendListenerConstants.RUN_TYPE.name(), request.getRunType()); arguments.addArgument(BackendListenerConstants.RETRY_ENABLE.name(), String.valueOf(request.isRetryEnable())); + if (MapUtils.isNotEmpty(request.getFakeErrorMap())) { + arguments.addArgument(BackendListenerConstants.FAKE_ERROR.name(), JSON.toJSONString(request.getFakeErrorMap())); + } if (MapUtils.isNotEmpty(request.getExtendedParameters())) { arguments.addArgument(BackendListenerConstants.EPT.name(), JsonUtils.toJSONString(request.getExtendedParameters())); } @@ -65,9 +69,8 @@ public class JMeterBase { LoggerUtil.info("报告添加BackendListener 结束", request.getTestId()); } - public static RequestResult getRequestResult(SampleResult result) { + public static RequestResult getRequestResult(SampleResult result, Map> fakeErrorMap) { LoggerUtil.debug("开始处理结果资源【" + result.getSampleLabel() + "】"); - String threadName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT); RequestResult requestResult = new RequestResult(); requestResult.setThreadName(threadName); @@ -92,7 +95,7 @@ public class JMeterBase { } for (SampleResult subResult : result.getSubResults()) { - requestResult.getSubRequestResults().add(getRequestResult(subResult)); + requestResult.getSubRequestResults().add(getRequestResult(subResult, fakeErrorMap)); } ResponseResult responseResult = requestResult.getResponseResult(); // 超过20M的文件不入库 @@ -140,6 +143,16 @@ public class JMeterBase { } LoggerUtil.debug("处理结果资源【" + result.getSampleLabel() + "】结束"); + // 误报处理 + FakeErrorLibraryDTO errorCodeDTO = FakeErrorUtils.parseAssertions(requestResult, fakeErrorMap); + if (CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())) { + requestResult.setFakeErrorCode(errorCodeDTO.getErrorCodeStr()); + } + String status = requestResult.getError() == 0 ? "SUCCESS" : "ERROR"; + if (StringUtils.equalsIgnoreCase(errorCodeDTO.getRequestStatus(), ApiReportStatus.FAKE_ERROR.name())) { + status = ApiReportStatus.FAKE_ERROR.name(); + } + requestResult.setStatus(status); return requestResult; } @@ -147,13 +160,13 @@ public class JMeterBase { ResponseAssertionResult responseAssertionResult = new ResponseAssertionResult(); responseAssertionResult.setName(assertionResult.getName()); - if (StringUtils.isNotEmpty(assertionResult.getName()) && assertionResult.getName().indexOf("split==") != -1) { + if (StringUtils.isNotEmpty(assertionResult.getName()) && assertionResult.getName().indexOf(SPLIT_EQ) != -1) { if (assertionResult.getName().indexOf("JSR223") != -1) { - String[] array = assertionResult.getName().split("split==", 3); + String[] array = assertionResult.getName().split(SPLIT_EQ, 3); if (array.length > 2 && "JSR223".equals(array[0])) { responseAssertionResult.setName(array[1]); - if (array[2].indexOf("split&&") != -1) { - String[] content = array[2].split("split&&"); + if (array[2].indexOf(SPLIT_AND) != -1) { + String[] content = array[2].split(SPLIT_AND); responseAssertionResult.setContent(content[0]); if (content.length > 1) { responseAssertionResult.setScript(content[1]); @@ -163,7 +176,7 @@ public class JMeterBase { } } } else { - String[] array = assertionResult.getName().split("split=="); + String[] array = assertionResult.getName().split(SPLIT_EQ); responseAssertionResult.setName(array[0]); StringBuffer content = new StringBuffer(); for (int i = 1; i < array.length; i++) { @@ -214,7 +227,7 @@ public class JMeterBase { List environmentList = new ArrayList<>(); sampleResults.forEach(result -> { ListenerUtil.setVars(result); - RequestResult requestResult = JMeterBase.getRequestResult(result); + RequestResult requestResult = JMeterBase.getRequestResult(result, dto.getFakeErrorMap()); if (StringUtils.equals(result.getSampleLabel(), ListenerUtil.RUNNING_DEBUG_SAMPLER_NAME)) { String evnStr = result.getResponseDataAsString(); environmentList.add(evnStr); @@ -222,7 +235,7 @@ public class JMeterBase { //检查是否有关系到最终执行结果的全局前后置脚本。 boolean resultNotFilterOut = ListenerUtil.checkResultIsNotFilterOut(requestResult); if (resultNotFilterOut) { - if (StringUtils.isNotEmpty(requestResult.getName()) && requestResult.getName().startsWith("Transaction=")) { + if (StringUtils.isNotEmpty(requestResult.getName()) && requestResult.getName().startsWith(TRANSACTION)) { transactionFormat(requestResult.getSubRequestResults(), requestResults); } else { requestResults.add(requestResult); diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/FakeErrorUtils.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/FakeErrorUtils.java new file mode 100644 index 0000000000..39ef7caedf --- /dev/null +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/FakeErrorUtils.java @@ -0,0 +1,84 @@ +package io.metersphere.utils; + +import io.metersphere.dto.FakeErrorDTO; +import io.metersphere.dto.FakeErrorLibraryDTO; +import io.metersphere.dto.MsRegexDTO; +import io.metersphere.dto.RequestResult; +import io.metersphere.enums.ApiReportStatus; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 误报解析类 + * + * @author xiaogang + */ +public class FakeErrorUtils { + public static FakeErrorLibraryDTO parseAssertions(RequestResult result, Map> fakeErrorMap) { + FakeErrorLibraryDTO fakeError = new FakeErrorLibraryDTO(); + try { + if (StringUtils.isNotBlank(result.getFakeErrorMessage())) { + FakeErrorDTO errorReportDTO = JsonUtils.parseObject(result.getFakeErrorMessage(), FakeErrorDTO.class); + if (MapUtils.isNotEmpty(fakeErrorMap) && errorReportDTO != null) { + List regexList = fakeErrorMap.get(errorReportDTO.getProjectId()); + //根据配置来筛选断言、获取误报编码、获取接口状态是否是误报 + List errorCodeList = new ArrayList<>(); + regexList.forEach(item -> { + if (StringUtils.isNotEmpty(item.getSubject())) { + switch (item.getSubject()) { + case "Response Code" -> + item.setPass(parseResponseCode(result.getResponseResult().getResponseCode(), item.getValue(), item.getCondition())); + + case "Response Headers" -> + item.setPass(parseResponseCode(result.getResponseResult().getHeaders(), item.getValue(), item.getCondition())); + + case "Response Data" -> + item.setPass(parseResponseCode(result.getResponseResult().getBody(), item.getValue(), item.getCondition())); + default -> item.setPass(false); + } + } + if (item.isPass()) { + errorCodeList.add(item.getErrorCode()); + } + }); + boolean higherThanError = errorReportDTO.isHigherThanError(); + boolean higherThanSuccess = errorReportDTO.isHigherThanSuccess(); + if (CollectionUtils.isNotEmpty(errorCodeList)) { + if ((higherThanError && !result.isSuccess()) || (higherThanSuccess && result.isSuccess())) { + fakeError.setRequestStatus(ApiReportStatus.FAKE_ERROR.name()); + } + fakeError.setErrorCodeList(errorCodeList); + } + } + } + } catch (Exception e) { + LoggerUtil.error("误报处理错误:", e); + } + return fakeError; + } + + private static boolean parseResponseCode(String result, String regexDTO, String condition) { + return switch (condition.toUpperCase()) { + case "CONTAINS" -> result.contains(regexDTO); + + case "NOT_CONTAINS" -> notContains(result, regexDTO); + + case "EQUALS" -> StringUtils.equals(result, regexDTO); + + case "START_WITH" -> result.startsWith(regexDTO); + + case "END_WITH" -> result.endsWith(regexDTO); + + default -> false; + }; + } + + private static boolean notContains(String result, String regexDTO) { + return !result.contains(regexDTO); + } +} \ No newline at end of file diff --git a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/JsonUtils.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/JsonUtils.java index c0158d03b3..6fa51e123c 100644 --- a/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/JsonUtils.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/JsonUtils.java @@ -72,4 +72,13 @@ public class JsonUtils { throw new RuntimeException(e); } } + + public static T convertValue(Object content, Class valueType) { + try { + return objectMapper.convertValue(content, valueType); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ReportStatusUtil.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/ReportStatusUtil.java similarity index 82% rename from api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ReportStatusUtil.java rename to framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/ReportStatusUtil.java index 9b0cfb9cbc..e1254e6543 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/utils/ReportStatusUtil.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/utils/ReportStatusUtil.java @@ -1,13 +1,9 @@ -package io.metersphere.api.jmeter.utils; +package io.metersphere.utils; -import io.metersphere.commons.constants.CommonConstants; -import io.metersphere.commons.enums.ApiReportStatus; -import io.metersphere.commons.utils.JSONUtil; -import io.metersphere.commons.vo.ResultVO; import io.metersphere.dto.RequestResult; import io.metersphere.dto.ResultDTO; -import io.metersphere.utils.LoggerUtil; -import io.metersphere.utils.RetryResultUtil; +import io.metersphere.enums.ApiReportStatus; +import io.metersphere.vo.ResultVO; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -18,6 +14,9 @@ import java.util.Map; import java.util.stream.Collectors; public class ReportStatusUtil { + public static final String LOCAL_STATUS_KEY = "LOCAL_STATUS_KEY"; + public static final String REPORT_STATUS = "REPORT_STATUS"; + public static List filterRetryResults(List results) { List list = new LinkedList<>(); if (CollectionUtils.isNotEmpty(results)) { @@ -50,9 +49,9 @@ public class ReportStatusUtil { if (StringUtils.equals(resultVO.getStatus(), ApiReportStatus.ERROR.name())) { return resultVO; } - if (MapUtils.isNotEmpty(dto.getArbitraryData()) && dto.getArbitraryData().containsKey(CommonConstants.REPORT_STATUS)) { + if (MapUtils.isNotEmpty(dto.getArbitraryData()) && dto.getArbitraryData().containsKey(REPORT_STATUS)) { // 资源池执行整体传输失败,单条传输内容,获取资源池执行统计的状态 - resultVO.setStatus(JSONUtil.convertValue(dto.getArbitraryData().get(CommonConstants.REPORT_STATUS), ResultVO.class).getStatus()); + resultVO.setStatus(JsonUtils.convertValue(dto.getArbitraryData().get(REPORT_STATUS), ResultVO.class).getStatus()); } // 过滤掉重试结果后进行统计 List requestResults = filterRetryResults(dto.getRequestResults()); @@ -84,13 +83,13 @@ public class ReportStatusUtil { public static ResultVO computedProcess(ResultDTO dto) { ResultVO result = new ResultVO(); - if (MapUtils.isNotEmpty(dto.getArbitraryData()) && dto.getArbitraryData().containsKey(CommonConstants.LOCAL_STATUS_KEY)) { + if (MapUtils.isNotEmpty(dto.getArbitraryData()) && dto.getArbitraryData().containsKey(LOCAL_STATUS_KEY)) { // 本地执行状态 - result = JSONUtil.convertValue(dto.getArbitraryData().get(CommonConstants.LOCAL_STATUS_KEY), ResultVO.class); + result = JsonUtils.convertValue(dto.getArbitraryData().get(LOCAL_STATUS_KEY), ResultVO.class); } - if (MapUtils.isNotEmpty(dto.getArbitraryData()) && dto.getArbitraryData().containsKey(CommonConstants.REPORT_STATUS)) { + if (MapUtils.isNotEmpty(dto.getArbitraryData()) && dto.getArbitraryData().containsKey(REPORT_STATUS)) { // 资源池执行整体传输失败,单条传输内容,获取资源池执行统计的状态 - result = JSONUtil.convertValue(dto.getArbitraryData().get(CommonConstants.REPORT_STATUS), ResultVO.class); + result = JsonUtils.convertValue(dto.getArbitraryData().get(REPORT_STATUS), ResultVO.class); } result = getStatus(dto, result); if (result != null && result.getScenarioTotal() > 0 && result.getScenarioTotal() == result.getScenarioSuccess()) { diff --git a/api-test/backend/src/main/java/io/metersphere/commons/vo/ResultVO.java b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/vo/ResultVO.java similarity index 93% rename from api-test/backend/src/main/java/io/metersphere/commons/vo/ResultVO.java rename to framework/sdk-parent/jmeter/src/main/java/io/metersphere/vo/ResultVO.java index 00b0a6623b..33b09bcadb 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/vo/ResultVO.java +++ b/framework/sdk-parent/jmeter/src/main/java/io/metersphere/vo/ResultVO.java @@ -1,4 +1,4 @@ -package io.metersphere.commons.vo; +package io.metersphere.vo; import lombok.Data; diff --git a/project-management/backend/src/main/java/io/metersphere/code/snippet/listener/MsDebugListener.java b/project-management/backend/src/main/java/io/metersphere/code/snippet/listener/MsDebugListener.java index 8d7b1fb8dc..49edd2af79 100644 --- a/project-management/backend/src/main/java/io/metersphere/code/snippet/listener/MsDebugListener.java +++ b/project-management/backend/src/main/java/io/metersphere/code/snippet/listener/MsDebugListener.java @@ -40,6 +40,7 @@ import org.apache.jmeter.testelement.property.BooleanProperty; import org.apache.jmeter.threads.JMeterVariables; import java.io.Serializable; +import java.util.HashMap; import java.util.Map; /** @@ -148,7 +149,7 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi SampleResult result = event.getResult(); this.setVars(result); if (isSampleWanted(result.isSuccessful(), result) && !StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) { - RequestResult requestResult = JMeterBase.getRequestResult(result); + RequestResult requestResult = JMeterBase.getRequestResult(result, new HashMap<>()); if (requestResult != null && ResultParseUtil.isNotAutoGenerateSampler(requestResult)) { MsgDto dto = new MsgDto(); dto.setExecEnd(false);