feat: 接口用例、用例列表、场景用例列表增加创建性能测试的功能

接口用例、用例列表、场景用例列表增加创建性能测试的功能
This commit is contained in:
song.tianyang 2021-01-04 11:28:17 +08:00
parent 3cb27580b7
commit 8e5105d579
13 changed files with 949 additions and 374 deletions

View File

@ -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.ApiDataCountDTO;
import io.metersphere.api.dto.datacount.response.ExecutedCaseInfoDTO; import io.metersphere.api.dto.datacount.response.ExecutedCaseInfoDTO;
import io.metersphere.api.dto.datacount.response.TaskInfoResult; 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.dto.scenario.request.dubbo.RegistryCenter;
import io.metersphere.api.service.*; import io.metersphere.api.service.*;
import io.metersphere.base.domain.ApiTest; import io.metersphere.base.domain.ApiTest;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.PerformanceTestStatus;
import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.constants.ScheduleGroup; import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CronUtils; 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.commons.utils.SessionUtils;
import io.metersphere.controller.request.QueryScheduleRequest; import io.metersphere.controller.request.QueryScheduleRequest;
import io.metersphere.dto.ScheduleDao; import io.metersphere.dto.ScheduleDao;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.service.CheckPermissionService; import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService; 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.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import static io.metersphere.commons.utils.JsonPathUtils.getListJson; import static io.metersphere.commons.utils.JsonPathUtils.getListJson;
@ -60,6 +68,10 @@ public class APITestController {
private ScheduleService scheduleService; private ScheduleService scheduleService;
@Resource @Resource
private APIReportService apiReportService; private APIReportService apiReportService;
@Resource
private PerformanceTestService performanceTestService;
@Resource
private CheckPermissionService checkPermissionService;
@GetMapping("recent/{count}") @GetMapping("recent/{count}")
public List<APITestResult> recentTest(@PathVariable int count) { public List<APITestResult> 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<String> selectIds) { public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List<String> selectIds) {
apiTestService.mergeCreate(request, file, selectIds); apiTestService.mergeCreate(request, file, selectIds);
} }
@PostMapping(value = "/update", consumes = {"multipart/form-data"}) @PostMapping(value = "/update", consumes = {"multipart/form-data"})
public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) { public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
checkownerService.checkApiTestOwner(request.getId()); checkownerService.checkApiTestOwner(request.getId());
@ -189,19 +202,19 @@ public class APITestController {
//查询完成率进行中已完成 //查询完成率进行中已完成
List<ApiDataCountResult> countResultByStatelList = apiDefinitionService.countStateByProjectID(projectId); List<ApiDataCountResult> countResultByStatelList = apiDefinitionService.countStateByProjectID(projectId);
apiCountResult.countStatus(countResultByStatelList); apiCountResult.countStatus(countResultByStatelList);
long allCount = apiCountResult.getFinishedCount()+apiCountResult.getRunningCount()+apiCountResult.getNotStartedCount(); long allCount = apiCountResult.getFinishedCount() + apiCountResult.getRunningCount() + apiCountResult.getNotStartedCount();
if(allCount!=0){ if (allCount != 0) {
float complateRageNumber =(float)apiCountResult.getFinishedCount()*100/allCount; float complateRageNumber = (float) apiCountResult.getFinishedCount() * 100 / allCount;
DecimalFormat df = new DecimalFormat("0.0"); DecimalFormat df = new DecimalFormat("0.0");
apiCountResult.setCompletionRage(df.format(complateRageNumber)+"%"); apiCountResult.setCompletionRage(df.format(complateRageNumber) + "%");
} }
apiCountResult.setHttpCountStr("HTTP&nbsp;&nbsp;<br/><br/>"+apiCountResult.getHttpApiDataCountNumber()); apiCountResult.setHttpCountStr("HTTP&nbsp;&nbsp;<br/><br/>" + apiCountResult.getHttpApiDataCountNumber());
apiCountResult.setRpcCountStr("RPC&nbsp;&nbsp;<br/><br/>"+apiCountResult.getRpcApiDataCountNumber()); apiCountResult.setRpcCountStr("RPC&nbsp;&nbsp;<br/><br/>" + apiCountResult.getRpcApiDataCountNumber());
apiCountResult.setTcpCountStr("TCP&nbsp;&nbsp;<br/><br/>"+apiCountResult.getTcpApiDataCountNumber()); apiCountResult.setTcpCountStr("TCP&nbsp;&nbsp;<br/><br/>" + apiCountResult.getTcpApiDataCountNumber());
apiCountResult.setSqlCountStr("SQL&nbsp;&nbsp;<br/><br/>"+apiCountResult.getSqlApiDataCountNumber()); apiCountResult.setSqlCountStr("SQL&nbsp;&nbsp;<br/><br/>" + apiCountResult.getSqlApiDataCountNumber());
return apiCountResult; return apiCountResult;
} }
@GetMapping("/testCaseInfoCount/{projectId}") @GetMapping("/testCaseInfoCount/{projectId}")
@ -222,21 +235,21 @@ public class APITestController {
//未覆盖 已覆盖 统计当前接口下是否含有案例 //未覆盖 已覆盖 统计当前接口下是否含有案例
List<ApiDataCountResult> countResultByApiCoverageList = apiDefinitionService.countApiCoverageByProjectID(projectId); List<ApiDataCountResult> countResultByApiCoverageList = apiDefinitionService.countApiCoverageByProjectID(projectId);
apiCountResult.countApiCoverage(countResultByApiCoverageList); apiCountResult.countApiCoverage(countResultByApiCoverageList);
long allCount = apiCountResult.getCoverageCount()+apiCountResult.getUncoverageCount(); long allCount = apiCountResult.getCoverageCount() + apiCountResult.getUncoverageCount();
if(allCount!=0){ if (allCount != 0) {
float coverageRageNumber =(float)apiCountResult.getCoverageCount()*100/allCount; float coverageRageNumber = (float) apiCountResult.getCoverageCount() * 100 / allCount;
DecimalFormat df = new DecimalFormat("0.0"); DecimalFormat df = new DecimalFormat("0.0");
apiCountResult.setCoverageRage(df.format(coverageRageNumber)+"%"); apiCountResult.setCoverageRage(df.format(coverageRageNumber) + "%");
} }
apiCountResult.setHttpCountStr("HTTP&nbsp;&nbsp;<br/><br/>"+apiCountResult.getHttpApiDataCountNumber()); apiCountResult.setHttpCountStr("HTTP&nbsp;&nbsp;<br/><br/>" + apiCountResult.getHttpApiDataCountNumber());
apiCountResult.setRpcCountStr("RPC&nbsp;&nbsp;<br/><br/>"+apiCountResult.getRpcApiDataCountNumber()); apiCountResult.setRpcCountStr("RPC&nbsp;&nbsp;<br/><br/>" + apiCountResult.getRpcApiDataCountNumber());
apiCountResult.setTcpCountStr("TCP&nbsp;&nbsp;<br/><br/>"+apiCountResult.getTcpApiDataCountNumber()); apiCountResult.setTcpCountStr("TCP&nbsp;&nbsp;<br/><br/>" + apiCountResult.getTcpApiDataCountNumber());
apiCountResult.setSqlCountStr("SQL&nbsp;&nbsp;<br/><br/>"+apiCountResult.getSqlApiDataCountNumber()); apiCountResult.setSqlCountStr("SQL&nbsp;&nbsp;<br/><br/>" + apiCountResult.getSqlApiDataCountNumber());
return apiCountResult; return apiCountResult;
} }
@GetMapping("/testSceneInfoCount/{projectId}") @GetMapping("/testSceneInfoCount/{projectId}")
@ -263,15 +276,15 @@ public class APITestController {
List<ApiDataCountResult> countResultByRunResult = apiAutomationService.countRunResultByProjectID(projectId); List<ApiDataCountResult> countResultByRunResult = apiAutomationService.countRunResultByProjectID(projectId);
apiCountResult.countRunResult(countResultByRunResult); apiCountResult.countRunResult(countResultByRunResult);
long allCount = apiCountResult.getUnexecuteCount()+apiCountResult.getExecutionPassCount()+apiCountResult.getExecutionFailedCount(); long allCount = apiCountResult.getUnexecuteCount() + apiCountResult.getExecutionPassCount() + apiCountResult.getExecutionFailedCount();
if(allCount!=0){ if (allCount != 0) {
float coverageRageNumber =(float)apiCountResult.getExecutionPassCount()*100/allCount; float coverageRageNumber = (float) apiCountResult.getExecutionPassCount() * 100 / allCount;
DecimalFormat df = new DecimalFormat("0.0"); 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); apiCountResult.setThisWeekAddedCount(taskCountInThisWeek);
long api_executedInThisWeekCountNumber = apiReportService.countByProjectIdAndCreateInThisWeek(projectId); long api_executedInThisWeekCountNumber = apiReportService.countByProjectIdAndCreateInThisWeek(projectId);
long scene_executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId); long scene_executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId);
long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber+scene_executedInThisWeekCountNumber; long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber + scene_executedInThisWeekCountNumber;
apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber); apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber);
//统计 失败 成功 以及总数 //统计 失败 成功 以及总数
@ -299,41 +312,41 @@ public class APITestController {
apiCountResult.countScheduleExecute(allExecuteResult); apiCountResult.countScheduleExecute(allExecuteResult);
long allCount = apiCountResult.getExecutedCount(); long allCount = apiCountResult.getExecutedCount();
if(allCount!=0){ if (allCount != 0) {
float coverageRageNumber =(float)apiCountResult.getSuccessCount()*100/allCount; float coverageRageNumber = (float) apiCountResult.getSuccessCount() * 100 / allCount;
DecimalFormat df = new DecimalFormat("0.0"); DecimalFormat df = new DecimalFormat("0.0");
apiCountResult.setSuccessRage(df.format(coverageRageNumber)+"%"); apiCountResult.setSuccessRage(df.format(coverageRageNumber) + "%");
} }
return apiCountResult; return apiCountResult;
} }
@GetMapping("/faliureCaseAboutTestPlan/{projectId}/{limitNumber}") @GetMapping("/faliureCaseAboutTestPlan/{projectId}/{limitNumber}")
public List<ExecutedCaseInfoDTO> faliureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable int limitNumber) { public List<ExecutedCaseInfoDTO> faliureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable int limitNumber) {
List<ExecutedCaseInfoResult> selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId,limitNumber); List<ExecutedCaseInfoResult> selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId, limitNumber);
List<ExecutedCaseInfoDTO> returnList = new ArrayList<>(limitNumber); List<ExecutedCaseInfoDTO> returnList = new ArrayList<>(limitNumber);
for(int dataIndex = 0;dataIndex < limitNumber;dataIndex ++){ for (int dataIndex = 0; dataIndex < limitNumber; dataIndex++) {
ExecutedCaseInfoDTO dataDTO = new ExecutedCaseInfoDTO(); ExecutedCaseInfoDTO dataDTO = new ExecutedCaseInfoDTO();
dataDTO.setSortIndex(dataIndex+1); dataDTO.setSortIndex(dataIndex + 1);
if(dataIndex<selectDataList.size()){ if (dataIndex < selectDataList.size()) {
ExecutedCaseInfoResult selectData = selectDataList.get(dataIndex); ExecutedCaseInfoResult selectData = selectDataList.get(dataIndex);
dataDTO.setCaseName(selectData.getCaseName()); dataDTO.setCaseName(selectData.getCaseName());
dataDTO.setTestPlan(selectData.getTestPlan()); dataDTO.setTestPlan(selectData.getTestPlan());
dataDTO.setFailureTimes(selectData.getFailureTimes()); dataDTO.setFailureTimes(selectData.getFailureTimes());
dataDTO.setCaseType(selectData.getCaseType()); dataDTO.setCaseType(selectData.getCaseType());
}else { } else {
dataDTO.setCaseName(""); dataDTO.setCaseName("");
dataDTO.setTestPlan(""); dataDTO.setTestPlan("");
} }
returnList.add(dataDTO); returnList.add(dataDTO);
} }
return returnList; return returnList;
} }
@GetMapping("/runningTask/{projectID}") @GetMapping("/runningTask/{projectID}")
@ -343,11 +356,11 @@ public class APITestController {
for (TaskInfoResult taskInfo : for (TaskInfoResult taskInfo :
resultList) { resultList) {
Date nextExecutionTime = CronUtils.getNextTriggerTime(taskInfo.getRule()); Date nextExecutionTime = CronUtils.getNextTriggerTime(taskInfo.getRule());
if(nextExecutionTime!=null){ if (nextExecutionTime != null) {
taskInfo.setNextExecutionTime(nextExecutionTime.getTime()); taskInfo.setNextExecutionTime(nextExecutionTime.getTime());
} }
} }
return resultList; return resultList;
} }
@PostMapping(value = "/schedule/updateEnableByPrimyKey") @PostMapping(value = "/schedule/updateEnableByPrimyKey")
@ -356,4 +369,17 @@ public class APITestController {
schedule.setEnable(request.isEnable()); schedule.setEnable(request.isEnable());
apiAutomationService.updateSchedule(schedule); apiAutomationService.updateSchedule(schedule);
} }
@PostMapping(value = "/genPerformanceTest", consumes = {"multipart/form-data"})
public String genPerformanceTest(@RequestPart("request") RunDefinitionRequest runRequest, @RequestPart(value = "files") List<MultipartFile> 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;
}
} }

View File

@ -1,25 +1,45 @@
package io.metersphere.api.controller; 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.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.definition.RunDefinitionRequest; 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.api.service.ApiAutomationService;
import io.metersphere.base.domain.ApiScenario; import io.metersphere.base.domain.ApiScenario;
import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.RoleConstants; 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.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils; 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.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.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID;
@RestController @RestController
@RequestMapping(value = "/api/automation") @RequestMapping(value = "/api/automation")
@ -28,6 +48,8 @@ public class ApiAutomationController {
@Resource @Resource
ApiAutomationService apiAutomationService; ApiAutomationService apiAutomationService;
@Resource
PerformanceTestService performanceTestService;
@PostMapping("/list/{goPage}/{pageSize}") @PostMapping("/list/{goPage}/{pageSize}")
@ -121,5 +143,12 @@ public class ApiAutomationController {
public void createSchedule(@RequestBody Schedule request) { public void createSchedule(@RequestBody Schedule request) {
apiAutomationService.createSchedule(request); apiAutomationService.createSchedule(request);
} }
//一键创建性能测试
@PostMapping(value = "/genPerformanceTest")
public String genPerformanceTest(@RequestBody RunScenarioRequest runRequest) {
runRequest.setExecuteType(ExecuteType.Completed.name());
return apiAutomationService.genPerformanceTest(runRequest);
}
} }

