refactor: 优化接口覆盖率的统计算法

优化接口覆盖率的统计算法
This commit is contained in:
song-tianyang 2021-06-21 15:50:03 +08:00 committed by 刘瑞斌
parent 21a35e82b4
commit 2f310e9258
18 changed files with 338 additions and 75 deletions

View File

@ -283,11 +283,11 @@ public class APITestController {
* 接口覆盖率
* 复制的接口定义/复制或引用的单接口用例/ 添加的自定义请求 url 路径与现有的接口定义一致的请求
*/
List<ApiScenarioWithBLOBs> allScenarioInfoList = apiAutomationService.selectIdAndScenarioByProjectId(projectId);
List<ApiScenarioWithBLOBs> allScenarioInfoList = apiAutomationService.selectIdAndUseUrlByProjectId(projectId);
List<ApiDefinition> allEffectiveApiIdList = apiDefinitionService.selectEffectiveIdByProjectId(projectId);
List<ApiTestCase> allEffectiveApiCaseList = apiTestCaseService.selectEffectiveTestCaseByProjectId(projectId);
// List<ApiTestCase> allEffectiveApiCaseList = apiTestCaseService.selectEffectiveTestCaseByProjectId(projectId);
try {
float intetfaceCoverageRageNumber = apiAutomationService.countInterfaceCoverage(allScenarioInfoList, allEffectiveApiIdList, allEffectiveApiCaseList);
float intetfaceCoverageRageNumber = apiAutomationService.countInterfaceCoverage(allScenarioInfoList, allEffectiveApiIdList);
DecimalFormat df = new DecimalFormat("0.0");
returnStr = df.format(intetfaceCoverageRageNumber) + "%";
}catch (Exception e){

View File

@ -0,0 +1,30 @@
package io.metersphere.api.dto.datacount;
import java.util.Objects;
/**
* @author song.tianyang
* @Date 2021/6/21 4:15 下午
*/
public class ApiMethodUrlDTO {
public String url;
public String method;
public ApiMethodUrlDTO(String url, String method) {
this.url = url == null ? "" : url;
this.method = method == null ? "" : method;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApiMethodUrlDTO that = (ApiMethodUrlDTO) o;
return url.equals(that.url) && method.equals(that.method);
}
@Override
public int hashCode() {
return Objects.hash(url, method);
}
}

View File

@ -13,6 +13,7 @@ import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.automation.parse.ScenarioImport;
import io.metersphere.api.dto.automation.parse.ScenarioImportParserFactory;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.datacount.ApiMethodUrlDTO;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.*;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
@ -104,8 +105,6 @@ public class ApiAutomationService {
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
@Resource
@Lazy
private TestPlanScenarioCaseService testPlanScenarioCaseService;
@Resource
@ -244,6 +243,8 @@ public class ApiAutomationService {
scenario.setCreateTime(System.currentTimeMillis());
scenario.setNum(getNextNum(request.getProjectId()));
List<ApiMethodUrlDTO> useUrl = this.parseUrl(scenario);
scenario.setUseUrl(JSONArray.toJSONString(useUrl));
//检查场景的请求步骤如果含有ESB请求步骤的话要做参数计算处理
esbApiParamService.checkScenarioRequests(request);
@ -319,6 +320,8 @@ public class ApiAutomationService {
final ApiScenarioWithBLOBs scenario = buildSaveScenario(request);
deleteUpdateBodyFile(scenario);
List<ApiMethodUrlDTO> useUrl = this.parseUrl(scenario);
scenario.setUseUrl(JSONArray.toJSONString(useUrl));
apiScenarioMapper.updateByPrimaryKeySelective(scenario);
extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name同步到修改首页定时任务
uploadFiles(request, bodyFiles, scenarioFiles);
@ -1414,8 +1417,8 @@ public class ApiAutomationService {
return extApiScenarioMapper.countByProjectID(projectId);
}
public List<ApiScenarioWithBLOBs> selectIdAndScenarioByProjectId(String projectId) {
return extApiScenarioMapper.selectIdAndScenarioByProjectId(projectId);
public List<ApiScenarioWithBLOBs> selectIdAndUseUrlByProjectId(String projectId) {
return extApiScenarioMapper.selectIdAndUseUrlByProjectId(projectId);
}
public long countScenarioByProjectIDAndCreatInThisWeek(String projectId) {
@ -1498,6 +1501,7 @@ public class ApiAutomationService {
return apiScenarioMapper.selectByExampleWithBLOBs(example);
}
public void createSchedule(ScheduleRequest request) {
Schedule schedule = scheduleService.buildApiTestSchedule(request);
ApiScenarioWithBLOBs apiScene = apiScenarioMapper.selectByPrimaryKey(request.getResourceId());
@ -1789,13 +1793,13 @@ public class ApiAutomationService {
* 2.场景中引用/复制的案例
* 3.场景中的自定义路径与接口定义中的匹配
*
* 匹配场景中用到的路径
*
* @param allScenarioInfoList 场景集合id / scenario大字段 必须有数据
* @param allEffectiveApiList 接口集合id / path 必须有数据
* @param allEffectiveApiCaseList 案例集合(id /api_definition_id 必须有数据)
* @return
*/
public float countInterfaceCoverage(List<ApiScenarioWithBLOBs> allScenarioInfoList, List<ApiDefinition> allEffectiveApiList, List<ApiTestCase> allEffectiveApiCaseList) {
// float coverageRageNumber = (float) apiCountResult.getExecutionPassCount() * 100 / allCount;
public float countInterfaceCoverage(List<ApiScenarioWithBLOBs> allScenarioInfoList, List<ApiDefinition> allEffectiveApiList) {
float intetfaceCoverage = 0;
if (allEffectiveApiList == null || allEffectiveApiList.isEmpty()) {
return 100;
@ -1803,58 +1807,47 @@ public class ApiAutomationService {
/**
* 前置工作
* 1将接口集合转化数据结构: map<url,List<id>> urlMap 用来做3的筛选
* 2将案例集合转化数据结构map<testCase.id,List<testCase.apiId>> caseIdMap 用来做2的筛选
* 3将接口集合转化数据结构: List<id> allApiIdList 用来做1的筛选
* 1将接口集合转化数据结构: map<method,Map<url,List<id>>> urlMap 用来做筛选
* 4自定义List<api.id> coveragedIdList 已覆盖的id集合 最终计算公式是 coveragedIdList/allApiIdList在
*
* 解析allScenarioList的scenarioDefinition字段
* 1提取每个步骤的url urlMap筛选
* 2提取每个步骤的id. 在caseIdMap allApiIdList
*/
Map<String, List<String>> urlMap = new HashMap<>();
List<String> allApiIdList = new ArrayList<>();
Map<String, List<String>> caseIdMap = new HashMap<>();
Map<ApiMethodUrlDTO,List<String>> urlMap = new HashMap<>();
for (ApiDefinition model : allEffectiveApiList) {
String url = model.getPath();
String method = model.getMethod();
String id = model.getId();
allApiIdList.add(id);
if (urlMap.containsKey(url)) {
urlMap.get(url).add(id);
} else {
ApiMethodUrlDTO dto = new ApiMethodUrlDTO(url,method);
if(urlMap.containsKey(dto)){
urlMap.get(dto).add(id);
}else{
List<String> list = new ArrayList<>();
list.add(id);
urlMap.put(url, list);
}
}
for (ApiTestCase model : allEffectiveApiCaseList) {
String caseId = model.getId();
String apiId = model.getApiDefinitionId();
if (urlMap.containsKey(caseId)) {
urlMap.get(caseId).add(apiId);
} else {
List<String> list = new ArrayList<>();
list.add(apiId);
urlMap.put(caseId, list);
urlMap.put(dto,list);
}
}
if (allApiIdList.isEmpty()) {
if (urlMap.isEmpty()) {
return 100;
}
List<String> urlList = new ArrayList<>();
List<String> idList = new ArrayList<>();
List<ApiMethodUrlDTO> urlList = new ArrayList<>();
for (ApiScenarioWithBLOBs model : allScenarioInfoList) {
String scenarioDefiniton = model.getScenarioDefinition();
this.addUrlAndIdToList(scenarioDefiniton, urlList, idList);
List<ApiMethodUrlDTO> useUrl = this.getScenarioUseUrl(model);
if(CollectionUtils.isNotEmpty(useUrl)){
for (ApiMethodUrlDTO dto :useUrl) {
if(!urlList.contains(dto)){
urlList.add(dto);
}
}
}
useUrl = null;
}
List<String> containsApiIdList = new ArrayList<>();
for (String url : urlList) {
List<String> apiIdList = urlMap.get(url);
for (ApiMethodUrlDTO urlDTO : urlList) {
List<String> apiIdList = urlMap.get(urlDTO);
if (apiIdList != null) {
for (String api : apiIdList) {
if (!containsApiIdList.contains(api)) {
@ -1864,27 +1857,102 @@ public class ApiAutomationService {
}
}
for (String id : idList) {
List<String> apiIdList = caseIdMap.get(id);
if (apiIdList != null) {
for (String api : apiIdList) {
if (!containsApiIdList.contains(api)) {
containsApiIdList.add(api);
}
}
}
if (allApiIdList.contains(id)) {
if (!containsApiIdList.contains(id)) {
containsApiIdList.add(id);
}
int allApiIdCount = 0;
for (List<String> allApiIdList:urlMap.values()){
if(CollectionUtils.isNotEmpty(allApiIdList)){
allApiIdCount += allApiIdList.size();
}
}
float coverageRageNumber = (float) containsApiIdList.size() * 100 / allApiIdList.size();
float coverageRageNumber = (float) containsApiIdList.size() * 100 / allApiIdCount;
return coverageRageNumber;
}
private List<ApiMethodUrlDTO> getScenarioUseUrl(ApiScenarioWithBLOBs model) {
List<ApiMethodUrlDTO> useUrlList = new ArrayList<>();
try {
useUrlList = JSONArray.parseArray(model.getUseUrl(),ApiMethodUrlDTO.class);
}catch (Exception e){
}
return useUrlList;
}
public List<ApiMethodUrlDTO> parseUrl(ApiScenarioWithBLOBs scenario) {
List<ApiMethodUrlDTO> urlList = new ArrayList<>();
try {
String scenarioDefiniton = scenario.getScenarioDefinition();
JSONObject scenarioObj = JSONObject.parseObject(scenarioDefiniton);
List<ApiMethodUrlDTO> stepUrlList = this.getMethodUrlDTOByHashTreeJsonObj(scenarioObj);
if(CollectionUtils.isNotEmpty(stepUrlList)){
Collection unionList = CollectionUtils.union(urlList,stepUrlList);
urlList = new ArrayList<>(unionList);
}
} catch (Exception e) {
e.printStackTrace();
}
return urlList;
}
private List<ApiMethodUrlDTO> getMethodUrlDTOByHashTreeJsonObj(JSONObject obj) {
List<ApiMethodUrlDTO> returnList = new ArrayList<>();
if (obj != null && obj.containsKey("hashTree")) {
JSONArray hashArr = obj.getJSONArray("hashTree");
for (int i = 0; i < hashArr.size(); i++) {
JSONObject elementObj = hashArr.getJSONObject(i);
if(elementObj == null){
continue;
}
if (elementObj.containsKey("url") && elementObj.containsKey("method")) {
String url = elementObj.getString("url");
String method = elementObj.getString("method");
ApiMethodUrlDTO dto = new ApiMethodUrlDTO(url,method);
if(!returnList.contains(dto)){
returnList.add(dto);
}
}
if (elementObj.containsKey("path") && elementObj.containsKey("method")) {
String path = elementObj.getString("path");
String method = elementObj.getString("method");
ApiMethodUrlDTO dto = new ApiMethodUrlDTO(path,method);
if(!returnList.contains(dto)){
returnList.add(dto);
}
}
if (elementObj.containsKey("id") && elementObj.containsKey("refType")) {
String refType = elementObj.getString("refType");
String id = elementObj.getString("id");
if(StringUtils.equals("CASE",refType)){
ApiDefinition apiDefinition = apiTestCaseService.findApiUrlAndMethodById(id);
if(apiDefinition != null){
ApiMethodUrlDTO dto = new ApiMethodUrlDTO(apiDefinition.getPath(),apiDefinition.getMethod());
if(!returnList.contains(dto)){
returnList.add(dto);
}
}
}else if(StringUtils.equals("API",refType)){
ApiDefinition apiDefinition = apiDefinitionService.selectUrlAndMethodById(id);
if(apiDefinition != null){
ApiMethodUrlDTO dto = new ApiMethodUrlDTO(apiDefinition.getPath(),apiDefinition.getMethod());
if(!returnList.contains(dto)){
returnList.add(dto);
}
}
}
}
List<ApiMethodUrlDTO> stepUrlList = this.getMethodUrlDTOByHashTreeJsonObj(elementObj);
if(CollectionUtils.isNotEmpty(stepUrlList)){
Collection unionList = CollectionUtils.union(returnList,stepUrlList);
returnList = new ArrayList<>(unionList);
}
}
}
return returnList;
}
private void addUrlAndIdToList(String scenarioDefiniton, List<String> urlList, List<String> idList) {
try {
JSONObject scenarioObj = JSONObject.parseObject(scenarioDefiniton);
@ -1910,6 +1978,8 @@ public class ApiAutomationService {
}
}
public ScenarioEnv getApiScenarioProjectId(String id) {
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(id);
ScenarioEnv scenarioEnv = new ScenarioEnv();
@ -2008,4 +2078,27 @@ public class ApiAutomationService {
}
return null;
}
public void checkApiScenarioUseUrl() {
List<String> noUrlScenarioIdList = extApiScenarioMapper.selectIdsByUseUrlIsNull();
for (String id : noUrlScenarioIdList) {
try{
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(id);
if(scenario.getUseUrl() == null){
List<ApiMethodUrlDTO> useUrl = this.parseUrl(scenario);
if(useUrl != null){
ApiScenarioWithBLOBs updateModel = new ApiScenarioWithBLOBs();
updateModel.setId(scenario.getId());
updateModel.setUseUrl(JSONArray.toJSONString(useUrl));
apiScenarioMapper.updateByPrimaryKeySelective(updateModel);
updateModel = null;
}
}
scenario = null;
}catch (Exception e){
e.printStackTrace();
}
}
}
}

View File

@ -1189,4 +1189,7 @@ public class ApiDefinitionService {
return null;
}
public ApiDefinition selectUrlAndMethodById(String id) {
return extApiDefinitionMapper.selectUrlAndMethodById(id);
}
}

View File

@ -757,4 +757,8 @@ public class ApiTestCaseService {
}
return null;
}
public ApiDefinition findApiUrlAndMethodById(String id) {
return extApiTestCaseMapper.findApiUrlAndMethodById(id);
}
}

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
import lombok.Data;
@Data
public class ApiScenario implements Serializable {
@ -50,5 +49,7 @@ public class ApiScenario implements Serializable {
private String createUser;
private Integer version;
private static final long serialVersionUID = 1L;
}

View File

@ -1603,6 +1603,66 @@ public class ApiScenarioExample {
addCriterion("create_user not between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andVersionIsNull() {
addCriterion("version is null");
return (Criteria) this;
}
public Criteria andVersionIsNotNull() {
addCriterion("version is not null");
return (Criteria) this;
}
public Criteria andVersionEqualTo(Integer value) {
addCriterion("version =", value, "version");
return (Criteria) this;
}
public Criteria andVersionNotEqualTo(Integer value) {
addCriterion("version <>", value, "version");
return (Criteria) this;
}
public Criteria andVersionGreaterThan(Integer value) {
addCriterion("version >", value, "version");
return (Criteria) this;
}
public Criteria andVersionGreaterThanOrEqualTo(Integer value) {
addCriterion("version >=", value, "version");
return (Criteria) this;
}
public Criteria andVersionLessThan(Integer value) {
addCriterion("version <", value, "version");
return (Criteria) this;
}
public Criteria andVersionLessThanOrEqualTo(Integer value) {
addCriterion("version <=", value, "version");
return (Criteria) this;
}
public Criteria andVersionIn(List<Integer> values) {
addCriterion("version in", values, "version");
return (Criteria) this;
}
public Criteria andVersionNotIn(List<Integer> values) {
addCriterion("version not in", values, "version");
return (Criteria) this;
}
public Criteria andVersionBetween(Integer value1, Integer value2) {
addCriterion("version between", value1, value2, "version");
return (Criteria) this;
}
public Criteria andVersionNotBetween(Integer value1, Integer value2) {
addCriterion("version not between", value1, value2, "version");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -13,5 +13,7 @@ public class ApiScenarioWithBLOBs extends ApiScenario implements Serializable {
private String description;
private String useUrl;
private static final long serialVersionUID = 1L;
}

View File

@ -24,10 +24,12 @@
<result column="original_state" jdbcType="VARCHAR" property="originalState" />
<result column="custom_num" jdbcType="VARCHAR" property="customNum" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="version" jdbcType="INTEGER" property="version" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioWithBLOBs">
<result column="scenario_definition" jdbcType="LONGVARCHAR" property="scenarioDefinition" />
<result column="description" jdbcType="LONGVARCHAR" property="description" />
<result column="use_url" jdbcType="LONGVARCHAR" property="useUrl" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -90,10 +92,11 @@
<sql id="Base_Column_List">
id, project_id, tags, user_id, api_scenario_module_id, module_path, `name`, `level`,
`status`, principal, step_total, follow_people, schedule, create_time, update_time,
pass_rate, last_result, report_id, num, original_state, custom_num, create_user
pass_rate, last_result, report_id, num, original_state, custom_num, create_user,
version
</sql>
<sql id="Blob_Column_List">
scenario_definition, description
scenario_definition, description, use_url
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioExample" resultMap="ResultMapWithBLOBs">
select
@ -151,8 +154,8 @@
schedule, create_time, update_time,
pass_rate, last_result, report_id,
num, original_state, custom_num,
create_user, scenario_definition, description
)
create_user, version, scenario_definition,
description, use_url)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{userId,jdbcType=VARCHAR}, #{apiScenarioModuleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{level,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
@ -160,8 +163,8 @@
#{schedule,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{num,jdbcType=INTEGER}, #{originalState,jdbcType=VARCHAR}, #{customNum,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR}, #{scenarioDefinition,jdbcType=LONGVARCHAR}, #{description,jdbcType=LONGVARCHAR}
)
#{createUser,jdbcType=VARCHAR}, #{version,jdbcType=INTEGER}, #{scenarioDefinition,jdbcType=LONGVARCHAR},
#{description,jdbcType=LONGVARCHAR}, #{useUrl,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioWithBLOBs">
insert into api_scenario
@ -232,12 +235,18 @@
<if test="createUser != null">
create_user,
</if>
<if test="version != null">
version,
</if>
<if test="scenarioDefinition != null">
scenario_definition,
</if>
<if test="description != null">
description,
</if>
<if test="useUrl != null">
use_url,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -306,12 +315,18 @@
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
<if test="version != null">
#{version,jdbcType=INTEGER},
</if>
<if test="scenarioDefinition != null">
#{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
<if test="useUrl != null">
#{useUrl,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiScenarioExample" resultType="java.lang.Long">
@ -389,12 +404,18 @@
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.version != null">
version = #{record.version,jdbcType=INTEGER},
</if>
<if test="record.scenarioDefinition != null">
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
<if test="record.useUrl != null">
use_url = #{record.useUrl,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -424,8 +445,10 @@
original_state = #{record.originalState,jdbcType=VARCHAR},
custom_num = #{record.customNum,jdbcType=VARCHAR},
create_user = #{record.createUser,jdbcType=VARCHAR},
version = #{record.version,jdbcType=INTEGER},
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}
description = #{record.description,jdbcType=LONGVARCHAR},
use_url = #{record.useUrl,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -453,7 +476,8 @@
num = #{record.num,jdbcType=INTEGER},
original_state = #{record.originalState,jdbcType=VARCHAR},
custom_num = #{record.customNum,jdbcType=VARCHAR},
create_user = #{record.createUser,jdbcType=VARCHAR}
create_user = #{record.createUser,jdbcType=VARCHAR},
version = #{record.version,jdbcType=INTEGER}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -524,12 +548,18 @@
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="version != null">
version = #{version,jdbcType=INTEGER},
</if>
<if test="scenarioDefinition != null">
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
<if test="useUrl != null">
use_url = #{useUrl,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -556,8 +586,10 @@
original_state = #{originalState,jdbcType=VARCHAR},
custom_num = #{customNum,jdbcType=VARCHAR},
create_user = #{createUser,jdbcType=VARCHAR},
version = #{version,jdbcType=INTEGER},
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
description = #{description,jdbcType=LONGVARCHAR}
description = #{description,jdbcType=LONGVARCHAR},
use_url = #{useUrl,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenario">
@ -582,7 +614,8 @@
num = #{num,jdbcType=INTEGER},
original_state = #{originalState,jdbcType=VARCHAR},
custom_num = #{customNum,jdbcType=VARCHAR},
create_user = #{createUser,jdbcType=VARCHAR}
create_user = #{createUser,jdbcType=VARCHAR},
version = #{version,jdbcType=INTEGER}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -51,4 +51,6 @@ public interface ExtApiDefinitionMapper {
List<ApiDefinitionResult> listByIds(@Param("ids") List<String> ids);
List<Map<String, Object>> moduleCountByCollection(@Param("request") ApiDefinitionRequest request);
ApiDefinition selectUrlAndMethodById(String id);
}

View File

@ -299,7 +299,9 @@
<select id="getNextNum" resultType="io.metersphere.base.domain.ApiDefinition">
SELECT * FROM api_definition WHERE api_definition.project_id = #{projectId} ORDER BY num DESC LIMIT 1;
</select>
<select id="selectUrlAndMethodById" resultType="io.metersphere.base.domain.ApiDefinition">
SELECT method,path FROM api_definition WHERE id = #{0}
</select>
<select id="listRelevance" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
select
<include refid="io.metersphere.base.mapper.ApiDefinitionMapper.Base_Column_List"/>
@ -482,7 +484,7 @@
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="selectEffectiveIdByProjectId" resultType="io.metersphere.base.domain.ApiDefinition">
select id,path
select id,path,method
from api_definition
WHERE project_id = #{0} AND status != 'Trash' AND protocol = 'HTTP'
</select>

View File

@ -36,6 +36,8 @@ public interface ExtApiScenarioMapper {
List<ApiScenarioWithBLOBs> selectIdAndScenarioByProjectId(String projectId);
List<ApiScenarioWithBLOBs> selectIdAndUseUrlByProjectId(String projectId);
long countByProjectIDAndCreatInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp);
List<ApiDataCountResult> countRunResultByProjectID(String projectId);
@ -51,4 +53,6 @@ public interface ExtApiScenarioMapper {
List<ApiScenarioWithBLOBs> listWithIds(@Param("ids") List<String> ids);
List<Map<String, Object>> listModuleByCollection(@Param("request") ApiScenarioRequest request);
List<String> selectIdsByUseUrlIsNull();
}

View File

@ -341,6 +341,9 @@
<select id="selectIdAndScenarioByProjectId" resultType="io.metersphere.base.domain.ApiScenarioWithBLOBs">
SELECT id,scenario_definition FROM api_scenario WHERE project_id = #{0} AND status != 'Trash'
</select>
<select id="selectIdAndUseUrlByProjectId" resultType="io.metersphere.base.domain.ApiScenarioWithBLOBs">
SELECT id,use_url FROM api_scenario WHERE project_id = #{0} AND status != 'Trash'
</select>
<select id="countByProjectIDAndCreatInThisWeek" resultType="java.lang.Long">
SELECT count(id) AS countNumber FROM api_scenario
WHERE project_id = #{projectId} AND status != 'Trash'
@ -387,6 +390,11 @@
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="selectIdsByUseUrlIsNull" resultType="java.lang.String">
select id
from api_scenario
WHERE use_url IS NULL
</select>
<sql id="queryWhereConditionReview">
<where>
<if test="request.combine != null">

View File

@ -5,6 +5,7 @@ import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseInfo;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.ApiTestCaseResult;
import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiTestCase;
import org.apache.ibatis.annotations.Param;
@ -35,4 +36,6 @@ public interface ExtApiTestCaseMapper {
List<String> idSimple(@Param("request") ApiTestCaseRequest request);
List<ApiTestCaseInfo> getCaseInfo(@Param("request") ApiTestCaseRequest request);
ApiDefinition findApiUrlAndMethodById(String id);
}

View File

@ -442,6 +442,11 @@
WHERE testCase.project_id = #{0} AND apiDef.status != "Trash"
GROUP BY apiDef.protocol
</select>
<select id="findApiUrlAndMethodById" resultType="io.metersphere.base.domain.ApiDefinition">
SELECT method,path FROM api_definition WHERE id IN (
SELECT api_definition_id FROM api_test_case WHERE id = #{0}
)
</select>
<select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long">
SELECT count(testCase.id) AS countNumber FROM api_test_case testCase

View File

@ -99,7 +99,9 @@
join project p on p.id = ug.source_id
<where>
g.type = 'PROJECT' and ug.user_id = #{proRequest.userId}
and p.workspace_id = #{proRequest.workspaceId}
<if test="proRequest.workspaceId != null and proRequest.workspaceId != ''">
and p.workspace_id = #{proRequest.workspaceId}
</if>
<if test="proRequest.name != null and proRequest.name != ''">
and p.name like #{proRequest.name, jdbcType=VARCHAR}
</if>

View File

@ -2,6 +2,7 @@ package io.metersphere.listener;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.NewDriverManager;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.JarConfig;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.service.JarConfigService;
@ -25,6 +26,8 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
private JMeterService jMeterService;
@Resource
private JarConfigService jarConfigService;
@Resource
private ApiAutomationService apiAutomationService;
@Value("${jmeter.home}")
private String jmeterHome;
@ -39,6 +42,8 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
initPythonEnv();
checkApiScenarioUseUrl();
try {
Thread.sleep(1 * 60 * 1000);
} catch (InterruptedException e) {
@ -48,6 +53,10 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
scheduleService.startEnableSchedules();
}
private void checkApiScenarioUseUrl() {
apiAutomationService.checkApiScenarioUseUrl();
}
/**
* 解决接口测试-无法导入内置python包
*/

View File

@ -3,4 +3,6 @@ ALTER TABLE test_plan
ADD automatic_status_update TINYINT(1) DEFAULT 0 NULL COMMENT '是否自定更新功能用例状态';
-- 添加当前评论所属用例状态
alter table test_case_comment
add status varchar(80) null;
add status varchar(80) null;
-- 添加使用到的url功能
ALTER TABLE api_scenario ADD use_url LONGTEXT DEFAULT NULL COMMENT '步骤中用到的url';