feat(接口测试): 重新设计接口测试首页场景面板覆盖率的统计方法

--bug=1012386
--user=宋天阳
[接口测试]github#12735场景的接口覆盖率不能按照api_scenario_reference_id 的api
的id 统计
https://www.tapd.cn/55049933/s/1143296
This commit is contained in:
song-tianyang 2022-04-21 18:32:19 +08:00 committed by TIanyang
parent 49089649ba
commit 59728e02e0
15 changed files with 368 additions and 64 deletions

View File

@ -28,10 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import static io.metersphere.commons.utils.JsonPathUtils.getListJson; import static io.metersphere.commons.utils.JsonPathUtils.getListJson;
@ -294,10 +291,10 @@ public class APITestController {
* 接口覆盖率 * 接口覆盖率
* 复制的接口定义/复制或引用的单接口用例/ 添加的自定义请求 url 路径与现有的接口定义一致的请求 * 复制的接口定义/复制或引用的单接口用例/ 添加的自定义请求 url 路径与现有的接口定义一致的请求
*/ */
List<String> allScenarioIdList = apiAutomationService.selectIdsByProjectId(projectId); Map<String,List<String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId);
List<ApiDefinition> allEffectiveApiIdList = apiDefinitionService.selectEffectiveIdByProjectId(projectId); List<ApiDefinition> allEffectiveApiIdList = apiDefinitionService.selectEffectiveIdByProjectId(projectId);
try { try {
float intetfaceCoverageRageNumber = apiAutomationService.countInterfaceCoverage(allScenarioIdList, allEffectiveApiIdList); float intetfaceCoverageRageNumber = apiAutomationService.countInterfaceCoverage(scenarioUrlList, allEffectiveApiIdList);
DecimalFormat df = new DecimalFormat("0.0"); DecimalFormat df = new DecimalFormat("0.0");
returnStr = df.format(intetfaceCoverageRageNumber) + "%"; returnStr = df.format(intetfaceCoverageRageNumber) + "%";
}catch (Exception e){ }catch (Exception e){

View File

@ -772,4 +772,48 @@ public class MockApiUtils {
return false; return false;
} }
} }
public static boolean isUrlInList(String url,List<String> urlList){
if(CollectionUtils.isEmpty(urlList)){
return false;
}
String urlSuffix = url;
if(urlSuffix.startsWith("/")){
urlSuffix = urlSuffix.substring(1);
}
String[] urlParams = urlSuffix.split("/");
for (String path : urlList) {
if (StringUtils.equalsAny(path, url, "/" + url)) {
return true;
} else {
if (StringUtils.isEmpty(path)) {
continue;
}
if (path.startsWith("/")) {
path = path.substring(1);
}
if (StringUtils.isNotEmpty(path)) {
String[] pathArr = path.split("/");
if (pathArr.length == urlParams.length) {
boolean isFetch = true;
for (int i = 0; i < urlParams.length; i++) {
String pathItem = pathArr[i];
String urlItem = urlParams[i];
if (!(pathItem.startsWith("{") && pathItem.endsWith("}")) && !(urlItem.startsWith("{") && urlItem.endsWith("}"))) {
if (!StringUtils.equals(pathArr[i], urlParams[i])) {
isFetch = false;
break;
}
}
}
if (isFetch) {
return true;
}
}
}
}
}
return false;
}
} }

View File

