diff --git a/backend/src/main/java/io/metersphere/api/dto/mock/MockApiUtils.java b/backend/src/main/java/io/metersphere/api/dto/mock/MockApiUtils.java index ad82976c23..91c71e4df6 100644 --- a/backend/src/main/java/io/metersphere/api/dto/mock/MockApiUtils.java +++ b/backend/src/main/java/io/metersphere/api/dto/mock/MockApiUtils.java @@ -471,11 +471,13 @@ public class MockApiUtils { JSON returnJson = null; try { String param = getRequestPostStr(request); - JSONValidator jsonValidator = JSONValidator.from(param); - if (StringUtils.equalsIgnoreCase("Array", jsonValidator.getType().name())) { - returnJson = JSONArray.parseArray(param); - } else if (StringUtils.equalsIgnoreCase("Object", jsonValidator.getType().name())) { - returnJson = JSONObject.parseObject(param); + if(StringUtils.isNotEmpty(param)){ + JSONValidator jsonValidator = JSONValidator.from(param); + if (StringUtils.equalsIgnoreCase("Array", jsonValidator.getType().name())) { + returnJson = JSONArray.parseArray(param); + } else if (StringUtils.equalsIgnoreCase("Object", jsonValidator.getType().name())) { + returnJson = JSONObject.parseObject(param); + } } } catch (Exception e) { e.printStackTrace(); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 7399c79596..5b66dc50da 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -1190,7 +1190,6 @@ public class ApiAutomationService { * @param executeQueue * @param scenarioIds * @param scenarioNames - * @param serialReportId */ private void prepareExecutedPlanScenario(List apiScenarios, RunScenarioRequest request, Map executeQueue, List scenarioIds, StringBuilder scenarioNames) { String reportId = request.getId(); @@ -1247,7 +1246,7 @@ public class ApiAutomationService { try { if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) { RunModeDataDTO runModeDataDTO = new RunModeDataDTO(); - runModeDataDTO.setTestId(scenario.getId()); + runModeDataDTO.setTestId(testPlanScenarioId); runModeDataDTO.setPlanEnvMap(planEnvMap); runModeDataDTO.setReport(report); executeQueue.put(report.getId(), runModeDataDTO); @@ -1462,12 +1461,14 @@ public class ApiAutomationService { // 增加一个本地锁,防止并发找不到资源 if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) { String testPlanScenarioId = ""; + String testId = executeQueue.get(reportId).getTestId(); if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(executeQueue.get(reportId).getTestId())) { - testPlanScenarioId = request.getScenarioTestPlanIdMap().get(executeQueue.get(reportId).getTestId()); + testPlanScenarioId = executeQueue.get(reportId).getTestId(); + testId = request.getScenarioTestPlanIdMap().get(executeQueue.get(reportId).getTestId()); } else { testPlanScenarioId = request.getPlanScenarioId(); } - jMeterService.runTest(executeQueue.get(reportId).getTestId(), reportId, request.getRunMode(), testPlanScenarioId, request.getConfig()); + jMeterService.runTest(testId, reportId, request.getRunMode(), testPlanScenarioId, request.getConfig()); } else { jMeterService.runLocal(reportId, request.getConfig(), executeQueue.get(reportId).getHashTree(), TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode()); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java index 649b23d58e..bbacaef326 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionExecResultService.java @@ -230,7 +230,6 @@ public class ApiDefinitionExecResultService { * @param type */ public void saveApiResultByScheduleTask(TestResult result, String testPlanReportId, String type) { - testPlanLog.info("TestPlanReportId[" + testPlanReportId + "] APICASE OVER."); String saveResultType = type; if (StringUtils.equalsAny(saveResultType, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) { saveResultType = ApiRunMode.API_PLAN.name(); @@ -240,14 +239,25 @@ public class ApiDefinitionExecResultService { Map apiIdResultMap = new HashMap<>(); Map caseReportMap = new HashMap<>(); + String testId = result.getTestId(); + if(testId.contains(":")){ + String [] testIdArr = testId.split(":"); + if(testIdArr.length == 3){ + result.setTestId(testIdArr[2]); + }else { + result.setTestId(testIdArr[0]); + } + testPlanReportId = testIdArr[1]; + } + String creator = TestPlanReportExecuteCatch.getCreator(testPlanReportId); if (CollectionUtils.isNotEmpty(result.getScenarios())) { result.getScenarios().forEach(scenarioResult -> { final boolean[] isFirst = {true}; if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) { scenarioResult.getRequestResults().forEach(item -> { - String creator = TestPlanReportExecuteCatch.getCreator(testPlanReportId); if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) { ApiDefinitionExecResult saveResult = MessageCache.caseExecResourceLock.get(result.getTestId()); + if (saveResult == null) { saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(result.getTestId()); } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiJmeterFileService.java b/backend/src/main/java/io/metersphere/api/service/ApiJmeterFileService.java index 3cbe813a2c..5660bc0f21 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiJmeterFileService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiJmeterFileService.java @@ -3,9 +3,7 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; import io.metersphere.api.dto.definition.request.MsTestPlan; import io.metersphere.api.dto.scenario.request.BodyFile; -import io.metersphere.base.domain.ApiScenarioWithBLOBs; -import io.metersphere.base.domain.JarConfig; -import io.metersphere.base.domain.TestPlanApiScenario; +import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.base.mapper.TestPlanApiScenarioMapper; import io.metersphere.commons.constants.ApiRunMode; @@ -52,27 +50,34 @@ public class ApiJmeterFileService { return listBytesToZip(files); } - public byte[] downloadJmeterFiles(String runMode, String testId, String reportId, String testPlanScenarioId) { + public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String testPlanScenarioId) { Map planEnvMap = new HashMap<>(); if (StringUtils.isNotEmpty(testPlanScenarioId)) { // 获取场景用例单独的执行环境 TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId); - String environment = planApiScenario.getEnvironment(); - if (StringUtils.isNotBlank(environment)) { - planEnvMap = JSON.parseObject(environment, Map.class); + if(planApiScenario != null){ + String environment = planApiScenario.getEnvironment(); + if (StringUtils.isNotBlank(environment)) { + planEnvMap = JSON.parseObject(environment, Map.class); + } } } HashTree hashTree; - if (ApiRunMode.DEFINITION.name().equals(runMode) || ApiRunMode.API_PLAN.name().equals(runMode)) { + if (ApiRunMode.DEFINITION.name().equals(runMode) || ApiRunMode.API_PLAN.name().equals(runMode) || ApiRunMode.MANUAL_PLAN.name().equals(runMode)) { + String testId = remoteTestId; + if(remoteTestId.contains(":")){ + //执行测试计划案例时会有拼接ID,ID为 planTestCaseId:测试计划报告ID + testId = remoteTestId.split(":")[0]; + } hashTree = testPlanApiCaseService.generateHashTree(testId); } else { - ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(testId); + ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(remoteTestId); if (item == null) { MSException.throwException("未找到执行场景。"); } hashTree = apiAutomationService.generateHashTree(item, reportId, planEnvMap); } - return zipFilesToByteArray(testId, hashTree); + return zipFilesToByteArray(remoteTestId, hashTree); } public byte[] downloadJmx(String runMode, String testId, String reportId, String testPlanScenarioId) { diff --git a/backend/src/main/java/io/metersphere/api/service/TestResultService.java b/backend/src/main/java/io/metersphere/api/service/TestResultService.java index fb4911b721..4be827db41 100644 --- a/backend/src/main/java/io/metersphere/api/service/TestResultService.java +++ b/backend/src/main/java/io/metersphere/api/service/TestResultService.java @@ -90,6 +90,10 @@ public class TestResultService { if (StringUtils.equalsAny(runMode, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) { apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult, debugReportId, runMode); } else { + String testResultTestId = testResult.getTestId(); + if(testResultTestId.contains(":")){ + testResult.setTestId(testResultTestId.split(":")[0]); + } apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.API_PLAN.name(), TriggerMode.MANUAL.name()); } } else if (StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) { diff --git a/backend/src/main/java/io/metersphere/api/service/task/SerialScenarioExecTask.java b/backend/src/main/java/io/metersphere/api/service/task/SerialScenarioExecTask.java index ada44c6a6f..f8330260ee 100644 --- a/backend/src/main/java/io/metersphere/api/service/task/SerialScenarioExecTask.java +++ b/backend/src/main/java/io/metersphere/api/service/task/SerialScenarioExecTask.java @@ -41,7 +41,9 @@ public class SerialScenarioExecTask implements Callable { if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) { String testPlanScenarioId = ""; if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(runModeDataDTO.getTestId())) { - testPlanScenarioId = request.getScenarioTestPlanIdMap().get(runModeDataDTO.getTestId()); + testPlanScenarioId = runModeDataDTO.getTestId(); + String scenarioId = request.getScenarioTestPlanIdMap().get(runModeDataDTO.getTestId()); + runModeDataDTO.setTestId(scenarioId); } else { testPlanScenarioId = request.getPlanScenarioId(); } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java index 4e17ec8127..d5cd6c4fee 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java @@ -391,6 +391,7 @@ public class TestPlanApiCaseService { apiResult.setStartTime(System.currentTimeMillis()); apiResult.setType(ApiRunMode.API_PLAN.name()); apiResult.setStatus(status); + apiResult.setContent(request.getPlanReportId()); batchMapper.insert(apiResult); return apiResult; } @@ -468,6 +469,7 @@ public class TestPlanApiCaseService { mapper.updateByPrimaryKey(execResult); modeDataDTO.setApiCaseId(execResult.getId()); modeDataDTO.setDebugReportId(request.getPlanReportId()); + modeDataDTO.setTestId(modeDataDTO.getTestId()+":"+request.getPlanReportId()+ ":"+ execResult.getId()); Future future = executorService.submit(new SerialApiExecTask(jMeterService, mapper, modeDataDTO, request.getConfig(), request.getTriggerMode())); ApiDefinitionExecResult report = future.get(); // 如果开启失败结束执行,则判断返回结果状态 @@ -538,14 +540,16 @@ public class TestPlanApiCaseService { try { String debugId = request.getPlanReportId(); if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) { - jMeterService.runTest(testPlanApiCase.getId(), reportId, request.getTriggerMode(), request.getPlanReportId(), request.getConfig()); + String testId = testPlanApiCase.getId()+":"+ request.getPlanReportId() + ":" +reportId; + jMeterService.runTest(testId, reportId, request.getTriggerMode(), request.getPlanReportId(), request.getConfig()); executeThreadIdMap.put(testPlanApiCase.getApiCaseId(),testPlanApiCase.getId()); } else { HashTree hashTree = generateHashTree(testPlanApiCase.getId()); if(StringUtils.isEmpty(debugId)){ debugId = TriggerMode.BATCH.name(); } - jMeterService.runLocal(reportId,request.getConfig(), hashTree, debugId, request.getTriggerMode()); + String testId = reportId+":"+ request.getPlanReportId(); + jMeterService.runLocal(testId,request.getConfig(), hashTree, debugId, request.getTriggerMode()); executeThreadIdMap.put(testPlanApiCase.getId(),reportId); } }catch (Exception e){ diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java index 07cfefc6f5..1d95f0f898 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java @@ -1182,4 +1182,13 @@ public class TestPlanReportService { testPlanReportDTO.setName(testPlanReport.getName()); return testPlanReportDTO; } + + public void finishReport(TestPlanReport testPlanReport) { + long endTime = System.currentTimeMillis(); + testPlanReport.setEndTime(endTime); + testPlanReport.setUpdateTime(endTime); + + testPlanReport.setStatus(TestPlanReportStatus.FAILED.name()); + testPlanReportMapper.updateByPrimaryKey(testPlanReport); + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java index 614fd90f77..a4651d56ce 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java @@ -182,7 +182,7 @@ public class TestPlanScenarioCaseService { Map scenarioIdApiScarionMap = new HashMap<>(); for (TestPlanApiScenario apiScenario : testPlanApiScenarioList) { scenarioIds.add(apiScenario.getApiScenarioId()); - scenarioIdApiScarionMap.put(apiScenario.getApiScenarioId(), apiScenario.getId()); + scenarioIdApiScarionMap.put(apiScenario.getId(), apiScenario.getApiScenarioId()); } if (scenarioIdApiScarionMap.isEmpty()) { MSException.throwException("未找到执行场景!"); diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java index b5034335fb..840900ba88 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -1063,15 +1063,53 @@ public class TestPlanService { @Transactional(propagation = Propagation.NOT_SUPPORTED) public String run(String testPlanID, String projectID, String userId, String triggerMode, String apiRunConfig) { - extTestPlanMapper.updateActualEndTimeIsNullById(testPlanID); + RunModeConfig runModeConfig = null; + try { + runModeConfig = JSONObject.parseObject(apiRunConfig, RunModeConfig.class); + runModeConfig.setOnSampleError(false); + } catch (Exception e) { + e.printStackTrace(); + } + + if (runModeConfig == null) { + runModeConfig = new RunModeConfig(); + runModeConfig.setMode("serial"); + runModeConfig.setReportType("iddReport"); + runModeConfig.setEnvMap(new HashMap<>()); + runModeConfig.setOnSampleError(false); + }else { + if(runModeConfig.getEnvMap() == null){ + runModeConfig.setEnvMap(new HashMap<>()); + } + } + //创建测试报告,然后返回的ID重新赋值为resourceID,作为后续的参数 TestPlanScheduleReportInfoDTO reportInfoDTO = testPlanReportService.genTestPlanReportBySchedule(projectID, testPlanID, userId, triggerMode); - TestPlanReport testPlanReport = reportInfoDTO.getTestPlanReport(); Map planScenarioIdsMap = reportInfoDTO.getPlanScenarioIdMap(); Map planApiCaseMap = reportInfoDTO.getApiTestCaseDataMap(); Map performanceIdMap = reportInfoDTO.getPerformanceIdMap(); + if (runModeConfig.getMode().equals(RunModeConstants.PARALLEL.toString())) { + // 校验并发数量 + int count = 50; + BaseSystemConfigDTO dto = systemParameterService.getBaseInfo(); + if (StringUtils.isNotEmpty(dto.getConcurrency())) { + count = Integer.parseInt(dto.getConcurrency()); + } + if (planApiCaseMap.size() > count) { + testPlanReportService.finishReport(reportInfoDTO.getTestPlanReport()); + MSException.throwException("并发超过"+count+",数量过大,请重新选择!"); + } + if (planScenarioIdsMap.size() > count) { + testPlanReportService.finishReport(reportInfoDTO.getTestPlanReport()); + MSException.throwException("并发超过"+count+",数量过大,请重新选择!"); + } + } + extTestPlanMapper.updateActualEndTimeIsNullById(testPlanID); + + + String planReportId = testPlanReport.getId(); testPlanLog.info("ReportId[" + planReportId + "] created. TestPlanID:[" + testPlanID + "]. " + "API Run Config:【" + apiRunConfig + "】"); @@ -1138,26 +1176,6 @@ public class TestPlanService { } testPlanLog.info("ReportId[" + planReportId + "] start run. TestPlanID:[" + testPlanID + "]. Execute api :" + JSONObject.toJSONString(executeApiCaseIdMap) + "; Execute scenario:" + JSONObject.toJSONString(executeScenarioCaseIdMap) + "; Execute performance:" + JSONObject.toJSONString(executePerformanceIdMap)); TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(planReportId, executeApiCaseIdMap, executeScenarioCaseIdMap, executePerformanceIdMap); - - RunModeConfig runModeConfig = null; - try { - runModeConfig = JSONObject.parseObject(apiRunConfig, RunModeConfig.class); - runModeConfig.setOnSampleError(false); - } catch (Exception e) { - e.printStackTrace(); - } - - if (runModeConfig == null) { - runModeConfig = new RunModeConfig(); - runModeConfig.setMode("serial"); - runModeConfig.setReportType("iddReport"); - runModeConfig.setEnvMap(new HashMap<>()); - runModeConfig.setOnSampleError(false); - }else { - if(runModeConfig.getEnvMap() == null){ - runModeConfig.setEnvMap(new HashMap<>()); - } - } //执行接口案例任务 this.executeApiTestCase(triggerMode, planReportId,new ArrayList<>(planApiCaseMap.keySet()), runModeConfig); //执行场景执行任务 diff --git a/backend/src/main/java/io/metersphere/track/service/task/SerialApiExecTask.java b/backend/src/main/java/io/metersphere/track/service/task/SerialApiExecTask.java index fd2153bb59..b3e8a9a0f6 100644 --- a/backend/src/main/java/io/metersphere/track/service/task/SerialApiExecTask.java +++ b/backend/src/main/java/io/metersphere/track/service/task/SerialApiExecTask.java @@ -39,13 +39,13 @@ public class SerialApiExecTask implements Callable { return null; } if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) { - jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, runModeDataDTO.getDebugReportId(), config); + jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config); } else { String debugId = runModeDataDTO.getDebugReportId(); if(debugId == null){ debugId = runModeDataDTO.getReport() != null ? runModeDataDTO.getReport().getTriggerMode() : null; } - jMeterService.runLocal(runModeDataDTO.getApiCaseId(), config, runModeDataDTO.getHashTree(), debugId, runMode); + jMeterService.runLocal(runModeDataDTO.getApiCaseId()+":"+debugId, config, runModeDataDTO.getHashTree(), debugId, runMode); } // 轮询查看报告状态,最多200次,防止死循环 ApiDefinitionExecResult report = null; @@ -53,7 +53,7 @@ public class SerialApiExecTask implements Callable { while (index < 200) { Thread.sleep(3000); index++; - report = mapper.selectByPrimaryKey(runModeDataDTO.getApiCaseId()); + report = mapper.selectByPrimaryKey(runModeDataDTO.getApiCaseId()); if (report != null && !report.getStatus().equals(APITestStatus.Running.name())) { break; } diff --git a/frontend/src/business/components/track/case/components/ShowMoreBtn.vue b/frontend/src/business/components/track/case/components/ShowMoreBtn.vue index 361c7fab0b..e700687439 100644 --- a/frontend/src/business/components/track/case/components/ShowMoreBtn.vue +++ b/frontend/src/business/components/track/case/components/ShowMoreBtn.vue @@ -1,5 +1,6 @@