fix(接口定义) 修复并发批量执行用例问题

This commit is contained in:
fit2-zhao 2021-09-24 18:59:56 +08:00 committed by fit2-zhao
parent ec092e4038
commit 6fd1ffdda7
8 changed files with 108 additions and 21 deletions

View File

@ -47,7 +47,7 @@ public class MsDNSCacheManager extends MsTestElement {
} }
public static void addEnvironmentDNS(HashTree samplerHashTree, String name, EnvironmentConfig config, HttpConfig httpConfig) { public static void addEnvironmentDNS(HashTree samplerHashTree, String name, EnvironmentConfig config, HttpConfig httpConfig) {
if (config.getCommonConfig().isEnableHost() && CollectionUtils.isNotEmpty(config.getCommonConfig().getHosts()) && httpConfig != null) { if (config.getCommonConfig().isEnableHost() && CollectionUtils.isNotEmpty(config.getCommonConfig().getHosts()) && httpConfig != null && httpConfig.getDomain() != null) {
String domain = httpConfig.getDomain().trim(); String domain = httpConfig.getDomain().trim();
List<Host> hosts = new ArrayList<>(); List<Host> hosts = new ArrayList<>();
config.getCommonConfig().getHosts().forEach(host -> { config.getCommonConfig().getHosts().forEach(host -> {

View File

@ -1,5 +1,6 @@
package io.metersphere.api.jmeter; package io.metersphere.api.jmeter;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import org.apache.jmeter.engine.StandardJMeterEngine; import org.apache.jmeter.engine.StandardJMeterEngine;
import javax.websocket.Session; import javax.websocket.Session;
@ -16,4 +17,7 @@ public class MessageCache {
public static ConcurrentHashMap<String, StandardJMeterEngine> runningEngine = new ConcurrentHashMap<>(); public static ConcurrentHashMap<String, StandardJMeterEngine> runningEngine = new ConcurrentHashMap<>();
public static ConcurrentLinkedDeque<String> terminationOrderDeque = new ConcurrentLinkedDeque<>(); public static ConcurrentLinkedDeque<String> terminationOrderDeque = new ConcurrentLinkedDeque<>();
public static ConcurrentHashMap<String, ApiDefinitionExecResult> batchTestCases = new ConcurrentHashMap<>();
} }

View File

@ -1966,7 +1966,7 @@ public class ApiAutomationService {
} }
} }
} }
if (CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) { if (object != null && CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) {
setHashTree(object.getJSONArray("hashTree")); setHashTree(object.getJSONArray("hashTree"));
} }
} }
@ -1985,8 +1985,10 @@ public class ApiAutomationService {
if (StringUtils.isNotEmpty(item.getScenarioDefinition())) { if (StringUtils.isNotEmpty(item.getScenarioDefinition())) {
JSONObject scenario = JSONObject.parseObject(item.getScenarioDefinition()); JSONObject scenario = JSONObject.parseObject(item.getScenarioDefinition());
JSONArray hashTree = scenario.getJSONArray("hashTree"); JSONArray hashTree = scenario.getJSONArray("hashTree");
setHashTree(hashTree); if (hashTree != null) {
scenario.put("hashTree", hashTree); setHashTree(hashTree);
scenario.put("hashTree", hashTree);
}
item.setScenarioDefinition(JSON.toJSONString(scenario)); item.setScenarioDefinition(JSON.toJSONString(scenario));
} }
}); });

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.cache.TestPlanReportExecuteCatch; import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult; import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.jmeter.TestResult; import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper; import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
@ -57,7 +58,8 @@ public class ApiDefinitionExecResultService {
TestCaseReviewApiCaseMapper testCaseReviewApiCaseMapper; TestCaseReviewApiCaseMapper testCaseReviewApiCaseMapper;
@Resource @Resource
SqlSessionFactory sqlSessionFactory; private ApiDefinitionService apiDefinitionService;
@Resource @Resource
private NoticeSendService noticeSendService; private NoticeSendService noticeSendService;
@ -67,13 +69,14 @@ public class ApiDefinitionExecResultService {
public void saveApiResult(TestResult result, String type, String triggerMode) { public void saveApiResult(TestResult result, String type, String triggerMode) {
if (CollectionUtils.isNotEmpty(result.getScenarios())) { if (CollectionUtils.isNotEmpty(result.getScenarios())) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper definitionExecResultMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
final boolean[] isFirst = {true}; final boolean[] isFirst = {true};
result.getScenarios().forEach(scenarioResult -> { result.getScenarios().forEach(scenarioResult -> {
if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) { if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) {
scenarioResult.getRequestResults().forEach(item -> { scenarioResult.getRequestResults().forEach(item -> {
ApiDefinitionExecResult saveResult = definitionExecResultMapper.selectByPrimaryKey(result.getTestId()); ApiDefinitionExecResult saveResult = MessageCache.batchTestCases.get(result.getTestId());
if (saveResult == null) {
saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(result.getTestId());
}
item.getResponseResult().setConsole(result.getConsole()); item.getResponseResult().setConsole(result.getConsole());
boolean saved = true; boolean saved = true;
if (saveResult == null || scenarioResult.getRequestResults().size() > 1) { if (saveResult == null || scenarioResult.getRequestResults().size() > 1) {
@ -88,6 +91,7 @@ public class ApiDefinitionExecResultService {
saveResult.setName(item.getName()); saveResult.setName(item.getName());
saveResult.setTriggerMode(triggerMode); saveResult.setTriggerMode(triggerMode);
saveResult.setType(type); saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (StringUtils.isNotEmpty(result.getUserId())) { if (StringUtils.isNotEmpty(result.getUserId())) {
saveResult.setUserId(result.getUserId()); saveResult.setUserId(result.getUserId());
} else { } else {
@ -98,7 +102,6 @@ public class ApiDefinitionExecResultService {
String status = item.isSuccess() ? "success" : "error"; String status = item.isSuccess() ? "success" : "error";
saveResult.setName(getName(type, item.getName(), status, saveResult.getCreateTime(), saveResult.getId())); saveResult.setName(getName(type, item.getName(), status, saveResult.getCreateTime(), saveResult.getId()));
saveResult.setStatus(status); saveResult.setStatus(status);
saveResult.setCreateTime(item.getStartTime());
saveResult.setResourceId(item.getName()); saveResult.setResourceId(item.getName());
saveResult.setContent(JSON.toJSONString(item)); saveResult.setContent(JSON.toJSONString(item));
saveResult.setStartTime(item.getStartTime()); saveResult.setStartTime(item.getStartTime());
@ -108,23 +111,23 @@ public class ApiDefinitionExecResultService {
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type); ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
if (prevResult != null) { if (prevResult != null) {
prevResult.setContent(null); prevResult.setContent(null);
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult); apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
} }
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) { if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name()); saveResult.setTriggerMode(TriggerMode.MANUAL.name());
} }
if (!saved) { if (!saved) {
definitionExecResultMapper.insert(saveResult); apiDefinitionExecResultMapper.insert(saveResult);
} else { } else {
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult); apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
} }
apiDefinitionService.removeCache(result.getTestId());
// 发送通知 // 发送通知
sendNotice(saveResult); sendNotice(saveResult);
}); });
} }
}); });
sqlSession.flushStatements();
} }
} }
@ -284,7 +287,7 @@ public class ApiDefinitionExecResultService {
if (StringUtils.equals(type, ApiRunMode.SCHEDULE_API_PLAN.name())) { if (StringUtils.equals(type, ApiRunMode.SCHEDULE_API_PLAN.name())) {
TestPlanApiCase apiCase = testPlanApiCaseService.getById(item.getName()); TestPlanApiCase apiCase = testPlanApiCaseService.getById(item.getName());
if(StringUtils.isEmpty(creator)){ if (StringUtils.isEmpty(creator)) {
creator = testPlanService.findScheduleCreateUserById(apiCase.getTestPlanId()); creator = testPlanService.findScheduleCreateUserById(apiCase.getTestPlanId());
} }
apiCase.setStatus(status); apiCase.setStatus(status);
@ -299,7 +302,7 @@ public class ApiDefinitionExecResultService {
testPlanApiCaseService.setExecResult(item.getName(), status, item.getStartTime()); testPlanApiCaseService.setExecResult(item.getName(), status, item.getStartTime());
testCaseReviewApiCaseService.setExecResult(item.getName(), status, item.getStartTime()); testCaseReviewApiCaseService.setExecResult(item.getName(), status, item.getStartTime());
} }
if(creator == null){ if (creator == null) {
creator = ""; creator = "";
} }
saveResult.setUserId(creator); saveResult.setUserId(creator);

View File

@ -97,8 +97,6 @@ public class ApiDefinitionService {
@Resource @Resource
private ExtSwaggerUrlScheduleMapper extSwaggerUrlScheduleMapper; private ExtSwaggerUrlScheduleMapper extSwaggerUrlScheduleMapper;
@Resource @Resource
private ScheduleMapper scheduleMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper; private ApiTestCaseMapper apiTestCaseMapper;
@Resource @Resource
private ApiTestEnvironmentService environmentService; private ApiTestEnvironmentService environmentService;
@ -117,7 +115,7 @@ public class ApiDefinitionService {
@Resource @Resource
private ExtApiTestCaseMapper extApiTestCaseMapper; private ExtApiTestCaseMapper extApiTestCaseMapper;
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24); private static Cache cache = Cache.newHardMemoryCache(0, 3600);
private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>(); private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>(); private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -800,6 +798,12 @@ public class ApiDefinitionService {
return null; return null;
} }
public void removeCache(String testId) {
if (StringUtils.isNotEmpty(testId)) {
cache.remove(testId);
}
}
/** /**
* 获取存储执行结果报告 * 获取存储执行结果报告
* *

View File

@ -18,6 +18,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*; import io.metersphere.base.mapper.ext.*;
@ -494,7 +495,7 @@ public class ApiTestCaseService {
ExtTestPlanApiCaseMapper batchMapper = sqlSession.getMapper(ExtTestPlanApiCaseMapper.class); ExtTestPlanApiCaseMapper batchMapper = sqlSession.getMapper(ExtTestPlanApiCaseMapper.class);
Long nextOrder = ServiceUtils.getNextOrder(request.getPlanId(), extTestPlanApiCaseMapper::getLastOrder); Long nextOrder = ServiceUtils.getNextOrder(request.getPlanId(), extTestPlanApiCaseMapper::getLastOrder);
for (ApiTestCase apiTestCase: apiTestCases) { for (ApiTestCase apiTestCase : apiTestCases) {
TestPlanApiCase testPlanApiCase = new TestPlanApiCase(); TestPlanApiCase testPlanApiCase = new TestPlanApiCase();
testPlanApiCase.setId(UUID.randomUUID().toString()); testPlanApiCase.setId(UUID.randomUUID().toString());
testPlanApiCase.setCreateUser(SessionUtils.getUserId()); testPlanApiCase.setCreateUser(SessionUtils.getUserId());
@ -701,7 +702,7 @@ public class ApiTestCaseService {
public void batchRun(ApiCaseBatchRequest request) { public void batchRun(ApiCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(), ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiTestCaseMapper.selectIdsByQuery((ApiTestCaseRequest)query)); (query) -> extApiTestCaseMapper.selectIdsByQuery((ApiTestCaseRequest) query));
Map<String, ApiDefinitionExecResult> executeQueue = new HashMap<>(); Map<String, ApiDefinitionExecResult> executeQueue = new HashMap<>();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class); ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
@ -727,6 +728,7 @@ public class ApiTestCaseService {
runCaseRequest.setReportId(executeQueue.get(caseId).getId()); runCaseRequest.setReportId(executeQueue.get(caseId).getId());
runCaseRequest.setEnvironmentId(request.getEnvironmentId()); runCaseRequest.setEnvironmentId(request.getEnvironmentId());
run(runCaseRequest); run(runCaseRequest);
MessageCache.batchTestCases.put(executeQueue.get(caseId).getId(), executeQueue.get(caseId));
} }
} }
@ -1089,6 +1091,7 @@ public class ApiTestCaseService {
/** /**
* 用例自定义排序 * 用例自定义排序
*
* @param request * @param request
*/ */
public void updateOrder(ResetOrderRequest request) { public void updateOrder(ResetOrderRequest request) {

View File

@ -212,7 +212,7 @@ export default {
mockSetting() { mockSetting() {
let mockParam = {}; let mockParam = {};
mockParam.projectId = this.projectId; mockParam.projectId = this.projectId;
if(this.currentApi.id){ if (this.currentApi.id) {
mockParam.apiId = this.currentApi.id; mockParam.apiId = this.currentApi.id;
this.$post('/mockConfig/genMockConfig', mockParam, response => { this.$post('/mockConfig/genMockConfig', mockParam, response => {
let mockConfig = response.data; let mockConfig = response.data;
@ -283,6 +283,7 @@ export default {
this.api = this.$store.state.currentApiCase.api; this.api = this.$store.state.currentApiCase.api;
this.$refs.caseList.open(); this.$refs.caseList.open();
} }
this.$store.state.currentApiCase = {case: true};
} else if (tabType === "test") { } else if (tabType === "test") {
this.showApiList = false; this.showApiList = false;
this.showTestCaseList = false; this.showTestCaseList = false;

View File

@ -230,6 +230,7 @@ import {
getCustomTableHeader, getCustomTableHeader,
getCustomTableWidth, getCustomTableWidth,
getLastTableSortField, getLastTableSortField,
handleRowDrop
} from "@/common/js/tableUtils"; } from "@/common/js/tableUtils";
import {API_CASE_LIST} from "@/common/js/constants"; import {API_CASE_LIST} from "@/common/js/constants";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate"; import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
@ -361,6 +362,7 @@ export default {
environments: [], environments: [],
resVisible: false, resVisible: false,
response: {}, response: {},
timeoutIndex: 0,
}; };
}, },
props: { props: {
@ -526,6 +528,7 @@ export default {
this.$refs.caseTable.openCustomHeader(); this.$refs.caseTable.openCustomHeader();
}, },
initTable(id) { initTable(id) {
this.timeoutIndex = 0;
if (this.$refs.caseTable) { if (this.$refs.caseTable) {
this.$refs.caseTable.clearSelectRows(); this.$refs.caseTable.clearSelectRows();
} }
@ -603,6 +606,73 @@ export default {
isNext = true; isNext = true;
} }
}); });
this.$nextTick(() => {
if (this.$refs.caseTable) {
this.$refs.caseTable.clear();
}
handleRowDrop(this.tableData, (param) => {
param.groupId = this.condition.projectId;
editApiTestCaseOrder(param);
});
})
if (isNext) {
this.refreshStatus();
}
});
}
},
refreshStatus() {
if (this.apiDefinitionId) {
this.condition.apiDefinitionId = this.apiDefinitionId;
}
this.condition.status = "";
this.condition.moduleIds = this.selectNodeIds;
if (this.condition.filters && !this.condition.filters.status) {
this.$delete(this.condition.filters, 'status');
}
if (!this.selectAll) {
this.selectAll = false;
this.unSelection = [];
this.selectDataCounts = 0;
}
this.condition.projectId = this.projectId;
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
//
this.isSelectThissWeekData();
this.condition.selectThisWeedData = false;
this.condition.id = null;
if (this.selectDataRange == 'thisWeekCount') {
this.condition.selectThisWeedData = true;
} else if (this.selectDataRange != null) {
let selectParamArr = this.selectDataRange.split("single:");
if (selectParamArr.length === 2) {
this.condition.id = selectParamArr[1];
}
}
if (this.condition.projectId) {
this.result = this.$post('/api/testcase/list/' + this.currentPage + "/" + this.pageSize, this.condition, response => {
let isNext = false;
let tableData = response.data.listObject;
this.tableData.forEach(item => {
for (let i in tableData) {
if (item.id === tableData[i].id) {
item.status = tableData[i].status;
item.lastResultId = tableData[i].lastResultId;
}
}
if (item.status === 'Running') {
isNext = true;
}
});
if (isNext && this.$store.state.currentApiCase && this.$store.state.currentApiCase.case && this.timeoutIndex < 12) {
this.timeoutIndex++;
setTimeout(() => {
this.refreshStatus();
}, 12000);
}
}); });
} }
}, },