@ -18,6 +18,7 @@ import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement;
import io.metersphere.api.exec.scenario.ApiScenarioEnvService; import io.metersphere.api.exec.scenario.ApiScenarioEnvService;
import io.metersphere.api.exec.scenario.ApiScenarioExecuteService; import io.metersphere.api.exec.scenario.ApiScenarioExecuteService;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil; import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.mock.utils.MockApiUtils;
import io.metersphere.api.parse.ApiImportParser; import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
@ -46,6 +47,7 @@ import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.request.testplan.FileOperationRequest; import io.metersphere.track.request.testplan.FileOperationRequest;
import io.metersphere.track.service.TestPlanScenarioCaseService; import io.metersphere.track.service.TestPlanScenarioCaseService;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -56,6 +58,7 @@ import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree; import org.apache.jorphan.collections.ListedHashTree;
import org.mybatis.spring.SqlSessionUtils; import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -515,7 +518,7 @@ public class ApiAutomationService {
apiScenarioFollowMapper.deleteByExample(example); apiScenarioFollowMapper.deleteByExample(example);
} }
public void preDelete(String scenarioId,String scenarioDefinition) { public void preDelete(String scenarioId, String scenarioDefinition) {
//删除引用 //删除引用
apiScenarioReferenceIdService.deleteByScenarioId(scenarioId); apiScenarioReferenceIdService.deleteByScenarioId(scenarioId);
@ -1552,8 +1555,8 @@ public class ApiAutomationService {
@Override @Override
public void run() { public void run() {
Thread.currentThread().setName("PRE_DELETE" + System.currentTimeMillis()); Thread.currentThread().setName("PRE_DELETE" + System.currentTimeMillis());
scenarioIdDefinitionMap.forEach((scenarioId,scenarioDefinition)->{ scenarioIdDefinitionMap.forEach((scenarioId, scenarioDefinition) -> {
preDelete(scenarioId,scenarioDefinition); preDelete(scenarioId, scenarioDefinition);
scheduleService.deleteByResourceId(scenarioId, ScheduleGroup.API_SCENARIO_TEST.name()); scheduleService.deleteByResourceId(scenarioId, ScheduleGroup.API_SCENARIO_TEST.name());
}); });
} }
@ -1569,23 +1572,22 @@ public class ApiAutomationService {
* <p> * <p>
* 匹配场景中用到的路径 * 匹配场景中用到的路径
* *
* @param scenarioIdList 场景集合id / scenario大字段 必须有数据 * @param scenarioUrlMap 场景使用到的url key:method
* @param allEffectiveApiList 接口集合id / path 必须有数据 * @param allEffectiveApiList 接口集合id / path 必须有数据
* @return * @return
*/ */
public float countInterfaceCoverage(List<String> scenarioIdList, List<ApiDefinition> allEffectiveApiList) { public float countInterfaceCoverage(Map<String, List<String>> scenarioUrlMap, List<ApiDefinition> allEffectiveApiList) {
if (CollectionUtils.isEmpty(scenarioIdList) || CollectionUtils.isEmpty(allEffectiveApiList)) { if (MapUtils.isEmpty(scenarioUrlMap) || CollectionUtils.isEmpty(allEffectiveApiList)) {
return 0; return 0;
} }
List<String> refIdList = apiScenarioReferenceIdService.findByScenarioIds(scenarioIdList);
int containsCount = 0; int containsCount = 0;
for (ApiDefinition model : allEffectiveApiList) { for (ApiDefinition model : allEffectiveApiList) {
if (refIdList.contains(model.getId())) { List<String> scenarioUrlList = scenarioUrlMap.get(model.getMethod());
boolean matchedUrl = MockApiUtils.isUrlInList(model.getPath(), scenarioUrlList);
if (matchedUrl) {
containsCount++; containsCount++;
} }
} }
float coverageRageNumber = (float) containsCount * 100 / allEffectiveApiList.size(); float coverageRageNumber = (float) containsCount * 100 / allEffectiveApiList.size();
return coverageRageNumber; return coverageRageNumber;
} }
@ -1689,11 +1691,22 @@ public class ApiAutomationService {
return null; return null;
} }
public void checkApiScenarioReferenceId() { @Async
List<ApiScenarioWithBLOBs> scenarioNoRefs = extApiScenarioMapper.selectByNoReferenceId(); public void resetApiScenarioReferenceId() {
for (ApiScenarioWithBLOBs model : scenarioNoRefs) { LogUtil.info("Reset apiScenarioReferenceId is start.");
apiScenarioReferenceIdService.saveApiAndScenarioRelation(model); List<ApiScenarioWithBLOBs> scenarios = extApiScenarioMapper.selectByStatusIsNotTrash();
Map<String, List<ApiScenarioWithBLOBs>> scenariosGroupByProjectId =
scenarios.stream().collect(Collectors.groupingBy(ApiScenarioWithBLOBs::getProjectId));
for (Map.Entry<String, List<ApiScenarioWithBLOBs>> entry : scenariosGroupByProjectId.entrySet()) {
String projectId = entry.getKey();
List<ApiScenarioWithBLOBs> list = entry.getValue();
try {
apiScenarioReferenceIdService.saveApiAndScenarioRelation(list);
} catch (Exception e) {
LogUtil.error("Reset scenario reference id error. Project_id:" + projectId + "; error :" + e.getMessage());
}
} }
LogUtil.info("Reset apiScenarioReferenceId is end.");
} }
public List<JmxInfoDTO> batchGenPerformanceTestJmx(ApiScenarioBatchRequest request) { public List<JmxInfoDTO> batchGenPerformanceTestJmx(ApiScenarioBatchRequest request) {
@ -2013,4 +2026,21 @@ public class ApiAutomationService {
} }
} }
} }
public Map<String, List<String>> selectScenarioUseUrlByProjectId(String projectId) {
List<ApiScenarioReferenceId> list = apiScenarioReferenceIdService.selectUrlByProjectId(projectId);
Map<String, List<String>> returnMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(list)) {
list.forEach(item -> {
if (returnMap.containsKey(item.getMethod())) {
returnMap.get(item.getMethod()).add(item.getUrl());
} else {
List<String> urlList = new ArrayList<>();
urlList.add(item.getUrl());
returnMap.put(item.getMethod(), urlList);
}
});
}
return returnMap;
}
} }

