fix(测试跟踪): 修复引用场景失败重试未执行问题
--bug=1024776 --user=王孝刚 【测试跟踪】测试计划-特定场景在执行测试计划时选择失败重试未执行重试执行 https://www.tapd.cn/55049933/s/1356728 Signed-off-by: fit2-zhao <yong.zhao@fit2cloud.com>
This commit is contained in:
parent
0691e1d226
commit
2a1bf7c906
|
@ -6,6 +6,7 @@ import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
|
|||
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsIfController;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsRetryLoopController;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsTransactionController;
|
||||
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
|
||||
import io.metersphere.api.dto.definition.request.extract.MsExtract;
|
||||
|
@ -1013,4 +1014,17 @@ public class ElementUtil {
|
|||
tree.add(headerManager);
|
||||
}
|
||||
}
|
||||
|
||||
public static HashTree retryHashTree(String name, long retryNum, HashTree tree) {
|
||||
if (StringUtils.isNotBlank(name) &&
|
||||
(name.startsWith(ResultParseUtil.POST_PROCESS_SCRIPT) ||
|
||||
name.startsWith(ResultParseUtil.PRE_PROCESS_SCRIPT))) {
|
||||
return tree;
|
||||
}
|
||||
MsRetryLoopController loopController = new MsRetryLoopController();
|
||||
loopController.setClazzName(MsRetryLoopController.class.getCanonicalName());
|
||||
loopController.setRetryNum(retryNum);
|
||||
loopController.setEnable(true);
|
||||
return loopController.controller(tree, name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ public class MsScenario extends MsTestElement {
|
|||
ParameterConfig newConfig = new ParameterConfig();
|
||||
if (this.isEnvironmentEnable()) {
|
||||
this.setNewConfig(envConfig, newConfig);
|
||||
newConfig.setRetryNum(config.getRetryNum());
|
||||
}
|
||||
if (config != null && StringUtils.equals(this.getId(), config.getScenarioId())) {
|
||||
config.setTransferVariables(this.variables);
|
||||
|
|
|
@ -71,7 +71,7 @@ public class ParameterConfig extends MsParameter {
|
|||
*/
|
||||
private boolean isOperating;
|
||||
/**
|
||||
* 导入/导出操作时取样器的testname值
|
||||
* 导入/导出操作时取样器的testName值
|
||||
*/
|
||||
private String operatingSampleTestName;
|
||||
/**
|
||||
|
@ -92,6 +92,10 @@ public class ParameterConfig extends MsParameter {
|
|||
|
||||
private String browserLanguage;
|
||||
private boolean isApi;
|
||||
/**
|
||||
* 失败重试次数
|
||||
*/
|
||||
private long retryNum;
|
||||
/**
|
||||
* 排除生成临界控制器的场景
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@ public class MsRetryLoopController extends MsTestElement {
|
|||
|
||||
@Override
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
|
||||
final HashTree groupTree = controller(tree);
|
||||
final HashTree groupTree = controller(tree, this.getName());
|
||||
|
||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
hashTree.forEach(el -> {
|
||||
|
@ -38,13 +38,13 @@ public class MsRetryLoopController extends MsTestElement {
|
|||
}
|
||||
}
|
||||
|
||||
private WhileController initWhileController(String condition) {
|
||||
private WhileController initWhileController(String condition, String name) {
|
||||
if (StringUtils.isEmpty(condition)) {
|
||||
return null;
|
||||
}
|
||||
WhileController controller = new WhileController();
|
||||
controller.setEnabled(this.isEnable());
|
||||
controller.setName("WhileController");
|
||||
controller.setName(StringUtils.join("RetryWhile_", name));
|
||||
controller.setProperty(TestElement.TEST_CLASS, WhileController.class.getName());
|
||||
controller.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("WhileControllerGui"));
|
||||
controller.setCondition(condition);
|
||||
|
@ -73,9 +73,9 @@ public class MsRetryLoopController extends MsTestElement {
|
|||
return script;
|
||||
}
|
||||
|
||||
private HashTree controller(HashTree tree) {
|
||||
public HashTree controller(HashTree tree, String name) {
|
||||
String whileCondition = "${__jexl3(" + "\"${" + ms_current_timer + "}\" !=\"stop\")}";
|
||||
HashTree hashTree = tree.add(initWhileController(whileCondition));
|
||||
HashTree hashTree = tree.add(initWhileController(whileCondition, name));
|
||||
// 添加超时处理,防止死循环
|
||||
JSR223Listener postProcessor = new JSR223Listener();
|
||||
postProcessor.setName("Retry-controller");
|
||||
|
|
|
@ -58,7 +58,14 @@ public class MsJSR223Processor extends MsTestElement {
|
|||
String resourceId = StringUtils.isNotEmpty(this.getId()) ? this.getId() : this.getResourceId();
|
||||
ElementUtil.setBaseParams(processor, this.getParent(), config, resourceId, this.getIndex());
|
||||
|
||||
final HashTree jsr223PreTree = tree.add(processor);
|
||||
// 失败重试
|
||||
HashTree jsr223PreTree;
|
||||
if (config.getRetryNum() > 0) {
|
||||
final HashTree loopTree = ElementUtil.retryHashTree(this.getName(), config.getRetryNum(), tree);
|
||||
jsr223PreTree = loopTree.add(processor);
|
||||
} else {
|
||||
jsr223PreTree = tree.add(processor);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
hashTree.forEach(el -> {
|
||||
el.toHashTree(jsr223PreTree, el.getHashTree(), config);
|
||||
|
|
|
@ -78,9 +78,14 @@ public class MsDubboSampler extends MsTestElement {
|
|||
}
|
||||
hashTree = this.getHashTree();
|
||||
}
|
||||
|
||||
final HashTree testPlanTree = tree.add(dubboSample(config));
|
||||
|
||||
// 失败重试
|
||||
HashTree testPlanTree;
|
||||
if (config.getRetryNum() > 0) {
|
||||
final HashTree loopTree = ElementUtil.retryHashTree(this.getName(), config.getRetryNum(), tree);
|
||||
testPlanTree = loopTree.add(dubboSample(config));
|
||||
} else {
|
||||
testPlanTree = tree.add(dubboSample(config));
|
||||
}
|
||||
//添加全局前后置脚本
|
||||
EnvironmentConfig envConfig = null;
|
||||
if (config.getConfig() != null) {
|
||||
|
|
|
@ -167,7 +167,14 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
}
|
||||
}
|
||||
}
|
||||
final HashTree httpSamplerTree = tree.add(sampler);
|
||||
// 失败重试
|
||||
HashTree httpSamplerTree;
|
||||
if (config.getRetryNum() > 0) {
|
||||
final HashTree loopTree = ElementUtil.retryHashTree(this.getName(), config.getRetryNum(), tree);
|
||||
httpSamplerTree = loopTree.add(sampler);
|
||||
} else {
|
||||
httpSamplerTree = tree.add(sampler);
|
||||
}
|
||||
// 注意顺序,放在config前面,会优先于环境的请求头生效
|
||||
if (httpConfig != null && httpConfig.isMock() && StringUtils.isNotEmpty(this.getId())) {
|
||||
//如果选择的是mock环境,则自动添加一个apiHeader。
|
||||
|
|
|
@ -114,7 +114,14 @@ public class MsJDBCSampler extends MsTestElement {
|
|||
MSException.throwException(StringUtils.isNotEmpty(this.getName()) ? this.getName() + ":" + message : message);
|
||||
}
|
||||
JDBCSampler jdbcSampler = jdbcSampler(config);
|
||||
final HashTree samplerHashTree = tree.add(jdbcSampler);
|
||||
// 失败重试
|
||||
HashTree samplerHashTree;
|
||||
if (config.getRetryNum() > 0) {
|
||||
final HashTree loopTree = ElementUtil.retryHashTree(this.getName(), config.getRetryNum(), tree);
|
||||
samplerHashTree = loopTree.add(jdbcSampler);
|
||||
} else {
|
||||
samplerHashTree = tree.add(jdbcSampler);
|
||||
}
|
||||
tree.add(ElementUtil.jdbcDataSource(jdbcSampler.getDataSource(), this.dataSource));
|
||||
ElementUtil.jdbcArguments(this.getName(), this.getVariables(), tree);
|
||||
|
||||
|
|
|
@ -140,7 +140,14 @@ public class MsTCPSampler extends MsTestElement {
|
|||
final HashTree samplerHashTree = new ListedHashTree();
|
||||
samplerHashTree.add(tcpConfig());
|
||||
TCPSampler tcpSampler = tcpSampler(config);
|
||||
tree.set(tcpSampler, samplerHashTree);
|
||||
// 失败重试
|
||||
if (config.getRetryNum() > 0) {
|
||||
final HashTree loopTree = ElementUtil.retryHashTree(this.getName(), config.getRetryNum(), tree);
|
||||
loopTree.set(tcpSampler, samplerHashTree);
|
||||
} else {
|
||||
tree.set(tcpSampler, samplerHashTree);
|
||||
}
|
||||
|
||||
setUserParameters(samplerHashTree);
|
||||
if (tcpPreProcessor != null && StringUtils.isNotBlank(tcpPreProcessor.getScript())) {
|
||||
samplerHashTree.add(tcpPreProcessor.getShellProcessor());
|
||||
|
|
|
@ -26,7 +26,6 @@ import io.metersphere.dto.JmeterRunRequestDTO;
|
|||
import io.metersphere.dto.ProjectJarConfig;
|
||||
import io.metersphere.environment.service.BaseEnvironmentService;
|
||||
import io.metersphere.plugin.core.MsTestElement;
|
||||
import io.metersphere.service.ApiRetryOnFailureService;
|
||||
import io.metersphere.service.RemakeReportService;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -54,8 +53,6 @@ public class ApiCaseSerialService {
|
|||
private RedisTemplate<String, Object> redisTemplate;
|
||||
@Resource
|
||||
private TestPlanApiCaseMapper testPlanApiCaseMapper;
|
||||
@Resource
|
||||
private ApiRetryOnFailureService apiRetryOnFailureService;
|
||||
|
||||
public void serial(DBTestQueue executionQueue) {
|
||||
ApiExecutionQueueDetail queue = executionQueue.getDetail();
|
||||
|
@ -148,21 +145,13 @@ public class ApiCaseSerialService {
|
|||
JSONObject element = JSONUtil.parseObject(caseWithBLOBs.getRequest());
|
||||
ElementUtil.dataFormatting(element);
|
||||
parse(element, testId, envId, caseWithBLOBs.getProjectId());
|
||||
String runData = element.toString();
|
||||
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
|
||||
try {
|
||||
// 失败重试
|
||||
String retryData = apiRetryOnFailureService.retry(runData, runRequest.getRetryNum(), true);
|
||||
if (StringUtils.isNotBlank(retryData)) {
|
||||
runData = retryData;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LoggerUtil.error("失败重试脚本生成失败 ", runRequest.getReportId(), e);
|
||||
}
|
||||
}
|
||||
group.getHashTree().add(JSONUtil.parseObject(runData, MsTestElement.class));
|
||||
group.getHashTree().add(JSONUtil.parseObject(element.toString(), MsTestElement.class));
|
||||
testPlan.getHashTree().add(group);
|
||||
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
|
||||
ParameterConfig config = new ParameterConfig();
|
||||
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
|
||||
config.setRetryNum(runRequest.getRetryNum());
|
||||
}
|
||||
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config);
|
||||
LoggerUtil.info("用例资源:" + caseWithBLOBs.getName() + ", 生成执行脚本JMX成功", runRequest.getReportId());
|
||||
return jmeterHashTree;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import io.metersphere.dto.*;
|
|||
import io.metersphere.environment.service.BaseEnvGroupProjectService;
|
||||
import io.metersphere.plugin.core.MsTestElement;
|
||||
import io.metersphere.service.ApiExecutionQueueService;
|
||||
import io.metersphere.service.ApiRetryOnFailureService;
|
||||
import io.metersphere.service.RemakeReportService;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import io.metersphere.vo.BooleanPool;
|
||||
|
@ -144,22 +143,7 @@ public class GenerateHashTreeUtil {
|
|||
Map<String, List<ProjectJarConfig>> jarsMap = NewDriverManager.getJars(projectIds, runRequest.getPool());
|
||||
testPlan.setProjectJarIds(jarsMap.keySet().stream().toList());
|
||||
testPlan.setPoolJarsMap(jarsMap);
|
||||
String data = definition;
|
||||
// 失败重试
|
||||
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
|
||||
try {
|
||||
ApiRetryOnFailureService apiRetryOnFailureService = CommonBeanFactory.getBean(ApiRetryOnFailureService.class);
|
||||
String retryData = apiRetryOnFailureService.retry(data, runRequest.getRetryNum(), false);
|
||||
if (StringUtils.isNotBlank(retryData)) {
|
||||
data = retryData;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LoggerUtil.error("失败重试脚本生成失败 ", runRequest.getReportId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
GenerateHashTreeUtil.parse(data, scenario);
|
||||
|
||||
GenerateHashTreeUtil.parse(definition, scenario);
|
||||
group.setEnableCookieShare(scenario.isEnableCookieShare());
|
||||
LinkedList<MsTestElement> scenarios = new LinkedList<>();
|
||||
scenarios.add(scenario);
|
||||
|
@ -170,6 +154,9 @@ public class GenerateHashTreeUtil {
|
|||
ParameterConfig config = new ParameterConfig();
|
||||
config.setScenarioId(item.getId());
|
||||
config.setReportType(runRequest.getReportType());
|
||||
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
|
||||
config.setRetryNum(runRequest.getRetryNum());
|
||||
}
|
||||
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config);
|
||||
|
||||
LoggerUtil.info("场景资源:" + item.getName() + ", 生成执行脚本JMX成功", runRequest.getReportId());
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
import io.metersphere.api.dto.definition.request.controller.MsRetryLoopController;
|
||||
import io.metersphere.commons.utils.JSONUtil;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.plugin.core.MsTestElement;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class ApiRetryOnFailureService {
|
||||
public final static List<String> requests = List.of(
|
||||
"HTTPSamplerProxy",
|
||||
"DubboSampler",
|
||||
"JDBCSampler",
|
||||
"TCPSampler",
|
||||
"JSR223Processor");
|
||||
|
||||
private final static String HASH_TREE_ELEMENT = "hashTree";
|
||||
private final static String TYPE = "type";
|
||||
private final static String RESOURCE_ID = "resourceId";
|
||||
private final static String RETRY = "MsRetry_";
|
||||
private final static String LOOP = "LoopController";
|
||||
|
||||
public String retry(String data, long retryNum, boolean isCase) {
|
||||
if (StringUtils.isNotEmpty(data)) {
|
||||
JSONObject element = JSONUtil.parseObject(data);
|
||||
if (element != null && isCase) {
|
||||
return formatSampler(element, retryNum).toString();
|
||||
}
|
||||
if (element != null && element.has(HASH_TREE_ELEMENT) && !StringUtils.equalsIgnoreCase(element.optString(TYPE), LOOP)) {
|
||||
JSONArray hashTree = element.getJSONArray(HASH_TREE_ELEMENT);
|
||||
setRetry(hashTree, retryNum);
|
||||
}
|
||||
return element.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MsTestElement retryParse(String data) {
|
||||
try {
|
||||
return JSONUtil.parseObject(data, MsRetryLoopController.class);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setRetry(JSONArray hashTree, long retryNum) {
|
||||
for (int i = 0; i < hashTree.length(); i++) {
|
||||
JSONObject element = hashTree.getJSONObject(i);
|
||||
if (StringUtils.equalsIgnoreCase(element.optString(TYPE), LOOP)) {
|
||||
continue;
|
||||
}
|
||||
JSONObject whileObj = formatSampler(element, retryNum);
|
||||
if (whileObj != null) {
|
||||
hashTree.put(i, whileObj);
|
||||
} else if (element.has(HASH_TREE_ELEMENT)) {
|
||||
JSONArray elementJSONArray = element.getJSONArray(HASH_TREE_ELEMENT);
|
||||
setRetry(elementJSONArray, retryNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject formatSampler(JSONObject element, long retryNum) {
|
||||
if (element.has(TYPE) && requests.contains(element.optString(TYPE))) {
|
||||
MsRetryLoopController loopController = new MsRetryLoopController();
|
||||
loopController.setClazzName(MsRetryLoopController.class.getCanonicalName());
|
||||
loopController.setName(RETRY + element.optString(RESOURCE_ID));
|
||||
loopController.setRetryNum(retryNum);
|
||||
loopController.setEnable(true);
|
||||
loopController.setResourceId(UUID.randomUUID().toString());
|
||||
|
||||
JSONObject whileObj = JSONUtil.parseObject(JSONUtil.toJSONString(loopController));
|
||||
JSONArray hashTree = new JSONArray();
|
||||
hashTree.put(element);
|
||||
|
||||
whileObj.put(HASH_TREE_ELEMENT, hashTree);
|
||||
return whileObj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue