From 8e5105d579d5c6aceb17f88912e24dfea30cbf8a Mon Sep 17 00:00:00 2001 From: "song.tianyang" Date: Mon, 4 Jan 2021 11:28:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8E=A5=E5=8F=A3=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E3=80=81=E7=94=A8=E4=BE=8B=E5=88=97=E8=A1=A8=E3=80=81=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=E7=94=A8=E4=BE=8B=E5=88=97=E8=A1=A8=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接口用例、用例列表、场景用例列表增加创建性能测试的功能 --- .../api/controller/APITestController.java | 106 ++- .../controller/ApiAutomationController.java | 29 + .../api/controller/ApiTestCaseController.java | 13 + .../api/service/ApiAutomationService.java | 147 ++++ .../service/PerformanceTestService.java | 16 +- .../io/metersphere/service/FileService.java | 19 + .../scenario/ScenarioExtendBtns.vue | 24 + .../components/basis/SetEnvironment.vue | 112 +++ .../components/case/ApiCaseItem.vue | 4 +- .../components/case/ApiCaseList.vue | 1 + .../components/list/ApiCaseSimpleList.vue | 743 ++++++++++-------- .../reference/ApiCaseTableExtendBtns.vue | 53 ++ .../components/reference/ApiExtendBtns.vue | 56 ++ 13 files changed, 949 insertions(+), 374 deletions(-) create mode 100644 frontend/src/business/components/api/definition/components/basis/SetEnvironment.vue create mode 100644 frontend/src/business/components/api/definition/components/reference/ApiCaseTableExtendBtns.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 421eec048a..150f990b83 100644 --- a/backend/src/main/java/io/metersphere/api/controller/APITestController.java +++ b/backend/src/main/java/io/metersphere/api/controller/APITestController.java @@ -9,10 +9,14 @@ import io.metersphere.api.dto.datacount.request.ScheduleInfoRequest; import io.metersphere.api.dto.datacount.response.ApiDataCountDTO; import io.metersphere.api.dto.datacount.response.ExecutedCaseInfoDTO; import io.metersphere.api.dto.datacount.response.TaskInfoResult; +import io.metersphere.api.dto.definition.RunDefinitionRequest; +import io.metersphere.api.dto.definition.request.MsTestElement; import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter; import io.metersphere.api.service.*; import io.metersphere.base.domain.ApiTest; +import io.metersphere.base.domain.LoadTest; import io.metersphere.base.domain.Schedule; +import io.metersphere.commons.constants.PerformanceTestStatus; import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.utils.CronUtils; @@ -21,19 +25,23 @@ import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.QueryScheduleRequest; import io.metersphere.dto.ScheduleDao; +import io.metersphere.performance.service.PerformanceTestService; import io.metersphere.service.CheckPermissionService; +import io.metersphere.service.FileService; import io.metersphere.service.ScheduleService; +import io.metersphere.track.request.testplan.SaveTestPlanRequest; +import org.apache.http.entity.ContentType; +import org.apache.jorphan.collections.HashTree; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; +import java.util.*; import static io.metersphere.commons.utils.JsonPathUtils.getListJson; @@ -60,6 +68,10 @@ public class APITestController { private ScheduleService scheduleService; @Resource private APIReportService apiReportService; + @Resource + private PerformanceTestService performanceTestService; + @Resource + private CheckPermissionService checkPermissionService; @GetMapping("recent/{count}") public List recentTest(@PathVariable int count) { @@ -109,6 +121,7 @@ public class APITestController { public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List selectIds) { apiTestService.mergeCreate(request, file, selectIds); } + @PostMapping(value = "/update", consumes = {"multipart/form-data"}) public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List bodyFiles) { checkownerService.checkApiTestOwner(request.getId()); @@ -189,19 +202,19 @@ public class APITestController { //查询完成率、进行中、已完成 List countResultByStatelList = apiDefinitionService.countStateByProjectID(projectId); apiCountResult.countStatus(countResultByStatelList); - long allCount = apiCountResult.getFinishedCount()+apiCountResult.getRunningCount()+apiCountResult.getNotStartedCount(); + long allCount = apiCountResult.getFinishedCount() + apiCountResult.getRunningCount() + apiCountResult.getNotStartedCount(); - if(allCount!=0){ - float complateRageNumber =(float)apiCountResult.getFinishedCount()*100/allCount; + if (allCount != 0) { + float complateRageNumber = (float) apiCountResult.getFinishedCount() * 100 / allCount; DecimalFormat df = new DecimalFormat("0.0"); - apiCountResult.setCompletionRage(df.format(complateRageNumber)+"%"); + apiCountResult.setCompletionRage(df.format(complateRageNumber) + "%"); } - apiCountResult.setHttpCountStr("HTTP  

"+apiCountResult.getHttpApiDataCountNumber()); - apiCountResult.setRpcCountStr("RPC  

"+apiCountResult.getRpcApiDataCountNumber()); - apiCountResult.setTcpCountStr("TCP  

"+apiCountResult.getTcpApiDataCountNumber()); - apiCountResult.setSqlCountStr("SQL  

"+apiCountResult.getSqlApiDataCountNumber()); - return apiCountResult; + apiCountResult.setHttpCountStr("HTTP  

" + apiCountResult.getHttpApiDataCountNumber()); + apiCountResult.setRpcCountStr("RPC  

" + apiCountResult.getRpcApiDataCountNumber()); + apiCountResult.setTcpCountStr("TCP  

" + apiCountResult.getTcpApiDataCountNumber()); + apiCountResult.setSqlCountStr("SQL  

" + apiCountResult.getSqlApiDataCountNumber()); + return apiCountResult; } @GetMapping("/testCaseInfoCount/{projectId}") @@ -222,21 +235,21 @@ public class APITestController { //未覆盖 已覆盖: 统计当前接口下是否含有案例 List countResultByApiCoverageList = apiDefinitionService.countApiCoverageByProjectID(projectId); apiCountResult.countApiCoverage(countResultByApiCoverageList); - long allCount = apiCountResult.getCoverageCount()+apiCountResult.getUncoverageCount(); + long allCount = apiCountResult.getCoverageCount() + apiCountResult.getUncoverageCount(); - if(allCount!=0){ - float coverageRageNumber =(float)apiCountResult.getCoverageCount()*100/allCount; + if (allCount != 0) { + float coverageRageNumber = (float) apiCountResult.getCoverageCount() * 100 / allCount; DecimalFormat df = new DecimalFormat("0.0"); - apiCountResult.setCoverageRage(df.format(coverageRageNumber)+"%"); + apiCountResult.setCoverageRage(df.format(coverageRageNumber) + "%"); } - apiCountResult.setHttpCountStr("HTTP  

"+apiCountResult.getHttpApiDataCountNumber()); - apiCountResult.setRpcCountStr("RPC  

"+apiCountResult.getRpcApiDataCountNumber()); - apiCountResult.setTcpCountStr("TCP  

"+apiCountResult.getTcpApiDataCountNumber()); - apiCountResult.setSqlCountStr("SQL  

"+apiCountResult.getSqlApiDataCountNumber()); + apiCountResult.setHttpCountStr("HTTP  

" + apiCountResult.getHttpApiDataCountNumber()); + apiCountResult.setRpcCountStr("RPC  

" + apiCountResult.getRpcApiDataCountNumber()); + apiCountResult.setTcpCountStr("TCP  

" + apiCountResult.getTcpApiDataCountNumber()); + apiCountResult.setSqlCountStr("SQL  

" + apiCountResult.getSqlApiDataCountNumber()); - return apiCountResult; + return apiCountResult; } @GetMapping("/testSceneInfoCount/{projectId}") @@ -263,15 +276,15 @@ public class APITestController { List countResultByRunResult = apiAutomationService.countRunResultByProjectID(projectId); apiCountResult.countRunResult(countResultByRunResult); - long allCount = apiCountResult.getUnexecuteCount()+apiCountResult.getExecutionPassCount()+apiCountResult.getExecutionFailedCount(); + long allCount = apiCountResult.getUnexecuteCount() + apiCountResult.getExecutionPassCount() + apiCountResult.getExecutionFailedCount(); - if(allCount!=0){ - float coverageRageNumber =(float)apiCountResult.getExecutionPassCount()*100/allCount; + if (allCount != 0) { + float coverageRageNumber = (float) apiCountResult.getExecutionPassCount() * 100 / allCount; DecimalFormat df = new DecimalFormat("0.0"); - apiCountResult.setPassRage(df.format(coverageRageNumber)+"%"); + apiCountResult.setPassRage(df.format(coverageRageNumber) + "%"); } - return apiCountResult; + return apiCountResult; } @@ -287,7 +300,7 @@ public class APITestController { apiCountResult.setThisWeekAddedCount(taskCountInThisWeek); long api_executedInThisWeekCountNumber = apiReportService.countByProjectIdAndCreateInThisWeek(projectId); long scene_executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId); - long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber+scene_executedInThisWeekCountNumber; + long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber + scene_executedInThisWeekCountNumber; apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); //统计 失败 成功 以及总数 @@ -299,41 +312,41 @@ public class APITestController { apiCountResult.countScheduleExecute(allExecuteResult); long allCount = apiCountResult.getExecutedCount(); - if(allCount!=0){ - float coverageRageNumber =(float)apiCountResult.getSuccessCount()*100/allCount; + if (allCount != 0) { + float coverageRageNumber = (float) apiCountResult.getSuccessCount() * 100 / allCount; DecimalFormat df = new DecimalFormat("0.0"); - apiCountResult.setSuccessRage(df.format(coverageRageNumber)+"%"); + apiCountResult.setSuccessRage(df.format(coverageRageNumber) + "%"); } - return apiCountResult; + return apiCountResult; } @GetMapping("/faliureCaseAboutTestPlan/{projectId}/{limitNumber}") public List faliureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable int limitNumber) { - List selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId,limitNumber); + List selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId, limitNumber); List returnList = new ArrayList<>(limitNumber); - for(int dataIndex = 0;dataIndex < limitNumber;dataIndex ++){ + for (int dataIndex = 0; dataIndex < limitNumber; dataIndex++) { ExecutedCaseInfoDTO dataDTO = new ExecutedCaseInfoDTO(); - dataDTO.setSortIndex(dataIndex+1); + dataDTO.setSortIndex(dataIndex + 1); - if(dataIndex bodyFiles) { + SaveTestPlanRequest request = new SaveTestPlanRequest(); + request.setName(runRequest.getName()); + request.setProjectId(runRequest.getProjectId()); + request.setAdvancedConfiguration("{\"timeout\":2000,\"responseTimeout\":0,\"statusCode\":[],\"params\":[],\"domains\":[]}"); + request.setLoadConfiguration("[]"); + HashTree hashTree = runRequest.getTestElement().generateHashTree(); + String jmxString = runRequest.getTestElement().getJmx(hashTree); + String testID = performanceTestService.save(request, jmxString.getBytes()); + return testID; + } } diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java index 2f8fbdbc06..fb9cf5f1bd 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -1,25 +1,45 @@ package io.metersphere.api.controller; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.definition.RunDefinitionRequest; +import io.metersphere.api.dto.definition.request.*; +import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.service.ApiAutomationService; import io.metersphere.base.domain.ApiScenario; import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.Schedule; +import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.constants.RoleConstants; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.i18n.Translator; +import io.metersphere.performance.service.PerformanceTestService; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; +import io.metersphere.track.request.testplan.SaveTestPlanRequest; +import org.apache.commons.lang3.StringUtils; +import org.apache.jmeter.save.SaveService; +import org.apache.jorphan.collections.HashTree; +import org.apache.jorphan.collections.ListedHashTree; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.io.ByteArrayOutputStream; +import java.util.LinkedList; import java.util.List; +import java.util.UUID; @RestController @RequestMapping(value = "/api/automation") @@ -28,6 +48,8 @@ public class ApiAutomationController { @Resource ApiAutomationService apiAutomationService; + @Resource + PerformanceTestService performanceTestService; @PostMapping("/list/{goPage}/{pageSize}") @@ -121,5 +143,12 @@ public class ApiAutomationController { public void createSchedule(@RequestBody Schedule request) { apiAutomationService.createSchedule(request); } + + //一键创建性能测试 + @PostMapping(value = "/genPerformanceTest") + public String genPerformanceTest(@RequestBody RunScenarioRequest runRequest) { + runRequest.setExecuteType(ExecuteType.Completed.name()); + return apiAutomationService.genPerformanceTest(runRequest); + } } diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiTestCaseController.java b/backend/src/main/java/io/metersphere/api/controller/ApiTestCaseController.java index 07f92a927d..2ce95c8e13 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiTestCaseController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiTestCaseController.java @@ -34,6 +34,19 @@ public class ApiTestCaseController { return apiTestCaseService.list(request); } + @GetMapping("/findById/{id}") + public ApiTestCaseResult single(@PathVariable String id ) { + ApiTestCaseRequest request = new ApiTestCaseRequest(); + request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); + request.setId(id); + List list = apiTestCaseService.list(request); + if(!list.isEmpty()){ + return list.get(0); + }else { + return null; + } + } + @PostMapping("/list/{goPage}/{pageSize}") public Pager> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) { Page page = PageHelper.startPage(goPage, pageSize, true); 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 9465a3caea..876c57b233 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -24,19 +24,23 @@ import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper; import io.metersphere.commons.constants.*; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.DateUtils; +import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.i18n.Translator; import io.metersphere.job.sechedule.ApiScenarioTestJob; +import io.metersphere.performance.service.PerformanceTestService; import io.metersphere.service.ScheduleService; import io.metersphere.track.dto.TestPlanDTO; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.QueryTestPlanRequest; +import io.metersphere.track.request.testplan.SaveTestPlanRequest; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.jmeter.save.SaveService; import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.ListedHashTree; import org.springframework.stereotype.Service; @@ -44,6 +48,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.io.ByteArrayOutputStream; import java.util.*; import java.util.stream.Collectors; @@ -72,6 +77,8 @@ public class ApiAutomationService { SqlSessionFactory sqlSessionFactory; @Resource private ApiScenarioReportMapper apiScenarioReportMapper; + @Resource + private PerformanceTestService performanceTestService; public List list(ApiScenarioRequest request) { request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); @@ -538,4 +545,144 @@ public class ApiAutomationService { scheduleService.addOrUpdateCronJob( request, ApiScenarioTestJob.getJobKey(request.getResourceId()), ApiScenarioTestJob.getTriggerKey(request.getResourceId()), ApiScenarioTestJob.class); } + + public String genPerformanceTest1(RunScenarioRequest runRequest) { + SaveTestPlanRequest request = new SaveTestPlanRequest(); + request.setName(runRequest.getName()); + request.setProjectId(runRequest.getProjectId()); + request.setAdvancedConfiguration("{\"timeout\":2000,\"responseTimeout\":0,\"statusCode\":[],\"params\":[],\"domains\":[]}"); + request.setLoadConfiguration("[]"); + + List ids = runRequest.getScenarioIds(); + if (runRequest.isSelectAllDate()) { + ids = this.getAllScenarioIdsByFontedSelect( + runRequest.getModuleIds(), request.getName(), request.getProjectId(), runRequest.getFilters(), runRequest.getUnSelectIds()); + } + List 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); + // 创建场景报告 +// createScenarioReport(group.getName(), item.getId(), item.getName(), runRequest.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : runRequest.getTriggerMode(), +// runRequest.getExecuteType(), item.getProjectId(), runRequest.getReportUserID()); + group.setHashTree(scenarios); + testPlan.getHashTree().add(group); + + } + } catch (Exception ex) { + MSException.throwException(ex.getMessage()); + } + + testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig()); + + + String jmxString = testPlan.getJmx(jmeterHashTree); + + String testID = performanceTestService.save(request, jmxString.getBytes()); + return testID; + } + + public String genPerformanceTest(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); + 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()); + String jmx = testPlan.getJmx(jmeterHashTree); + + SaveTestPlanRequest saveRequest = new SaveTestPlanRequest(); + saveRequest.setName(request.getName()); + saveRequest.setProjectId(request.getProjectId()); + saveRequest.setAdvancedConfiguration("{\"timeout\":2000,\"responseTimeout\":0,\"statusCode\":[],\"params\":[],\"domains\":[]}"); + saveRequest.setLoadConfiguration("[]"); + String testID = performanceTestService.save(saveRequest, jmx.getBytes()); + return testID; + } } 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 609830785e..0ec344e683 100644 --- a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java +++ b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java @@ -127,9 +127,7 @@ public class PerformanceTestService { if (files == null) { throw new IllegalArgumentException(Translator.get("file_cannot_be_null")); } - checkQuota(request, true); - final LoadTestWithBLOBs loadTest = saveLoadTest(request); files.forEach(file -> { final FileMetadata fileMetadata = fileService.saveFile(file); @@ -141,6 +139,20 @@ public class PerformanceTestService { return loadTest.getId(); } + public String save(SaveTestPlanRequest request, byte[] file) { + if (file == null) { + throw new IllegalArgumentException(Translator.get("file_cannot_be_null")); + } + checkQuota(request, true); + final LoadTestWithBLOBs loadTest = saveLoadTest(request); + final FileMetadata fileMetadata = fileService.saveFile(file, request.getName() + ".JMX", new Long(file.length)); + LoadTestFile loadTestFile = new LoadTestFile(); + loadTestFile.setTestId(loadTest.getId()); + loadTestFile.setFileId(fileMetadata.getId()); + loadTestFileMapper.insert(loadTestFile); + return loadTest.getId(); + } + private LoadTestWithBLOBs saveLoadTest(SaveTestPlanRequest request) { LoadTestExample example = new LoadTestExample(); diff --git a/backend/src/main/java/io/metersphere/service/FileService.java b/backend/src/main/java/io/metersphere/service/FileService.java index 37c10e7042..08d3fa0748 100644 --- a/backend/src/main/java/io/metersphere/service/FileService.java +++ b/backend/src/main/java/io/metersphere/service/FileService.java @@ -107,6 +107,25 @@ public class FileService { return fileMetadata; } + public FileMetadata saveFile(byte[] fileByte,String fileName,Long fileSize) { + final FileMetadata fileMetadata = new FileMetadata(); + fileMetadata.setId(UUID.randomUUID().toString()); + fileMetadata.setName(fileName); + fileMetadata.setSize(fileSize); + fileMetadata.setCreateTime(System.currentTimeMillis()); + fileMetadata.setUpdateTime(System.currentTimeMillis()); + FileType fileType = getFileType(fileMetadata.getName()); + fileMetadata.setType(fileType.name()); + fileMetadataMapper.insert(fileMetadata); + + FileContent fileContent = new FileContent(); + fileContent.setFileId(fileMetadata.getId()); + fileContent.setFile(fileByte); + fileContentMapper.insert(fileContent); + + return fileMetadata; + } + public FileMetadata copyFile(String fileId) { FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId); FileContent fileContent = getFileContent(fileId); diff --git a/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue b/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue index 087f701c38..4bfb783d89 100644 --- a/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue +++ b/frontend/src/business/components/api/automation/scenario/ScenarioExtendBtns.vue @@ -6,6 +6,7 @@ {{ $t('api_test.automation.view_ref') }} {{ $t('api_test.automation.schedule') }} + {{ $t('api_test.create_performance_test') }} @@ -15,6 +16,7 @@ diff --git a/frontend/src/business/components/api/definition/components/basis/SetEnvironment.vue b/frontend/src/business/components/api/definition/components/basis/SetEnvironment.vue new file mode 100644 index 0000000000..c3f2f9f6c2 --- /dev/null +++ b/frontend/src/business/components/api/definition/components/basis/SetEnvironment.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue b/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue index 9585e3dee7..2b5ecf5e4b 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue @@ -40,7 +40,7 @@ size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/> - + @@ -102,7 +102,6 @@ return { result: {}, grades: [], - environment: {}, isReadOnly: false, selectedEvent: Object, priorities: PRIORITY, @@ -121,6 +120,7 @@ return {} } }, + environment: {}, index: { type: Number, default() { diff --git a/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue b/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue index 47df25c3c3..d12443905c 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue @@ -25,6 +25,7 @@ @singleRun="singleRun" @copyCase="copyCase" @showExecResult="showExecResult" + :environment="environment" :is-case-edit="isCaseEdit" :api="api" :api-case="item" :index="index"/> diff --git a/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue b/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue index dad5520ea2..f47384d2e7 100644 --- a/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue +++ b/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue @@ -4,7 +4,8 @@ :is-api-list-enable="isApiListEnable" @isApiListEnableChange="isApiListEnableChange"> - + - {{$t('api_test.batch_menus.select_all_data',[total])}} + {{ $t('api_test.batch_menus.select_all_data', [total]) }} - {{$t('api_test.batch_menus.select_show_data',[tableData.length])}} + {{ $t('api_test.batch_menus.select_show_data', [tableData.length]) }} @@ -72,11 +73,13 @@ - @@ -85,359 +88,439 @@ + + + + diff --git a/frontend/src/business/components/api/definition/components/reference/ApiCaseTableExtendBtns.vue b/frontend/src/business/components/api/definition/components/reference/ApiCaseTableExtendBtns.vue new file mode 100644 index 0000000000..4c1152cc6d --- /dev/null +++ b/frontend/src/business/components/api/definition/components/reference/ApiCaseTableExtendBtns.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/frontend/src/business/components/api/definition/components/reference/ApiExtendBtns.vue b/frontend/src/business/components/api/definition/components/reference/ApiExtendBtns.vue index b9c884dbbe..9b270a8bac 100644 --- a/frontend/src/business/components/api/definition/components/reference/ApiExtendBtns.vue +++ b/frontend/src/business/components/api/definition/components/reference/ApiExtendBtns.vue @@ -6,6 +6,7 @@ {{ $t('api_test.automation.view_ref') }} {{ $t('api_test.automation.batch_add_plan') }} + {{ $t('api_test.create_performance_test') }} @@ -18,6 +19,9 @@