View File

@ -1705,14 +1705,12 @@ public class ApiDefinitionService {
} }
public List<ApiDefinitionWithBLOBs> preparedUrl(String projectId, String method, String baseUrlSuffix) { public List<ApiDefinitionWithBLOBs> preparedUrl(String projectId, String method, String baseUrlSuffix) {
if (StringUtils.isEmpty(baseUrlSuffix)) { if (StringUtils.isEmpty(baseUrlSuffix)) {
return new ArrayList<>(); return new ArrayList<>();
} else { } else {
ApiDefinitionExample example = new ApiDefinitionExample(); ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andMethodEqualTo(method).andProjectIdEqualTo(projectId).andStatusNotEqualTo("Trash").andProtocolEqualTo("HTTP"); example.createCriteria().andMethodEqualTo(method).andProjectIdEqualTo(projectId).andStatusNotEqualTo("Trash").andProtocolEqualTo("HTTP");
List<ApiDefinition> apiList = apiDefinitionMapper.selectByExample(example); List<ApiDefinition> apiList = apiDefinitionMapper.selectByExample(example);
List<String> apiIdList = new ArrayList<>(); List<String> apiIdList = new ArrayList<>();
boolean urlSuffixEndEmpty = false; boolean urlSuffixEndEmpty = false;
String urlSuffix = baseUrlSuffix; String urlSuffix = baseUrlSuffix;

View File

@ -63,11 +63,50 @@ public class ApiScenarioReferenceIdService {
return; return;
} }
this.deleteByScenarioId(scenario.getId()); this.deleteByScenarioId(scenario.getId());
List<ApiScenarioReferenceId> savedList = this.getApiAndScenarioRelation(scenario);
this.insertApiScenarioReferenceIds(savedList);
}
public void saveApiAndScenarioRelation(List<ApiScenarioWithBLOBs> scenarios) {
if (CollectionUtils.isNotEmpty(scenarios)) {
List<String> idList = new ArrayList<>(scenarios.size());
LinkedList<ApiScenarioReferenceId> savedList = new LinkedList<>();
scenarios.forEach(scenario -> {
if (StringUtils.isNotEmpty(scenario.getId())) {
idList.add(scenario.getId());
savedList.addAll(this.getApiAndScenarioRelation(scenario));
}
});
if (CollectionUtils.isNotEmpty(idList)) {
ApiScenarioReferenceIdExample example = new ApiScenarioReferenceIdExample();
example.createCriteria().andApiScenarioIdIn(idList);
apiScenarioReferenceIdMapper.deleteByExample(example);
}
this.insertApiScenarioReferenceIds(savedList);
}
}
public void insertApiScenarioReferenceIds(List<ApiScenarioReferenceId> list) {
if (CollectionUtils.isNotEmpty(list)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioReferenceIdMapper referenceIdMapper = sqlSession.getMapper(ApiScenarioReferenceIdMapper.class);
for (ApiScenarioReferenceId apiScenarioReferenceId : list) {
referenceIdMapper.insert(apiScenarioReferenceId);
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
public List<ApiScenarioReferenceId> getApiAndScenarioRelation(ApiScenarioWithBLOBs scenario) {
List<ApiScenarioReferenceId> returnList = new ArrayList<>();
Map<String, ApiScenarioReferenceId> referenceIdMap = new HashMap<>(); Map<String, ApiScenarioReferenceId> referenceIdMap = new HashMap<>();
if (StringUtils.isNotEmpty(scenario.getScenarioDefinition())) { if (StringUtils.isNotEmpty(scenario.getScenarioDefinition())) {
JSONObject jsonObject = JSONObject.parseObject(scenario.getScenarioDefinition(), Feature.DisableSpecialKeyDetect); JSONObject jsonObject = JSONObject.parseObject(scenario.getScenarioDefinition(), Feature.DisableSpecialKeyDetect);
if (!jsonObject.containsKey(MsHashTreeService.HASH_TREE)) { if (!jsonObject.containsKey(MsHashTreeService.HASH_TREE)) {
return; return returnList;
} }
JSONArray hashTree = jsonObject.getJSONArray(MsHashTreeService.HASH_TREE); JSONArray hashTree = jsonObject.getJSONArray(MsHashTreeService.HASH_TREE);
for (int index = 0; index < hashTree.size(); index++) { for (int index = 0; index < hashTree.size(); index++) {
@ -75,13 +114,28 @@ public class ApiScenarioReferenceIdService {
if (item == null) { if (item == null) {
continue; continue;
} }
if (item.containsKey(MsHashTreeService.ID) && item.containsKey(MsHashTreeService.REFERENCED)) { if (item.containsKey(MsHashTreeService.ID) && item.containsKey(MsHashTreeService.REFERENCED)) {
String url = null;
String method = null;
if (item.containsKey(MsHashTreeService.PATH) && StringUtils.isNotEmpty(MsHashTreeService.PATH)) {
url = item.getString(MsHashTreeService.PATH);
} else if (item.containsKey(MsHashTreeService.URL)) {
url = item.getString(MsHashTreeService.URL);
}
if (item.containsKey(MsHashTreeService.METHOD)) {
method = item.getString(MsHashTreeService.METHOD);
}
ApiScenarioReferenceId saveItem = new ApiScenarioReferenceId(); ApiScenarioReferenceId saveItem = new ApiScenarioReferenceId();
saveItem.setId(UUID.randomUUID().toString()); saveItem.setId(UUID.randomUUID().toString());
saveItem.setApiScenarioId(scenario.getId()); saveItem.setApiScenarioId(scenario.getId());
saveItem.setReferenceId(item.getString(MsHashTreeService.ID)); saveItem.setReferenceId(item.getString(MsHashTreeService.ID));
saveItem.setReferenceType(item.getString(MsHashTreeService.REFERENCED)); saveItem.setReferenceType(item.getString(MsHashTreeService.REFERENCED));
saveItem.setDataType(item.getString(MsHashTreeService.REF_TYPE)); saveItem.setDataType(item.getString(MsHashTreeService.REF_TYPE));
saveItem.setCreateTime(System.currentTimeMillis());
saveItem.setCreateUserId(SessionUtils.getUserId());
saveItem.setUrl(url);
saveItem.setMethod(method);
referenceIdMap.put(item.getString(MsHashTreeService.ID), saveItem); referenceIdMap.put(item.getString(MsHashTreeService.ID), saveItem);
} }
if (item.containsKey(MsHashTreeService.HASH_TREE)) { if (item.containsKey(MsHashTreeService.HASH_TREE)) {
@ -90,26 +144,16 @@ public class ApiScenarioReferenceIdService {
} }
} }
if (MapUtils.isNotEmpty(referenceIdMap)) { if (MapUtils.isNotEmpty(referenceIdMap)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); returnList.addAll(referenceIdMap.values());
ApiScenarioReferenceIdMapper referenceIdMapper = sqlSession.getMapper(ApiScenarioReferenceIdMapper.class);
for (ApiScenarioReferenceId apiScenarioReferenceId : referenceIdMap.values()) {
apiScenarioReferenceId.setCreateTime(System.currentTimeMillis());
apiScenarioReferenceId.setCreateUserId(SessionUtils.getUserId());
referenceIdMapper.insert(apiScenarioReferenceId);
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
} else { } else {
ApiScenarioReferenceId saveItem = new ApiScenarioReferenceId(); ApiScenarioReferenceId saveItem = new ApiScenarioReferenceId();
saveItem.setId(UUID.randomUUID().toString()); saveItem.setId(UUID.randomUUID().toString());
saveItem.setApiScenarioId(scenario.getId()); saveItem.setApiScenarioId(scenario.getId());
saveItem.setCreateTime(System.currentTimeMillis()); saveItem.setCreateTime(System.currentTimeMillis());
saveItem.setCreateUserId(SessionUtils.getUserId()); saveItem.setCreateUserId(SessionUtils.getUserId());
apiScenarioReferenceIdMapper.insert(saveItem); returnList.add(saveItem);
} }
return returnList;
} }
public Map<String, ApiScenarioReferenceId> deepElementRelation(String scenarioId, JSONArray hashTree) { public Map<String, ApiScenarioReferenceId> deepElementRelation(String scenarioId, JSONArray hashTree) {
@ -118,12 +162,26 @@ public class ApiScenarioReferenceIdService {
for (int index = 0; index < hashTree.size(); index++) { for (int index = 0; index < hashTree.size(); index++) {
JSONObject item = hashTree.getJSONObject(index); JSONObject item = hashTree.getJSONObject(index);
if (item.containsKey(MsHashTreeService.ID) && item.containsKey(MsHashTreeService.REFERENCED)) { if (item.containsKey(MsHashTreeService.ID) && item.containsKey(MsHashTreeService.REFERENCED)) {
String method = null;
String url = null;
if (item.containsKey(MsHashTreeService.PATH) && StringUtils.isNotEmpty(MsHashTreeService.PATH)) {
url = item.getString(MsHashTreeService.PATH);
} else if (item.containsKey(MsHashTreeService.URL)) {
url = item.getString(MsHashTreeService.URL);
}
if (item.containsKey(MsHashTreeService.METHOD)) {
method = item.getString(MsHashTreeService.METHOD);
}
ApiScenarioReferenceId saveItem = new ApiScenarioReferenceId(); ApiScenarioReferenceId saveItem = new ApiScenarioReferenceId();
saveItem.setId(UUID.randomUUID().toString()); saveItem.setId(UUID.randomUUID().toString());
saveItem.setApiScenarioId(scenarioId); saveItem.setApiScenarioId(scenarioId);
saveItem.setReferenceId(item.getString(MsHashTreeService.ID)); saveItem.setReferenceId(item.getString(MsHashTreeService.ID));
saveItem.setReferenceType(item.getString(MsHashTreeService.REFERENCED)); saveItem.setReferenceType(item.getString(MsHashTreeService.REFERENCED));
saveItem.setDataType(item.getString(MsHashTreeService.REF_TYPE)); saveItem.setDataType(item.getString(MsHashTreeService.REF_TYPE));
saveItem.setCreateTime(System.currentTimeMillis());
saveItem.setCreateUserId(SessionUtils.getUserId());
saveItem.setMethod(method);
saveItem.setUrl(url);
deepRelations.put(item.getString(MsHashTreeService.ID), saveItem); deepRelations.put(item.getString(MsHashTreeService.ID), saveItem);
} }
if (item.containsKey(MsHashTreeService.HASH_TREE)) { if (item.containsKey(MsHashTreeService.HASH_TREE)) {
@ -144,11 +202,7 @@ public class ApiScenarioReferenceIdService {
} }
} }
public List<String> findByScenarioIds(List<String> scenarioIdList) { public List<ApiScenarioReferenceId> selectUrlByProjectId(String projectId) {
if(CollectionUtils.isEmpty(scenarioIdList)){ return extApiScenarioReferenceIdMapper.selectUrlByProjectId(projectId);
return new ArrayList<>();
}else {
return extApiScenarioReferenceIdMapper.selectRefIdsFromScenarioIds(scenarioIdList);
}
} }
} }

View File

@ -19,5 +19,9 @@ public class ApiScenarioReferenceId implements Serializable {
private String dataType; private String dataType;
private String url;
private String method;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -583,6 +583,146 @@ public class ApiScenarioReferenceIdExample {
addCriterion("data_type not between", value1, value2, "dataType"); addCriterion("data_type not between", value1, value2, "dataType");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andUrlIsNull() {
addCriterion("url is null");
return (Criteria) this;
}
public Criteria andUrlIsNotNull() {
addCriterion("url is not null");
return (Criteria) this;
}
public Criteria andUrlEqualTo(String value) {
addCriterion("url =", value, "url");
return (Criteria) this;
}
public Criteria andUrlNotEqualTo(String value) {
addCriterion("url <>", value, "url");
return (Criteria) this;
}
public Criteria andUrlGreaterThan(String value) {
addCriterion("url >", value, "url");
return (Criteria) this;
}
public Criteria andUrlGreaterThanOrEqualTo(String value) {
addCriterion("url >=", value, "url");
return (Criteria) this;
}
public Criteria andUrlLessThan(String value) {
addCriterion("url <", value, "url");
return (Criteria) this;
}
public Criteria andUrlLessThanOrEqualTo(String value) {
addCriterion("url <=", value, "url");
return (Criteria) this;
}
public Criteria andUrlLike(String value) {
addCriterion("url like", value, "url");
return (Criteria) this;
}
public Criteria andUrlNotLike(String value) {
addCriterion("url not like", value, "url");
return (Criteria) this;
}
public Criteria andUrlIn(List<String> values) {
addCriterion("url in", values, "url");
return (Criteria) this;
}
public Criteria andUrlNotIn(List<String> values) {
addCriterion("url not in", values, "url");
return (Criteria) this;
}
public Criteria andUrlBetween(String value1, String value2) {
addCriterion("url between", value1, value2, "url");
return (Criteria) this;
}
public Criteria andUrlNotBetween(String value1, String value2) {
addCriterion("url not between", value1, value2, "url");
return (Criteria) this;
}
public Criteria andMethodIsNull() {
addCriterion("`method` is null");
return (Criteria) this;
}
public Criteria andMethodIsNotNull() {
addCriterion("`method` is not null");
return (Criteria) this;
}
public Criteria andMethodEqualTo(String value) {
addCriterion("`method` =", value, "method");
return (Criteria) this;
}
public Criteria andMethodNotEqualTo(String value) {
addCriterion("`method` <>", value, "method");
return (Criteria) this;
}
public Criteria andMethodGreaterThan(String value) {
addCriterion("`method` >", value, "method");
return (Criteria) this;
}
public Criteria andMethodGreaterThanOrEqualTo(String value) {
addCriterion("`method` >=", value, "method");
return (Criteria) this;
}
public Criteria andMethodLessThan(String value) {
addCriterion("`method` <", value, "method");
return (Criteria) this;
}
public Criteria andMethodLessThanOrEqualTo(String value) {
addCriterion("`method` <=", value, "method");
return (Criteria) this;
}
public Criteria andMethodLike(String value) {
addCriterion("`method` like", value, "method");
return (Criteria) this;
}
public Criteria andMethodNotLike(String value) {
addCriterion("`method` not like", value, "method");
return (Criteria) this;
}
public Criteria andMethodIn(List<String> values) {
addCriterion("`method` in", values, "method");
return (Criteria) this;
}
public Criteria andMethodNotIn(List<String> values) {
addCriterion("`method` not in", values, "method");
return (Criteria) this;
}
public Criteria andMethodBetween(String value1, String value2) {
addCriterion("`method` between", value1, value2, "method");
return (Criteria) this;
}
public Criteria andMethodNotBetween(String value1, String value2) {
addCriterion("`method` not between", value1, value2, "method");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -9,6 +9,8 @@
<result column="reference_id" jdbcType="VARCHAR" property="referenceId" /> <result column="reference_id" jdbcType="VARCHAR" property="referenceId" />
<result column="reference_type" jdbcType="VARCHAR" property="referenceType" /> <result column="reference_type" jdbcType="VARCHAR" property="referenceType" />
<result column="data_type" jdbcType="VARCHAR" property="dataType" /> <result column="data_type" jdbcType="VARCHAR" property="dataType" />
<result column="url" jdbcType="VARCHAR" property="url" />
<result column="method" jdbcType="VARCHAR" property="method" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@ -69,7 +71,8 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, api_scenario_id, create_time, create_user_id, reference_id, reference_type, data_type id, api_scenario_id, create_time, create_user_id, reference_id, reference_type, data_type,
url, `method`
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReferenceIdExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReferenceIdExample" resultMap="BaseResultMap">
select select
@ -104,10 +107,12 @@
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReferenceId"> <insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReferenceId">
insert into api_scenario_reference_id (id, api_scenario_id, create_time, insert into api_scenario_reference_id (id, api_scenario_id, create_time,
create_user_id, reference_id, reference_type, create_user_id, reference_id, reference_type,
data_type) data_type, url, `method`
)
values (#{id,jdbcType=VARCHAR}, #{apiScenarioId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, values (#{id,jdbcType=VARCHAR}, #{apiScenarioId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{createUserId,jdbcType=VARCHAR}, #{referenceId,jdbcType=VARCHAR}, #{referenceType,jdbcType=VARCHAR}, #{createUserId,jdbcType=VARCHAR}, #{referenceId,jdbcType=VARCHAR}, #{referenceType,jdbcType=VARCHAR},
#{dataType,jdbcType=VARCHAR}) #{dataType,jdbcType=VARCHAR}, #{url,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR}
)
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReferenceId"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReferenceId">
insert into api_scenario_reference_id insert into api_scenario_reference_id
@ -133,6 +138,12 @@
<if test="dataType != null"> <if test="dataType != null">
data_type, data_type,
</if> </if>
<if test="url != null">
url,
</if>
<if test="method != null">
`method`,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null"> <if test="id != null">
@ -156,6 +167,12 @@
<if test="dataType != null"> <if test="dataType != null">
#{dataType,jdbcType=VARCHAR}, #{dataType,jdbcType=VARCHAR},
</if> </if>
<if test="url != null">
#{url,jdbcType=VARCHAR},
</if>
<if test="method != null">
#{method,jdbcType=VARCHAR},
</if>
</trim> </trim>
</insert> </insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiScenarioReferenceIdExample" resultType="java.lang.Long"> <select id="countByExample" parameterType="io.metersphere.base.domain.ApiScenarioReferenceIdExample" resultType="java.lang.Long">
@ -188,6 +205,12 @@
<if test="record.dataType != null"> <if test="record.dataType != null">
data_type = #{record.dataType,jdbcType=VARCHAR}, data_type = #{record.dataType,jdbcType=VARCHAR},
</if> </if>
<if test="record.url != null">
url = #{record.url,jdbcType=VARCHAR},
</if>
<if test="record.method != null">
`method` = #{record.method,jdbcType=VARCHAR},
</if>
</set> </set>
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
@ -201,7 +224,9 @@
create_user_id = #{record.createUserId,jdbcType=VARCHAR}, create_user_id = #{record.createUserId,jdbcType=VARCHAR},
reference_id = #{record.referenceId,jdbcType=VARCHAR}, reference_id = #{record.referenceId,jdbcType=VARCHAR},
reference_type = #{record.referenceType,jdbcType=VARCHAR}, reference_type = #{record.referenceType,jdbcType=VARCHAR},
data_type = #{record.dataType,jdbcType=VARCHAR} data_type = #{record.dataType,jdbcType=VARCHAR},
url = #{record.url,jdbcType=VARCHAR},
`method` = #{record.method,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -227,6 +252,12 @@
<if test="dataType != null"> <if test="dataType != null">
data_type = #{dataType,jdbcType=VARCHAR}, data_type = #{dataType,jdbcType=VARCHAR},
</if> </if>
<if test="url != null">
url = #{url,jdbcType=VARCHAR},
</if>
<if test="method != null">
`method` = #{method,jdbcType=VARCHAR},
</if>
</set> </set>
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
@ -237,7 +268,9 @@
create_user_id = #{createUserId,jdbcType=VARCHAR}, create_user_id = #{createUserId,jdbcType=VARCHAR},
reference_id = #{referenceId,jdbcType=VARCHAR}, reference_id = #{referenceId,jdbcType=VARCHAR},
reference_type = #{referenceType,jdbcType=VARCHAR}, reference_type = #{referenceType,jdbcType=VARCHAR},
data_type = #{dataType,jdbcType=VARCHAR} data_type = #{dataType,jdbcType=VARCHAR},
url = #{url,jdbcType=VARCHAR},
`method` = #{method,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -88,4 +88,6 @@ public interface ExtApiScenarioMapper {
void addLatestVersion(String refId); void addLatestVersion(String refId);
List<String> selectRefIdsForVersionChange(@Param("versionId") String versionId, @Param("projectId") String projectId); List<String> selectRefIdsForVersionChange(@Param("versionId") String versionId, @Param("projectId") String projectId);
List<ApiScenarioWithBLOBs> selectByStatusIsNotTrash();
} }

View File

@ -713,4 +713,7 @@
</foreach> </foreach>
) )
</select> </select>
<select id="selectByStatusIsNotTrash" resultType="io.metersphere.base.domain.ApiScenarioWithBLOBs">
SELECT * FROM api_scenario WHERE `status` != 'Trash' AND project_id IN (SELECT id FROM project);
</select>
</mapper> </mapper>

View File

@ -1,9 +1,10 @@
package io.metersphere.base.mapper.ext; package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.ApiScenarioReferenceId;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
public interface ExtApiScenarioReferenceIdMapper { public interface ExtApiScenarioReferenceIdMapper {
List<String> selectRefIdsFromScenarioIds(@Param("ids") List<String> scenarioIds); List<ApiScenarioReferenceId> selectUrlByProjectId(String projectId);
} }

View File

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ext.ExtApiScenarioReferenceIdMapper"> <mapper namespace="io.metersphere.base.mapper.ext.ExtApiScenarioReferenceIdMapper">
<select id="selectRefIdsFromScenarioIds" resultType="java.lang.String"> <select id="selectUrlByProjectId" resultType="io.metersphere.base.domain.ApiScenarioReferenceId">
select reference_id from api_scenario_reference_id SELECT method,url from api_scenario_reference_id WHERE api_scenario_id in (
where api_scenario_id IN SELECT id from api_scenario WHERE project_id = #{0}
<foreach collection="ids" item="v" separator="," open="(" close=")"> ) AND url IS NOT NULL AND method IS NOT NULL;
#{v}
</foreach>
</select> </select>
</mapper> </mapper>

View File

@ -137,7 +137,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
} }
private void initOnceOperate() { private void initOnceOperate() {
initOnceOperate(apiAutomationService::checkApiScenarioReferenceId, "init.scenario.referenceId"); initOnceOperate(apiAutomationService::resetApiScenarioReferenceId, "init.scenario.referenceId.reset");
initOnceOperate(apiAutomationService::initExecuteTimes, "init.scenario.executeTimes"); initOnceOperate(apiAutomationService::initExecuteTimes, "init.scenario.executeTimes");
initOnceOperate(issuesService::syncThirdPartyIssues, "init.issue"); initOnceOperate(issuesService::syncThirdPartyIssues, "init.issue");
initOnceOperate(issuesService::issuesCount, "init.issueCount"); initOnceOperate(issuesService::issuesCount, "init.issueCount");

View File

@ -307,3 +307,10 @@ CREATE PROCEDURE schema_change_rela_two() BEGIN
END// END//
DELIMITER ; DELIMITER ;
CALL schema_change_rela_two(); CALL schema_change_rela_two();
-- 场景步骤引用表增加URL字段记录引用的api/case/自定义请求中的地址,用于计算覆盖率
ALTER TABLE api_scenario_reference_id ADD url VARCHAR(500) NULL;
ALTER TABLE api_scenario_reference_id ADD method VARCHAR(20);
ALTER TABLE `api_scenario_reference_id` ADD INDEX index_url ( `url`);
ALTER TABLE `api_scenario_reference_id` ADD INDEX index_method ( `method` );
ALTER TABLE `api_scenario` ADD INDEX index_project_id ( `project_id`);

View File

@ -184,14 +184,6 @@
:content="itemName" style="margin-left: 0px; margin-right: 2px"></ms-tag> :content="itemName" style="margin-left: 0px; margin-right: 2px"></ms-tag>
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column
prop="executionTimes"
:field="item"
:fields-width="fieldsWidth"
sortable
:label="$t('commons.execution_times')"
min-width="160px">
</ms-table-column>
<ms-table-column <ms-table-column
prop="testPlanTestCaseCount" prop="testPlanTestCaseCount"
:field="item" :field="item"