fix(测试计划): 修复资源池执行测试计划的缺陷

修复资源池执行测试计划的缺陷
This commit is contained in:
song-tianyang 2021-11-12 21:35:53 +08:00 committed by song-tianyang
parent 99ad51cfaa
commit 8f34c4694e
13 changed files with 108 additions and 52 deletions

View File

@ -471,11 +471,13 @@ public class MockApiUtils {
JSON returnJson = null;
try {
String param = getRequestPostStr(request);
JSONValidator jsonValidator = JSONValidator.from(param);
if (StringUtils.equalsIgnoreCase("Array", jsonValidator.getType().name())) {
returnJson = JSONArray.parseArray(param);
} else if (StringUtils.equalsIgnoreCase("Object", jsonValidator.getType().name())) {
returnJson = JSONObject.parseObject(param);
if(StringUtils.isNotEmpty(param)){
JSONValidator jsonValidator = JSONValidator.from(param);
if (StringUtils.equalsIgnoreCase("Array", jsonValidator.getType().name())) {
returnJson = JSONArray.parseArray(param);
} else if (StringUtils.equalsIgnoreCase("Object", jsonValidator.getType().name())) {
returnJson = JSONObject.parseObject(param);
}
}
} catch (Exception e) {
e.printStackTrace();

View File

@ -1190,7 +1190,6 @@ public class ApiAutomationService {
* @param executeQueue
* @param scenarioIds
* @param scenarioNames
* @param serialReportId
*/
private void prepareExecutedPlanScenario(List<ApiScenarioWithBLOBs> apiScenarios, RunScenarioRequest request, Map<String, RunModeDataDTO> executeQueue, List<String> scenarioIds, StringBuilder scenarioNames) {
String reportId = request.getId();
@ -1247,7 +1246,7 @@ public class ApiAutomationService {
try {
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO();
runModeDataDTO.setTestId(scenario.getId());
runModeDataDTO.setTestId(testPlanScenarioId);
runModeDataDTO.setPlanEnvMap(planEnvMap);
runModeDataDTO.setReport(report);
executeQueue.put(report.getId(), runModeDataDTO);
@ -1462,12 +1461,14 @@ public class ApiAutomationService {
// 增加一个本地锁防止并发找不到资源
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
String testPlanScenarioId = "";
String testId = executeQueue.get(reportId).getTestId();
if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(executeQueue.get(reportId).getTestId())) {
testPlanScenarioId = request.getScenarioTestPlanIdMap().get(executeQueue.get(reportId).getTestId());
testPlanScenarioId = executeQueue.get(reportId).getTestId();
testId = request.getScenarioTestPlanIdMap().get(executeQueue.get(reportId).getTestId());
} else {
testPlanScenarioId = request.getPlanScenarioId();
}
jMeterService.runTest(executeQueue.get(reportId).getTestId(), reportId, request.getRunMode(), testPlanScenarioId, request.getConfig());
jMeterService.runTest(testId, reportId, request.getRunMode(), testPlanScenarioId, request.getConfig());
} else {
jMeterService.runLocal(reportId, request.getConfig(), executeQueue.get(reportId).getHashTree(),
TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());

View File

@ -230,7 +230,6 @@ public class ApiDefinitionExecResultService {
* @param type
*/
public void saveApiResultByScheduleTask(TestResult result, String testPlanReportId, String type) {
testPlanLog.info("TestPlanReportId[" + testPlanReportId + "] APICASE OVER.");
String saveResultType = type;
if (StringUtils.equalsAny(saveResultType, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
saveResultType = ApiRunMode.API_PLAN.name();
@ -240,14 +239,25 @@ public class ApiDefinitionExecResultService {
Map<String, String> apiIdResultMap = new HashMap<>();
Map<String, String> caseReportMap = new HashMap<>();
String testId = result.getTestId();
if(testId.contains(":")){
String [] testIdArr = testId.split(":");
if(testIdArr.length == 3){
result.setTestId(testIdArr[2]);
}else {
result.setTestId(testIdArr[0]);
}
testPlanReportId = testIdArr[1];
}
String creator = TestPlanReportExecuteCatch.getCreator(testPlanReportId);
if (CollectionUtils.isNotEmpty(result.getScenarios())) {
result.getScenarios().forEach(scenarioResult -> {
final boolean[] isFirst = {true};
if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) {
scenarioResult.getRequestResults().forEach(item -> {
String creator = TestPlanReportExecuteCatch.getCreator(testPlanReportId);
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
ApiDefinitionExecResult saveResult = MessageCache.caseExecResourceLock.get(result.getTestId());
if (saveResult == null) {
saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(result.getTestId());
}

View File

@ -3,9 +3,7 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.JarConfig;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.commons.constants.ApiRunMode;
@ -52,27 +50,34 @@ public class ApiJmeterFileService {
return listBytesToZip(files);
}
public byte[] downloadJmeterFiles(String runMode, String testId, String reportId, String testPlanScenarioId) {
public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String testPlanScenarioId) {
Map<String, String> planEnvMap = new HashMap<>();
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
// 获取场景用例单独的执行环境
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
String environment = planApiScenario.getEnvironment();
if (StringUtils.isNotBlank(environment)) {
planEnvMap = JSON.parseObject(environment, Map.class);
if(planApiScenario != null){
String environment = planApiScenario.getEnvironment();
if (StringUtils.isNotBlank(environment)) {
planEnvMap = JSON.parseObject(environment, Map.class);
}
}
}
HashTree hashTree;
if (ApiRunMode.DEFINITION.name().equals(runMode) || ApiRunMode.API_PLAN.name().equals(runMode)) {
if (ApiRunMode.DEFINITION.name().equals(runMode) || ApiRunMode.API_PLAN.name().equals(runMode) || ApiRunMode.MANUAL_PLAN.name().equals(runMode)) {
String testId = remoteTestId;
if(remoteTestId.contains(":")){
//执行测试计划案例时会有拼接ID,ID为 planTestCaseId:测试计划报告ID
testId = remoteTestId.split(":")[0];
}
hashTree = testPlanApiCaseService.generateHashTree(testId);
} else {
ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(testId);
ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(remoteTestId);
if (item == null) {
MSException.throwException("未找到执行场景。");
}
hashTree = apiAutomationService.generateHashTree(item, reportId, planEnvMap);
}
return zipFilesToByteArray(testId, hashTree);
return zipFilesToByteArray(remoteTestId, hashTree);
}
public byte[] downloadJmx(String runMode, String testId, String reportId, String testPlanScenarioId) {

View File

@ -90,6 +90,10 @@ public class TestResultService {
if (StringUtils.equalsAny(runMode, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult, debugReportId, runMode);
} else {
String testResultTestId = testResult.getTestId();
if(testResultTestId.contains(":")){
testResult.setTestId(testResultTestId.split(":")[0]);
}
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.API_PLAN.name(), TriggerMode.MANUAL.name());
}
} else if (StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {

View File

@ -41,7 +41,9 @@ public class SerialScenarioExecTask<T> implements Callable<T> {
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
String testPlanScenarioId = "";
if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(runModeDataDTO.getTestId())) {
testPlanScenarioId = request.getScenarioTestPlanIdMap().get(runModeDataDTO.getTestId());
testPlanScenarioId = runModeDataDTO.getTestId();
String scenarioId = request.getScenarioTestPlanIdMap().get(runModeDataDTO.getTestId());
runModeDataDTO.setTestId(scenarioId);
} else {
testPlanScenarioId = request.getPlanScenarioId();
}

View File

@ -391,6 +391,7 @@ public class TestPlanApiCaseService {
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.API_PLAN.name());
apiResult.setStatus(status);
apiResult.setContent(request.getPlanReportId());
batchMapper.insert(apiResult);
return apiResult;
}
@ -468,6 +469,7 @@ public class TestPlanApiCaseService {
mapper.updateByPrimaryKey(execResult);
modeDataDTO.setApiCaseId(execResult.getId());
modeDataDTO.setDebugReportId(request.getPlanReportId());
modeDataDTO.setTestId(modeDataDTO.getTestId()+":"+request.getPlanReportId()+ ":"+ execResult.getId());
Future<ApiDefinitionExecResult> future = executorService.submit(new SerialApiExecTask(jMeterService, mapper, modeDataDTO, request.getConfig(), request.getTriggerMode()));
ApiDefinitionExecResult report = future.get();
// 如果开启失败结束执行则判断返回结果状态
@ -538,14 +540,16 @@ public class TestPlanApiCaseService {
try {
String debugId = request.getPlanReportId();
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
jMeterService.runTest(testPlanApiCase.getId(), reportId, request.getTriggerMode(), request.getPlanReportId(), request.getConfig());
String testId = testPlanApiCase.getId()+":"+ request.getPlanReportId() + ":" +reportId;
jMeterService.runTest(testId, reportId, request.getTriggerMode(), request.getPlanReportId(), request.getConfig());
executeThreadIdMap.put(testPlanApiCase.getApiCaseId(),testPlanApiCase.getId());
} else {
HashTree hashTree = generateHashTree(testPlanApiCase.getId());
if(StringUtils.isEmpty(debugId)){
debugId = TriggerMode.BATCH.name();
}
jMeterService.runLocal(reportId,request.getConfig(), hashTree, debugId, request.getTriggerMode());
String testId = reportId+":"+ request.getPlanReportId();
jMeterService.runLocal(testId,request.getConfig(), hashTree, debugId, request.getTriggerMode());
executeThreadIdMap.put(testPlanApiCase.getId(),reportId);
}
}catch (Exception e){

View File

@ -1182,4 +1182,13 @@ public class TestPlanReportService {
testPlanReportDTO.setName(testPlanReport.getName());
return testPlanReportDTO;
}
public void finishReport(TestPlanReport testPlanReport) {
long endTime = System.currentTimeMillis();
testPlanReport.setEndTime(endTime);
testPlanReport.setUpdateTime(endTime);
testPlanReport.setStatus(TestPlanReportStatus.FAILED.name());
testPlanReportMapper.updateByPrimaryKey(testPlanReport);
}
}

View File

@ -182,7 +182,7 @@ public class TestPlanScenarioCaseService {
Map<String, String> scenarioIdApiScarionMap = new HashMap<>();
for (TestPlanApiScenario apiScenario : testPlanApiScenarioList) {
scenarioIds.add(apiScenario.getApiScenarioId());
scenarioIdApiScarionMap.put(apiScenario.getApiScenarioId(), apiScenario.getId());
scenarioIdApiScarionMap.put(apiScenario.getId(), apiScenario.getApiScenarioId());
}
if (scenarioIdApiScarionMap.isEmpty()) {
MSException.throwException("未找到执行场景!");

View File

@ -1063,15 +1063,53 @@ public class TestPlanService {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public String run(String testPlanID, String projectID, String userId, String triggerMode, String apiRunConfig) {
extTestPlanMapper.updateActualEndTimeIsNullById(testPlanID);
RunModeConfig runModeConfig = null;
try {
runModeConfig = JSONObject.parseObject(apiRunConfig, RunModeConfig.class);
runModeConfig.setOnSampleError(false);
} catch (Exception e) {
e.printStackTrace();
}
if (runModeConfig == null) {
runModeConfig = new RunModeConfig();
runModeConfig.setMode("serial");
runModeConfig.setReportType("iddReport");
runModeConfig.setEnvMap(new HashMap<>());
runModeConfig.setOnSampleError(false);
}else {
if(runModeConfig.getEnvMap() == null){
runModeConfig.setEnvMap(new HashMap<>());
}
}
//创建测试报告然后返回的ID重新赋值为resourceID作为后续的参数
TestPlanScheduleReportInfoDTO reportInfoDTO = testPlanReportService.genTestPlanReportBySchedule(projectID, testPlanID, userId, triggerMode);
TestPlanReport testPlanReport = reportInfoDTO.getTestPlanReport();
Map<String, String> planScenarioIdsMap = reportInfoDTO.getPlanScenarioIdMap();
Map<String, String> planApiCaseMap = reportInfoDTO.getApiTestCaseDataMap();
Map<String, String> performanceIdMap = reportInfoDTO.getPerformanceIdMap();
if (runModeConfig.getMode().equals(RunModeConstants.PARALLEL.toString())) {
// 校验并发数量
int count = 50;
BaseSystemConfigDTO dto = systemParameterService.getBaseInfo();
if (StringUtils.isNotEmpty(dto.getConcurrency())) {
count = Integer.parseInt(dto.getConcurrency());
}
if (planApiCaseMap.size() > count) {
testPlanReportService.finishReport(reportInfoDTO.getTestPlanReport());
MSException.throwException("并发超过"+count+",数量过大,请重新选择!");
}
if (planScenarioIdsMap.size() > count) {
testPlanReportService.finishReport(reportInfoDTO.getTestPlanReport());
MSException.throwException("并发超过"+count+",数量过大,请重新选择!");
}
}
extTestPlanMapper.updateActualEndTimeIsNullById(testPlanID);
String planReportId = testPlanReport.getId();
testPlanLog.info("ReportId[" + planReportId + "] created. TestPlanID:[" + testPlanID + "]. " + "API Run Config:【" + apiRunConfig + "");
@ -1138,26 +1176,6 @@ public class TestPlanService {
}
testPlanLog.info("ReportId[" + planReportId + "] start run. TestPlanID:[" + testPlanID + "]. Execute api :" + JSONObject.toJSONString(executeApiCaseIdMap) + "; Execute scenario:" + JSONObject.toJSONString(executeScenarioCaseIdMap) + "; Execute performance:" + JSONObject.toJSONString(executePerformanceIdMap));
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(planReportId, executeApiCaseIdMap, executeScenarioCaseIdMap, executePerformanceIdMap);
RunModeConfig runModeConfig = null;
try {
runModeConfig = JSONObject.parseObject(apiRunConfig, RunModeConfig.class);
runModeConfig.setOnSampleError(false);
} catch (Exception e) {
e.printStackTrace();
}
if (runModeConfig == null) {
runModeConfig = new RunModeConfig();
runModeConfig.setMode("serial");
runModeConfig.setReportType("iddReport");
runModeConfig.setEnvMap(new HashMap<>());
runModeConfig.setOnSampleError(false);
}else {
if(runModeConfig.getEnvMap() == null){
runModeConfig.setEnvMap(new HashMap<>());
}
}
//执行接口案例任务
this.executeApiTestCase(triggerMode, planReportId,new ArrayList<>(planApiCaseMap.keySet()), runModeConfig);
//执行场景执行任务

View File

@ -39,13 +39,13 @@ public class SerialApiExecTask<T> implements Callable<T> {
return null;
}
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, runModeDataDTO.getDebugReportId(), config);
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config);
} else {
String debugId = runModeDataDTO.getDebugReportId();
if(debugId == null){
debugId = runModeDataDTO.getReport() != null ? runModeDataDTO.getReport().getTriggerMode() : null;
}
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), config, runModeDataDTO.getHashTree(), debugId, runMode);
jMeterService.runLocal(runModeDataDTO.getApiCaseId()+":"+debugId, config, runModeDataDTO.getHashTree(), debugId, runMode);
}
// 轮询查看报告状态最多200次防止死循环
ApiDefinitionExecResult report = null;
@ -53,7 +53,7 @@ public class SerialApiExecTask<T> implements Callable<T> {
while (index < 200) {
Thread.sleep(3000);
index++;
report = mapper.selectByPrimaryKey(runModeDataDTO.getApiCaseId());
report = mapper.selectByPrimaryKey(runModeDataDTO.getApiCaseId());
if (report != null && !report.getStatus().equals(APITestStatus.Running.name())) {
break;
}

View File

@ -1,5 +1,6 @@
<template>
<div v-if="isShow">
<!-- <div :style="isShow? {} : {display: 'none'}">-->
<el-dropdown placement="bottom" trigger="click" size="medium">
<div @click.stop class="show-more-btn">
<el-tooltip popper-class="batch-popper" :value="true && !hasShowed" effect="dark" :content="$t('test_track.case.batch_operate')"

View File

@ -526,8 +526,8 @@ export default {
this.$refs.taskCenter.open();
this.result = this.$post('test/plan/run/', param,() => {
this.$success(this.$t('commons.run_success'));
}, () => {
this.$error(this.$t('commons.run_fail'));
}, error => {
// this.$error(error.message);
});
}
}