refactor(接口测试): 优化场景步骤加载逻辑

Signed-off-by: fit2-zhao <yong.zhao@fit2cloud.com>
This commit is contained in:
fit2-zhao 2023-07-03 15:57:21 +08:00 committed by 刘瑞斌
parent af5de2521d
commit d3423a1b9a
4 changed files with 128 additions and 129 deletions

View File

@ -64,6 +64,8 @@ public interface ExtApiDefinitionMapper {
int countByIds(@Param("ids") List<String> ids);
List<ApiDefinitionResult> selectApiByIds(@Param("ids") List<String> ids);
long countByExample(ApiDefinitionExample example);
void clearLatestVersion(String refId);

View File

@ -348,6 +348,19 @@
</if>
</select>
<select id="selectApiByIds" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
select api_definition.id, api_definition.project_id, api_definition.num,
api_definition.name, api_definition.version_id, api_definition.latest,
project_version.name as version_name, api_definition.ref_id, user.name as user_name
from api_definition
left join user on api_definition.user_id = user.id
LEFT JOIN project_version ON project_version.id = api_definition.version_id
where api_definition.id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="weekList" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
select api_definition.id, api_definition.project_id, api_definition.num,
api_definition.tags,api_definition.original_state,

View File

@ -5,11 +5,8 @@ import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.ApiTestCaseInfo;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.Project;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.commons.constants.CommonConstants;
@ -23,6 +20,7 @@ import io.metersphere.service.definition.ApiDefinitionService;
import io.metersphere.service.definition.ApiTestCaseService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
@ -39,18 +37,16 @@ public class MsHashTreeService {
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private BaseProjectApplicationService baseProjectApplicationService;
@Resource
private ProjectMapper projectMapper;
public static final String CASE = CommonConstants.CASE;
public static final String API = "API";
public static final String REFERENCED = "referenced";
public static final String REF = "REF";
public static final String COPY = "Copy";
@ -86,7 +82,6 @@ public class MsHashTreeService {
public static final String CUSTOM_NUM = "customNum";
public static final String SHOW_CUSTOM_NUM = "showCustomNum";
public static final String VERSION_ID = "versionId";
public static final String RESOURCE_ID = ElementConstants.RESOURCE_ID;
private static final String CONNECT_TIMEOUT = "connectTimeout";
private static final String RESPONSE_TIMEOUT = "responseTimeout";
private static final String FOLLOW_REDIRECTS = "followRedirects";
@ -95,7 +90,7 @@ public class MsHashTreeService {
public static final String INDEX = "index";
private static final String QUERY = "query";
private static final String VARIABLE_NAMES = "variableNames";
private static final String DATASOURCEID = "dataSourceId";
private static final String DATA_SOURCE_ID = "dataSourceId";
private static final String RESULT_VARIABLE = "resultVariable";
private static final String ENV_Id = "environmentId";
@ -109,47 +104,6 @@ public class MsHashTreeService {
private final static String LABEL = "label";
private final static String SCENARIO_REF = "SCENARIO-REF-STEP";
public void setHashTree(JSONArray hashTree) {
// 将引用转成复制
if (hashTree == null) {
return;
}
for (int i = 0; i < hashTree.length(); i++) {
JSONObject object = (JSONObject) hashTree.opt(i);
String referenced = object.optString(REFERENCED);
if (StringUtils.isNotBlank(referenced) && StringUtils.equals(referenced, REF)) {
// 检测引用对象是否存在若果不存在则改成复制对象
String refType = object.optString(REF_TYPE);
if (StringUtils.isNotEmpty(refType)) {
if (refType.equals(CASE)) {
ApiTestCaseWithBLOBs bloBs = apiTestCaseService.get(object.optString(ID));
if (bloBs != null) {
object = JSONUtil.parseObject(bloBs.getRequest());
object.put(ID, bloBs.getId());
object.put(NAME, bloBs.getName());
hashTree.put(i, object);
}
} else {
ApiScenarioWithBLOBs bloBs = apiScenarioMapper.selectByPrimaryKey(object.optString(ID));
if (bloBs != null) {
object = JSONUtil.parseObject(bloBs.getScenarioDefinition());
hashTree.put(i, object);
}
}
} else if (SCENARIO.equals(object.optString(TYPE))) {
ApiScenarioWithBLOBs bloBs = apiScenarioMapper.selectByPrimaryKey(object.optString(ID));
if (bloBs != null) {
object = JSONUtil.parseObject(bloBs.getScenarioDefinition());
hashTree.put(i, object);
}
}
}
if (object != null && object.optJSONArray(HASH_TREE) != null) {
setHashTree(object.optJSONArray(HASH_TREE));
}
}
}
private void setElement(JSONObject element, Integer num,
Boolean enable, String versionName,
Boolean versionEnable, ParameterConfig msParameter) {
@ -162,69 +116,75 @@ public class MsHashTreeService {
}
}
private JSONObject setRequest(JSONObject element, Map<String, ApiTestCaseInfo> caseMap, ParameterConfig msParameter) {
private void handleCopyReference(ApiTestCaseInfo apiCase, JSONObject element) {
JSONObject refElement = JSONUtil.parseObject(apiCase.getRequest());
refElement.remove(INDEX);
ElementUtil.dataFormatting(refElement);
ElementUtil.copyBean(element, refElement);
element.put(HEADERS, refElement.opt(HEADERS));
element.put(REST, refElement.opt(REST));
element.put(PATH, refElement.opt(PATH));
element.put(BODY, refElement.opt(BODY));
element.put(ACTIVE, false);
element.put(AUTH_MANAGER, refElement.opt(AUTH_MANAGER));
element.put(ARGUMENTS, refElement.opt(ARGUMENTS));
element.put(PROJECT_ID, apiCase.getProjectId());
element.put(CONNECT_TIMEOUT, refElement.opt(CONNECT_TIMEOUT));
element.put(RESPONSE_TIMEOUT, refElement.opt(RESPONSE_TIMEOUT));
element.put(FOLLOW_REDIRECTS, refElement.opt(FOLLOW_REDIRECTS));
element.put(AUTO_REDIRECTS, refElement.opt(AUTO_REDIRECTS));
element.put(ALIAS, refElement.opt(ALIAS));
if (StringUtils.equals(refElement.optString(TYPE), ElementConstants.JDBC_SAMPLER)) {
element.put(QUERY, refElement.opt(QUERY));
element.put(VARIABLE_NAMES, refElement.opt(VARIABLE_NAMES));
element.put(DATA_SOURCE_ID, refElement.opt(DATA_SOURCE_ID));
element.put(RESULT_VARIABLE, refElement.opt(RESULT_VARIABLE));
element.put(ENV_Id, refElement.opt(ENV_Id));
}
JSONArray array = refElement.optJSONArray(HASH_TREE);
if (array != null) {
JSONArray sourceHashTree = element.optJSONArray(HASH_TREE);
Map<String, List<JSONObject>> groupMap = ElementUtil.group(sourceHashTree);
Map<String, List<JSONObject>> targetGroupMap = ElementUtil.group(refElement.optJSONArray(HASH_TREE));
List<JSONObject> pre = ElementUtil.mergeHashTree(groupMap.get(PRE), targetGroupMap.get(PRE));
List<JSONObject> post = ElementUtil.mergeHashTree(groupMap.get(POST), targetGroupMap.get(POST));
List<JSONObject> rules = mergeAssertions(groupMap.get(ASSERTIONS), targetGroupMap.get(ASSERTIONS));
List<JSONObject> step = new LinkedList<>();
if (CollectionUtils.isNotEmpty(pre)) {
step.addAll(pre);
}
if (CollectionUtils.isNotEmpty(post)) {
step.addAll(post);
}
if (CollectionUtils.isNotEmpty(rules)) {
step.addAll(rules);
}
element.put(HASH_TREE, step);
}
element.put(REFERENCED, REF);
element.put(DISABLED, true);
element.put(NAME, apiCase.getName());
}
private JSONObject setRequest(JSONObject element, Map<String, ApiTestCaseInfo> caseMap,
Map<String, ApiDefinitionResult> apiMap, ParameterConfig msParameter) {
boolean enable = element.optBoolean(ENABLE);
boolean isExist = false;
if (StringUtils.equalsIgnoreCase(element.optString(REF_TYPE), CASE)) {
ApiTestCaseInfo apiTestCase = caseMap.get(element.optString(ID));
if (apiTestCase != null) {
if (StringUtils.equalsIgnoreCase(element.optString(REF_TYPE), CASE) && MapUtils.isNotEmpty(caseMap)) {
ApiTestCaseInfo apiCase = caseMap.get(element.optString(ID));
if (apiCase != null) {
if (StringUtils.equalsIgnoreCase(element.optString(REFERENCED), REF)) {
JSONObject refElement = JSONUtil.parseObject(apiTestCase.getRequest());
refElement.remove(INDEX);
ElementUtil.dataFormatting(refElement);
JSONArray array = refElement.optJSONArray(HASH_TREE);
ElementUtil.copyBean(element, refElement);
element.put(HEADERS, refElement.opt(HEADERS));
element.put(REST, refElement.opt(REST));
element.put(PATH, refElement.opt(PATH));
element.put(BODY, refElement.opt(BODY));
element.put(ACTIVE, false);
element.put(AUTH_MANAGER, refElement.opt(AUTH_MANAGER));
element.put(ARGUMENTS, refElement.opt(ARGUMENTS));
element.put(PROJECT_ID, apiTestCase.getProjectId());
element.put(CONNECT_TIMEOUT, refElement.opt(CONNECT_TIMEOUT));
element.put(RESPONSE_TIMEOUT, refElement.opt(RESPONSE_TIMEOUT));
element.put(FOLLOW_REDIRECTS, refElement.opt(FOLLOW_REDIRECTS));
element.put(AUTO_REDIRECTS, refElement.opt(AUTO_REDIRECTS));
element.put(ALIAS, refElement.opt(ALIAS));
if (StringUtils.equals(refElement.optString(TYPE), "JDBCSampler")) {
element.put(QUERY, refElement.opt(QUERY));
element.put(VARIABLE_NAMES, refElement.opt(VARIABLE_NAMES));
element.put(DATASOURCEID, refElement.opt(DATASOURCEID));
element.put(RESULT_VARIABLE, refElement.opt(RESULT_VARIABLE));
element.put(ENV_Id, refElement.opt(ENV_Id));
}
if (array != null) {
JSONArray sourceHashTree = element.optJSONArray(HASH_TREE);
Map<String, List<JSONObject>> groupMap = ElementUtil.group(sourceHashTree);
Map<String, List<JSONObject>> targetGroupMap = ElementUtil.group(refElement.optJSONArray(HASH_TREE));
List<JSONObject> pre = ElementUtil.mergeHashTree(groupMap.get(PRE), targetGroupMap.get(PRE));
List<JSONObject> post = ElementUtil.mergeHashTree(groupMap.get(POST), targetGroupMap.get(POST));
List<JSONObject> rules = mergeAssertions(groupMap.get(ASSERTIONS), targetGroupMap.get(ASSERTIONS));
List<JSONObject> step = new LinkedList<>();
if (CollectionUtils.isNotEmpty(pre)) {
step.addAll(pre);
}
if (CollectionUtils.isNotEmpty(post)) {
step.addAll(post);
}
if (CollectionUtils.isNotEmpty(rules)) {
step.addAll(rules);
}
element.put(HASH_TREE, step);
}
element.put(REFERENCED, REF);
element.put(DISABLED, true);
element.put(NAME, apiTestCase.getName());
handleCopyReference(apiCase, element);
}
element.put(ID, apiTestCase.getId());
element.put(ID, apiCase.getId());
isExist = true;
this.setElement(element, apiTestCase.getNum(), enable, apiTestCase.getVersionName(), apiTestCase.getVersionEnable(), msParameter);
this.setElement(element, apiCase.getNum(), enable, apiCase.getVersionName(), apiCase.getVersionEnable(), msParameter);
}
} else if (StringUtils.equalsIgnoreCase(element.optString(REFERENCED), COPY)) {
ApiDefinitionResult definition = apiDefinitionService.getById(element.optString(ID));
} else if (StringUtils.equalsIgnoreCase(element.optString(REFERENCED), COPY) && MapUtils.isNotEmpty(apiMap)) {
ApiDefinitionResult definition = apiMap.get(element.optString(ID));
if (definition != null) {
Project project = projectMapper.selectByPrimaryKey(definition.getProjectId());
element.put(ID, definition.getId());
@ -306,8 +266,8 @@ public class MsHashTreeService {
target.put(type, jsonArray);
}
private void getCaseIds(JSONObject element, List<String> caseIds) {
if (StringUtils.equalsIgnoreCase(element.optString(REF_TYPE), CASE) && element.has(ID)) {
private void addCaseIds(JSONObject element, List<String> caseIds) {
if (StringUtils.equalsAnyIgnoreCase(element.optString(REF_TYPE), CASE, API) && element.has(ID)) {
caseIds.add(element.optString(ID));
}
}
@ -318,24 +278,24 @@ public class MsHashTreeService {
element.put(MIX_ENABLE, false);
}
ApiScenarioDTO scenarioWithBLOBs = extApiScenarioMapper.selectById(element.optString(ID));
if (scenarioWithBLOBs != null && StringUtils.isNotEmpty(scenarioWithBLOBs.getScenarioDefinition())) {
ApiScenarioDTO scenario = extApiScenarioMapper.selectById(element.optString(ID));
if (scenario != null && StringUtils.isNotEmpty(scenario.getScenarioDefinition())) {
boolean environmentEnable = element.has(ENV_ENABLE) ? element.optBoolean(ENV_ENABLE) : false;
boolean variableEnable = element.has(VARIABLE_ENABLE) ? element.optBoolean(VARIABLE_ENABLE) : false;
boolean mixEnable = element.has(MIX_ENABLE)
? element.getBoolean(MIX_ENABLE) : false;
if (environmentEnable && StringUtils.isNotEmpty(scenarioWithBLOBs.getEnvironmentJson())) {
element.put(ENV_MAP, JSON.parseObject(scenarioWithBLOBs.getEnvironmentJson(), Map.class));
if (environmentEnable && StringUtils.isNotEmpty(scenario.getEnvironmentJson())) {
element.put(ENV_MAP, JSON.parseObject(scenario.getEnvironmentJson(), Map.class));
}
if (StringUtils.equalsIgnoreCase(element.optString(REFERENCED), REF)) {
JSONObject object = JSONUtil.parseObject(scenarioWithBLOBs.getScenarioDefinition());
JSONObject object = JSONUtil.parseObject(scenario.getScenarioDefinition());
object.put(INDEX, element.optString(INDEX));
element = object;
element.put(REFERENCED, REF);
element.put(NAME, scenarioWithBLOBs.getName());
element.put(NAME, scenario.getName());
}
element.put(ID, scenarioWithBLOBs.getId());
element.put(ID, scenario.getId());
element.put(ENV_ENABLE, environmentEnable);
if (!element.has(VARIABLE_ENABLE)) {
element.put(VARIABLE_ENABLE, variableEnable);
@ -344,11 +304,13 @@ public class MsHashTreeService {
element.put(MIX_ENABLE, mixEnable);
}
//获取场景的当前项目是否开启了自定义id
ProjectConfig projectApplication = baseProjectApplicationService.getSpecificTypeValue(scenarioWithBLOBs.getProjectId(), "SCENARIO_CUSTOM_NUM");
element.put(SHOW_CUSTOM_NUM, projectApplication.getScenarioCustomNum());
element.put(CUSTOM_NUM, scenarioWithBLOBs.getCustomNum());
this.setElement(element, scenarioWithBLOBs.getNum(), enable,
scenarioWithBLOBs.getVersionName(), scenarioWithBLOBs.getVersionEnable(), null);
ProjectConfig project = baseProjectApplicationService.getSpecificTypeValue(scenario.getProjectId(), "SCENARIO_CUSTOM_NUM");
if (project != null) {
element.put(SHOW_CUSTOM_NUM, project.getScenarioCustomNum());
}
element.put(CUSTOM_NUM, scenario.getCustomNum());
this.setElement(element, scenario.getNum(), enable,
scenario.getVersionName(), scenario.getVersionEnable(), null);
} else {
if (StringUtils.equalsIgnoreCase(element.optString(REFERENCED), REF)) {
element.put(ENABLE, false);
@ -368,7 +330,7 @@ public class MsHashTreeService {
element = this.setRefScenario(element);
hashTree.put(i, element);
} else if (element != null && ElementConstants.REQUESTS.contains(element.optString(TYPE))) {
this.getCaseIds(element, caseIds);
this.addCaseIds(element, caseIds);
hashTree.put(i, element);
}
if (element.has(HASH_TREE)) {
@ -382,27 +344,30 @@ public class MsHashTreeService {
if (element == null) {
return;
}
if (StringUtils.equalsIgnoreCase(element.optString(TYPE), SCENARIO)) {
element = this.setRefScenario(element);
} else if (ElementConstants.REQUESTS.contains(element.optString(TYPE))) {
this.getCaseIds(element, caseIds);
this.addCaseIds(element, caseIds);
}
if (element.has(HASH_TREE)) {
JSONArray elementJSONArray = element.optJSONArray(HASH_TREE);
dataFormatting(elementJSONArray, caseIds);
}
}
public void caseFormatting(JSONArray hashTree, Map<String, ApiTestCaseInfo> caseMap, ParameterConfig msParameter) {
public void caseFormatting(JSONArray hashTree, Map<String, ApiTestCaseInfo> caseMap,
Map<String, ApiDefinitionResult> apiMap, ParameterConfig msParameter) {
for (int i = 0; i < hashTree.length(); i++) {
JSONObject element = hashTree.optJSONObject(i);
if (element != null && ElementConstants.REQUESTS.contains(element.optString(TYPE))) {
element = this.setRequest(element, caseMap, msParameter);
element = this.setRequest(element, caseMap, apiMap, msParameter);
hashTree.put(i, element);
}
if (element.has(HASH_TREE)) {
JSONArray elementJSONArray = element.optJSONArray(HASH_TREE);
caseFormatting(elementJSONArray, caseMap, msParameter);
caseFormatting(elementJSONArray, caseMap, apiMap, msParameter);
}
}
}
@ -411,12 +376,21 @@ public class MsHashTreeService {
List<ApiTestCaseInfo> caseInfos = apiTestCaseService.selectByCaseIds(caseIds);
Map<String, ApiTestCaseInfo> caseMap = caseInfos.stream()
.collect(Collectors.toMap(ApiTestCase::getId, a -> a, (k1, k2) -> k1));
caseIds = caseIds.stream()
.filter(n -> !caseMap.containsKey(n))
.collect(Collectors.toList());
// 接口
List<ApiDefinitionResult> apis = apiDefinitionService.getApiByIds(caseIds);
Map<String, ApiDefinitionResult> apiMap = apis.stream()
.collect(Collectors.toMap(ApiDefinitionResult::getId, a -> a, (k1, k2) -> k1));
if (element != null && ElementConstants.REQUESTS.contains(element.optString(TYPE))) {
element = this.setRequest(element, caseMap, msParameter);
element = this.setRequest(element, caseMap, apiMap, msParameter);
}
if (element != null && element.has(HASH_TREE)) {
JSONArray elementJSONArray = element.optJSONArray(HASH_TREE);
caseFormatting(elementJSONArray, caseMap, msParameter);
JSONArray array = element.optJSONArray(HASH_TREE);
caseFormatting(array, caseMap, apiMap, msParameter);
}
}
}

View File

@ -1153,6 +1153,7 @@ public class ApiDefinitionService {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
private void batchEditDefinitionTags(ApiBatchRequest request) {
if (request.getTagList().isEmpty()) {
return;
@ -1739,6 +1740,15 @@ public class ApiDefinitionService {
return result;
}
public List<ApiDefinitionResult> getApiByIds(List<String> ids) {
if(CollectionUtils.isNotEmpty(ids)) {
List<ApiDefinitionResult> list = extApiDefinitionMapper.selectApiByIds(ids);
buildCustomField(list);
return list;
}
return new ArrayList<>();
}
public Map<String, List<ApiDefinition>> countEffectiveByProjectId(String projectId, String versionId) {
if (StringUtils.isEmpty(projectId)) {
@ -1919,7 +1929,7 @@ public class ApiDefinitionService {
ApiFileUtil.copyBodyFiles(sourceId, api.getId());
List<CustomFieldResourceDTO> byResourceId = customFieldApiService.getByResourceId(sourceId);
if (CollectionUtils.isNotEmpty(byResourceId)){
if (CollectionUtils.isNotEmpty(byResourceId)) {
customFieldApiService.addFields(api.getId(), byResourceId);
}
mapper.insert(api);