View File

@ -34,6 +34,19 @@ public class ApiTestCaseController {
return apiTestCaseService.list(request); 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<ApiTestCaseResult> list = apiTestCaseService.list(request);
if(!list.isEmpty()){
return list.get(0);
}else {
return null;
}
}
@PostMapping("/list/{goPage}/{pageSize}") @PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<ApiTestCaseDTO>> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) { public Pager<List<ApiTestCaseDTO>> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true); Page<Object> page = PageHelper.startPage(goPage, pageSize, true);

View File

@ -24,19 +24,23 @@ import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper;
import io.metersphere.commons.constants.*; import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.DateUtils; import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.ApiScenarioTestJob; import io.metersphere.job.sechedule.ApiScenarioTestJob;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.service.ScheduleService; import io.metersphere.service.ScheduleService;
import io.metersphere.track.dto.TestPlanDTO; import io.metersphere.track.dto.TestPlanDTO;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest; import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.request.testplan.SaveTestPlanRequest;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jmeter.save.SaveService;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree; import org.apache.jorphan.collections.ListedHashTree;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -44,6 +48,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -72,6 +77,8 @@ public class ApiAutomationService {
SqlSessionFactory sqlSessionFactory; SqlSessionFactory sqlSessionFactory;
@Resource @Resource
private ApiScenarioReportMapper apiScenarioReportMapper; private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private PerformanceTestService performanceTestService;
public List<ApiScenarioDTO> list(ApiScenarioRequest request) { public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
@ -538,4 +545,144 @@ public class ApiAutomationService {
scheduleService.addOrUpdateCronJob( scheduleService.addOrUpdateCronJob(
request, ApiScenarioTestJob.getJobKey(request.getResourceId()), ApiScenarioTestJob.getTriggerKey(request.getResourceId()), ApiScenarioTestJob.class); 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<String> ids = runRequest.getScenarioIds();
if (runRequest.isSelectAllDate()) {
ids = this.getAllScenarioIdsByFontedSelect(
runRequest.getModuleIds(), request.getName(), request.getProjectId(), runRequest.getFilters(), runRequest.getUnSelectIds());
}
List<ApiScenarioWithBLOBs> 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<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
scenario.setHashTree(elements);
}
if (StringUtils.isNotEmpty(element.getString("variables"))) {
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<KeyValue>>() {
});
scenario.setVariables(variables);
}
group.setEnableCookieShare(scenario.isEnableCookieShare());
LinkedList<MsTestElement> 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<ApiScenarioWithBLOBs> apiScenarios = null;
List<String> 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<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
scenario.setHashTree(elements);
}
if (StringUtils.isNotEmpty(element.getString("variables"))) {
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<KeyValue>>() {
});
scenario.setVariables(variables);
}
group.setEnableCookieShare(scenario.isEnableCookieShare());
LinkedList<MsTestElement> 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;
}
} }

View File

