refactor(工作台): 尝试优化查询时间

This commit is contained in:
guoyuqi 2024-12-09 15:35:02 +08:00 committed by Craftsman
parent 06d4d6a79b
commit d5a598b2f9
4 changed files with 111 additions and 30 deletions

View File

@ -48,30 +48,23 @@ import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.service.PermissionCheckService; import io.metersphere.project.service.PermissionCheckService;
import io.metersphere.project.service.ProjectApplicationService; import io.metersphere.project.service.ProjectApplicationService;
import io.metersphere.project.service.ProjectService; import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.ExecStatus; import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.ResultStatus;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.dto.CombineCondition; import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch; import io.metersphere.sdk.dto.CombineSearch;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.*;
import io.metersphere.system.domain.UserExample;
import io.metersphere.system.domain.UserLayout;
import io.metersphere.system.domain.UserLayoutExample;
import io.metersphere.system.dto.ProtocolDTO; import io.metersphere.system.dto.ProtocolDTO;
import io.metersphere.system.dto.request.schedule.BaseScheduleConfigRequest;
import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.user.ProjectUserMemberDTO; import io.metersphere.system.dto.user.ProjectUserMemberDTO;
import io.metersphere.system.dto.user.UserExtendDTO; import io.metersphere.system.dto.user.UserExtendDTO;
import io.metersphere.system.mapper.ExtExecTaskItemMapper; import io.metersphere.system.mapper.*;
import io.metersphere.system.mapper.ExtSystemProjectMapper;
import io.metersphere.system.mapper.UserLayoutMapper;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.PageUtils; import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.ScheduleUtils;
import io.metersphere.system.utils.SessionUtils; import io.metersphere.system.utils.SessionUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -151,6 +144,10 @@ public class DashboardService {
private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper; private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper;
@Resource @Resource
private ExtTestPlanBugMapper extTestPlanBugMapper; private ExtTestPlanBugMapper extTestPlanBugMapper;
@Resource
private TestPlanConfigMapper testPlanConfigMapper;
@Resource
private ScheduleMapper scheduleMapper;
public static final String FUNCTIONAL = "FUNCTIONAL"; // 功能用例 public static final String FUNCTIONAL = "FUNCTIONAL"; // 功能用例
@ -711,27 +708,97 @@ public class DashboardService {
return overViewCountDTO; return overViewCountDTO;
} }
@NotNull
private TestPlanStatisticsResponse buildStatisticsResponse(String planId, List<TestPlanFunctionalCase> functionalCases, List<TestPlanApiCase> apiCases, List<TestPlanApiScenario> apiScenarios) {
//查出计划
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(planId);
// 计划的更多配置
TestPlanConfig planConfig = this.selectConfig(planId);
//查询定时任务
Schedule schedule = this.selectSchedule(planId);
//构建TestPlanStatisticsResponse
TestPlanStatisticsResponse statisticsResponse = new TestPlanStatisticsResponse();
statisticsResponse.setId(planId);
statisticsResponse.setStatus(testPlan.getStatus());
// 测试计划组没有测试计划配置同理也不用参与用例等数据的计算
if (planConfig != null) {
statisticsResponse.setPassThreshold(planConfig.getPassThreshold());
// 功能用例分组统计开始 (为空时, 默认为未执行)
Map<String, Long> functionalCaseResultCountMap = planStatisticsService.countFunctionalCaseExecResultMap(functionalCases);
// 接口用例分组统计开始 (为空时, 默认为未执行)
Map<String, Long> apiCaseResultCountMap = planStatisticsService.countApiTestCaseExecResultMap(apiCases);
// 接口场景用例分组统计开始 (为空时, 默认为未执行)
Map<String, Long> apiScenarioResultCountMap = planStatisticsService.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(planStatisticsService.countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.SUCCESS.name()));
statisticsResponse.setErrorCount(planStatisticsService.countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.ERROR.name()));
statisticsResponse.setFakeErrorCount(planStatisticsService.countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.FAKE_ERROR.name()));
statisticsResponse.setBlockCount(planStatisticsService.countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.BLOCKED.name()));
statisticsResponse.setPendingCount(planStatisticsService.countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.PENDING.name()));
statisticsResponse.calculateCaseTotal();
statisticsResponse.calculatePassRate();
statisticsResponse.calculateExecuteRate();
statisticsResponse.calculateTestPlanIsPass();
}
//定时任务
if (schedule != null) {
BaseScheduleConfigRequest request = new BaseScheduleConfigRequest();
request.setEnable(schedule.getEnable());
request.setCron(schedule.getValue());
request.setResourceId(planId);
if (schedule.getConfig() != null) {
request.setRunConfig(JSON.parseObject(schedule.getConfig(), Map.class));
}
statisticsResponse.setScheduleConfig(request);
if (schedule.getEnable()) {
statisticsResponse.setNextTriggerTime(ScheduleUtils.getNextTriggerTime(schedule.getValue()));
}
}
statisticsResponse.calculateCaseTotal();
statisticsResponse.calculatePassRate();
statisticsResponse.calculateExecuteRate();
statisticsResponse.calculateStatus();
statisticsResponse.calculateTestPlanIsPass();
return statisticsResponse;
}
private Schedule selectSchedule(String testPlanId) {
ScheduleExample scheduleExample = new ScheduleExample();
scheduleExample.createCriteria().andResourceIdEqualTo(testPlanId).andResourceTypeEqualTo(ScheduleResourceType.TEST_PLAN.name());
List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample);
return CollectionUtils.isNotEmpty(schedules) ? schedules.getFirst() : null;
}
private TestPlanConfig selectConfig(String testPlanId) {
return testPlanConfigMapper.selectByPrimaryKey(testPlanId);
}
public OverViewCountDTO projectPlanViewCount(DashboardFrontPageRequest request, String currentUserId) { public OverViewCountDTO projectPlanViewCount(DashboardFrontPageRequest request, String currentUserId) {
OverViewCountDTO overViewCountDTO = new OverViewCountDTO(); OverViewCountDTO overViewCountDTO = new OverViewCountDTO();
String projectId = request.getProjectIds().getFirst(); String projectId = request.getProjectIds().getFirst();
String planId = request.getPlanId();
if (Boolean.FALSE.equals(permissionCheckService.checkModule(projectId, TEST_PLAN_MODULE, currentUserId, PermissionConstants.TEST_PLAN_READ))) { if (Boolean.FALSE.equals(permissionCheckService.checkModule(projectId, TEST_PLAN_MODULE, currentUserId, PermissionConstants.TEST_PLAN_READ))) {
overViewCountDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode()); overViewCountDTO.setErrorCode(NO_PROJECT_PERMISSION.getCode());
} }
if (StringUtils.isBlank(request.getPlanId())) { if (StringUtils.isBlank(planId)) {
return new OverViewCountDTO(new HashMap<>(), new ArrayList<>(), new ArrayList<>(), 0); return new OverViewCountDTO(new HashMap<>(), new ArrayList<>(), new ArrayList<>(), 0);
} }
List<String> planIds = List.of(request.getPlanId());
List<TestPlanStatisticsResponse> testPlanStatisticsResponses = planStatisticsService.calculateRate(planIds); // 关联的用例数据
TestPlanStatisticsResponse planCount = testPlanStatisticsResponses.getFirst(); List<TestPlanFunctionalCase> planFunctionalCases = extTestPlanFunctionalCaseMapper.selectByTestPlanIdAndNotDeleted(planId);
List<TestPlanFunctionalCase> planFunctionalCases = extTestPlanFunctionalCaseMapper.getPlanFunctionalCaseByIds(planIds); List<TestPlanApiCase> planApiCases = extTestPlanApiCaseMapper.selectByTestPlanIdAndNotDeleted(planId);
List<TestPlanApiCase> planApiCases = extTestPlanApiCaseMapper.getPlanApiCaseByIds(planIds); List<TestPlanApiScenario> planApiScenarios = extTestPlanApiScenarioMapper.selectByTestPlanIdAndNotDeleted(planId);
List<TestPlanApiScenario> planApiScenarios = extTestPlanApiScenarioMapper.getPlanApiScenarioByIds(planIds); TestPlanStatisticsResponse statisticsResponse = buildStatisticsResponse(planId, planFunctionalCases, planApiCases, planApiScenarios);
// 计划-缺陷的关联数据 // 计划-缺陷的关联数据
List<TestPlanBugPageResponse> planBugs = extTestPlanBugMapper.countBugByIds(planIds); List<TestPlanBugPageResponse> planBugs = extTestPlanBugMapper.selectBugCountByPlanId(planId);
//获取卡片数据 //获取卡片数据
boolean addDefaultUser = false; boolean addDefaultUser = false;
buildCountMap(planCount, planBugs, overViewCountDTO); buildCountMap(statisticsResponse, planBugs, overViewCountDTO);
List<TestPlanFunctionalCase> caseUserNullList = planFunctionalCases.stream().filter(t -> StringUtils.isBlank(t.getExecuteUser())).toList(); List<TestPlanFunctionalCase> caseUserNullList = planFunctionalCases.stream().filter(t -> StringUtils.isBlank(t.getExecuteUser())).toList();
Map<String, List<TestPlanFunctionalCase>> caseUserMap = planFunctionalCases.stream().filter(t -> StringUtils.isNotBlank(t.getExecuteUser())).collect(Collectors.groupingBy(TestPlanFunctionalCase::getExecuteUser)); Map<String, List<TestPlanFunctionalCase>> caseUserMap = planFunctionalCases.stream().filter(t -> StringUtils.isNotBlank(t.getExecuteUser())).collect(Collectors.groupingBy(TestPlanFunctionalCase::getExecuteUser));
if (CollectionUtils.isNotEmpty(caseUserNullList)) { if (CollectionUtils.isNotEmpty(caseUserNullList)) {

View File

@ -33,6 +33,9 @@ public interface ExtTestPlanBugMapper {
List<TestPlanBugPageResponse> countBugByIds(@Param("planIds") List<String> planIds); List<TestPlanBugPageResponse> countBugByIds(@Param("planIds") List<String> planIds);
List<TestPlanBugPageResponse> selectBugCountByPlanId(@Param("planId") String planId);
/** /**
* 根据用例关系ID集合获取计划下用例关联的缺陷集合 * 根据用例关系ID集合获取计划下用例关联的缺陷集合
* @param caseIds 用例ID集合 * @param caseIds 用例ID集合

View File

@ -39,6 +39,17 @@
group by brc.bug_id group by brc.bug_id
</select> </select>
<select id="selectBugCountByPlanId" resultType="io.metersphere.plan.dto.response.TestPlanBugPageResponse">
select b.id as id, b.num as num, b.title as title, bc.description content, b.handle_user handleUser, b.status as status, b.create_user createUser, b.create_time createTime,brc.test_plan_id testPlanId
from bug_relation_case brc join bug b on brc.bug_id = b.id
left join bug_content bc on b.id = bc.bug_id
<where>
b.deleted = false
and brc.test_plan_id = #{planId}
</where>
group by brc.bug_id
</select>
<select id="getBugRelatedCase" resultType="io.metersphere.plan.dto.TestPlanBugCaseDTO"> <select id="getBugRelatedCase" resultType="io.metersphere.plan.dto.TestPlanBugCaseDTO">
select brc.case_id as id, fc.num as num, 'FUNCTIONAL' as type, brc.bug_id as bugId, fc.name as name, fc.project_id as projectId select brc.case_id as id, fc.num as num, 'FUNCTIONAL' as type, brc.bug_id as bugId, fc.name as name, fc.project_id as projectId

View File

@ -178,17 +178,17 @@ public class TestPlanStatisticsService {
return returnResponse; return returnResponse;
} }
private Map<String, Long> countApiScenarioExecResultMap(List<TestPlanApiScenario> apiScenarios) { public Map<String, Long> countApiScenarioExecResultMap(List<TestPlanApiScenario> apiScenarios) {
return CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect( return CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect(
Collectors.groupingBy(apiScenario -> StringUtils.isEmpty(apiScenario.getLastExecResult()) ? ExecStatus.PENDING.name() : apiScenario.getLastExecResult(), Collectors.counting())); Collectors.groupingBy(apiScenario -> StringUtils.isEmpty(apiScenario.getLastExecResult()) ? ExecStatus.PENDING.name() : apiScenario.getLastExecResult(), Collectors.counting()));
} }
private Map<String, Long> countApiTestCaseExecResultMap(List<TestPlanApiCase> apiCases) { public Map<String, Long> countApiTestCaseExecResultMap(List<TestPlanApiCase> apiCases) {
return CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect( return CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect(
Collectors.groupingBy(apiCase -> StringUtils.isEmpty(apiCase.getLastExecResult()) ? ExecStatus.PENDING.name() : apiCase.getLastExecResult(), Collectors.counting())); Collectors.groupingBy(apiCase -> StringUtils.isEmpty(apiCase.getLastExecResult()) ? ExecStatus.PENDING.name() : apiCase.getLastExecResult(), Collectors.counting()));
} }
private Map<String, Long> countFunctionalCaseExecResultMap(List<TestPlanFunctionalCase> functionalCases) { public Map<String, Long> countFunctionalCaseExecResultMap(List<TestPlanFunctionalCase> functionalCases) {
return CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect( return CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
Collectors.groupingBy(functionalCase -> StringUtils.isEmpty(functionalCase.getLastExecResult()) ? ExecStatus.PENDING.name() : functionalCase.getLastExecResult(), Collectors.counting())); Collectors.groupingBy(functionalCase -> StringUtils.isEmpty(functionalCase.getLastExecResult()) ? ExecStatus.PENDING.name() : functionalCase.getLastExecResult(), Collectors.counting()));
} }
@ -277,7 +277,7 @@ public class TestPlanStatisticsService {
* @param countKey 汇总的key * @param countKey 汇总的key
* @return 总数 * @return 总数
*/ */
private Integer countCaseMap(Map<String, Long> functionalCaseMap, Map<String, Long> apiCaseMap, Map<String, Long> apiScenarioMap, String countKey) { public Integer countCaseMap(Map<String, Long> functionalCaseMap, Map<String, Long> apiCaseMap, Map<String, Long> apiScenarioMap, String countKey) {
return (functionalCaseMap.containsKey(countKey) ? functionalCaseMap.get(countKey).intValue() : 0) + return (functionalCaseMap.containsKey(countKey) ? functionalCaseMap.get(countKey).intValue() : 0) +
(apiCaseMap.containsKey(countKey) ? apiCaseMap.get(countKey).intValue() : 0) + (apiCaseMap.containsKey(countKey) ? apiCaseMap.get(countKey).intValue() : 0) +
(apiScenarioMap.containsKey(countKey) ? apiScenarioMap.get(countKey).intValue() : 0); (apiScenarioMap.containsKey(countKey) ? apiScenarioMap.get(countKey).intValue() : 0);