feat(接口自动化): 数据迁移初版

This commit is contained in:
fit2-zhao 2021-01-06 12:24:13 +08:00
parent b65c79424b
commit fc8c997716
13 changed files with 555 additions and 71 deletions

View File

@ -14,7 +14,6 @@ import io.metersphere.api.service.*;
import io.metersphere.base.domain.ApiTest; import io.metersphere.base.domain.ApiTest;
import io.metersphere.base.domain.Schedule; import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CronUtils; import io.metersphere.commons.utils.CronUtils;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
@ -60,6 +59,8 @@ public class APITestController {
private ScheduleService scheduleService; private ScheduleService scheduleService;
@Resource @Resource
private APIReportService apiReportService; private APIReportService apiReportService;
@Resource
private HistoricalDataUpgradeService historicalDataUpgradeService;
@GetMapping("recent/{count}") @GetMapping("recent/{count}")
public List<APITestResult> recentTest(@PathVariable int count) { public List<APITestResult> recentTest(@PathVariable int count) {
@ -109,6 +110,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 +191,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 +224,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 +265,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 +289,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 +301,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 +345,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 +358,10 @@ public class APITestController {
schedule.setEnable(request.isEnable()); schedule.setEnable(request.isEnable());
apiAutomationService.updateSchedule(schedule); apiAutomationService.updateSchedule(schedule);
} }
@PostMapping(value = "/historicalDataUpgrade")
public String historicalDataUpgrade(@RequestBody SaveHistoricalDataUpgrade request) {
return historicalDataUpgradeService.upgrade(request);
}
} }

View File

@ -121,5 +121,6 @@ public class ApiAutomationController {
public void createSchedule(@RequestBody Schedule request) { public void createSchedule(@RequestBody Schedule request) {
apiAutomationService.createSchedule(request); apiAutomationService.createSchedule(request);
} }
} }

View File

@ -0,0 +1,18 @@
package io.metersphere.api.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class SaveHistoricalDataUpgrade {
private List<String> testIds;
private String projectId;
private String modulePath;
private String moduleId;
}

View File

@ -31,7 +31,7 @@ public class MsDubboSampler extends MsTestElement {
private String type = "DubboSampler"; private String type = "DubboSampler";
@JSONField(ordinal = 52) @JSONField(ordinal = 52)
private String protocol; private String protocol = "DUBBO";
@JsonProperty(value = "interface") @JsonProperty(value = "interface")
@JSONField(ordinal = 53, name = "interface") @JSONField(ordinal = 53, name = "interface")
private String _interface; private String _interface;

View File

@ -172,7 +172,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
LogUtil.error(e); LogUtil.error(e);
} }
// REST参数 // REST参数
if (CollectionUtils.isNotEmpty(this.getArguments())) { if (CollectionUtils.isNotEmpty(this.getRest())) {
sampler.setArguments(httpArguments(this.getRest())); sampler.setArguments(httpArguments(this.getRest()));
} }
// 请求参数 // 请求参数
@ -186,7 +186,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
if (StringUtils.isNotEmpty(this.body.getType()) && this.body.getType().equals("Form Data")) { if (StringUtils.isNotEmpty(this.body.getType()) && this.body.getType().equals("Form Data")) {
sampler.setDoMultipart(true); sampler.setDoMultipart(true);
} }
sampler.setArguments(httpArguments(bodyParams)); if (CollectionUtils.isNotEmpty(bodyParams)) {
sampler.setArguments(httpArguments(bodyParams));
}
} }
} }

View File

