From 3dcf2f0f2a1b3f060146a36aae87d7a25945634e Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Wed, 8 Jul 2020 11:57:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95=E5=AF=BC?= =?UTF-8?q?=E5=85=A5-=20Metersphere(json)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/APITestController.java | 6 + .../metersphere/api/dto/parse/ApiImport.java | 11 ++ .../api/parse/ApiImportParser.java | 9 ++ .../api/parse/ApiImportParserFactory.java | 16 +++ .../io/metersphere/api/parse/MsParser.java | 36 +++++ .../api/service/APITestService.java | 51 ++++++- .../commons/constants/ApiImportPlatform.java | 5 + .../commons/constants/FileType.java | 2 +- .../components/api/test/ApiTestConfig.vue | 14 +- .../api/test/components/import/ApiImport.vue | 132 ++++++++++++++++++ .../track/case/components/TestCaseImport.vue | 6 +- 11 files changed, 280 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/api/dto/parse/ApiImport.java create mode 100644 backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java create mode 100644 backend/src/main/java/io/metersphere/api/parse/ApiImportParserFactory.java create mode 100644 backend/src/main/java/io/metersphere/api/parse/MsParser.java create mode 100644 backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java create mode 100644 frontend/src/business/components/api/test/components/import/ApiImport.vue diff --git a/backend/src/main/java/io/metersphere/api/controller/APITestController.java b/backend/src/main/java/io/metersphere/api/controller/APITestController.java index 84cff582b..ced4f7f2d 100644 --- a/backend/src/main/java/io/metersphere/api/controller/APITestController.java +++ b/backend/src/main/java/io/metersphere/api/controller/APITestController.java @@ -96,4 +96,10 @@ public class APITestController { return apiTestService.run(request); } + @PostMapping("/import/{platform}/{projectId}") + @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) + public ApiTest testCaseImport(MultipartFile file, @PathVariable String platform, @PathVariable String projectId) { + return apiTestService.apiTestImport(file, platform, projectId); + } + } diff --git a/backend/src/main/java/io/metersphere/api/dto/parse/ApiImport.java b/backend/src/main/java/io/metersphere/api/dto/parse/ApiImport.java new file mode 100644 index 000000000..deddba481 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/parse/ApiImport.java @@ -0,0 +1,11 @@ +package io.metersphere.api.dto.parse; + +import io.metersphere.api.dto.scenario.Scenario; +import lombok.Data; + +import java.util.List; + +@Data +public class ApiImport { + private List scenarios; +} diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java new file mode 100644 index 000000000..659e9ea6d --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java @@ -0,0 +1,9 @@ +package io.metersphere.api.parse; + +import io.metersphere.api.dto.parse.ApiImport; + +import java.io.InputStream; + +public interface ApiImportParser { + ApiImport parse(InputStream source); +} diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportParserFactory.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportParserFactory.java new file mode 100644 index 000000000..a6b425df5 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportParserFactory.java @@ -0,0 +1,16 @@ +package io.metersphere.api.parse; + +import io.metersphere.commons.constants.ApiImportPlatform; +import io.metersphere.commons.constants.FileType; +import io.metersphere.performance.parse.EngineSourceParser; +import io.metersphere.performance.parse.xml.XmlEngineSourceParse; +import org.apache.commons.lang3.StringUtils; + +public class ApiImportParserFactory { + public static ApiImportParser getApiImportParser(String platform) { + if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) { + return new MsParser(); + } + return null; + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/MsParser.java b/backend/src/main/java/io/metersphere/api/parse/MsParser.java new file mode 100644 index 000000000..8eec7b836 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/MsParser.java @@ -0,0 +1,36 @@ +package io.metersphere.api.parse; + +import com.alibaba.fastjson.JSON; +import io.metersphere.api.dto.parse.ApiImport; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; + +import java.io.*; + +public class MsParser implements ApiImportParser { + + @Override + public ApiImport parse(InputStream source) {BufferedReader bufferedReader = null; + StringBuilder testStr = null; + try { + bufferedReader = new BufferedReader(new InputStreamReader(source, "UTF-8")); + testStr = new StringBuilder(); + String inputStr = null; + while ((inputStr = bufferedReader.readLine()) != null) { + testStr.append(inputStr); + } + } catch (Exception e) { + MSException.throwException(e.getMessage()); + LogUtil.error(e.getMessage(), e); + } finally { + try { + source.close(); + } catch (IOException e) { + MSException.throwException(e.getMessage()); + LogUtil.error(e.getMessage(), e); + } + } + return JSON.parseObject(testStr.toString(), ApiImport.class); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/service/APITestService.java b/backend/src/main/java/io/metersphere/api/service/APITestService.java index fa81f7317..52cea0148 100644 --- a/backend/src/main/java/io/metersphere/api/service/APITestService.java +++ b/backend/src/main/java/io/metersphere/api/service/APITestService.java @@ -2,14 +2,19 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.APITestResult; +import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.QueryAPITestRequest; import io.metersphere.api.dto.SaveAPITestRequest; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.api.parse.ApiImportParser; +import io.metersphere.api.parse.ApiImportParserFactory; +import io.metersphere.api.parse.MsParser; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiTestFileMapper; import io.metersphere.base.mapper.ApiTestMapper; import io.metersphere.base.mapper.ext.ExtApiTestMapper; import io.metersphere.commons.constants.APITestStatus; +import io.metersphere.commons.constants.FileType; import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.constants.ScheduleType; import io.metersphere.commons.exception.MSException; @@ -26,8 +31,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; -import java.io.ByteArrayInputStream; -import java.io.InputStream; +import java.io.*; import java.util.List; import java.util.Objects; import java.util.Random; @@ -163,6 +167,15 @@ public class APITestService { } } + private Boolean isNameExist(SaveAPITestRequest request) { + ApiTestExample example = new ApiTestExample(); + example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); + if (apiTestMapper.countByExample(example) > 0) { + return true; + } + return false; + } + private ApiTest updateTest(SaveAPITestRequest request) { checkNameExist(request); final ApiTest test = new ApiTest(); @@ -246,4 +259,38 @@ public class APITestService { private void addOrUpdateApiTestCronJob(Schedule request) { scheduleService.addOrUpdateCronJob(request, ApiTestJob.getJobKey(request.getResourceId()), ApiTestJob.getTriggerKey(request.getResourceId()), ApiTestJob.class); } + + public ApiTest apiTestImport(MultipartFile file, String platform, String projectId) { + try { + + ApiImportParser apiImportParser = ApiImportParserFactory.getApiImportParser(platform); + ApiImport apiImport = apiImportParser.parse(file.getInputStream()); + SaveAPITestRequest request = getImportApiTest(file, projectId, apiImport); + ApiTest test = createTest(request); + return test; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private SaveAPITestRequest getImportApiTest(MultipartFile file, String projectId, ApiImport apiImport) { + SaveAPITestRequest request = new SaveAPITestRequest(); + request.setName(file.getOriginalFilename()); + request.setProjectId(projectId); + request.setScenarioDefinition(apiImport.getScenarios()); + request.setUserId(SessionUtils.getUser().getId()); + request.setId(UUID.randomUUID().toString()); + for (FileType fileType : FileType.values()) { + String suffix = fileType.suffix(); + String name = request.getName(); + if (name.endsWith(suffix)) { + request.setName(name.substring(0, name.length() - suffix.length())); + } + }; + if (isNameExist(request)) { + request.setName(request.getName() + "_" + request.getId().substring(0, 5)); + } + return request; + } } diff --git a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java new file mode 100644 index 000000000..a5bea45b7 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java @@ -0,0 +1,5 @@ +package io.metersphere.commons.constants; + +public enum ApiImportPlatform { + Metersphere, Postman +} diff --git a/backend/src/main/java/io/metersphere/commons/constants/FileType.java b/backend/src/main/java/io/metersphere/commons/constants/FileType.java index 6b800133f..db8236c2e 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/FileType.java +++ b/backend/src/main/java/io/metersphere/commons/constants/FileType.java @@ -1,7 +1,7 @@ package io.metersphere.commons.constants; public enum FileType { - JMX(".jmx"), CSV(".csv"); + JMX(".jmx"), CSV(".csv"), JSON(".json"); // 保存后缀 private String suffix; diff --git a/frontend/src/business/components/api/test/ApiTestConfig.vue b/frontend/src/business/components/api/test/ApiTestConfig.vue index 299a7883c..1013f64f1 100644 --- a/frontend/src/business/components/api/test/ApiTestConfig.vue +++ b/frontend/src/business/components/api/test/ApiTestConfig.vue @@ -39,12 +39,18 @@ {{$t('api_test.create_performance_test')}} - + {{$t('api_test.export_config')}} + + 导入 + + + + @@ -64,11 +70,12 @@ import MsApiReportDialog from "./ApiReportDialog"; import {checkoutTestManagerOrTestUser, downloadFile} from "../../../../common/js/utils"; import MsScheduleConfig from "../../common/components/MsScheduleConfig"; + import ApiImport from "./components/import/ApiImport"; export default { name: "MsApiTestConfig", - components: {MsScheduleConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig}, + components: {ApiImport, MsScheduleConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig}, props: ["id"], @@ -211,6 +218,9 @@ case "export": downloadFile(this.test.name + ".json", this.test.export()); break; + case "import": + this.$refs.apiImport.open(); + break; } }, saveCronExpression(cronExpression) { diff --git a/frontend/src/business/components/api/test/components/import/ApiImport.vue b/frontend/src/business/components/api/test/components/import/ApiImport.vue new file mode 100644 index 000000000..ab7406556 --- /dev/null +++ b/frontend/src/business/components/api/test/components/import/ApiImport.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/frontend/src/business/components/track/case/components/TestCaseImport.vue b/frontend/src/business/components/track/case/components/TestCaseImport.vue index 908849963..f41ada12f 100644 --- a/frontend/src/business/components/track/case/components/TestCaseImport.vue +++ b/frontend/src/business/components/track/case/components/TestCaseImport.vue @@ -16,7 +16,7 @@ :limit="1" action="" :on-exceed="handleExceed" - :beforeUpload="UploadValidate" + :beforeUpload="uploadValidate" :on-error="handleError" :show-file-list="false" :http-request="upload" @@ -66,8 +66,8 @@ handleExceed(files, fileList) { this.$warning(this.$t('test_track.case.import.upload_limit_count')); }, - UploadValidate(file) { - var suffix =file.name.substring(file.name.lastIndexOf('.') + 1); + uploadValidate(file) { + let suffix = file.name.substring(file.name.lastIndexOf('.') + 1); if (suffix != 'xls' && suffix != 'xlsx') { this.$warning(this.$t('test_track.case.import.upload_limit_format')); return false; -- GitLab