From 329ed8dd779ffe4e5dadaadfd57c6c4169c5d60b Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Thu, 4 Mar 2021 17:26:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E7=94=B1=E7=BB=84=E5=90=88=E5=9C=BA?= =?UTF-8?q?=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/mapper/ext/ExtLoadTestMapper.java | 2 +- .../base/mapper/ext/ExtLoadTestMapper.xml | 2 +- .../controller/PerformanceTestController.java | 10 +- .../performance/dto/LoadTestExportJmx.java | 16 + .../dto/LoadTestFileDTO.java | 2 +- .../performance/engine/EngineFactory.java | 85 +++++- .../service/PerformanceTestService.java | 48 ++- .../request/testplan/TestPlanRequest.java | 2 - .../components/PerformancePressureConfig.vue | 12 +- .../test/components/ExistFiles.vue | 168 +++++++++++ .../test/components/ExistScenarios.vue | 163 ++++++++++ .../components/PerformanceBasicConfig.vue | 278 +++--------------- .../components/PerformancePressureConfig.vue | 28 +- .../performance/test/model/ThreadGroup.js | 3 +- frontend/src/i18n/en-US.js | 2 +- frontend/src/i18n/zh-CN.js | 2 +- frontend/src/i18n/zh-TW.js | 2 +- 17 files changed, 525 insertions(+), 300 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/performance/dto/LoadTestExportJmx.java rename backend/src/main/java/io/metersphere/{ => performance}/dto/LoadTestFileDTO.java (84%) create mode 100644 frontend/src/business/components/performance/test/components/ExistFiles.vue create mode 100644 frontend/src/business/components/performance/test/components/ExistScenarios.vue diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.java index 6c95dc1a2b..4f70333abb 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.java @@ -2,7 +2,7 @@ package io.metersphere.base.mapper.ext; import io.metersphere.base.domain.LoadTest; import io.metersphere.dto.LoadTestDTO; -import io.metersphere.dto.LoadTestFileDTO; +import io.metersphere.performance.dto.LoadTestFileDTO; import io.metersphere.track.request.testplan.QueryTestPlanRequest; import org.apache.ibatis.annotations.Param; diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml index 885b380e80..a1ecde7a3b 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml @@ -132,7 +132,7 @@ select * from load_test lt where lt.project_id = #{projectId} ORDER BY num DESC LIMIT 1; - SELECT file_metadata.*, load_test.id as testId, load_test.name as testName FROM load_test JOIN load_test_file ON load_test.id = load_test_file.test_id diff --git a/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java b/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java index 30d23051a3..c6d54076e9 100644 --- a/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java +++ b/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java @@ -12,8 +12,9 @@ import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.QueryScheduleRequest; import io.metersphere.dto.DashboardTestDTO; import io.metersphere.dto.LoadTestDTO; -import io.metersphere.dto.LoadTestFileDTO; import io.metersphere.dto.ScheduleDao; +import io.metersphere.performance.dto.LoadTestExportJmx; +import io.metersphere.performance.dto.LoadTestFileDTO; import io.metersphere.performance.service.PerformanceTestService; import io.metersphere.service.CheckPermissionService; import io.metersphere.service.FileService; @@ -108,11 +109,16 @@ public class PerformanceTestController { } @GetMapping("/get-jmx-content/{testId}") - public String getJmxContent(@PathVariable String testId) { + public List getJmxContent(@PathVariable String testId) { checkPermissionService.checkPerformanceTestOwner(testId); return performanceTestService.getJmxContent(testId); } + @PostMapping("/export/jmx") + public List exportJmx(@RequestBody List fileIds) { + return performanceTestService.exportJmx(fileIds); + } + @GetMapping("/project/{loadType}/{projectId}/{goPage}/{pageSize}") public Pager> getProjectFiles(@PathVariable String projectId, @PathVariable String loadType, @PathVariable int goPage, @PathVariable int pageSize) { diff --git a/backend/src/main/java/io/metersphere/performance/dto/LoadTestExportJmx.java b/backend/src/main/java/io/metersphere/performance/dto/LoadTestExportJmx.java new file mode 100644 index 0000000000..bb7900793b --- /dev/null +++ b/backend/src/main/java/io/metersphere/performance/dto/LoadTestExportJmx.java @@ -0,0 +1,16 @@ +package io.metersphere.performance.dto; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class LoadTestExportJmx { + private String name; + private String jmx; + + public LoadTestExportJmx(String name, String jmx) { + this.name = name; + this.jmx = jmx; + } +} diff --git a/backend/src/main/java/io/metersphere/dto/LoadTestFileDTO.java b/backend/src/main/java/io/metersphere/performance/dto/LoadTestFileDTO.java similarity index 84% rename from backend/src/main/java/io/metersphere/dto/LoadTestFileDTO.java rename to backend/src/main/java/io/metersphere/performance/dto/LoadTestFileDTO.java index a5f9522e10..56b4f2c07e 100644 --- a/backend/src/main/java/io/metersphere/dto/LoadTestFileDTO.java +++ b/backend/src/main/java/io/metersphere/performance/dto/LoadTestFileDTO.java @@ -1,4 +1,4 @@ -package io.metersphere.dto; +package io.metersphere.performance.dto; import io.metersphere.base.domain.FileMetadata; import lombok.Getter; diff --git a/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java b/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java index 0e1520f2fc..454e7c16c8 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java +++ b/backend/src/main/java/io/metersphere/performance/engine/EngineFactory.java @@ -23,9 +23,22 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.reflections8.Reflections; import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; import javax.annotation.Resource; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.util.*; import java.util.stream.Collectors; @@ -77,22 +90,17 @@ public class EngineFactory { if (org.springframework.util.CollectionUtils.isEmpty(fileMetadataList)) { MSException.throwException(Translator.get("run_load_test_file_not_found") + loadTest.getId()); } - FileMetadata jmxFile = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JMX.name())) - .findFirst().orElseGet(() -> { - throw new RuntimeException(Translator.get("run_load_test_file_not_found") + loadTest.getId()); - }); + List jmxFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JMX.name())).collect(Collectors.toList()); List csvFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.CSV.name())).collect(Collectors.toList()); List jarFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JAR.name())).collect(Collectors.toList()); - final FileContent fileContent = fileService.getFileContent(jmxFile.getId()); - if (fileContent == null) { - MSException.throwException(Translator.get("run_load_test_file_content_not_found") + loadTest.getId()); - } + // 合并上传的jmx + byte[] jmxBytes = mergeJmx(jmxFiles); final EngineContext engineContext = new EngineContext(); engineContext.setTestId(loadTest.getId()); engineContext.setTestName(loadTest.getName()); engineContext.setNamespace(loadTest.getProjectId()); - engineContext.setFileType(jmxFile.getType()); + engineContext.setFileType(FileType.JMX.name()); engineContext.setResourcePoolId(loadTest.getTestResourcePoolId()); engineContext.setStartTime(startTime); engineContext.setReportId(reportId); @@ -146,7 +154,7 @@ public class EngineFactory { MSException.throwException("File type unknown"); } - try (ByteArrayInputStream source = new ByteArrayInputStream(fileContent.getFile())) { + try (ByteArrayInputStream source = new ByteArrayInputStream(jmxBytes)) { String content = engineSourceParser.parse(engineContext, source); engineContext.setContent(content); } catch (MSException e) { @@ -178,6 +186,63 @@ public class EngineFactory { return engineContext; } + public static byte[] mergeJmx(List jmxFiles) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = factory.newDocumentBuilder(); + Element hashTree = null; + Document rootDocument = null; + for (FileMetadata fileMetadata : jmxFiles) { + FileContent fileContent = fileService.getFileContent(fileMetadata.getId()); + final InputSource inputSource = new InputSource(new ByteArrayInputStream(fileContent.getFile())); + if (hashTree == null) { + rootDocument = docBuilder.parse(inputSource); + Element jmeterTestPlan = rootDocument.getDocumentElement(); + NodeList childNodes = jmeterTestPlan.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node instanceof Element) { + // jmeterTestPlan的子元素肯定是 + hashTree = (Element) node; + break; + } + } + } else { + Document document = docBuilder.parse(inputSource); + Element jmeterTestPlan = document.getDocumentElement(); + NodeList childNodes = jmeterTestPlan.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node instanceof Element) { + // jmeterTestPlan的子元素肯定是 + Element secondHashTree = (Element) node; + NodeList secondChildNodes = secondHashTree.getChildNodes(); + for (int j = 0; j < secondChildNodes.getLength(); j++) { + Node item = secondChildNodes.item(j); + Node newNode = item.cloneNode(true); + rootDocument.adoptNode(newNode); + hashTree.appendChild(newNode); + } + } + } + } + } + return documentToBytes(rootDocument); + } catch (Exception e) { + MSException.throwException(e); + } + return new byte[0]; + } + + private static byte[] documentToBytes(Document document) throws TransformerException { + DOMSource domSource = new DOMSource(document); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamResult result = new StreamResult(out); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + return out.toByteArray(); + } @Resource private void setFileService(FileService fileService) { diff --git a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java index f8e2ccf152..f9edf73705 100644 --- a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java +++ b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java @@ -16,10 +16,11 @@ import io.metersphere.controller.request.OrderRequest; import io.metersphere.controller.request.QueryScheduleRequest; import io.metersphere.dto.DashboardTestDTO; import io.metersphere.dto.LoadTestDTO; -import io.metersphere.dto.LoadTestFileDTO; import io.metersphere.dto.ScheduleDao; import io.metersphere.i18n.Translator; import io.metersphere.job.sechedule.PerformanceTestJob; +import io.metersphere.performance.dto.LoadTestExportJmx; +import io.metersphere.performance.dto.LoadTestFileDTO; import io.metersphere.performance.engine.Engine; import io.metersphere.performance.engine.EngineFactory; import io.metersphere.performance.engine.producer.LoadTestProducer; @@ -131,23 +132,13 @@ public class PerformanceTestService { checkQuota(request, true); LoadTestWithBLOBs loadTest = saveLoadTest(request); - // 新选择了一个文件,删除原来的文件 List importFiles = request.getUpdatedFileList(); List importFileIds = importFiles.stream().map(FileMetadata::getId).collect(Collectors.toList()); // 导入项目里其他的文件 this.importFiles(importFileIds, loadTest.getId()); - // 保存上传的问题件 + // 保存上传的文件 this.saveUploadFiles(files, loadTest.getId()); - // 直接上传了jmx,用于API导入的场景 - String jmx = request.getJmx(); - if (StringUtils.isNotBlank(jmx)) { - byte[] bytes = jmx.getBytes(StandardCharsets.UTF_8); - FileMetadata fileMetadata = fileService.saveFile(bytes, request.getName() + ".jmx", (long) bytes.length); - LoadTestFile loadTestFile = new LoadTestFile(); - loadTestFile.setTestId(loadTest.getId()); - loadTestFile.setFileId(fileMetadata.getId()); - loadTestFileMapper.insert(loadTestFile); - } + return loadTest.getId(); } @@ -222,16 +213,6 @@ public class PerformanceTestService { List addFileIds = ListUtils.subtract(updatedFileIds, originFileIds); this.importFiles(addFileIds, request.getId()); this.saveUploadFiles(files, request.getId()); - // 直接上传了jmx,用于API导入的场景 - String jmx = request.getJmx(); - if (StringUtils.isNotBlank(jmx)) { - byte[] bytes = jmx.getBytes(StandardCharsets.UTF_8); - FileMetadata fileMetadata = fileService.saveFile(bytes, request.getName() + ".jmx", (long) bytes.length); - LoadTestFile loadTestFile = new LoadTestFile(); - loadTestFile.setTestId(request.getId()); - loadTestFile.setFileId(fileMetadata.getId()); - loadTestFileMapper.insert(loadTestFile); - } loadTest.setName(request.getName()); loadTest.setProjectId(request.getProjectId()); @@ -391,15 +372,16 @@ public class PerformanceTestService { return Optional.ofNullable(loadTestWithBLOBs).orElse(new LoadTestWithBLOBs()).getLoadConfiguration(); } - public String getJmxContent(String testId) { + public List getJmxContent(String testId) { List fileMetadataList = fileService.getFileMetadataByTestId(testId); + List results = new ArrayList<>(); for (FileMetadata metadata : fileMetadataList) { if (FileType.JMX.name().equals(metadata.getType())) { FileContent fileContent = fileService.getFileContent(metadata.getId()); - return new String(fileContent.getFile()); + results.add(new LoadTestExportJmx(metadata.getName(), new String(fileContent.getFile(), StandardCharsets.UTF_8))); } } - return null; + return results; } public List selectByTestResourcePoolId(String resourcePoolId) { @@ -557,4 +539,18 @@ public class PerformanceTestService { } return extLoadTestMapper.getProjectFiles(projectId, loadTypes); } + + public List exportJmx(List fileIds) { + if (CollectionUtils.isEmpty(fileIds)) { + return null; + } + List results = new ArrayList<>(); + fileIds.forEach(id -> { + FileMetadata fileMetadata = fileService.getFileMetadataById(id); + FileContent fileContent = fileService.getFileContent(id); + results.add(new LoadTestExportJmx(fileMetadata.getName(), new String(fileContent.getFile(), StandardCharsets.UTF_8))); + }); + + return results; + } } diff --git a/backend/src/main/java/io/metersphere/track/request/testplan/TestPlanRequest.java b/backend/src/main/java/io/metersphere/track/request/testplan/TestPlanRequest.java index 89de645106..25c5ee6de8 100644 --- a/backend/src/main/java/io/metersphere/track/request/testplan/TestPlanRequest.java +++ b/backend/src/main/java/io/metersphere/track/request/testplan/TestPlanRequest.java @@ -16,8 +16,6 @@ public class TestPlanRequest { private String description; - private String jmx; - private Long createTime; private Long updateTime; diff --git a/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue b/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue index 2592f89233..f9b594afd1 100644 --- a/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue +++ b/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue @@ -117,6 +117,7 @@ import echarts from "echarts"; import MsChart from "@/business/components/common/chart/MsChart"; import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup"; +const HANDLER = "handler"; const TARGET_LEVEL = "TargetLevel"; const RAMP_UP = "RampUp"; const STEPS = "Steps"; @@ -204,6 +205,9 @@ export default { case DELETED: this.threadGroups[i].deleted = item.value; break; + case HANDLER: + this.threadGroups[i].handler = item.value; + break; default: break; } @@ -241,13 +245,13 @@ export default { return; } this.result = this.$get('/performance/get-jmx-content/' + this.report.testId, (response) => { - if (response.data) { - this.threadGroups = findThreadGroup(response.data); + response.data.forEach(d => { + this.threadGroups = this.threadGroups.concat(findThreadGroup(d.jmx, d.name)); this.threadGroups.forEach(tg => { tg.options = {}; }); - this.getLoadConfig(); - } + }); + this.getLoadConfig(); }); }, calculateTotalChart() { diff --git a/frontend/src/business/components/performance/test/components/ExistFiles.vue b/frontend/src/business/components/performance/test/components/ExistFiles.vue new file mode 100644 index 0000000000..880b559eda --- /dev/null +++ b/frontend/src/business/components/performance/test/components/ExistFiles.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/frontend/src/business/components/performance/test/components/ExistScenarios.vue b/frontend/src/business/components/performance/test/components/ExistScenarios.vue new file mode 100644 index 0000000000..ededff4630 --- /dev/null +++ b/frontend/src/business/components/performance/test/components/ExistScenarios.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/frontend/src/business/components/performance/test/components/PerformanceBasicConfig.vue b/frontend/src/business/components/performance/test/components/PerformanceBasicConfig.vue index 1c3849924d..bf6643ec18 100644 --- a/frontend/src/business/components/performance/test/components/PerformanceBasicConfig.vue +++ b/frontend/src/business/components/performance/test/components/PerformanceBasicConfig.vue @@ -8,6 +8,7 @@ style="padding-right: 10px;" accept=".jmx" action="" + multiple :limit="fileNumLimit" :show-file-list="false" :before-upload="beforeUploadJmx" @@ -83,7 +84,7 @@ - + @@ -116,79 +117,36 @@ - + - - - - - - - - - - - - - - - - - + - - - - - - - - - - -