@ -127,9 +127,7 @@ public class PerformanceTestService {
if (files == null) { if (files == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null")); throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
} }
checkQuota(request, true); checkQuota(request, true);
final LoadTestWithBLOBs loadTest = saveLoadTest(request); final LoadTestWithBLOBs loadTest = saveLoadTest(request);
files.forEach(file -> { files.forEach(file -> {
final FileMetadata fileMetadata = fileService.saveFile(file); final FileMetadata fileMetadata = fileService.saveFile(file);
@ -141,6 +139,20 @@ public class PerformanceTestService {
return loadTest.getId(); 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) { private LoadTestWithBLOBs saveLoadTest(SaveTestPlanRequest request) {
LoadTestExample example = new LoadTestExample(); LoadTestExample example = new LoadTestExample();

View File

@ -107,6 +107,25 @@ public class FileService {
return fileMetadata; 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) { public FileMetadata copyFile(String fileId) {
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId); FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileId);
FileContent fileContent = getFileContent(fileId); FileContent fileContent = getFileContent(fileId);

View File

@ -6,6 +6,7 @@
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item> <el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item>
<el-dropdown-item command="schedule" v-tester>{{ $t('api_test.automation.schedule') }}</el-dropdown-item> <el-dropdown-item command="schedule" v-tester>{{ $t('api_test.automation.schedule') }}</el-dropdown-item>
<el-dropdown-item command="create_performance" v-tester>{{ $t('api_test.create_performance_test') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
<ms-reference-view ref="viewRef"/> <ms-reference-view ref="viewRef"/>
<ms-schedule-maintain ref="scheduleMaintain" /> <ms-schedule-maintain ref="scheduleMaintain" />
@ -15,6 +16,7 @@
<script> <script>
import MsReferenceView from "@/business/components/api/automation/scenario/ReferenceView"; import MsReferenceView from "@/business/components/api/automation/scenario/ReferenceView";
import MsScheduleMaintain from "@/business/components/api/automation/schedule/ScheduleMaintain" import MsScheduleMaintain from "@/business/components/api/automation/schedule/ScheduleMaintain"
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
export default { export default {
name: "MsScenarioExtendButtons", name: "MsScenarioExtendButtons",
@ -31,8 +33,30 @@
case "schedule": case "schedule":
this.$refs.scheduleMaintain.open(this.row); this.$refs.scheduleMaintain.open(this.row);
break; break;
case "create_performance":
this.createPerformance(this.row);
break;
} }
}, },
createPerformance(row) {
this.infoDb = false;
let url = "/api/automation/genPerformanceTest";
let run = {};
let scenarioIds = [];
scenarioIds.push(row.id);
run.projectId = getCurrentProjectID();
run.scenarioIds = scenarioIds;
run.id = getUUID();
run.name = row.name;
this.$post(url, run, response => {
let performanceId = response.data;
if(performanceId!=null){
this.$router.push({
path: "/performance/test/edit/"+performanceId,
})
}
});
},
} }
} }
</script> </script>

View File

@ -0,0 +1,112 @@
<template>
<div>
<el-dialog
:title="$t('api_test.environment.select_environment')"
:visible.sync="dialogVisible"
width="25%"
:destroy-on-close="true"
@close="handleClose"
>
<el-form label-position="right" label-width="150px" size="medium" ref="form">
<el-form-item prop="type">
<el-select v-model="environmentId" value-key="id" size="small" class="ms-htt-width"
:placeholder="$t('api_test.definition.request.run_env')"
clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<template v-slot:empty>
<div class="empty-environment">
</div>
</template>
</el-select>
</el-form-item>
</el-form>
<template v-slot:footer>
<!-- <el-button onclick="this.handleClose">{{ $t('commons.cancel') }}</el-button>-->
<el-button type="primary" @click="createPerformance" @keydown.enter.native.prevent>
{{ $t('commons.confirm') }}
</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import {parseEnvironment} from "@/business/components/api/test/model/EnvironmentModel";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
export default {
name: "MsSetEnvironment",
components: {},
props: {
testCase: Object,
row: Object,
},
data() {
return {
dialogVisible: false,
filterable: false,
environments: [],
environmentId: "",
dialogTitle: {
type: String,
default() {
return this.$t('api_test.environment.select_environment')
}
}
}
},
watch: {
environmentId() {
this.environmentChange(this.environmentId);
},
},
methods: {
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.environment = this.environments[i];
break;
}
}
},
getEnvironments() {
let selectProjectId = getCurrentProjectID();
if (selectProjectId) {
this.$get('/api/environment/list/' + selectProjectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
});
} else {
this.environment = undefined;
}
},
open() {
this.dialogVisible = true;
this.getEnvironments();
listenGoBack(this.handleClose);
},
handleClose() {
this.form = {};
this.options = [];
removeGoBackListener(this.handleClose);
},
createPerformance() {
this.$get('/api/testcase/findById/' + this.testCase.id, response => {
let testCaseInfo = response.data;
if(testCaseInfo!=null){
this.$emit("createPerformance", testCaseInfo, this.environment);
}
});
},
}
}
</script>
<style scoped>
</style>

View File

