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 3e33bdc4d4..9cac5e2f88 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -325,22 +325,17 @@ public class ApiAutomationService { } /** - * 场景测试执行 + * 生成HashTree * - * @param request - * @return + * @param apiScenarios 场景 + * @param request 请求参数 + * @param isSave 是否需要生成报告 + * @return hashTree */ - public String run(RunScenarioRequest request) { - List apiScenarios = null; - List ids = request.getScenarioIds(); - if (request.isSelectAllDate()) { - ids = this.getAllScenarioIdsByFontedSelect( - request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds()); - } - apiScenarios = extApiScenarioMapper.selectIds(ids); + private HashTree generateHashTree(List apiScenarios, RunScenarioRequest request, boolean isSave) { + HashTree jmeterHashTree = new ListedHashTree(); MsTestPlan testPlan = new MsTestPlan(); testPlan.setHashTree(new LinkedList<>()); - HashTree jmeterHashTree = new ListedHashTree(); try { boolean isFirst = true; for (ApiScenarioWithBLOBs item : apiScenarios) { @@ -380,49 +375,44 @@ public class ApiAutomationService { LinkedList scenarios = new LinkedList<>(); scenarios.add(scenario); // 创建场景报告 - createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), - request.getExecuteType(), item.getProjectId(), request.getReportUserID()); + if (isSave) { + createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), + request.getExecuteType(), item.getProjectId(), request.getReportUserID()); + } group.setHashTree(scenarios); testPlan.getHashTree().add(group); - } } catch (Exception ex) { MSException.throwException(ex.getMessage()); } testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig()); + return jmeterHashTree; + } + + /** + * 场景测试执行 + * + * @param request + * @return + */ + public String run(RunScenarioRequest request) { + List apiScenarios = null; + List ids = request.getScenarioIds(); + if (request.isSelectAllDate()) { + ids = this.getAllScenarioIdsByFontedSelect( + request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds()); + } + apiScenarios = extApiScenarioMapper.selectIds(ids); + String runMode = ApiRunMode.SCENARIO.name(); if (StringUtils.isNotBlank(request.getRunMode()) && StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) { runMode = ApiRunMode.SCENARIO_PLAN.name(); } // 调用执行方法 - jMeterService.runDefinition(request.getId(), jmeterHashTree, request.getReportId(), runMode); + jMeterService.runDefinition(request.getId(), generateHashTree(apiScenarios, request, true), request.getReportId(), runMode); return request.getId(); } - - /** - * 获取前台查询条件查询的所有(未经分页筛选)数据ID - * - * @param moduleIds 模块ID_前台查询时所选择的 - * @param name 搜索条件_名称_前台查询时所输入的 - * @param projectId 所属项目_前台查询时所在项目 - * @param filters 过滤集合__前台查询时的过滤条件 - * @param unSelectIds 未勾选ID_前台没有勾选的ID - * @return - */ - private List getAllScenarioIdsByFontedSelect(List moduleIds, String name, String projectId, List filters, List unSelectIds) { - ApiScenarioRequest selectRequest = new ApiScenarioRequest(); - selectRequest.setModuleIds(moduleIds); - selectRequest.setName(name); - selectRequest.setProjectId(projectId); - selectRequest.setFilters(filters); - selectRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); - List list = extApiScenarioMapper.list(selectRequest); - List allIds = list.stream().map(ApiScenarioDTO::getId).collect(Collectors.toList()); - List ids = allIds.stream().filter(id -> !unSelectIds.contains(id)).collect(Collectors.toList()); - return ids; - } - /** * 场景测试执行 * @@ -460,6 +450,29 @@ public class ApiAutomationService { return dto; } + /** + * 获取前台查询条件查询的所有(未经分页筛选)数据ID + * + * @param moduleIds 模块ID_前台查询时所选择的 + * @param name 搜索条件_名称_前台查询时所输入的 + * @param projectId 所属项目_前台查询时所在项目 + * @param filters 过滤集合__前台查询时的过滤条件 + * @param unSelectIds 未勾选ID_前台没有勾选的ID + * @return + */ + private List getAllScenarioIdsByFontedSelect(List moduleIds, String name, String projectId, List filters, List unSelectIds) { + ApiScenarioRequest selectRequest = new ApiScenarioRequest(); + selectRequest.setModuleIds(moduleIds); + selectRequest.setName(name); + selectRequest.setProjectId(projectId); + selectRequest.setFilters(filters); + selectRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); + List list = extApiScenarioMapper.list(selectRequest); + List allIds = list.stream().map(ApiScenarioDTO::getId).collect(Collectors.toList()); + List ids = allIds.stream().filter(id -> !unSelectIds.contains(id)).collect(Collectors.toList()); + return ids; + } + public String addScenarioToPlan(SaveApiPlanRequest request) { if (CollectionUtils.isEmpty(request.getPlanIds())) { MSException.throwException(Translator.get("plan id is null ")); @@ -578,51 +591,8 @@ public class ApiAutomationService { apiScenarios = extApiScenarioMapper.selectIds(ids); MsTestPlan testPlan = new MsTestPlan(); testPlan.setHashTree(new LinkedList<>()); - HashTree jmeterHashTree = new ListedHashTree(); - try { - boolean isFirst = true; - for (ApiScenarioWithBLOBs item : apiScenarios) { - if (item.getStepTotal() == 0) { - MSException.throwException(item.getName() + "," + Translator.get("automation_exec_info")); - break; - } - MsThreadGroup group = new MsThreadGroup(); - group.setLabel(item.getName()); - group.setName(UUID.randomUUID().toString()); - // 批量执行的结果直接存储为报告 - if (isFirst) { - group.setName(request.getId()); - isFirst = false; - } - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - JSONObject element = JSON.parseObject(item.getScenarioDefinition()); - MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class); - // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 - if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) { - LinkedList elements = mapper.readValue(element.getString("hashTree"), - new TypeReference>() { - }); - scenario.setHashTree(elements); - } - if (StringUtils.isNotEmpty(element.getString("variables"))) { - LinkedList variables = mapper.readValue(element.getString("variables"), - new TypeReference>() { - }); - scenario.setVariables(variables); - } - group.setEnableCookieShare(scenario.isEnableCookieShare()); - LinkedList scenarios = new LinkedList<>(); - scenarios.add(scenario); - group.setHashTree(scenarios); - testPlan.getHashTree().add(group); - } - } catch (Exception ex) { - MSException.throwException(ex.getMessage()); - } - - testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig()); + HashTree jmeterHashTree = generateHashTree(apiScenarios, request, false); String jmx = testPlan.getJmx(jmeterHashTree); String name = request.getName() + ".jmx"; diff --git a/backend/src/main/java/io/metersphere/track/domain/ReportComponent.java b/backend/src/main/java/io/metersphere/track/domain/ReportComponent.java index 8f734dfa3d..924ae232f4 100644 --- a/backend/src/main/java/io/metersphere/track/domain/ReportComponent.java +++ b/backend/src/main/java/io/metersphere/track/domain/ReportComponent.java @@ -6,6 +6,7 @@ import io.metersphere.commons.constants.APITestStatus; import io.metersphere.track.dto.TestCaseReportMetricDTO; import io.metersphere.track.dto.TestPlanCaseDTO; import io.metersphere.track.dto.TestPlanDTO; +import io.metersphere.track.dto.TestPlanLoadCaseDTO; import org.apache.commons.lang3.StringUtils; public abstract class ReportComponent { @@ -26,4 +27,7 @@ public abstract class ReportComponent { public void readRecord(ApiScenarioDTO testCase) { } + public void readRecord(TestPlanLoadCaseDTO testCase) { + } + } diff --git a/backend/src/main/java/io/metersphere/track/domain/ReportFailureAdvanceResultComponent.java b/backend/src/main/java/io/metersphere/track/domain/ReportFailureAdvanceResultComponent.java index 180f2c0001..6ab3b4a1e4 100644 --- a/backend/src/main/java/io/metersphere/track/domain/ReportFailureAdvanceResultComponent.java +++ b/backend/src/main/java/io/metersphere/track/domain/ReportFailureAdvanceResultComponent.java @@ -4,10 +4,7 @@ import io.metersphere.api.dto.automation.ApiScenarioDTO; import io.metersphere.api.dto.automation.ScenarioStatus; import io.metersphere.api.dto.definition.TestPlanApiCaseDTO; import io.metersphere.commons.constants.TestPlanTestCaseStatus; -import io.metersphere.track.dto.FailureTestCasesAdvanceDTO; -import io.metersphere.track.dto.TestCaseReportMetricDTO; -import io.metersphere.track.dto.TestPlanCaseDTO; -import io.metersphere.track.dto.TestPlanDTO; +import io.metersphere.track.dto.*; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; @@ -17,6 +14,7 @@ public class ReportFailureAdvanceResultComponent extends ReportComponent { private List functionalTestCases = new ArrayList<>(); private List apiTestCases = new ArrayList<>(); private List scenarioTestCases = new ArrayList<>(); + private List loadTestCases = new ArrayList<>(); public ReportFailureAdvanceResultComponent(TestPlanDTO testPlan) { super(testPlan); @@ -44,12 +42,20 @@ public class ReportFailureAdvanceResultComponent extends ReportComponent { } } + @Override + public void readRecord(TestPlanLoadCaseDTO testCase) { + if (StringUtils.equals(testCase.getCaseStatus(), "error")) { + this.loadTestCases.add(testCase); + } + } + @Override public void afterBuild(TestCaseReportMetricDTO testCaseReportMetric) { FailureTestCasesAdvanceDTO failureTestCasesAdvanceDTO = new FailureTestCasesAdvanceDTO(); failureTestCasesAdvanceDTO.setFunctionalTestCases(functionalTestCases); failureTestCasesAdvanceDTO.setApiTestCases(apiTestCases); failureTestCasesAdvanceDTO.setScenarioTestCases(scenarioTestCases); + failureTestCasesAdvanceDTO.setLoadTestCases(loadTestCases); testCaseReportMetric.setFailureTestCases(failureTestCasesAdvanceDTO); } } diff --git a/backend/src/main/java/io/metersphere/track/domain/ReportResultAdvancedChartComponent.java b/backend/src/main/java/io/metersphere/track/domain/ReportResultAdvancedChartComponent.java index 3c465d9079..d05293cfe0 100644 --- a/backend/src/main/java/io/metersphere/track/domain/ReportResultAdvancedChartComponent.java +++ b/backend/src/main/java/io/metersphere/track/domain/ReportResultAdvancedChartComponent.java @@ -16,15 +16,19 @@ public class ReportResultAdvancedChartComponent extends ReportComponent { Map functionalStatusResultMap = new HashMap<>(); Map apiStatusResultMap = new HashMap<>(); Map scenarioStatusResultMap = new HashMap<>(); + Map loadStatusResultMap = new HashMap<>(); private static Map apiResultMap = new HashMap<>(); private static Map scenarioResultMap = new HashMap<>(); + private static Map loadResultMap = new HashMap<>(); static { apiResultMap.put("success", TestPlanTestCaseStatus.Pass.name()); apiResultMap.put("error", TestPlanTestCaseStatus.Failure.name()); scenarioResultMap.put(ScenarioStatus.Success.name(), TestPlanTestCaseStatus.Pass.name()); scenarioResultMap.put(ScenarioStatus.Fail.name(), TestPlanTestCaseStatus.Failure.name()); + loadResultMap.put("success", TestPlanTestCaseStatus.Pass.name()); + loadResultMap.put("error", TestPlanTestCaseStatus.Failure.name()); } public ReportResultAdvancedChartComponent(TestPlanDTO testPlan) { @@ -47,6 +51,11 @@ public class ReportResultAdvancedChartComponent extends ReportComponent { getStatusResultMap(scenarioStatusResultMap, scenarioResultMap.get(testCase.getLastResult())); } + @Override + public void readRecord(TestPlanLoadCaseDTO testCase) { + getStatusResultMap(loadStatusResultMap, loadResultMap.get(testCase.getCaseStatus())); + } + @Override public void afterBuild(TestCaseReportMetricDTO testCaseReportMetric) { testCaseReportMetric.setExecuteResult(getReportStatusResult()); @@ -57,6 +66,7 @@ public class ReportResultAdvancedChartComponent extends ReportComponent { buildFunctionalStatusResult(reportStatusResult); buildApiStatusResult(reportStatusResult); buildScenarioStatusResult(reportStatusResult); + buildLoadStatusResult(reportStatusResult); return reportStatusResult; } @@ -87,6 +97,14 @@ public class ReportResultAdvancedChartComponent extends ReportComponent { reportStatusResult.setScenarioResult(scenarioStatusResult); } + private void buildLoadStatusResult(TestCaseReportAdvanceStatusResultDTO reportStatusResult) { + List loadStatusResult = new ArrayList<>(); + addToReportStatusResultList(loadStatusResultMap, loadStatusResult, TestPlanTestCaseStatus.Pass.name()); + addToReportStatusResultList(loadStatusResultMap, loadStatusResult, TestPlanTestCaseStatus.Failure.name()); + addToReportStatusResultList(loadStatusResultMap, loadStatusResult, TestPlanTestCaseStatus.Underway.name()); + reportStatusResult.setLoadResult(loadStatusResult); + } + private void addToReportStatusResultList(Map resultMap, List reportStatusResultList, String status) { if (resultMap.get(status) != null) { reportStatusResultList.add(resultMap.get(status)); diff --git a/backend/src/main/java/io/metersphere/track/dto/FailureTestCasesAdvanceDTO.java b/backend/src/main/java/io/metersphere/track/dto/FailureTestCasesAdvanceDTO.java index ba39267353..3688014bb9 100644 --- a/backend/src/main/java/io/metersphere/track/dto/FailureTestCasesAdvanceDTO.java +++ b/backend/src/main/java/io/metersphere/track/dto/FailureTestCasesAdvanceDTO.java @@ -13,4 +13,5 @@ public class FailureTestCasesAdvanceDTO { private List functionalTestCases; private List apiTestCases; private List scenarioTestCases; + private List loadTestCases; } diff --git a/backend/src/main/java/io/metersphere/track/dto/TestCaseReportAdvanceStatusResultDTO.java b/backend/src/main/java/io/metersphere/track/dto/TestCaseReportAdvanceStatusResultDTO.java index a092ebd190..3b79964746 100644 --- a/backend/src/main/java/io/metersphere/track/dto/TestCaseReportAdvanceStatusResultDTO.java +++ b/backend/src/main/java/io/metersphere/track/dto/TestCaseReportAdvanceStatusResultDTO.java @@ -11,5 +11,6 @@ public class TestCaseReportAdvanceStatusResultDTO { private List functionalResult; private List apiResult; private List scenarioResult; + private List loadResult; } 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 24521392db..d9c6519a1e 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -26,13 +26,11 @@ import io.metersphere.notice.service.NoticeSendService; import io.metersphere.service.SystemParameterService; import io.metersphere.track.Factory.ReportComponentFactory; import io.metersphere.track.domain.ReportComponent; -import io.metersphere.track.dto.TestCaseReportMetricDTO; -import io.metersphere.track.dto.TestPlanCaseDTO; -import io.metersphere.track.dto.TestPlanDTO; -import io.metersphere.track.dto.TestPlanDTOWithMetric; +import io.metersphere.track.dto.*; import io.metersphere.track.request.testcase.PlanCaseRelevanceRequest; import io.metersphere.track.request.testcase.QueryTestPlanRequest; import io.metersphere.track.request.testplan.AddTestPlanRequest; +import io.metersphere.track.request.testplan.LoadCaseRequest; import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.annotations.Param; @@ -649,6 +647,7 @@ public class TestPlanService { List issues = buildFunctionalCaseReport(planId, components); buildApiCaseReport(planId, components); buildScenarioCaseReport(planId, components); + buildLoadCaseReport(planId, components); TestCaseReportMetricDTO testCaseReportMetricDTO = new TestCaseReportMetricDTO(); components.forEach(component -> { @@ -680,6 +679,17 @@ public class TestPlanService { } } + public void buildLoadCaseReport(String planId, List components) { + LoadCaseRequest request = new LoadCaseRequest(); + request.setTestPlanId(planId); + List loadDTOs = testPlanLoadCaseService.list(request); + for (TestPlanLoadCaseDTO item : loadDTOs) { + for (ReportComponent component : components) { + component.readRecord(item); + } + } + } + public List buildFunctionalCaseReport(String planId, List components) { IssuesService issuesService = (IssuesService) CommonBeanFactory.getBean("issuesService"); List testPlanTestCases = listTestCaseByPlanId(planId); diff --git a/frontend/src/business/components/api/automation/scenario/ApiComponent.vue b/frontend/src/business/components/api/automation/scenario/ApiComponent.vue index 7bac52dada..334c10abbd 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiComponent.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiComponent.vue @@ -13,7 +13,7 @@ - {{request.name}} diff --git a/frontend/src/business/components/api/automation/scenario/Jsr233Processor.vue b/frontend/src/business/components/api/automation/scenario/Jsr233Processor.vue index d239c70cfe..8656e238ca 100644 --- a/frontend/src/business/components/api/automation/scenario/Jsr233Processor.vue +++ b/frontend/src/business/components/api/automation/scenario/Jsr233Processor.vue @@ -3,7 +3,7 @@ @copy="copyRow" @remove="remove" :data="jsr223ProcessorData" - :draggable="true" + :draggable="draggable" color="#B8741A" background-color="#F9F1EA" :title="title"> @@ -39,6 +39,7 @@ import MsInstructionsIcon from "../../../common/components/MsInstructionsIcon"; import MsDropdown from "../../../common/components/MsDropdown"; import ApiBaseComponent from "./common/ApiBaseComponent"; + export default { name: "MsJsr233Processor", components: {ApiBaseComponent, MsDropdown, MsInstructionsIcon, MsCodeEdit}, @@ -92,6 +93,10 @@ this.jsr223ProcessorData = this.jsr223Processor; }, props: { + draggable: { + type: Boolean, + default: false, + }, isReadOnly: { type: Boolean, default: @@ -147,26 +152,33 @@ .ace_editor { border-radius: 5px; } + .script-content { height: calc(100vh - 570px); } + .script-index { padding: 0 20px; } + .template-title { margin-bottom: 5px; font-weight: bold; font-size: 15px; } + .document-url { margin-top: 10px; } + .instructions-icon { margin-left: 5px; } + .ms-dropdown { margin-bottom: 20px; } + /deep/ .el-divider { margin-bottom: 10px; } diff --git a/frontend/src/business/components/api/automation/scenario/LoopController.vue b/frontend/src/business/components/api/automation/scenario/LoopController.vue index 08a84e1fda..c6b2864741 100644 --- a/frontend/src/business/components/api/automation/scenario/LoopController.vue +++ b/frontend/src/business/components/api/automation/scenario/LoopController.vue @@ -10,6 +10,7 @@ :title="$t('api_test.automation.loop_controller')">