@ -0,0 +1,331 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.SaveHistoricalDataUpgrade;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
import io.metersphere.api.dto.definition.request.controller.MsIfController;
import io.metersphere.api.dto.definition.request.extract.MsExtract;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
import io.metersphere.api.dto.scenario.Scenario;
import io.metersphere.api.dto.scenario.request.*;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
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.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.*;
import java.net.URL;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class HistoricalDataUpgradeService {
@Resource
private ApiTestMapper apiTestMapper;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
SqlSessionFactory sqlSessionFactory;
private int getNextNum(String projectId) {
ApiScenario apiScenario = extApiScenarioMapper.getNextNum(projectId);
if (apiScenario == null) {
return 100001;
} else {
return Optional.of(apiScenario.getNum() + 1).orElse(100001);
}
}
private MsScenario createScenario(Scenario oldScenario) {
MsScenario scenario = new MsScenario();
scenario.setVariables(oldScenario.getVariables());
scenario.setName(oldScenario.getName());
scenario.setEnableCookieShare(oldScenario.isEnableCookieShare());
scenario.setEnvironmentId(oldScenario.getEnvironmentId());
scenario.setReferenced("Upgrade");
scenario.setId(oldScenario.getId());
scenario.setResourceId(UUID.randomUUID().toString());
LinkedList<MsTestElement> testElements = new LinkedList<>();
int index = 1;
for (Request request : oldScenario.getRequests()) {
// 条件控制器
MsIfController ifController = null;
if (request.getController() != null && StringUtils.isNotEmpty(request.getController().getValue())
&& StringUtils.isNotEmpty(request.getController().getVariable())) {
ifController = new MsIfController();
BeanUtils.copyBean(ifController, request.getController());
ifController.setType("IfController");
ifController.setName("IfController");
ifController.setIndex(index + "");
ifController.setResourceId(UUID.randomUUID().toString());
}
// 等待控制器
if (request.getTimer() != null && StringUtils.isNotEmpty(request.getTimer().getDelay())) {
MsConstantTimer constantTimer = new MsConstantTimer();
BeanUtils.copyBean(constantTimer, request.getTimer());
constantTimer.setType("ConstantTimer");
constantTimer.setIndex(index + "");
constantTimer.setResourceId(UUID.randomUUID().toString());
testElements.add(constantTimer);
}
MsTestElement element = null;
if (request instanceof HttpRequest) {
element = new MsHTTPSamplerProxy();
HttpRequest request1 = (HttpRequest) request;
if (StringUtils.isEmpty(request1.getPath()) && StringUtils.isNotEmpty(request1.getUrl())) {
try {
URL urlObject = new URL(request1.getUrl());
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
request1.setPath(envPath);
} catch (Exception ex) {
LogUtil.error(ex.getMessage());
}
}
BeanUtils.copyBean(element, request1);
((MsHTTPSamplerProxy) element).setProtocol(RequestType.HTTP);
((MsHTTPSamplerProxy) element).setArguments(request1.getParameters());
element.setType("HTTPSamplerProxy");
}
if (request instanceof DubboRequest) {
String requestJson = JSON.toJSONString(request);
element = JSON.parseObject(requestJson, MsDubboSampler.class);
element.setType("DubboSampler");
}
if (request instanceof SqlRequest) {
element = new MsJDBCSampler();
SqlRequest request1 = (SqlRequest) request;
BeanUtils.copyBean(element, request1);
element.setType("JDBCSampler");
}
if (request instanceof TCPRequest) {
element = new MsTCPSampler();
TCPRequest request1 = (TCPRequest) request;
BeanUtils.copyBean(element, request1);
element.setType("TCPSampler");
}
element.setIndex(index + "");
element.setResourceId(UUID.randomUUID().toString());
LinkedList<MsTestElement> msTestElements = new LinkedList<>();
// 断言规则
if (request.getAssertions() != null && ((request.getAssertions().getDuration() != null && request.getAssertions().getDuration().getValue() > 0) ||
CollectionUtils.isNotEmpty(request.getAssertions().getJsonPath()) || CollectionUtils.isNotEmpty(request.getAssertions().getJsr223()) ||
CollectionUtils.isNotEmpty(request.getAssertions().getRegex()) || CollectionUtils.isNotEmpty(request.getAssertions().getXpath2()))) {
String assertions = JSON.toJSONString(request.getAssertions());
MsAssertions msAssertions = JSON.parseObject(assertions, MsAssertions.class);
msAssertions.setType("Assertions");
msAssertions.setIndex(index + "");
msAssertions.setResourceId(UUID.randomUUID().toString());
msTestElements.add(msAssertions);
}
// 提取规则
if (request.getExtract() != null && (CollectionUtils.isNotEmpty(request.getExtract().getJson()) ||
CollectionUtils.isNotEmpty(request.getExtract().getRegex()) || CollectionUtils.isNotEmpty(request.getExtract().getXpath()))) {
String extractJson = JSON.toJSONString(request.getExtract());
MsExtract extract = JSON.parseObject(extractJson, MsExtract.class);
extract.setType("Extract");
extract.setIndex(index + "");
extract.setResourceId(UUID.randomUUID().toString());
msTestElements.add(extract);
}
// 前置脚本
if (request.getJsr223PreProcessor() != null && StringUtils.isNotEmpty(request.getJsr223PreProcessor().getScript())) {
String preJson = JSON.toJSONString(request.getJsr223PreProcessor());
MsJSR223PreProcessor preProcessor = JSON.parseObject(preJson, MsJSR223PreProcessor.class);
preProcessor.setType("JSR223PreProcessor");
preProcessor.setIndex(index + "");
preProcessor.setResourceId(UUID.randomUUID().toString());
msTestElements.add(preProcessor);
}
// 后置脚本
if (request.getJsr223PostProcessor() != null && StringUtils.isNotEmpty(request.getJsr223PostProcessor().getScript())) {
String preJson = JSON.toJSONString(request.getJsr223PostProcessor());
MsJSR223PostProcessor preProcessor = JSON.parseObject(preJson, MsJSR223PostProcessor.class);
preProcessor.setType("JSR223PostProcessor");
preProcessor.setIndex(index + "");
preProcessor.setResourceId(UUID.randomUUID().toString());
msTestElements.add(preProcessor);
}
if (CollectionUtils.isNotEmpty(msTestElements)) {
element.setHashTree(msTestElements);
}
if (ifController != null) {
LinkedList<MsTestElement> elements = new LinkedList<>();
elements.add(element);
ifController.setHashTree(elements);
testElements.add(ifController);
} else {
testElements.add(element);
}
index++;
}
scenario.setHashTree(testElements);
return scenario;
}
private ApiScenarioWithBLOBs checkNameExist(Scenario oldScenario, String projectId, ApiScenarioMapper mapper) {
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdEqualTo(oldScenario.getId());
List<ApiScenarioWithBLOBs> list = mapper.selectByExampleWithBLOBs(example);
if (list.size() > 0) {
return list.get(0);
}
return null;
}
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
//文件的拷贝
private static void copyFile(String sourcePath, String newPath) {
File readfile = new File(sourcePath);
File newFile = new File(newPath);
BufferedWriter bufferedWriter = null;
Writer writer = null;
FileOutputStream fileOutputStream = null;
BufferedReader bufferedReader = null;
try {
fileOutputStream = new FileOutputStream(newFile, true);
writer = new OutputStreamWriter(fileOutputStream, "UTF-8");
bufferedWriter = new BufferedWriter(writer);
bufferedReader = new BufferedReader(new FileReader(readfile));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
bufferedWriter.newLine();
bufferedWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedWriter != null) {
bufferedWriter.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (writer != null) {
writer.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void copyDir(String sourcePathDir, String newPathDir) {
File start = new File(sourcePathDir);
File end = new File(newPathDir);
String[] filePath = start.list();
if (!end.exists()) {
end.mkdir();
}
for (String temp : filePath) {
//添加满足情况的条件
if (new File(sourcePathDir + File.separator + temp).isFile()) {
//为文件则进行拷贝
copyFile(sourcePathDir + File.separator + temp, newPathDir + File.separator + temp);
}
}
}
private void createBodyFiles(String testId) {
String dir = BODY_FILE_DIR + "/" + testId;
File testDir = new File(dir);
if (testDir.exists()) {
testDir.mkdirs();
}
copyDir(dir, BODY_FILE_DIR);
}
private void createApiScenarioWithBLOBs(SaveHistoricalDataUpgrade saveHistoricalDataUpgrade, Scenario oldScenario, String scenarioDefinition, ApiScenarioMapper mapper) {
if (StringUtils.isEmpty(oldScenario.getName())) {
oldScenario.setName("默认名称-" + DateUtils.getTimeStr(System.currentTimeMillis()));
}
ApiScenarioWithBLOBs scenario = checkNameExist(oldScenario, saveHistoricalDataUpgrade.getProjectId(), mapper);
if (scenario != null) {
scenario.setName(oldScenario.getName());
scenario.setProjectId(saveHistoricalDataUpgrade.getProjectId());
scenario.setTags(scenario.getTags());
scenario.setLevel("P0");
scenario.setModulePath(saveHistoricalDataUpgrade.getModulePath());
scenario.setApiScenarioModuleId(saveHistoricalDataUpgrade.getModuleId());
scenario.setPrincipal(Objects.requireNonNull(SessionUtils.getUser()).getId());
scenario.setStepTotal(oldScenario.getRequests().size());
scenario.setScenarioDefinition(scenarioDefinition);
scenario.setUpdateTime(System.currentTimeMillis());
scenario.setStatus(ScenarioStatus.Underway.name());
scenario.setUserId(SessionUtils.getUserId());
scenario.setNum(getNextNum(saveHistoricalDataUpgrade.getProjectId()));
mapper.updateByPrimaryKeySelective(scenario);
} else {
scenario = new ApiScenarioWithBLOBs();
scenario.setId(oldScenario.getId());
scenario.setName(oldScenario.getName());
scenario.setProjectId(saveHistoricalDataUpgrade.getProjectId());
scenario.setTags(scenario.getTags());
scenario.setLevel("P0");
scenario.setModulePath(saveHistoricalDataUpgrade.getModulePath());
scenario.setApiScenarioModuleId(saveHistoricalDataUpgrade.getModuleId());
scenario.setPrincipal(Objects.requireNonNull(SessionUtils.getUser()).getId());
scenario.setStepTotal(oldScenario.getRequests().size());
scenario.setScenarioDefinition(scenarioDefinition);
scenario.setCreateTime(System.currentTimeMillis());
scenario.setUpdateTime(System.currentTimeMillis());
scenario.setStatus(ScenarioStatus.Underway.name());
scenario.setUserId(SessionUtils.getUserId());
scenario.setNum(getNextNum(saveHistoricalDataUpgrade.getProjectId()));
mapper.insert(scenario);
}
}
public String upgrade(SaveHistoricalDataUpgrade saveHistoricalDataUpgrade) {
ApiTestExample example = new ApiTestExample();
example.createCriteria().andIdIn(saveHistoricalDataUpgrade.getTestIds());
List<ApiTest> blobs = apiTestMapper.selectByExampleWithBLOBs(example);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioMapper mapper = sqlSession.getMapper(ApiScenarioMapper.class);
for (ApiTest test : blobs) {
// 附件迁移
createBodyFiles(test.getId());
List<Scenario> scenarios = JSON.parseArray(test.getScenarioDefinition(), Scenario.class);
if (CollectionUtils.isNotEmpty(scenarios)) {
// 批量处理
for (Scenario scenario : scenarios) {
MsScenario scenario1 = createScenario(scenario);
String scenarioDefinition = JSON.toJSONString(scenario1);
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenario, scenarioDefinition, mapper);
}
}
}
sqlSession.flushStatements();
return null;
}
}

View File

@ -58,8 +58,8 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p> <p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :referenced="true" :headers="request.headers " :request="request" v-if="request.protocol==='HTTP' || request.type==='HTTPSamplerProxy'"/> <ms-api-request-form :referenced="true" :headers="request.headers " :request="request" v-if="request.protocol==='HTTP' || request.type==='HTTPSamplerProxy'"/>
<ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'|| request.type==='TCPSampler'"/> <ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'|| request.type==='TCPSampler'"/>
<ms-sql-basis-parameters :request="request" v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"/> <ms-sql-basis-parameters :request="request" v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'" :showScript="false"/>
<ms-dubbo-basis-parameters :request="request" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"/> <ms-dubbo-basis-parameters :request="request" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'" :showScript="false"/>
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p> <p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<ms-request-result-tail :currentProtocol="request.protocol" :response="request.requestResult" ref="runResult"/> <ms-request-result-tail :currentProtocol="request.protocol" :response="request.requestResult" ref="runResult"/>

View File

@ -55,7 +55,7 @@
import MsApiAssertionRegex from "./ApiAssertionRegex"; import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration"; import MsApiAssertionDuration from "./ApiAssertionDuration";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath"; import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223"; import MsApiAssertionJsr223 from "./ApiAssertionJsr223";
import MsApiAssertionXPath2 from "./ApiAssertionXPath2"; import MsApiAssertionXPath2 from "./ApiAssertionXPath2";
export default { export default {

View File

@ -63,18 +63,19 @@
</el-tabs> </el-tabs>
</el-form> </el-form>
</div> </div>
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%"> <div v-if="showScript">
<!-- 前置脚本 --> <div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%">
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="color: #B8741A;background-color: #F9F1EA" <!-- 前置脚本 -->
:jsr223-processor="row"/> <ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="color: #B8741A;background-color: #F9F1EA"
<!--后置脚本--> :jsr223-processor="row"/>
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="color: #783887;background-color: #F2ECF3" <!--后置脚本-->
:jsr223-processor="row"/> <ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="color: #783887;background-color: #F2ECF3"
<!--断言规则--> :jsr223-processor="row"/>
<ms-api-assertions v-if="row.type==='Assertions'" @copyRow="copyRow" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/> <!--断言规则-->
<!--提取规则--> <ms-api-assertions v-if="row.type==='Assertions'" @copyRow="copyRow" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<ms-api-extract :is-read-only="isReadOnly" @copyRow="copyRow" @remove="remove" v-if="row.type==='Extract'" :extract="row"/> <!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @copyRow="copyRow" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
</div>
</div> </div>
</el-col> </el-col>
<el-col :span="3" class="ms-left-cell" v-if="showScript"> <el-col :span="3" class="ms-left-cell" v-if="showScript">

View File

@ -41,19 +41,19 @@
</el-form> </el-form>
</div> </div>
<div v-if="showScript">
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%"> <div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData" style="margin-left: 20px;width: 100%">
<!-- 前置脚本 --> <!-- 前置脚本 -->
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="color: #B8741A;background-color: #F9F1EA" <ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="color: #B8741A;background-color: #F9F1EA"
:jsr223-processor="row"/> :jsr223-processor="row"/>
<!--后置脚本--> <!--后置脚本-->
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="color: #783887;background-color: #F2ECF3" <ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @copyRow="copyRow" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="color: #783887;background-color: #F2ECF3"
:jsr223-processor="row"/> :jsr223-processor="row"/>
<!--断言规则--> <!--断言规则-->
<ms-api-assertions v-if="row.type==='Assertions'" @copyRow="copyRow" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/> <ms-api-assertions v-if="row.type==='Assertions'" @copyRow="copyRow" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<!--提取规则--> <!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @copyRow="copyRow" @remove="remove" v-if="row.type==='Extract'" :extract="row"/> <ms-api-extract :is-read-only="isReadOnly" @copyRow="copyRow" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
</div>
</div> </div>
</el-col> </el-col>

View File

@ -7,7 +7,7 @@
:title="$t('commons.test')" :title="$t('commons.test')"
@create="create" :createTip="$t('load_test.create')" :runTip="$t('load_test.run')" @create="create" :createTip="$t('load_test.create')" :runTip="$t('load_test.run')"
:show-run="true" :show-run="true"
@runTest="runTest"/> @runTest="runTest" @historicalDataUpgrade="historicalDataUpgrade"/>
</template> </template>
@ -54,7 +54,8 @@
</el-card> </el-card>
<api-copy-dialog ref="apiCopy" @refresh="search"/> <api-copy-dialog ref="apiCopy" @refresh="search"/>
<ms-upgrade ref="upgrade" :select-ids="selectIds"
:select-project-names="selectProjectNames" :select-project-id="selectProjectId"/>
</ms-main-container> </ms-main-container>
</ms-container> </ms-container>
</template> </template>
@ -72,13 +73,14 @@
import {TEST_CONFIGS} from "../../common/components/search/search-components"; import {TEST_CONFIGS} from "../../common/components/search/search-components";
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent"; import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
import ApiCopyDialog from "./components/ApiCopyDialog"; import ApiCopyDialog from "./components/ApiCopyDialog";
import MsUpgrade from "./Upgrade";
export default { export default {
components: { components: {
ApiCopyDialog, ApiCopyDialog,
OneClickOperation, OneClickOperation,
MsTableOperators, MsTableOperators,
MsApiTestStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, MsTableOperator MsApiTestStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, MsTableOperator, MsUpgrade
}, },
data() { data() {
return { return {
@ -204,6 +206,13 @@
_filter(filters, this.condition); _filter(filters, this.condition);
this.init(); this.init();
}, },
historicalDataUpgrade() {
if (this.selectIds.size < 1) {
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
} else {
this.$refs.upgrade.openOneClickOperation();
}
}
}, },
created() { created() {
this.init(); this.init();

View File

@ -0,0 +1,109 @@
<template>
<el-dialog
title="选则模块"
:visible.sync="oneClickOperationVisible"
width="600px"
left
:destroy-on-close="true"
show-close
@closed="handleClose" v-loading="loading">
<el-form :model="ruleForm" label-position="right" label-width="80px" size="small" :rules="rule">
<el-form-item :label="$t('test_track.module.module')" prop="apiScenarioModuleId">
<el-select size="small" style="width: 80%" v-model="apiScenarioModuleId">
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<ms-dialog-footer
@cancel="oneClickOperationVisible = false"
@confirm="confirm"/>
</span>
</el-dialog>
</template>
<script>
import MsDialogFooter from '../../common/components/MsDialogFooter'
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
import MsApiReportStatus from "../report/ApiReportStatus";
import MsApiReportDialog from "./ApiReportDialog";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import {buildNodePath} from "../definition/model/NodeTree";
export default {
name: "MsUpgrade",
components: {
MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig, MsDialogFooter
},
data() {
return {
oneClickOperationVisible: false,
apiScenarioModuleId: "",
moduleOptions: [],
ruleForm: {},
loading: false,
rule: {
apiScenarioModuleId: [
{required: true, message: this.$t('test_track.module.module'), trigger: 'blur'},
],
}
};
},
created() {
this.initModule();
},
props: {
selectIds: {
type: Set
},
selectProjectNames: {
type: Set
},
selectProjectId: {
type: Set
}
},
methods: {
openOneClickOperation() {
this.oneClickOperationVisible = true;
},
getPath(id) {
let path = this.moduleOptions.filter(function (item) {
return item.id === id ? item.path : "";
});
return path[0].path;
},
confirm() {
this.loading = true;
let arr = Array.from(this.selectIds);
let obj = {testIds: arr, projectId: getCurrentProjectID(), modulePath: this.getPath(this.apiScenarioModuleId), moduleId: this.apiScenarioModuleId};
this.$post("/api/historicalDataUpgrade", obj, response => {
this.loading = false;
this.$success(this.$t('organization.integration.successful_operation'));
this.oneClickOperationVisible = false;
})
},
initModule() {
let url = "/api/automation/module/list/" + getCurrentProjectID();
this.$get(url, response => {
if (response.data != undefined && response.data != null) {
this.data = response.data;
let modules = [];
this.data.forEach(node => {
buildNodePath(node, {path: ''}, modules);
});
this.moduleOptions = modules;
}
});
},
handleClose() {
this.ruleForm = {}
},
}
}
</script>
<style scoped>
</style>

View File

@ -13,6 +13,8 @@
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showRun" icon="el-icon-video-play" <ms-table-button :is-tester-permission="isTesterPermission" v-if="showRun" icon="el-icon-video-play"
type="primary" type="primary"
:content="runTip" @click="runTest"/> :content="runTip" @click="runTest"/>
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showRun" icon="el-icon-circle-plus-outline"
content="转场景测试" @click="historicalDataUpgrade"/>
<slot name="button"></slot> <slot name="button"></slot>
</span> </span>
@ -84,6 +86,9 @@
}, },
runTest() { runTest() {
this.$emit('runTest') this.$emit('runTest')
},
historicalDataUpgrade() {
this.$emit('historicalDataUpgrade');
} }
}, },
computed: { computed: {