@ -40,7 +40,7 @@
size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/> size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/>
<ms-tip-button @click="deleteCase(index,apiCase)" :tip="$t('commons.delete')" icon="el-icon-delete" <ms-tip-button @click="deleteCase(index,apiCase)" :tip="$t('commons.delete')" icon="el-icon-delete"
size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/> size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/>
<ms-api-extend-btns :is-case-edit="isCaseEdit" :row="apiCase" v-tester/> <ms-api-extend-btns :is-case-edit="isCaseEdit" :environment="environment" :row="apiCase" v-tester/>
</el-col> </el-col>
<el-col :span="3"> <el-col :span="3">
@ -102,7 +102,6 @@
return { return {
result: {}, result: {},
grades: [], grades: [],
environment: {},
isReadOnly: false, isReadOnly: false,
selectedEvent: Object, selectedEvent: Object,
priorities: PRIORITY, priorities: PRIORITY,
@ -121,6 +120,7 @@
return {} return {}
} }
}, },
environment: {},
index: { index: {
type: Number, type: Number,
default() { default() {

View File

@ -25,6 +25,7 @@
@singleRun="singleRun" @singleRun="singleRun"
@copyCase="copyCase" @copyCase="copyCase"
@showExecResult="showExecResult" @showExecResult="showExecResult"
:environment="environment"
:is-case-edit="isCaseEdit" :is-case-edit="isCaseEdit"
:api="api" :api="api"
:api-case="item" :index="index"/> :api-case="item" :index="index"/>

View File

@ -4,7 +4,8 @@
:is-api-list-enable="isApiListEnable" :is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange"> @isApiListEnableChange="isApiListEnableChange">
<el-input placeholder="搜索" @blur="search" @keyup.enter.native="search" class="search-input" size="small" v-model="condition.name"/> <el-input placeholder="搜索" @blur="search" @keyup.enter.native="search" class="search-input" size="small"
v-model="condition.name"/>
<el-table v-loading="result.loading" <el-table v-loading="result.loading"
ref="caseTable" ref="caseTable"
@ -22,10 +23,10 @@
</span> </span>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native.stop="isSelectDataAll(true)"> <el-dropdown-item @click.native.stop="isSelectDataAll(true)">
{{$t('api_test.batch_menus.select_all_data',[total])}} {{ $t('api_test.batch_menus.select_all_data', [total]) }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click.native.stop="isSelectDataAll(false)"> <el-dropdown-item @click.native.stop="isSelectDataAll(false)">
{{$t('api_test.batch_menus.select_show_data',[tableData.length])}} {{ $t('api_test.batch_menus.select_show_data', [tableData.length]) }}
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
@ -72,11 +73,13 @@
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" min-width="130" align="center"> <el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" min-width="130" align="center">
<template v-slot:default="scope"> <template v-slot:default="scope">
<!--<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable">{{$t('commons.reduction')}}</el-button>--> <!--<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable">{{$t('commons.reduction')}}</el-button>-->
<el-button type="text" @click="handleTestCase(scope.row)" v-if="!trashEnable">{{$t('commons.edit')}}</el-button> <el-button type="text" @click="handleTestCase(scope.row)" v-if="!trashEnable">{{ $t('commons.edit') }}
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">{{$t('commons.delete')}}</el-button> </el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">{{ $t('commons.delete') }}
</el-button>
<ms-api-case-table-extend-btns @showCaseRef="showCaseRef" @showEnvironment="showEnvironment" @createPerformance="createPerformance" :row="scope.row" v-tester/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/> :total="total"/>
@ -85,359 +88,439 @@
<api-case-list @showExecResult="showExecResult" @refresh="initTable" :currentApi="selectCase" ref="caseList"/> <api-case-list @showExecResult="showExecResult" @refresh="initTable" :currentApi="selectCase" ref="caseList"/>
<!--批量编辑--> <!--批量编辑-->
<ms-batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"/> <ms-batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"/>
<!--选择环境(当创建性能测试的时候)-->
<ms-set-environment ref="setEnvironment" :testCase="clickRow" @createPerformance="createPerformance"/>
<!--查看引用-->
<ms-reference-view ref="viewRef"/>
</div> </div>
</template> </template>
<script> <script>
import MsTableOperator from "../../../../common/components/MsTableOperator"; import MsTableOperator from "../../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton"; import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent"; import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import MsTablePagination from "../../../../common/pagination/TablePagination"; import MsTablePagination from "../../../../common/pagination/TablePagination";
import MsTag from "../../../../common/components/MsTag"; import MsTag from "../../../../common/components/MsTag";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer"; import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn"; import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
import MsBatchEdit from "../basis/BatchEdit"; import MsBatchEdit from "../basis/BatchEdit";
import {API_METHOD_COLOUR, CASE_PRIORITY} from "../../model/JsonData"; import {API_METHOD_COLOUR, CASE_PRIORITY} from "../../model/JsonData";
import {getCurrentProjectID} from "@/common/js/utils"; import {getBodyUploadFiles, getCurrentProjectID} from "@/common/js/utils";
import ApiListContainer from "./ApiListContainer"; import ApiListContainer from "./ApiListContainer";
import PriorityTableItem from "../../../../track/common/tableItems/planview/PriorityTableItem"; import PriorityTableItem from "../../../../track/common/tableItems/planview/PriorityTableItem";
import ApiCaseList from "../case/ApiCaseList"; import ApiCaseList from "../case/ApiCaseList";
import {_filter, _sort} from "../../../../../../common/js/utils"; import {_filter, _sort} from "../../../../../../common/js/utils";
import TestPlanCaseListHeader from "../../../../track/plan/view/comonents/api/TestPlanCaseListHeader"; import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils";
import MsEnvironmentSelect from "../case/MsEnvironmentSelect"; import MsApiCaseTableExtendBtns from "../reference/ApiCaseTableExtendBtns";
import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils"; import MsReferenceView from "../reference/ReferenceView";
import MsSetEnvironment from "@/business/components/api/definition/components/basis/SetEnvironment";
import TestPlan from "@/business/components/api/definition/components/jmeter/components/test-plan";
import ThreadGroup from "@/business/components/api/definition/components/jmeter/components/thread-group";
import {parseEnvironment} from "@/business/components/api/test/model/EnvironmentModel";
export default {
name: "ApiCaseSimpleList", export default {
components: { name: "ApiCaseSimpleList",
ApiCaseList, components: {
PriorityTableItem, MsSetEnvironment,
ApiListContainer, ApiCaseList,
MsTableOperatorButton, PriorityTableItem,
MsTableOperator, ApiListContainer,
MsTablePagination, MsTableOperatorButton,
MsTag, MsTableOperator,
MsApiCaseList, MsTablePagination,
MsContainer, MsTag,
MsBottomContainer, MsApiCaseList,
ShowMoreBtn, MsContainer,
MsBatchEdit MsBottomContainer,
ShowMoreBtn,
MsBatchEdit,
MsApiCaseTableExtendBtns,
MsReferenceView,
},
data() {
return {
condition: {},
selectCase: {},
result: {},
moduleId: "",
deletePath: "/test/case/delete",
selectRows: new Set(),
clickRow: {},
buttons: [
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch},
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch}
],
typeArr: [
{id: 'priority', name: this.$t('test_track.case.priority')},
],
priorityFilters: [
{text: 'P0', value: 'P0'},
{text: 'P1', value: 'P1'},
{text: 'P2', value: 'P2'},
{text: 'P3', value: 'P3'}
],
valueArr: {
priority: CASE_PRIORITY,
},
methodColorMap: new Map(API_METHOD_COLOUR),
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
screenHeight: document.documentElement.clientHeight - 330,//
environmentId: undefined,
selectAll: false,
unSelection: [],
selectDataCounts: 0,
environments: [],
}
},
props: {
currentProtocol: String,
selectNodeIds: Array,
visible: {
type: Boolean,
default: false,
}, },
data() { trashEnable: {
return { type: Boolean,
condition: {}, default: false,
selectCase: {}, },
result: {}, isApiListEnable: {
moduleId: "", type: Boolean,
deletePath: "/test/case/delete", default: false,
selectRows: new Set(), },
buttons: [ isReadOnly: {
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch}, type: Boolean,
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch} default: false
], },
typeArr: [ isCaseRelevance: {
{id: 'priority', name: this.$t('test_track.case.priority')}, type: Boolean,
], default: false,
priorityFilters: [ },
{text: 'P0', value: 'P0'}, relevanceProjectId: String,
{text: 'P1', value: 'P1'}, model: {
{text: 'P2', value: 'P2'}, type: String,
{text: 'P3', value: 'P3'} default() {
], 'api'
valueArr: {
priority: CASE_PRIORITY,
},
methodColorMap: new Map(API_METHOD_COLOUR),
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
screenHeight: document.documentElement.clientHeight - 330,//
environmentId: undefined,
selectAll: false,
unSelection:[],
selectDataCounts:0,
} }
}, },
props: { planId: String
currentProtocol: String, },
selectNodeIds: Array, created: function () {
visible: { this.initTable();
type: Boolean, },
default: false, watch: {
}, selectNodeIds() {
trashEnable: {
type: Boolean,
default: false,
},
isApiListEnable: {
type: Boolean,
default: false,
},
isReadOnly: {
type: Boolean,
default: false
},
isCaseRelevance: {
type: Boolean,
default: false,
},
relevanceProjectId: String,
model: {
type: String,
default() {
'api'
}
},
planId: String
},
created: function () {
this.initTable(); this.initTable();
}, },
watch: { currentProtocol() {
selectNodeIds() { this.initTable();
this.initTable(); },
}, trashEnable() {
currentProtocol() { if (this.trashEnable) {
this.initTable();
},
trashEnable() {
if (this.trashEnable) {
this.initTable();
}
},
relevanceProjectId() {
this.initTable(); this.initTable();
} }
}, },
computed: { relevanceProjectId() {
this.initTable();
}
},
computed: {
// //
isApiModel() { isApiModel() {
return this.model === 'api' return this.model === 'api'
},
}, },
methods: { },
isApiListEnableChange(data) { methods: {
this.$emit('isApiListEnableChange', data); isApiListEnableChange(data) {
}, this.$emit('isApiListEnableChange', data);
initTable() { },
this.selectRows = new Set(); initTable() {
this.condition.status = ""; this.selectRows = new Set();
this.condition.moduleIds = this.selectNodeIds; this.condition.status = "";
if (this.trashEnable) { this.condition.moduleIds = this.selectNodeIds;
this.condition.status = "Trash"; if (this.trashEnable) {
this.condition.moduleIds = []; this.condition.status = "Trash";
} this.condition.moduleIds = [];
this.selectAll = false; }
this.unSelection = []; this.selectAll = false;
this.selectDataCounts = 0; this.unSelection = [];
this.condition.projectId = getCurrentProjectID(); this.selectDataCounts = 0;
this.condition.projectId = getCurrentProjectID();
if (this.currentProtocol != null) { if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol; this.condition.protocol = this.currentProtocol;
}
if (this.condition.projectId) {
this.result = this.$post('/api/testcase/list/' + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
this.unSelection = response.data.listObject.map(s => s.id);
});
}
},
// getMaintainerOptions() {
// let workspaceId = localStorage.getItem(WORKSPACE_ID);
// this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
// this.valueArr.userId = response.data;
// });
// },
handleSelect(selection, row) {
_handleSelect(this, selection, row, this.selectRows);
this.selectRowsCount(this.selectRows)
},
showExecResult(row) {
this.visible = false;
this.$emit('showExecResult', row);
},
filter(filters) {
_filter(filters, this.condition);
this.initTable();
},
sort(column) {
//
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.initTable();
},
handleSelectAll(selection) {
_handleSelectAll(this, selection, this.tableData, this.selectRows);
this.selectRowsCount(this.selectRows)
},
search() {
this.initTable();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
handleTestCase(testCase) {
this.$get('/api/definition/get/' + testCase.apiDefinitionId, (response) => {
let api = response.data;
let selectApi = api;
let request = {};
if (Object.prototype.toString.call(api.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') {
request = api.request;
} else {
request = JSON.parse(api.request);
} }
if (this.condition.projectId) { if (!request.hashTree) {
this.result = this.$post('/api/testcase/list/' + this.currentPage + "/" + this.pageSize, this.condition, response => { request.hashTree = [];
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
this.unSelection = response.data.listObject.map(s=>s.id);
});
} }
}, selectApi.url = request.path;
// getMaintainerOptions() { this.$refs.caseList.open(selectApi, testCase.id);
// let workspaceId = localStorage.getItem(WORKSPACE_ID); });
// this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => { },
// this.valueArr.userId = response.data; reductionApi(row) {
let ids = [row.id];
this.$post('/api/testcase/reduction/', ids, () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
},
handleDeleteBatch() {
// if (this.trashEnable) {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let obj = {};
obj.projectId = getCurrentProjectID();
obj.selectAllDate = this.isSelectAllDate;
obj.unSelectIds = this.unSelection;
obj.ids = Array.from(this.selectRows).map(row => row.id);
obj = Object.assign(obj, this.condition);
this.$post('/api/testcase/deleteBatchByParam/', obj, () => {
this.selectRows.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
});
}
}
});
// } else {
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
// confirmButtonText: this.$t('commons.confirm'),
// callback: (action) => {
// if (action === 'confirm') {
// let ids = Array.from(this.selectRows).map(row => row.id);
// this.$post('/api/testcase/removeToGc/', ids, () => {
// this.selectRows.clear();
// this.initTable();
// this.$success(this.$t('commons.delete_success'));
// });
// }
// }
// }); // });
// }, // }
handleSelect(selection, row) { },
_handleSelect(this, selection, row, this.selectRows); handleEditBatch() {
this.selectRowsCount(this.selectRows) this.$refs.batchEdit.open();
}, },
showExecResult(row) { batchEdit(form) {
this.visible = false; let arr = Array.from(this.selectRows);
this.$emit('showExecResult', row); let ids = arr.map(row => row.id);
}, let param = {};
filter(filters) { param[form.type] = form.value;
_filter(filters, this.condition); param.ids = ids;
this.initTable();
},
sort(column) {
//
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.initTable();
},
handleSelectAll(selection) {
_handleSelectAll(this, selection, this.tableData, this.selectRows);
this.selectRowsCount(this.selectRows)
},
search() {
this.initTable();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
handleTestCase(testCase) { param.projectId = getCurrentProjectID();
this.$get('/api/definition/get/' + testCase.apiDefinitionId, (response) => { param.selectAllDate = this.isSelectAllDate;
let api = response.data; param.unSelectIds = this.unSelection;
let selectApi = api; param = Object.assign(param, this.condition);
let request = {}; this.$post('/api/testcase/batch/editByParam', param, () => {
if (Object.prototype.toString.call(api.request).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object') { this.$success(this.$t('commons.save_success'));
request = api.request; this.initTable();
} else { });
request = JSON.parse(api.request); },
} handleDelete(apiCase) {
if (!request.hashTree) { // if (this.trashEnable) {
request.hashTree = []; this.$get('/api/testcase/delete/' + apiCase.id, () => {
} this.$success(this.$t('commons.delete_success'));
selectApi.url = request.path; this.initTable();
this.$refs.caseList.open(selectApi, testCase.id); });
}); return;
}, // }
reductionApi(row) { // this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + apiCase.name + " ", '', {
let ids = [row.id]; // confirmButtonText: this.$t('commons.confirm'),
this.$post('/api/testcase/reduction/', ids, () => { // callback: (action) => {
this.$success(this.$t('commons.save_success')); // if (action === 'confirm') {
this.search(); // let ids = [apiCase.id];
}); // this.$post('/api/testcase/removeToGc/', ids, () => {
}, // this.$success(this.$t('commons.delete_success'));
handleDeleteBatch() { // this.initTable();
// if (this.trashEnable) { // });
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', { // }
confirmButtonText: this.$t('commons.confirm'), // }
callback: (action) => { // });
if (action === 'confirm') { },
let obj = {}; setEnvironment(data) {
obj.projectId = getCurrentProjectID(); this.environmentId = data.id;
obj.selectAllDate = this.isSelectAllDate; },
obj.unSelectIds = this.unSelection; selectRowsCount(selection) {
obj.ids = Array.from(this.selectRows).map(row => row.id); let selectedIDs = this.getIds(selection);
obj = Object.assign(obj, this.condition); let allIDs = this.tableData.map(s => s.id);
this.$post('/api/testcase/deleteBatchByParam/', obj , () => { this.unSelection = allIDs.filter(function (val) {
this.selectRows.clear(); return selectedIDs.indexOf(val) === -1
this.initTable(); });
this.$success(this.$t('commons.delete_success')); if (this.isSelectAllDate) {
}); this.selectDataCounts = this.total - this.unSelection.length;
} } else {
} this.selectDataCounts = selection.size;
});
// } else {
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
// confirmButtonText: this.$t('commons.confirm'),
// callback: (action) => {
// if (action === 'confirm') {
// let ids = Array.from(this.selectRows).map(row => row.id);
// this.$post('/api/testcase/removeToGc/', ids, () => {
// this.selectRows.clear();
// this.initTable();
// this.$success(this.$t('commons.delete_success'));
// });
// }
// }
// });
// }
},
handleEditBatch() {
this.$refs.batchEdit.open();
},
batchEdit(form) {
let arr = Array.from(this.selectRows);
let ids = arr.map(row => row.id);
let param = {};
param[form.type] = form.value;
param.ids = ids;
param.projectId = getCurrentProjectID();
param.selectAllDate = this.isSelectAllDate;
param.unSelectIds = this.unSelection;
param = Object.assign(param, this.condition);
this.$post('/api/testcase/batch/editByParam', param, () => {
this.$success(this.$t('commons.save_success'));
this.initTable();
});
},
handleDelete(apiCase) {
// if (this.trashEnable) {
this.$get('/api/testcase/delete/' + apiCase.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initTable();
});
return;
// }
// this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + apiCase.name + " ", '', {
// confirmButtonText: this.$t('commons.confirm'),
// callback: (action) => {
// if (action === 'confirm') {
// let ids = [apiCase.id];
// this.$post('/api/testcase/removeToGc/', ids, () => {
// this.$success(this.$t('commons.delete_success'));
// this.initTable();
// });
// }
// }
// });
},
setEnvironment(data) {
this.environmentId = data.id;
},
selectRowsCount(selection){
let selectedIDs = this.getIds(selection);
let allIDs = this.tableData.map(s=>s.id);
this.unSelection = allIDs.filter(function (val) {
return selectedIDs.indexOf(val) === -1
});
if(this.isSelectAllDate){
this.selectDataCounts =this.total - this.unSelection.length;
}else {
this.selectDataCounts =selection.size;
}
},
isSelectDataAll(dataType) {
this.isSelectAllDate = dataType;
this.selectRowsCount(this.selectRows)
//
if (this.selectRows.size != this.tableData.length) {
this.$refs.caseTable.toggleAllSelection(true);
}
},
getIds(rowSets){
let rowArray = Array.from(rowSets)
let ids = rowArray.map(s=>s.id);
return ids;
} }
}, },
} isSelectDataAll(dataType) {
this.isSelectAllDate = dataType;
this.selectRowsCount(this.selectRows)
//
if (this.selectRows.size != this.tableData.length) {
this.$refs.caseTable.toggleAllSelection(true);
}
},
getIds(rowSets) {
let rowArray = Array.from(rowSets)
let ids = rowArray.map(s => s.id);
return ids;
},
showCaseRef(row) {
this.$refs.viewRef.open(row);
},
showEnvironment(row) {
let projectID = getCurrentProjectID();
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
});
} else {
this.environment = undefined;
}
this.clickRow = row;
this.$refs.setEnvironment.open(row);
},
createPerformance(row,environment){
/**
* 思路调用后台创建性能测试的方法把当前案例的hashTree在后台转化为jmx并文件创建性能测试
* 然后跳转到修改性能测试的页面
*
* 性能测试保存地址 performance/save
*
*/
if (!environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
let runData = [];
let singleLoading = true;
row.request = JSON.parse( row.request );
row.request.name = row.id;
row.request.useEnvironment = environment.id;
runData.push(row.request);
/*触发执行操作*/
let testPlan = new TestPlan();
let threadGroup = new ThreadGroup();
threadGroup.hashTree = [];
testPlan.hashTree = [threadGroup];
runData.forEach(item => {
threadGroup.hashTree.push(item);
})
let reqObj = {id: row.id,
testElement: testPlan,
name:row.name,
projectId:getCurrentProjectID(),
};
let bodyFiles = getBodyUploadFiles(reqObj, runData);
reqObj.reportId = "run";
let url = "/api/genPerformanceTest";
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
let performanceId = response.data;
if(performanceId!=null){
this.$router.push({
path: "/performance/test/edit/"+performanceId,
})
}
}, erro => {
this.$emit('runRefresh', {});
});
},
},
}
</script> </script>
<style scoped> <style scoped>
.operate-button > div { .operate-button > div {
display: inline-block; display: inline-block;
margin-left: 10px; margin-left: 10px;
} }
.request-method { .request-method {
padding: 0 5px; padding: 0 5px;
color: #1E90FF; color: #1E90FF;
} }
.api-el-tag { .api-el-tag {
color: white; color: white;
} }
.search-input { .search-input {
float: right; float: right;
width: 300px; width: 300px;
/*margin-bottom: 20px;*/ /*margin-bottom: 20px;*/
margin-right: 20px; margin-right: 20px;
} }
</style> </style>

