refactor(测试计划): 测试计划状态重构
This commit is contained in:
parent
54c102aad3
commit
01c7a365e0
|
@ -47,5 +47,10 @@ CALL UpdatePosForNoneGroup();
|
|||
DROP PROCEDURE IF EXISTS UpdatePosForNoneGroup;
|
||||
-- 清洗测试计划表的pos数据结束
|
||||
|
||||
-- 修改未归档测试计划的存储状态
|
||||
UPDATE test_plan
|
||||
SET status = 'NOT_ARCHIVED'
|
||||
WHERE status != 'ARCHIVED';
|
||||
|
||||
-- set innodb lock wait timeout to default
|
||||
SET SESSION innodb_lock_wait_timeout = DEFAULT;
|
|
@ -5,19 +5,21 @@ public class TestPlanConstants {
|
|||
public static final String TEST_PLAN_TYPE_PLAN = "TEST_PLAN";
|
||||
//测试计划类型-测试计划组
|
||||
public static final String TEST_PLAN_TYPE_GROUP = "GROUP";
|
||||
|
||||
//测试计划组默认ID
|
||||
public static final String TEST_PLAN_DEFAULT_GROUP_ID = "NONE";
|
||||
|
||||
//测试计划中相关的默认父ID
|
||||
public static final String DEFAULT_PARENT_ID = "NONE";
|
||||
|
||||
//测试计划状态-未开始
|
||||
public static final String TEST_PLAN_STATUS_PREPARED = "PREPARED";
|
||||
//测试计划状态-进行中
|
||||
public static final String TEST_PLAN_STATUS_UNDERWAY = "UNDERWAY";
|
||||
//测试计划状态-已完成
|
||||
public static final String TEST_PLAN_STATUS_COMPLETED = "COMPLETED";
|
||||
public static final String TEST_PLAN_STATUS_NOT_ARCHIVED = "NOT_ARCHIVED";
|
||||
//测试计划状态-已归档
|
||||
public static final String TEST_PLAN_STATUS_ARCHIVED = "ARCHIVED";
|
||||
|
||||
//测试计划对外展示状态-未开始
|
||||
public static final String TEST_PLAN_SHOW_STATUS_PREPARED = "PREPARED";
|
||||
//测试计划对外展示状态-进行中
|
||||
public static final String TEST_PLAN_SHOW_STATUS_UNDERWAY = "UNDERWAY";
|
||||
//测试计划对外展示状态-已完成
|
||||
public static final String TEST_PLAN_SHOW_STATUS_COMPLETED = "COMPLETED";
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ import io.metersphere.system.utils.SessionUtils;
|
|||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
@ -36,10 +36,10 @@ import java.util.List;
|
|||
@RequestMapping("/project/log")
|
||||
public class ProjectLogController {
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private SimpleUserService simpleUserService;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private OperationLogService operationLogService;
|
||||
|
||||
@GetMapping("/user/list/{projectId}")
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.metersphere.plan.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TestPlanGroupCountDTO {
|
||||
private String groupId;
|
||||
private long count;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package io.metersphere.plan.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TestPlanResourceExecResultDTO {
|
||||
private String testPlanId;
|
||||
private String execResult;
|
||||
private String testPlanGroupId;
|
||||
}
|
|
@ -26,6 +26,9 @@ public class TestPlanTableRequest extends BasePageRequest {
|
|||
@Schema(description = "通过Keyword过滤出的测试子计划的测试计划组id")
|
||||
private List<String> keywordFilterIds;
|
||||
|
||||
@Schema(description = "通过其他条件查询出来的,必须要包含的测试计划ID")
|
||||
private List<String> innerIds;
|
||||
|
||||
public String getSortString() {
|
||||
if (StringUtils.isEmpty(super.getSortString())) {
|
||||
return "t.update_time desc";
|
||||
|
|
|
@ -16,8 +16,6 @@ public class TestPlanResponse extends TestPlanStatisticsResponse {
|
|||
private long num;
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
@Schema(description = "状态")
|
||||
private String status;
|
||||
@Schema(description = "测试计划类型 测试计划/测试计划组")
|
||||
private String type;
|
||||
@Schema(description = "标签")
|
||||
|
|
|
@ -2,6 +2,8 @@ package io.metersphere.plan.dto.response;
|
|||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import io.metersphere.plan.serializer.CustomRateSerializer;
|
||||
import io.metersphere.plan.utils.RateCalculateUtils;
|
||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||
import io.metersphere.system.dto.request.schedule.BaseScheduleConfigRequest;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
@ -16,7 +18,8 @@ public class TestPlanStatisticsResponse {
|
|||
|
||||
@Schema(description = "测试计划ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "测试计划状态")
|
||||
private String status;
|
||||
@Schema(description = "测试计划通过阈值{0-100}")
|
||||
@JsonSerialize(using = CustomRateSerializer.class)
|
||||
private Double passThreshold;
|
||||
|
@ -33,31 +36,70 @@ public class TestPlanStatisticsResponse {
|
|||
* 执行进度中的用例数量统计
|
||||
*/
|
||||
@Schema(description = "成功用例数量")
|
||||
private Integer successCount = 0;
|
||||
private long successCount = 0;
|
||||
@Schema(description = "失败用例数量")
|
||||
private Integer errorCount = 0;
|
||||
private long errorCount = 0;
|
||||
@Schema(description = "误报用例数量")
|
||||
private Integer fakeErrorCount = 0;
|
||||
private long fakeErrorCount = 0;
|
||||
@Schema(description = "阻塞用例数量")
|
||||
private Integer blockCount = 0;
|
||||
private long blockCount = 0;
|
||||
@Schema(description = "未执行用例数量")
|
||||
private Integer pendingCount = 0;
|
||||
private long pendingCount = 0;
|
||||
|
||||
/**
|
||||
* 用例数中用例数量统计
|
||||
*/
|
||||
@Schema(description = "用例总数")
|
||||
private Integer caseTotal = 0;
|
||||
private long caseTotal = 0;
|
||||
@Schema(description = "功能用例数量")
|
||||
private Integer functionalCaseCount = 0;
|
||||
private long functionalCaseCount = 0;
|
||||
@Schema(description = "接口用例数量")
|
||||
private Integer apiCaseCount = 0;
|
||||
private long apiCaseCount = 0;
|
||||
@Schema(description = "接口场景数量")
|
||||
private Integer apiScenarioCount = 0;
|
||||
private long apiScenarioCount = 0;
|
||||
@Schema(description = "缺陷数量")
|
||||
private Integer bugCount = 0;
|
||||
private long bugCount = 0;
|
||||
@Schema(description = "定时任务配置")
|
||||
private BaseScheduleConfigRequest scheduleConfig;
|
||||
@Schema(description = "定时任务下一次执行时间")
|
||||
private Long nextTriggerTime;
|
||||
|
||||
/**
|
||||
* 计算测试计划状态
|
||||
* 未开始:执行进度0%
|
||||
* 进行中:执行进度不到100%
|
||||
* 已完成:执行进度100%
|
||||
*/
|
||||
public void calculateStatus() {
|
||||
if (this.successCount == 0 && errorCount == 0 && fakeErrorCount == 0 && blockCount == 0) {
|
||||
this.status = TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED;
|
||||
} else if (this.pendingCount == 0) {
|
||||
this.status = TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED;
|
||||
} else {
|
||||
this.status = TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
|
||||
}
|
||||
}
|
||||
|
||||
public void calculateCaseTotal() {
|
||||
this.caseTotal = this.functionalCaseCount + this.apiCaseCount + this.apiScenarioCount;
|
||||
}
|
||||
|
||||
public void calculatePassRate() {
|
||||
this.passRate = RateCalculateUtils.divWithPrecision(this.successCount, this.caseTotal, 2);
|
||||
}
|
||||
|
||||
public void calculateExecuteRate() {
|
||||
this.executeRate = RateCalculateUtils.divWithPrecision(this.successCount - this.pendingCount, this.caseTotal, 2);
|
||||
}
|
||||
|
||||
public void calculateAllNumber(TestPlanStatisticsResponse childResponse) {
|
||||
this.functionalCaseCount += childResponse.getFunctionalCaseCount();
|
||||
this.apiCaseCount += childResponse.getApiCaseCount();
|
||||
this.apiScenarioCount += childResponse.getApiScenarioCount();
|
||||
this.successCount += childResponse.getSuccessCount();
|
||||
this.errorCount += childResponse.getErrorCount();
|
||||
this.fakeErrorCount += childResponse.getFakeErrorCount();
|
||||
this.blockCount += childResponse.getBlockCount();
|
||||
this.pendingCount += childResponse.getPendingCount();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.metersphere.plan.mapper;
|
||||
|
||||
import io.metersphere.api.domain.ApiTestCase;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionDTO;
|
||||
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
|
||||
import io.metersphere.functional.dto.ProjectOptionDTO;
|
||||
|
@ -8,6 +7,7 @@ import io.metersphere.plan.domain.TestPlanApiCase;
|
|||
import io.metersphere.plan.dto.ApiCaseModuleDTO;
|
||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanApiCaseModuleRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanApiCaseRequest;
|
||||
|
@ -75,4 +75,5 @@ public interface ExtTestPlanApiCaseMapper {
|
|||
|
||||
List<TestPlanApiCase> getPlanApiCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
|
||||
|
||||
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
|
||||
}
|
||||
|
|
|
@ -717,4 +717,23 @@
|
|||
WHERE t.test_plan_id = #{request.testPlanId} AND atc.deleted = false
|
||||
<include refid="queryWhereConditionByBatchQueryRequest"/>
|
||||
</select>
|
||||
<select id="selectDistinctExecResult" resultType="io.metersphere.plan.dto.TestPlanResourceExecResultDTO">
|
||||
select distinct resource.test_plan_id AS testPlanId,
|
||||
CASE
|
||||
WHEN resource.last_exec_result = 'BLOCKED'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'FAKE_ERROR'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'ERROR'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'SUCCESS'
|
||||
THEN 'COMPLETED'
|
||||
ELSE 'PENDING'
|
||||
END AS execResult,
|
||||
test_plan.group_id AS testPlanGroupId
|
||||
from test_plan_api_case resource
|
||||
INNER JOIN test_plan ON test_plan.id = resource.test_plan_id
|
||||
where test_plan.project_id = #{projectId}
|
||||
AND test_plan.status != 'ARCHIVED'
|
||||
</select>
|
||||
</mapper>
|
|
@ -6,6 +6,7 @@ import io.metersphere.plan.domain.TestPlanApiScenario;
|
|||
import io.metersphere.plan.dto.ApiScenarioModuleDTO;
|
||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest;
|
||||
|
@ -69,4 +70,6 @@ public interface ExtTestPlanApiScenarioMapper {
|
|||
List<String> getIdsByReportIdAndCollectionId(@Param("testPlanReportId") String testPlanReportId, @Param("collectionId") String collectionId);
|
||||
|
||||
List<TestPlanApiScenario> getPlanScenarioCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
|
||||
|
||||
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
|
||||
}
|
||||
|
|
|
@ -485,6 +485,25 @@
|
|||
</foreach>
|
||||
AND a.deleted = false
|
||||
</select>
|
||||
<select id="selectDistinctExecResult" resultType="io.metersphere.plan.dto.TestPlanResourceExecResultDTO">
|
||||
select distinct resource.test_plan_id AS testPlanId,
|
||||
CASE
|
||||
WHEN resource.last_exec_result = 'BLOCKED'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'FAKE_ERROR'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'ERROR'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'SUCCESS'
|
||||
THEN 'COMPLETED'
|
||||
ELSE 'PENDING'
|
||||
END AS execResult,
|
||||
test_plan.group_id AS testPlanGroupId
|
||||
from test_plan_api_scenario resource
|
||||
INNER JOIN test_plan ON test_plan.id = resource.test_plan_id
|
||||
where test_plan.project_id = #{projectId}
|
||||
AND test_plan.status != 'ARCHIVED'
|
||||
</select>
|
||||
|
||||
|
||||
<update id="batchUpdateExecutor">
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.functional.dto.ProjectOptionDTO;
|
|||
import io.metersphere.plan.domain.TestPlanFunctionalCase;
|
||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanCaseModuleRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
|
||||
|
@ -67,4 +68,5 @@ public interface ExtTestPlanFunctionalCaseMapper {
|
|||
|
||||
List<TestPlanFunctionalCase> getPlanCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
|
||||
|
||||
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
|
||||
}
|
||||
|
|
|
@ -578,4 +578,23 @@
|
|||
GROUP BY
|
||||
test_plan_functional_case.test_plan_collection_id
|
||||
</select>
|
||||
<select id="selectDistinctExecResult" resultType="io.metersphere.plan.dto.TestPlanResourceExecResultDTO">
|
||||
select distinct resource.test_plan_id AS testPlanId,
|
||||
CASE
|
||||
WHEN resource.last_exec_result = 'BLOCKED'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'FAKE_ERROR'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'ERROR'
|
||||
THEN 'COMPLETED'
|
||||
WHEN resource.last_exec_result = 'SUCCESS'
|
||||
THEN 'COMPLETED'
|
||||
ELSE 'PENDING'
|
||||
END AS execResult,
|
||||
test_plan.group_id AS testPlanGroupId
|
||||
from test_plan_functional_case resource
|
||||
INNER JOIN test_plan ON test_plan.id = resource.test_plan_id
|
||||
where test_plan.project_id = #{projectId}
|
||||
AND test_plan.status != 'ARCHIVED'
|
||||
</select>
|
||||
</mapper>
|
|
@ -2,6 +2,7 @@ package io.metersphere.plan.mapper;
|
|||
|
||||
import io.metersphere.plan.domain.TestPlan;
|
||||
import io.metersphere.plan.dto.TestPlanExecuteHisDTO;
|
||||
import io.metersphere.plan.dto.TestPlanGroupCountDTO;
|
||||
import io.metersphere.plan.dto.TestPlanQueryConditions;
|
||||
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanExecuteHisPageRequest;
|
||||
|
@ -66,4 +67,8 @@ public interface ExtTestPlanMapper {
|
|||
List<TestPlanExecuteHisDTO> listHis(@Param("request")TestPlanExecuteHisPageRequest request);
|
||||
|
||||
List<String> selectGroupIdByKeyword(@Param("projectId") String projectId, @Param("keyword") String keyword);
|
||||
|
||||
List<TestPlanGroupCountDTO> countByGroupPlan(String projectId);
|
||||
|
||||
List<String> selectIdByProjectIdAndWithoutList(@Param("projectId") String projectId, @Param("withoutList") List<String> withoutList);
|
||||
}
|
||||
|
|
|
@ -106,6 +106,13 @@
|
|||
</if>
|
||||
)
|
||||
</if>
|
||||
<if test="request.innerIds != null and request.innerIds.size() > 0">
|
||||
and t.id in
|
||||
<foreach collection="request.innerIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
|
||||
<choose>
|
||||
<when test='request.searchMode == "AND"'>
|
||||
AND <include refid="queryCombine"/>
|
||||
|
@ -483,6 +490,27 @@
|
|||
or t.tags like concat('%', #{keyword}, '%')
|
||||
)
|
||||
</select>
|
||||
<select id="countByGroupPlan" resultType="io.metersphere.plan.dto.TestPlanGroupCountDTO">
|
||||
SELECT group_id AS groupId, count(id) AS count
|
||||
FROM test_plan
|
||||
WHERE project_id = #{0}
|
||||
AND status != 'ARCHIVED'
|
||||
AND group_id != 'NONE'
|
||||
GROUP BY group_id;
|
||||
</select>
|
||||
<select id="selectIdByProjectIdAndWithoutList" resultType="java.lang.String">
|
||||
SELECT id
|
||||
FROM test_plan
|
||||
WHERE project_id = #{projectId}
|
||||
AND status != 'ARCHIVED'
|
||||
AND group_id = 'NONE'
|
||||
<if test="withoutList != null and withoutList.size() != ''">
|
||||
AND id not in
|
||||
<foreach collection="withoutList" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<update id="batchUpdate">
|
||||
update test_plan
|
||||
|
|
|
@ -118,6 +118,10 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
|
|||
@Resource
|
||||
private ExtApiTestCaseMapper extApiTestCaseMapper;
|
||||
|
||||
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
|
||||
return extTestPlanApiCaseMapper.selectDistinctExecResult(projectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteBatchByTestPlanId(List<String> testPlanIdList) {
|
||||
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||
|
|
|
@ -112,6 +112,10 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
|
|||
@Resource
|
||||
private TestPlanConfigService testPlanConfigService;
|
||||
|
||||
@Override
|
||||
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
|
||||
return extTestPlanApiScenarioMapper.selectDistinctExecResult(projectId);
|
||||
}
|
||||
@Override
|
||||
public void deleteBatchByTestPlanId(List<String> testPlanIdList) {
|
||||
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package io.metersphere.plan.service;
|
||||
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.mapper.ExtTestPlanMapper;
|
||||
import io.metersphere.plan.mapper.TestPlanMapper;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.domain.TestPlanModuleExample;
|
||||
|
@ -12,6 +14,11 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class TestPlanBaseUtilsService {
|
||||
|
@ -40,4 +47,64 @@ public class TestPlanBaseUtilsService {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<String, Map<String, List<String>>> parseExecResult(List<TestPlanResourceExecResultDTO> execResults) {
|
||||
Map<String, Map<String, List<String>>> returnMap = new HashMap<>();
|
||||
for (TestPlanResourceExecResultDTO execResult : execResults) {
|
||||
String groupId = execResult.getTestPlanGroupId();
|
||||
String planId = execResult.getTestPlanId();
|
||||
|
||||
Map<String, List<String>> planMap;
|
||||
if (returnMap.containsKey(groupId)) {
|
||||
planMap = returnMap.get(groupId);
|
||||
List<String> resultList;
|
||||
if (planMap.containsKey(planId)) {
|
||||
resultList = planMap.get(planId);
|
||||
} else {
|
||||
resultList = new ArrayList<>();
|
||||
}
|
||||
resultList.add(execResult.getExecResult());
|
||||
planMap.put(planId, resultList);
|
||||
} else {
|
||||
planMap = new HashMap<>();
|
||||
List<String> resultList = new ArrayList<>();
|
||||
resultList.add(execResult.getExecResult());
|
||||
planMap.put(planId, resultList);
|
||||
}
|
||||
returnMap.put(groupId, planMap);
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
public String calculateTestPlanStatus(List<String> resultList) {
|
||||
//同时包含两种状态:进行中
|
||||
if (resultList.size() == 1) {
|
||||
if (resultList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED;
|
||||
} else
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED;
|
||||
} else {
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
|
||||
}
|
||||
}
|
||||
|
||||
public String calculateStatusByChildren(List<String> childStatus) {
|
||||
// 首先去重
|
||||
childStatus = childStatus.stream().distinct().toList();
|
||||
|
||||
/*
|
||||
1:全部都未开始 则为未开始
|
||||
2:全部都已完成 则为已完成
|
||||
3:包含进行中 则为进行中
|
||||
4:未开始+已完成:进行中
|
||||
*/
|
||||
if (childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
|
||||
} else if (childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED) && childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
|
||||
} else if (childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED;
|
||||
} else {
|
||||
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
|
|||
testPlan.setPos(testPlanGroupService.getNextOrder(targetId));
|
||||
testPlan.setActualEndTime(null);
|
||||
testPlan.setActualStartTime(null);
|
||||
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
|
||||
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
testPlanMapper.insert(testPlan);
|
||||
|
||||
//测试配置信息
|
||||
|
@ -286,7 +286,7 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
|
|||
testPlanGroup.setPos(testPlanGroupService.getNextOrder(originalGroup.getGroupId()));
|
||||
testPlanGroup.setActualEndTime(null);
|
||||
testPlanGroup.setActualStartTime(null);
|
||||
testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
|
||||
testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
testPlanMapper.insert(testPlanGroup);
|
||||
|
||||
//测试配置信息
|
||||
|
|
|
@ -5,6 +5,7 @@ import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
|||
import io.metersphere.bug.service.BugCommonService;
|
||||
import io.metersphere.plan.dto.TestPlanBugCaseDTO;
|
||||
import io.metersphere.plan.dto.TestPlanCollectionDTO;
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest;
|
||||
import io.metersphere.plan.dto.request.TestPlanBugPageRequest;
|
||||
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
|
||||
|
@ -62,6 +63,11 @@ public class TestPlanBugService extends TestPlanResourceService {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long getNextOrder(String testPlanId) {
|
||||
|
|
|
@ -137,6 +137,10 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
|
|||
@Resource
|
||||
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
|
||||
|
||||
@Override
|
||||
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
|
||||
return extTestPlanFunctionalCaseMapper.selectDistinctExecResult(projectId);
|
||||
}
|
||||
@Override
|
||||
public long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime) {
|
||||
List<TestPlanFunctionalCase> copyList = new ArrayList<>();
|
||||
|
|
|
@ -5,6 +5,8 @@ import com.github.pagehelper.PageHelper;
|
|||
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
||||
import io.metersphere.plan.domain.TestPlan;
|
||||
import io.metersphere.plan.domain.TestPlanExample;
|
||||
import io.metersphere.plan.dto.TestPlanGroupCountDTO;
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.dto.request.TestPlanTableRequest;
|
||||
import io.metersphere.plan.dto.response.TestPlanResponse;
|
||||
import io.metersphere.plan.mapper.ExtTestPlanMapper;
|
||||
|
@ -23,6 +25,8 @@ import jakarta.annotation.Resource;
|
|||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -43,6 +47,8 @@ public class TestPlanManagementService {
|
|||
@Resource
|
||||
private TestPlanStatisticsService testPlanStatisticsService;
|
||||
@Resource
|
||||
private TestPlanBaseUtilsService testPlanBaseUtilsService;
|
||||
@Resource
|
||||
private TestPlanMapper testPlanMapper;
|
||||
|
||||
public Map<String, Long> moduleCount(TestPlanTableRequest request) {
|
||||
|
@ -69,12 +75,13 @@ public class TestPlanManagementService {
|
|||
return PageUtils.setPageInfo(page, this.list(request));
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
private void initDefaultFilter(TestPlanTableRequest request) {
|
||||
if (request.getFilter() == null || !request.getFilter().containsKey("status")) {
|
||||
|
||||
List<String> defaultStatusList = new ArrayList<>();
|
||||
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
|
||||
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY);
|
||||
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
|
||||
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
if (request.getFilter() == null || !request.getFilter().containsKey("status")) {
|
||||
if (request.getFilter() == null) {
|
||||
request.setFilter(new HashMap<>() {{
|
||||
this.put("status", defaultStatusList);
|
||||
|
@ -82,6 +89,76 @@ public class TestPlanManagementService {
|
|||
} else {
|
||||
request.getFilter().put("status", defaultStatusList);
|
||||
}
|
||||
} else if (!request.getFilter().get("status").contains(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) {
|
||||
List<String> statusList = request.getFilter().get("status");
|
||||
request.getFilter().put("status", defaultStatusList);
|
||||
if (statusList.size() < 3) {
|
||||
List<String> innerIdList = new ArrayList<>();
|
||||
// 条件过滤
|
||||
Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
|
||||
// 将当前项目下未归档的测试计划结果查询出来,进行下列符合条件的筛选
|
||||
List<TestPlanResourceExecResultDTO> execResults = new ArrayList<>();
|
||||
beansOfType.forEach((k, v) -> execResults.addAll(v.selectDistinctExecResult(request.getProjectId())));
|
||||
Map<String, Map<String, List<String>>> testPlanExecMap = testPlanBaseUtilsService.parseExecResult(execResults);
|
||||
Map<String, Long> groupCountMap = extTestPlanMapper.countByGroupPlan(request.getProjectId())
|
||||
.stream().collect(Collectors.toMap(TestPlanGroupCountDTO::getGroupId, TestPlanGroupCountDTO::getCount));
|
||||
|
||||
List<String> completedTestPlanIds = new ArrayList<>();
|
||||
List<String> preparedTestPlanIds = new ArrayList<>();
|
||||
List<String> underwayTestPlanIds = new ArrayList<>();
|
||||
testPlanExecMap.forEach((groupId, planMap) -> {
|
||||
if (StringUtils.equalsIgnoreCase(groupId, TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
|
||||
planMap.forEach((planId, resultList) -> {
|
||||
String result = testPlanBaseUtilsService.calculateTestPlanStatus(resultList);
|
||||
if (StringUtils.equals(result, TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
|
||||
completedTestPlanIds.add(planId);
|
||||
} else if (StringUtils.equals(result, TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
|
||||
underwayTestPlanIds.add(planId);
|
||||
} else if (StringUtils.equals(result, TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
|
||||
preparedTestPlanIds.add(planId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
long itemPlanCount = groupCountMap.getOrDefault(groupId, 0L);
|
||||
List<String> itemStatusList = new ArrayList<>();
|
||||
if (itemPlanCount > planMap.size()) {
|
||||
// 存在未执行或者没有用例的测试计划。 此时这种测试计划的状态为未开始
|
||||
itemStatusList.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
|
||||
}
|
||||
planMap.forEach((planId, resultList) -> {
|
||||
itemStatusList.add(testPlanBaseUtilsService.calculateTestPlanStatus(resultList));
|
||||
});
|
||||
String groupStatus = testPlanBaseUtilsService.calculateStatusByChildren(itemStatusList);
|
||||
if (StringUtils.equals(groupStatus, TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
|
||||
completedTestPlanIds.add(groupId);
|
||||
} else if (StringUtils.equals(groupStatus, TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
|
||||
underwayTestPlanIds.add(groupId);
|
||||
} else if (StringUtils.equals(groupStatus, TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
|
||||
preparedTestPlanIds.add(groupId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
testPlanExecMap = null;
|
||||
if (statusList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
|
||||
// 已完成
|
||||
innerIdList.addAll(completedTestPlanIds);
|
||||
}
|
||||
|
||||
if (statusList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
|
||||
// 进行中
|
||||
innerIdList.addAll(underwayTestPlanIds);
|
||||
}
|
||||
if (statusList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
|
||||
// 未开始 有一些测试计划/计划组没有用例 / 测试计划, 在上面的计算中无法过滤。所以用排除法机型处理
|
||||
List<String> withoutList = new ArrayList<>();
|
||||
withoutList.addAll(completedTestPlanIds);
|
||||
withoutList.addAll(underwayTestPlanIds);
|
||||
innerIdList.addAll(extTestPlanMapper.selectIdByProjectIdAndWithoutList(request.getProjectId(), withoutList));
|
||||
withoutList = null;
|
||||
}
|
||||
request.setInnerIds(innerIdList);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(request.getKeyword())) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import io.metersphere.plan.domain.TestPlanCollectionExample;
|
|||
import io.metersphere.plan.dto.ModuleSelectDTO;
|
||||
import io.metersphere.plan.dto.TestPlanCollectionDTO;
|
||||
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
|
||||
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
|
||||
import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest;
|
||||
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
|
||||
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
|
||||
|
@ -65,6 +66,7 @@ public abstract class TestPlanResourceService extends TestPlanSortService {
|
|||
|
||||
public abstract long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime);
|
||||
|
||||
public abstract List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
|
||||
/**
|
||||
* 关联用例
|
||||
*
|
||||
|
@ -124,6 +126,4 @@ public abstract class TestPlanResourceService extends TestPlanSortService {
|
|||
AssociateCaseDTO associateCaseDTO = new AssociateCaseDTO(excludeIds, selectIds, moduleIds);
|
||||
return associateCaseDTO;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ public class TestPlanSendNoticeService {
|
|||
public TestPlanDTO sendAddNotice(TestPlanCreateRequest request) {
|
||||
TestPlanDTO dto = new TestPlanDTO();
|
||||
BeanUtils.copyBean(dto, request);
|
||||
dto.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
|
||||
dto.setStatus(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
|
||||
return dto;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.plan.dto.TestPlanExecuteHisDTO;
|
|||
import io.metersphere.plan.dto.request.*;
|
||||
import io.metersphere.plan.dto.response.TestPlanDetailResponse;
|
||||
import io.metersphere.plan.dto.response.TestPlanOperationResponse;
|
||||
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
|
||||
import io.metersphere.plan.enums.ExecuteMethod;
|
||||
import io.metersphere.plan.job.TestPlanScheduleJob;
|
||||
import io.metersphere.plan.mapper.*;
|
||||
|
@ -102,7 +103,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
|
||||
private static final int MAX_TAG_SIZE = 10;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private TestPlanReportService testPlanReportService;
|
||||
|
||||
/**
|
||||
|
@ -151,7 +152,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
createTestPlan.setUpdateUser(operator);
|
||||
createTestPlan.setCreateTime(operateTime);
|
||||
createTestPlan.setUpdateTime(operateTime);
|
||||
createTestPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
|
||||
createTestPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
|
||||
TestPlanConfig testPlanConfig = new TestPlanConfig();
|
||||
testPlanConfig.setTestPlanId(createTestPlan.getId());
|
||||
|
@ -395,18 +396,20 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
|
||||
/**
|
||||
* 测试计划归档
|
||||
*
|
||||
* @param id
|
||||
* @param userId
|
||||
*/
|
||||
public void archived(String id, String userId) {
|
||||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id);
|
||||
|
||||
if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
|
||||
//判断当前计划组下是否都已完成 (由于算法原因,只需要校验当前测试计划组即可)
|
||||
if (!this.isTestPlanCompleted(id)) {
|
||||
throw new MSException(Translator.get("test_plan.group.not_plan"));
|
||||
}
|
||||
//测试计划组归档
|
||||
updateGroupStatus(testPlan.getId(), userId);
|
||||
updateCompletedGroupStatus(testPlan.getId(), userId);
|
||||
//关闭定时任务
|
||||
this.deleteScheduleConfig(testPlan.getId());
|
||||
} else if (StringUtils.equals(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
|
||||
} else if (this.isTestPlanCompleted(id) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
|
||||
//测试计划
|
||||
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
|
||||
testPlan.setUpdateUser(userId);
|
||||
|
@ -417,7 +420,37 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
} else {
|
||||
throw new MSException(Translator.get("test_plan.cannot.archived"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试计划归档
|
||||
*/
|
||||
public boolean archived(TestPlan testPlan, String userId) {
|
||||
if (!this.isTestPlanCompleted(testPlan.getId())) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
|
||||
//测试计划组归档
|
||||
updateCompletedGroupStatus(testPlan.getId(), userId);
|
||||
//关闭定时任务
|
||||
this.deleteScheduleConfig(testPlan.getId());
|
||||
return true;
|
||||
} else if (StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
|
||||
//测试计划
|
||||
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
|
||||
testPlan.setUpdateUser(userId);
|
||||
testPlan.setUpdateTime(System.currentTimeMillis());
|
||||
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||
//关闭定时任务
|
||||
this.deleteScheduleConfig(testPlan.getId());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTestPlanCompleted(String testPlanId) {
|
||||
TestPlanStatisticsResponse statisticsResponse = testPlanStatisticsService.calculateRate(Collections.singletonList(testPlanId)).getFirst();
|
||||
return StringUtils.equalsIgnoreCase(statisticsResponse.getStatus(), TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -430,14 +463,20 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
List<String> batchArchivedIds = request.getSelectIds();
|
||||
if (CollectionUtils.isNotEmpty(batchArchivedIds)) {
|
||||
TestPlanExample example = new TestPlanExample();
|
||||
example.createCriteria().andIdIn(batchArchivedIds);
|
||||
List<TestPlan> archivedPlanList = testPlanMapper.selectByExample(example).stream().filter(
|
||||
example.createCriteria().andIdIn(batchArchivedIds).andStatusNotEqualTo(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
|
||||
List<TestPlan> testPlanList = testPlanMapper.selectByExample(example).stream().filter(
|
||||
testPlan -> StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)
|
||||
|| (StringUtils.equals(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID))
|
||||
).collect(Collectors.toList());
|
||||
archivedPlanList.forEach(item -> this.archived(item.getId(), currentUser));
|
||||
|| (StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID))
|
||||
).toList();
|
||||
List<TestPlan> archivedPlanGroupList = new ArrayList<>();
|
||||
testPlanList.forEach(item -> {
|
||||
boolean result = this.archived(item, currentUser);
|
||||
if (result) {
|
||||
archivedPlanGroupList.add(item);
|
||||
}
|
||||
});
|
||||
//日志
|
||||
testPlanLogService.saveBatchLog(archivedPlanList, currentUser, "/test-plan/batch-archived", HttpMethodConstants.POST.name(), OperationLogType.ARCHIVED.name(), "archive");
|
||||
testPlanLogService.saveBatchLog(archivedPlanGroupList, currentUser, "/test-plan/batch-archived", HttpMethodConstants.POST.name(), OperationLogType.ARCHIVED.name(), "archive");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,17 +486,14 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
* @param id
|
||||
* @param userId
|
||||
*/
|
||||
private void updateGroupStatus(String id, String userId) {
|
||||
private void updateCompletedGroupStatus(String id, String userId) {
|
||||
TestPlanExample example = new TestPlanExample();
|
||||
example.createCriteria().andGroupIdEqualTo(id);
|
||||
List<TestPlan> testPlanList = testPlanMapper.selectByExample(example);
|
||||
if (CollectionUtils.isEmpty(testPlanList)) {
|
||||
throw new MSException(Translator.get("test_plan.group.not_plan"));
|
||||
}
|
||||
List<String> ids = testPlanList.stream().filter(item -> StringUtils.equalsIgnoreCase(item.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)).map(TestPlan::getId).collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
throw new MSException(Translator.get("test_plan.group.not_plan"));
|
||||
}
|
||||
List<String> ids = testPlanList.stream().map(TestPlan::getId).collect(Collectors.toList());
|
||||
ids.add(id);
|
||||
extTestPlanMapper.batchUpdateStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED, userId, System.currentTimeMillis(), ids);
|
||||
}
|
||||
|
@ -772,37 +808,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// private void updateTestPlanStatus(String testPlanId) {
|
||||
// Map<String, Long> caseExecResultCount = new HashMap<>();
|
||||
// Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
|
||||
// beansOfType.forEach((k, v) -> {
|
||||
// Map<String, Long> map = v.caseExecResultCount(testPlanId);
|
||||
// map.forEach((key, value) -> {
|
||||
// if (value != 0) {
|
||||
// caseExecResultCount.merge(key, value, Long::sum);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// String testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY;
|
||||
// if (MapUtils.isEmpty(caseExecResultCount)) {
|
||||
// // 没有任何执行结果: 状态是未开始
|
||||
// testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED;
|
||||
// extTestPlanMapper.clearActualEndTime(testPlanId);
|
||||
// } else if (caseExecResultCount.size() == 1 && caseExecResultCount.containsKey(ExecStatus.PENDING.name()) && caseExecResultCount.get(ExecStatus.PENDING.name()) > 0) {
|
||||
// // 执行结果只有未开始: 状态是未开始
|
||||
// testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED;
|
||||
// extTestPlanMapper.clearActualEndTime(testPlanId);
|
||||
// } else if (!caseExecResultCount.containsKey(ExecStatus.PENDING.name())) {
|
||||
// // 执行结果没有未开始: 已完成
|
||||
// testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_COMPLETED;
|
||||
// extTestPlanMapper.setActualEndTime(testPlanId, System.currentTimeMillis());
|
||||
// }
|
||||
//
|
||||
// this.updateTestPlanStatusAndGroupStatus(testPlanId, testPlanFinalStatus);
|
||||
// }
|
||||
|
||||
public TestPlanOperationResponse sort(PosRequest request, LogInsertModule logInsertModule) {
|
||||
testPlanGroupService.sort(request);
|
||||
testPlanLogService.saveMoveLog(testPlanMapper.selectByPrimaryKey(request.getMoveId()), request.getMoveId(), logInsertModule);
|
||||
|
|
|
@ -4,7 +4,6 @@ import io.metersphere.plan.domain.*;
|
|||
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
|
||||
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
|
||||
import io.metersphere.plan.mapper.*;
|
||||
import io.metersphere.plan.utils.RateCalculateUtils;
|
||||
import io.metersphere.sdk.constants.ExecStatus;
|
||||
import io.metersphere.sdk.constants.ResultStatus;
|
||||
import io.metersphere.sdk.constants.ScheduleResourceType;
|
||||
|
@ -16,6 +15,7 @@ import io.metersphere.system.mapper.ScheduleMapper;
|
|||
import io.metersphere.system.utils.ScheduleUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -41,6 +41,8 @@ public class TestPlanStatisticsService {
|
|||
private ExtTestPlanBugMapper extTestPlanBugMapper;
|
||||
@Resource
|
||||
private ScheduleMapper scheduleMapper;
|
||||
@Resource
|
||||
private TestPlanBaseUtilsService testPlanBaseUtilsService;
|
||||
|
||||
/**
|
||||
* 计划/计划组的用例统计数据
|
||||
|
@ -71,74 +73,144 @@ public class TestPlanStatisticsService {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划/计划组的{通过率, 执行进度}统计数据
|
||||
*
|
||||
* @param planIds 计划ID集合
|
||||
*/
|
||||
public List<TestPlanStatisticsResponse> calculateRate(List<String> planIds) {
|
||||
// 查出子计划
|
||||
TestPlanExample testPlanExample = new TestPlanExample();
|
||||
testPlanExample.createCriteria().andGroupIdIn(planIds);
|
||||
List<TestPlan> childrenPlan = testPlanMapper.selectByExample(testPlanExample);
|
||||
childrenPlan.forEach(item -> planIds.add(item.getId()));
|
||||
|
||||
List<TestPlanStatisticsResponse> planStatisticsResponses = new ArrayList<>();
|
||||
/*
|
||||
* 1. 查询计划下的用例数据集合
|
||||
* 2. 根据执行结果统计(结果小数保留两位)
|
||||
*/
|
||||
// 计划的更多配置
|
||||
private Map<String, TestPlanConfig> selectConfig(List<String> testPlanIds) {
|
||||
TestPlanConfigExample example = new TestPlanConfigExample();
|
||||
example.createCriteria().andTestPlanIdIn(planIds);
|
||||
example.createCriteria().andTestPlanIdIn(testPlanIds);
|
||||
List<TestPlanConfig> testPlanConfigList = testPlanConfigMapper.selectByExample(example);
|
||||
Map<String, TestPlanConfig> planConfigMap = testPlanConfigList.stream().collect(Collectors.toMap(TestPlanConfig::getTestPlanId, p -> p));
|
||||
// 关联的用例数据
|
||||
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = getFunctionalCaseMapByPlanIds(planIds);
|
||||
Map<String, List<TestPlanApiCase>> planApiCaseMap = getApiCaseMapByPlanIds(planIds);
|
||||
Map<String, List<TestPlanApiScenario>> planApiScenarioMap = getApiScenarioByPlanIds(planIds);
|
||||
return testPlanConfigList.stream().collect(Collectors.toMap(TestPlanConfig::getTestPlanId, p -> p));
|
||||
}
|
||||
|
||||
//查询定时任务
|
||||
private Map<String, Schedule> selectSchedule(List<String> testPlanIds) {
|
||||
ScheduleExample scheduleExample = new ScheduleExample();
|
||||
scheduleExample.createCriteria().andResourceIdIn(planIds).andResourceTypeEqualTo(ScheduleResourceType.TEST_PLAN.name());
|
||||
scheduleExample.createCriteria().andResourceIdIn(testPlanIds).andResourceTypeEqualTo(ScheduleResourceType.TEST_PLAN.name());
|
||||
List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample);
|
||||
Map<String, Schedule> scheduleMap = schedules.stream().collect(Collectors.toMap(Schedule::getResourceId, t -> t));
|
||||
return schedules.stream().collect(Collectors.toMap(Schedule::getResourceId, t -> t));
|
||||
}
|
||||
|
||||
planIds.forEach(planId -> {
|
||||
/**
|
||||
* 计划/计划组的{通过率, 执行进度, 状态}统计数据
|
||||
*
|
||||
*/
|
||||
public List<TestPlanStatisticsResponse> calculateRate(List<String> paramIds) {
|
||||
// 查出所有计划
|
||||
TestPlanExample testPlanExample = new TestPlanExample();
|
||||
testPlanExample.createCriteria().andIdIn(paramIds);
|
||||
List<TestPlan> paramTestPlanList = testPlanMapper.selectByExample(testPlanExample);
|
||||
testPlanExample.clear();
|
||||
testPlanExample.createCriteria().andGroupIdIn(paramIds);
|
||||
List<TestPlan> childrenTestPlan = testPlanMapper.selectByExample(testPlanExample);
|
||||
paramTestPlanList.removeAll(childrenTestPlan);
|
||||
List<String> allTestPlanIdList = new ArrayList<>();
|
||||
allTestPlanIdList.addAll(paramTestPlanList.stream().map(TestPlan::getId).toList());
|
||||
allTestPlanIdList.addAll(childrenTestPlan.stream().map(TestPlan::getId).toList());
|
||||
|
||||
Map<TestPlan, List<TestPlan>> groupTestPlanMap = new HashMap<>();
|
||||
for (TestPlan testPlan : paramTestPlanList) {
|
||||
List<TestPlan> children = new ArrayList<>();
|
||||
for (TestPlan child : childrenTestPlan) {
|
||||
if (StringUtils.equalsIgnoreCase(child.getGroupId(), testPlan.getId())) {
|
||||
children.add(child);
|
||||
}
|
||||
}
|
||||
groupTestPlanMap.put(testPlan, children);
|
||||
childrenTestPlan.removeAll(children);
|
||||
}
|
||||
childrenTestPlan = null;
|
||||
paramTestPlanList = null;
|
||||
|
||||
List<TestPlanStatisticsResponse> returnResponse = new ArrayList<>();
|
||||
|
||||
// 计划的更多配置
|
||||
Map<String, TestPlanConfig> planConfigMap = this.selectConfig(allTestPlanIdList);
|
||||
// 关联的用例数据
|
||||
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = getFunctionalCaseMapByPlanIds(allTestPlanIdList);
|
||||
Map<String, List<TestPlanApiCase>> planApiCaseMap = getApiCaseMapByPlanIds(allTestPlanIdList);
|
||||
Map<String, List<TestPlanApiScenario>> planApiScenarioMap = getApiScenarioByPlanIds(allTestPlanIdList);
|
||||
//查询定时任务
|
||||
Map<String, Schedule> scheduleMap = this.selectSchedule(allTestPlanIdList);
|
||||
|
||||
groupTestPlanMap.forEach((rootPlan, children) -> {
|
||||
TestPlanStatisticsResponse rootResponse = this.genTestPlanStatisticsResponse(rootPlan, planConfigMap, planFunctionalCaseMap, planApiCaseMap, planApiScenarioMap, scheduleMap);
|
||||
List<TestPlanStatisticsResponse> childrenResponse = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
List<String> childStatus = new ArrayList<>();
|
||||
children.forEach(child -> {
|
||||
TestPlanStatisticsResponse childResponse = this.genTestPlanStatisticsResponse(child, planConfigMap, planFunctionalCaseMap, planApiCaseMap, planApiScenarioMap, scheduleMap);
|
||||
childResponse.calculateStatus();
|
||||
childStatus.add(childResponse.getStatus());
|
||||
//添加到rootResponse中
|
||||
rootResponse.calculateAllNumber(childResponse);
|
||||
childrenResponse.add(childResponse);
|
||||
});
|
||||
rootResponse.calculateCaseTotal();
|
||||
rootResponse.calculatePassRate();
|
||||
rootResponse.calculateExecuteRate();
|
||||
rootResponse.setStatus(testPlanBaseUtilsService.calculateStatusByChildren(childStatus));
|
||||
} else {
|
||||
rootResponse.calculateCaseTotal();
|
||||
rootResponse.calculatePassRate();
|
||||
rootResponse.calculateExecuteRate();
|
||||
rootResponse.calculateStatus();
|
||||
}
|
||||
returnResponse.add(rootResponse);
|
||||
returnResponse.addAll(childrenResponse);
|
||||
});
|
||||
return returnResponse;
|
||||
}
|
||||
|
||||
private Map<String, Long> countApiScenarioExecResultMap(List<TestPlanApiScenario> apiScenarios) {
|
||||
return CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect(
|
||||
Collectors.groupingBy(apiScenario -> Optional.ofNullable(apiScenario.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||
}
|
||||
|
||||
private Map<String, Long> countApiTestCaseExecResultMap(List<TestPlanApiCase> apiCases) {
|
||||
return CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect(
|
||||
Collectors.groupingBy(apiCase -> Optional.ofNullable(apiCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||
}
|
||||
|
||||
private Map<String, Long> countFunctionalCaseExecResultMap(List<TestPlanFunctionalCase> functionalCases) {
|
||||
return CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
|
||||
Collectors.groupingBy(functionalCase -> Optional.ofNullable(functionalCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||
}
|
||||
|
||||
private TestPlanStatisticsResponse genTestPlanStatisticsResponse(TestPlan child,
|
||||
Map<String, TestPlanConfig> planConfigMap,
|
||||
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap,
|
||||
Map<String, List<TestPlanApiCase>> planApiCaseMap,
|
||||
Map<String, List<TestPlanApiScenario>> planApiScenarioMap,
|
||||
Map<String, Schedule> scheduleMap) {
|
||||
String planId = child.getId();
|
||||
TestPlanStatisticsResponse statisticsResponse = new TestPlanStatisticsResponse();
|
||||
statisticsResponse.setId(planId);
|
||||
|
||||
// 测试计划组没有测试计划配置。同理,也不用参与用例等数据的计算
|
||||
if (planConfigMap.containsKey(planId)) {
|
||||
statisticsResponse.setPassThreshold(planConfigMap.get(planId).getPassThreshold());
|
||||
// 功能用例分组统计开始 (为空时, 默认为未执行)
|
||||
|
||||
List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(planId);
|
||||
statisticsResponse.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
|
||||
Map<String, Long> functionalCaseResultCountMap = CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
|
||||
Collectors.groupingBy(functionalCase -> Optional.ofNullable(functionalCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||
// 接口用例分组统计开始 (为空时, 默认为未执行)
|
||||
List<TestPlanApiCase> apiCases = planApiCaseMap.get(planId);
|
||||
statisticsResponse.setApiCaseCount(CollectionUtils.isNotEmpty(apiCases) ? apiCases.size() : 0);
|
||||
Map<String, Long> apiCaseResultCountMap = CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect(
|
||||
Collectors.groupingBy(apiCase -> Optional.ofNullable(apiCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||
// 接口场景用例分组统计开始 (为空时, 默认为未执行)
|
||||
List<TestPlanApiScenario> apiScenarios = planApiScenarioMap.get(planId);
|
||||
statisticsResponse.setApiScenarioCount(CollectionUtils.isNotEmpty(apiScenarios) ? apiScenarios.size() : 0);
|
||||
Map<String, Long> apiScenarioResultCountMap = CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect(
|
||||
Collectors.groupingBy(apiScenario -> Optional.ofNullable(apiScenario.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||
|
||||
|
||||
// 功能用例分组统计开始 (为空时, 默认为未执行)
|
||||
Map<String, Long> functionalCaseResultCountMap = this.countFunctionalCaseExecResultMap(functionalCases);
|
||||
// 接口用例分组统计开始 (为空时, 默认为未执行)
|
||||
Map<String, Long> apiCaseResultCountMap = this.countApiTestCaseExecResultMap(apiCases);
|
||||
// 接口场景用例分组统计开始 (为空时, 默认为未执行)
|
||||
Map<String, Long> apiScenarioResultCountMap = this.countApiScenarioExecResultMap(apiScenarios);
|
||||
|
||||
// 用例数据汇总
|
||||
statisticsResponse.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
|
||||
statisticsResponse.setApiCaseCount(CollectionUtils.isNotEmpty(apiCases) ? apiCases.size() : 0);
|
||||
statisticsResponse.setApiScenarioCount(CollectionUtils.isNotEmpty(apiScenarios) ? apiScenarios.size() : 0);
|
||||
statisticsResponse.setSuccessCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.SUCCESS.name()));
|
||||
statisticsResponse.setErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.ERROR.name()));
|
||||
statisticsResponse.setFakeErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.FAKE_ERROR.name()));
|
||||
statisticsResponse.setBlockCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.BLOCKED.name()));
|
||||
statisticsResponse.setPendingCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.PENDING.name()));
|
||||
statisticsResponse.setCaseTotal(statisticsResponse.getFunctionalCaseCount() + statisticsResponse.getApiCaseCount() + statisticsResponse.getApiScenarioCount());
|
||||
// 通过率 {通过用例数/总用例数} && 执行进度 {非未执行的用例数/总用例数}
|
||||
statisticsResponse.setPassRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getSuccessCount(), statisticsResponse.getCaseTotal(), 2));
|
||||
statisticsResponse.setExecuteRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getCaseTotal() - statisticsResponse.getPendingCount(), statisticsResponse.getCaseTotal(), 2));
|
||||
statisticsResponse.calculateCaseTotal();
|
||||
statisticsResponse.calculatePassRate();
|
||||
statisticsResponse.calculateExecuteRate();
|
||||
}
|
||||
planStatisticsResponses.add(statisticsResponse);
|
||||
|
||||
//定时任务
|
||||
if (scheduleMap.containsKey(planId)) {
|
||||
Schedule schedule = scheduleMap.get(planId);
|
||||
|
@ -154,9 +226,7 @@ public class TestPlanStatisticsService {
|
|||
statisticsResponse.setNextTriggerTime(ScheduleUtils.getNextTriggerTime(schedule.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return planStatisticsResponses;
|
||||
return statisticsResponse;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public class RateCalculateUtils {
|
|||
* @param precision 精度
|
||||
* @return rate
|
||||
*/
|
||||
public static Double divWithPrecision(Integer molecular, Integer denominator, Integer precision) {
|
||||
public static Double divWithPrecision(Long molecular, Long denominator, Integer precision) {
|
||||
DecimalFormat rateFormat = new DecimalFormat("#.##");
|
||||
rateFormat.setMinimumFractionDigits(precision);
|
||||
rateFormat.setMaximumFractionDigits(precision);
|
||||
|
@ -38,4 +38,8 @@ public class RateCalculateUtils {
|
|||
}
|
||||
return rate;
|
||||
}
|
||||
|
||||
public static Double divWithPrecision(Integer molecular, Integer denominator, Integer precision) {
|
||||
return divWithPrecision((long) molecular, (long) denominator, precision);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,9 @@ package io.metersphere.plan.controller;
|
|||
import io.metersphere.api.domain.ApiScenario;
|
||||
import io.metersphere.api.domain.ApiTestCase;
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import io.metersphere.functional.mapper.FunctionalCaseMapper;
|
||||
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
||||
import io.metersphere.plan.domain.TestPlan;
|
||||
import io.metersphere.plan.domain.TestPlanConfig;
|
||||
import io.metersphere.plan.domain.TestPlanExample;
|
||||
import io.metersphere.plan.domain.TestPlanReport;
|
||||
import io.metersphere.plan.domain.*;
|
||||
import io.metersphere.plan.dto.request.*;
|
||||
import io.metersphere.plan.dto.response.TestPlanOperationResponse;
|
||||
import io.metersphere.plan.dto.response.TestPlanResponse;
|
||||
|
@ -21,10 +19,7 @@ import io.metersphere.plan.utils.TestPlanTestUtils;
|
|||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
|
||||
import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.constants.SessionConstants;
|
||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
|
@ -43,6 +38,7 @@ import io.metersphere.system.log.constants.OperationLogType;
|
|||
import io.metersphere.system.mapper.TestPlanModuleMapper;
|
||||
import io.metersphere.system.service.CommonProjectService;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.uid.NumGenerator;
|
||||
import io.metersphere.system.utils.CheckLogModel;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -138,9 +134,13 @@ public class TestPlanTests extends BaseTest {
|
|||
private static final String URL_TEST_PLAN_BATCH_ARCHIVED = "/test-plan/batch-archived";
|
||||
private static final String URL_TEST_PLAN_BATCH_EDIT = "/test-plan/batch-edit";
|
||||
|
||||
private static String testPlanId6 = null;
|
||||
private static String testPlanId16 = null;
|
||||
private static String groupTestPlanId7 = null;
|
||||
private static String groupTestPlanId15 = null;
|
||||
private static String groupTestPlanId35 = null;
|
||||
private static String groupTestPlanId45 = null;
|
||||
private static String groupTestPlanId46 = null;
|
||||
|
||||
private static List<String> rootPlanIds = new ArrayList<>();
|
||||
|
||||
|
@ -154,6 +154,10 @@ public class TestPlanTests extends BaseTest {
|
|||
private ExtTestPlanMapper extTestPlanMapper;
|
||||
@Resource
|
||||
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
|
||||
@Resource
|
||||
private FunctionalCaseMapper functionalCaseMapper;
|
||||
|
||||
private static List<String> functionalCaseId = new ArrayList<>();
|
||||
|
||||
@BeforeEach
|
||||
public void initTestData() {
|
||||
|
@ -542,7 +546,7 @@ public class TestPlanTests extends BaseTest {
|
|||
String moduleId;
|
||||
if (i < 50) {
|
||||
moduleId = a1Node.getId();
|
||||
if (i == 7 || i == 15 || i == 35) {
|
||||
if (i == 7 || i == 15 || i == 35 || i == 45 || i == 46) {
|
||||
request.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
|
||||
}
|
||||
a1NodeCount++;
|
||||
|
@ -574,13 +578,20 @@ public class TestPlanTests extends BaseTest {
|
|||
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
Assertions.assertNotNull(returnId);
|
||||
|
||||
if (i == 7) {
|
||||
if (i == 6) {
|
||||
testPlanId6 = returnId;
|
||||
} else if (i == 7) {
|
||||
groupTestPlanId7 = returnId;
|
||||
} else if (i == 15) {
|
||||
groupTestPlanId15 = returnId;
|
||||
} else if (i == 16) {
|
||||
testPlanId16 = returnId;
|
||||
} else if (i == 35) {
|
||||
groupTestPlanId35 = returnId;
|
||||
} else if (i == 45) {
|
||||
groupTestPlanId45 = returnId;
|
||||
} else if (i == 46) {
|
||||
groupTestPlanId46 = returnId;
|
||||
} else if (i > 700 && i < 725) {
|
||||
// 701-749 要创建测试计划报告 每个测试计划创建250个报告
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
|
@ -676,6 +687,32 @@ public class TestPlanTests extends BaseTest {
|
|||
}
|
||||
}
|
||||
|
||||
// testPlanId6关联两条已完成用例
|
||||
this.associationFuncCase(testPlanId6, true);
|
||||
// testPlanId16 关联未开始用例
|
||||
this.associationFuncCase(testPlanId16, false);
|
||||
//在groupTestPlanId35 和 groupTestPlanId46下面各创建2条测试计划并关联已完成用例
|
||||
for (int i = 0; i < 4; i++) {
|
||||
TestPlanCreateRequest itemRequest = new TestPlanCreateRequest();
|
||||
itemRequest.setProjectId(project.getId());
|
||||
itemRequest.setModuleId(a1Node.getId());
|
||||
if (i > 2) {
|
||||
itemRequest.setGroupId(groupTestPlanId46);
|
||||
itemRequest.setName("testPlan_group46_" + i);
|
||||
} else {
|
||||
itemRequest.setGroupId(groupTestPlanId35);
|
||||
itemRequest.setName("testPlan_group35_" + i);
|
||||
}
|
||||
itemRequest.setBaseAssociateCaseRequest(associateCaseRequest);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest);
|
||||
String returnStr = mvcResult.getResponse().getContentAsString();
|
||||
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
|
||||
Assertions.assertNotNull(JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId());
|
||||
String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
|
||||
this.associationFuncCase(returnId, true);
|
||||
}
|
||||
|
||||
|
||||
//校验Group数量
|
||||
List<TestPlan> groupList = JSON.parseArray(
|
||||
JSON.toJSONString(
|
||||
|
@ -683,7 +720,7 @@ public class TestPlanTests extends BaseTest {
|
|||
this.requestGetWithOkAndReturn(String.format(URL_POST_TEST_PLAN_GROUP_LIST, project.getId()))
|
||||
.getResponse().getContentAsString(), ResultHolder.class).getData()),
|
||||
TestPlan.class);
|
||||
Assertions.assertEquals(groupList.size(), 3);
|
||||
Assertions.assertEquals(groupList.size(), 5);
|
||||
|
||||
/*
|
||||
反例
|
||||
|
@ -717,7 +754,49 @@ public class TestPlanTests extends BaseTest {
|
|||
this.checkTestPlanSortWithOutGroup();
|
||||
this.checkTestPlanSortInGroup(groupTestPlanId7);
|
||||
this.checkTestPlanMoveToGroup();
|
||||
this.checkTestPlanGroupArchived(groupTestPlanId7);
|
||||
this.checkTestPlanGroupArchived(groupTestPlanId35);
|
||||
}
|
||||
|
||||
private void associationFuncCase(String testPlanId, boolean isFinish) {
|
||||
FunctionalCase functionalCase = new FunctionalCase();
|
||||
functionalCase.setProjectId(project.getId());
|
||||
functionalCase.setName(String.valueOf(System.currentTimeMillis()));
|
||||
functionalCase.setId(IDGenerator.nextStr());
|
||||
functionalCase.setModuleId("root");
|
||||
functionalCase.setTemplateId("root");
|
||||
functionalCase.setReviewStatus("PREPARED");
|
||||
functionalCase.setCaseEditType("STEP");
|
||||
functionalCase.setPos(4096L);
|
||||
functionalCase.setVersionId("root");
|
||||
functionalCase.setRefId(functionalCase.getId());
|
||||
functionalCase.setLastExecuteResult("PREPARED");
|
||||
functionalCase.setDeleted(false);
|
||||
functionalCase.setPublicCase(false);
|
||||
functionalCase.setLatest(true);
|
||||
functionalCase.setCreateUser("admin");
|
||||
functionalCase.setCreateTime(System.currentTimeMillis());
|
||||
functionalCase.setUpdateTime(System.currentTimeMillis());
|
||||
functionalCase.setNum(NumGenerator.nextNum(project.getId(), ApplicationNumScope.CASE_MANAGEMENT));
|
||||
functionalCaseMapper.insert(functionalCase);
|
||||
functionalCaseId.add(functionalCase.getId());
|
||||
|
||||
TestPlanFunctionalCase testPlanFunctionalCase = new TestPlanFunctionalCase();
|
||||
testPlanFunctionalCase.setId(IDGenerator.nextStr());
|
||||
testPlanFunctionalCase.setTestPlanId(testPlanId);
|
||||
testPlanFunctionalCase.setFunctionalCaseId(functionalCase.getId());
|
||||
testPlanFunctionalCase.setCreateTime(System.currentTimeMillis());
|
||||
testPlanFunctionalCase.setCreateUser("admin");
|
||||
testPlanFunctionalCase.setPos(4096L);
|
||||
testPlanFunctionalCase.setLastExecResult("SUCCESS");
|
||||
testPlanFunctionalCase.setTestPlanCollectionId("root");
|
||||
testPlanFunctionalCaseMapper.insert(testPlanFunctionalCase);
|
||||
|
||||
if (!isFinish) {
|
||||
testPlanFunctionalCase.setId(IDGenerator.nextStr());
|
||||
testPlanFunctionalCase.setPos(8192L);
|
||||
testPlanFunctionalCase.setLastExecResult("PENDING");
|
||||
testPlanFunctionalCaseMapper.insert(testPlanFunctionalCase);
|
||||
}
|
||||
}
|
||||
|
||||
private List<TestPlanResponse> selectByGroupId(String groupId) throws Exception {
|
||||
|
@ -912,16 +991,16 @@ public class TestPlanTests extends BaseTest {
|
|||
|
||||
//判断组归档
|
||||
TestPlan updatePlan = new TestPlan();
|
||||
updatePlan.setId(groupTestPlanId35);
|
||||
updatePlan.setId(groupTestPlanId45);
|
||||
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
|
||||
testPlanMapper.updateByPrimaryKeySelective(updatePlan);
|
||||
this.requestPost(URL_TEST_PLAN_BATCH_MOVE, request).andExpect(status().is5xxServerError());
|
||||
//改回来
|
||||
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED);
|
||||
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
testPlanMapper.updateByPrimaryKeySelective(updatePlan);
|
||||
|
||||
//正式测试
|
||||
groupId = groupTestPlanId35;
|
||||
groupId = groupTestPlanId45;
|
||||
request.setTargetId(groupId);
|
||||
this.requestPostWithOkAndReturn(URL_TEST_PLAN_BATCH_MOVE, request);
|
||||
List<TestPlanResponse> groups = this.selectByGroupId(groupId);
|
||||
|
@ -950,20 +1029,21 @@ public class TestPlanTests extends BaseTest {
|
|||
// 测试计划组内的测试计划不能归档
|
||||
List<TestPlanResponse> testPlanResponseList = this.selectByGroupId(groupId);
|
||||
TestPlanResponse cannotArchivedPlan = testPlanResponseList.getFirst();
|
||||
testPlanMapper.updateByPrimaryKeySelective(new TestPlan() {{
|
||||
this.setId(cannotArchivedPlan.getId());
|
||||
this.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
|
||||
}});
|
||||
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, cannotArchivedPlan.getId())).andExpect(status().is5xxServerError());
|
||||
|
||||
//归档测试组内的测试计划
|
||||
for (TestPlanResponse testPlanResponse : testPlanResponseList) {
|
||||
testPlanMapper.updateByPrimaryKeySelective(new TestPlan() {{
|
||||
this.setId(testPlanResponse.getId());
|
||||
this.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
|
||||
}});
|
||||
}
|
||||
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, groupId));
|
||||
|
||||
//归档不能归档的测试计划
|
||||
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, rootPlanIds.getFirst())).andExpect(status().is5xxServerError());
|
||||
|
||||
//归档普通测试计划
|
||||
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, testPlanId6));
|
||||
// testPlan6更改回去
|
||||
TestPlan testPlan = new TestPlan();
|
||||
testPlan.setId(testPlanId6);
|
||||
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1003,11 +1083,104 @@ public class TestPlanTests extends BaseTest {
|
|||
TestPlanTableRequest groupRequest = new TestPlanTableRequest();
|
||||
//查询游离态测试计划
|
||||
TestPlanTableRequest onlyPlanRequest = new TestPlanTableRequest();
|
||||
// 状态过滤的测试计划
|
||||
TestPlanTableRequest statusRequest = new TestPlanTableRequest();
|
||||
BeanUtils.copyBean(groupRequest, dataRequest);
|
||||
BeanUtils.copyBean(onlyPlanRequest, dataRequest);
|
||||
BeanUtils.copyBean(statusRequest, dataRequest);
|
||||
groupRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
|
||||
onlyPlanRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
|
||||
|
||||
|
||||
//进行状态筛选 -- 空状态
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
999 - 1);
|
||||
/*
|
||||
现有数据状态:
|
||||
已完成的 6 47(组)
|
||||
进行中的 16
|
||||
已归档的 35(组)
|
||||
*/
|
||||
//进行状态筛选 -- 未开始
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED));
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
999 - 1 - 1 - 2);
|
||||
//进行状态筛选 -- 已完成
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED));
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
2);
|
||||
//进行状态筛选 -- 进行中
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY));
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
1);
|
||||
//进行状态筛选 -- 已完成和未开始
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", new ArrayList<String>() {{
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
|
||||
}});
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
999 - 1 - 1);
|
||||
//进行状态筛选 -- 已完成和进行中
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", new ArrayList<String>() {{
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY);
|
||||
}});
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
3);
|
||||
//进行状态筛选 -- 进行中和未开始
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", new ArrayList<String>() {{
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY);
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
|
||||
}});
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
999 - 1 - 2);
|
||||
//进行状态筛选 -- 已完成、未开始、进行中
|
||||
statusRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", new ArrayList<String>() {{
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY);
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
|
||||
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
|
||||
}});
|
||||
}});
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
999 - 1);
|
||||
|
||||
BaseTreeNode a1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1");
|
||||
BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2");
|
||||
BaseTreeNode a3Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a3");
|
||||
|
@ -1024,6 +1197,7 @@ public class TestPlanTests extends BaseTest {
|
|||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
999 - 1);
|
||||
|
||||
//查询归档的
|
||||
dataRequest.setFilter(new HashMap<>() {{
|
||||
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED));
|
||||
|
@ -1038,13 +1212,13 @@ public class TestPlanTests extends BaseTest {
|
|||
URL_POST_TEST_PLAN_PAGE, groupRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
3 - 1);
|
||||
5 - 1);
|
||||
//只查询计划
|
||||
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
|
||||
URL_POST_TEST_PLAN_PAGE, onlyPlanRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
|
||||
dataRequest.getCurrent(),
|
||||
dataRequest.getPageSize(),
|
||||
996);
|
||||
999 - 5);
|
||||
|
||||
//按照名称倒叙
|
||||
dataRequest.setSort(new HashMap<>() {{
|
||||
|
@ -1243,17 +1417,17 @@ public class TestPlanTests extends BaseTest {
|
|||
|
||||
//修改a2节点下的数据(91,92)的所属测试计划组
|
||||
updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_91").getId());
|
||||
updateRequest.setGroupId(groupTestPlanId35);
|
||||
updateRequest.setGroupId(groupTestPlanId45);
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
|
||||
a2NodeCount--;
|
||||
updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_92").getId());
|
||||
updateRequest.setGroupId(groupTestPlanId35);
|
||||
updateRequest.setGroupId(groupTestPlanId45);
|
||||
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
|
||||
a2NodeCount--;
|
||||
|
||||
TestPlan updatePlan = new TestPlan();
|
||||
updatePlan.setId(groupTestPlanId7);
|
||||
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY);
|
||||
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
|
||||
testPlanMapper.updateByPrimaryKeySelective(updatePlan);
|
||||
//修改测试计划组信息
|
||||
updateRequest = testPlanTestService.generateUpdateRequest(groupTestPlanId7);
|
||||
|
@ -2113,25 +2287,15 @@ public class TestPlanTests extends BaseTest {
|
|||
public void testArchived() throws Exception {
|
||||
//计划 -- 首先状态不是已完成
|
||||
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_1")).andExpect(status().is5xxServerError());
|
||||
//更改状态再归档
|
||||
TestPlan testPlan = new TestPlan();
|
||||
testPlan.setId("wx_test_plan_id_1");
|
||||
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
|
||||
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_1"));
|
||||
|
||||
//计划组没有可归档的测试计划:
|
||||
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_2")).andExpect(status().is5xxServerError());
|
||||
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_5"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(303)
|
||||
public void testCopy() throws Exception {
|
||||
// 1. 已归档的不能再归档计划 无用例
|
||||
requestGet(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_1")).andExpect(status().is5xxServerError());
|
||||
|
||||
requestGet(String.format(URL_TEST_PLAN_COPY, groupTestPlanId35)).andExpect(status().is5xxServerError());
|
||||
|
||||
// 2.计划 有用例
|
||||
MvcResult mvcResult1 = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_4"));
|
||||
|
|
Loading…
Reference in New Issue