View File

@ -0,0 +1,53 @@
<template>
<el-dropdown @command="handleCommand" class="scenario-ext-btn">
<el-link type="primary" :underline="false">
<el-icon class="el-icon-more"></el-icon>
</el-link>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item>
<el-dropdown-item command="create_performance">{{ $t('api_test.create_performance_test') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
name: "MsApiCaseTableExtendBtns",
components: {},
props: {
row: Object,
},
data() {
return {
planVisible: false,
}
},
methods: {
handleCommand(cmd) {
if (this.row.id) {
switch (cmd) {
case "ref":
this.$emit("showCaseRef", this.row);
break;
case "create_performance":
this.$emit("showEnvironment", this.row);
break;
}
} else {
this.$warning(this.$t('api_test.automation.save_case_info'))
}
},
createPerformance(row, environment) {
this.$emit("createPerformance", row, environment);
}
}
}
</script>
<style scoped>
.scenario-ext-btn {
margin-left: 10px;
}
</style>

View File

@ -6,6 +6,7 @@
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item> <el-dropdown-item command="ref">{{ $t('api_test.automation.view_ref') }}</el-dropdown-item>
<el-dropdown-item :disabled="isCaseEdit" command="add_plan">{{ $t('api_test.automation.batch_add_plan') }}</el-dropdown-item> <el-dropdown-item :disabled="isCaseEdit" command="add_plan">{{ $t('api_test.automation.batch_add_plan') }}</el-dropdown-item>
<el-dropdown-item :disabled="isCaseEdit" command="create_performance">{{ $t('api_test.create_performance_test') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
<ms-reference-view ref="viewRef"/> <ms-reference-view ref="viewRef"/>
<!--测试计划--> <!--测试计划-->
@ -18,6 +19,9 @@
<script> <script>
import MsReferenceView from "./ReferenceView"; import MsReferenceView from "./ReferenceView";
import MsTestPlanList from "../../../automation/scenario/testplan/TestPlanList"; import MsTestPlanList from "../../../automation/scenario/testplan/TestPlanList";
import {getBodyUploadFiles, getCurrentProjectID, getUUID} from "@/common/js/utils";
import TestPlan from "@/business/components/api/definition/components/jmeter/components/test-plan";
import ThreadGroup from "@/business/components/api/definition/components/jmeter/components/thread-group";
export default { export default {
name: "MsApiExtendBtns", name: "MsApiExtendBtns",
@ -25,6 +29,7 @@
props: { props: {
row: Object, row: Object,
isCaseEdit: Boolean, isCaseEdit: Boolean,
environment: {},
}, },
data() { data() {
return { return {
@ -42,11 +47,62 @@
case "add_plan": case "add_plan":
this.addCaseToPlan(); this.addCaseToPlan();
break; break;
case "create_performance":
this.createPerformance(this.row);
break;
} }
} else { } else {
this.$warning(this.$t('api_test.automation.save_case_info')) this.$warning(this.$t('api_test.automation.save_case_info'))
} }
}, },
createPerformance(row){
/**
* 思路调用后台创建性能测试的方法把当前案例的hashTree在后台转化为jmx并文件创建性能测试
* 然后跳转到修改性能测试的页面
*
* 性能测试保存地址 performance/save
*
*/
if (!this.environment || !this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.runData = [];
this.singleLoading = true;
this.row.request.name = this.row.id;
this.row.request.useEnvironment = this.environment.id;
this.runData.push(this.row.request);
/*触发执行操作*/
let testPlan = new TestPlan();
let threadGroup = new ThreadGroup();
threadGroup.hashTree = [];
testPlan.hashTree = [threadGroup];
this.runData.forEach(item => {
threadGroup.hashTree.push(item);
})
let reqObj = {id: this.row.id,
testElement: testPlan,
type: this.type,
name:this.row.name,
projectId:getCurrentProjectID(),
};
let bodyFiles = getBodyUploadFiles(reqObj, this.runData);
reqObj.reportId = "run";
let url = "/api/genPerformanceTest";
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
let performanceId = response.data;
if(performanceId!=null){
this.$router.push({
path: "/performance/test/edit/"+performanceId,
})
}
}, erro => {
this.$emit('runRefresh', {});
});
},
addCaseToPlan() { addCaseToPlan() {
this.planVisible = true; this.planVisible = true;
}, },