fix: 测试计划与评审性能优化

--bug=1010009 --user=陈建星 【测试跟踪】github#9985,用例评审左侧模块加载慢 https://www.tapd.cn/55049933/s/10994900
This commit is contained in:
chenjianxing 2022-01-26 17:51:58 +08:00 committed by john1298308460
parent c2e342792e
commit 9492b4df70
9 changed files with 125 additions and 136 deletions

View File

@ -27,4 +27,4 @@ public interface TestCaseReviewTestCaseMapper {
int updateByPrimaryKeySelective(TestCaseReviewTestCase record); int updateByPrimaryKeySelective(TestCaseReviewTestCase record);
int updateByPrimaryKey(TestCaseReviewTestCase record); int updateByPrimaryKey(TestCaseReviewTestCase record);
} }

View File

@ -8,6 +8,7 @@ import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.request.testcase.QueryTestCaseRequest; import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import io.metersphere.track.request.testcase.TestCaseBatchRequest; import io.metersphere.track.request.testcase.TestCaseBatchRequest;
import io.metersphere.track.response.TrackCountResult; import io.metersphere.track.response.TrackCountResult;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -145,4 +146,7 @@ public interface ExtTestCaseMapper {
List<String> selectRefIdsForVersionChange(@Param("versionId") String versionId, @Param("projectId") String projectId); List<String> selectRefIdsForVersionChange(@Param("versionId") String versionId, @Param("projectId") String projectId);
int addLatestVersion(@Param("refId") String refId); int addLatestVersion(@Param("refId") String refId);
@MapKey("id")
Map<String, TestCase> getMaintainerMap(@Param("request") QueryTestCaseRequest request);
} }

View File

@ -993,6 +993,13 @@
) )
AND project_id = #{projectId} AND project_id = #{projectId}
</select> </select>
<select id="getMaintainerMap" resultType="io.metersphere.base.domain.TestCase">
select test_case.id as id, test_case.maintainer as maintainer
from test_case as test_case
left join test_plan_test_case as T2 on test_case.id=T2.case_id and T2.plan_id =#{request.planId}
<include refid="notInQueryWhereCondition"/>
and T2.case_id is null
</select>
<update id="addLatestVersion"> <update id="addLatestVersion">
UPDATE test_case UPDATE test_case

View File

@ -0,0 +1,10 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.TestCase;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestCaseReviewTestCaseMapper {
List<TestCase> getTestCaseWithNodeInfo(@Param("reviewId") String reviewId);
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseReviewTestCaseMapper">
<select id="getTestCaseWithNodeInfo" resultType="io.metersphere.base.domain.TestCase">
select DISTINCT tc.project_id, tc.node_id
from test_case_review_test_case tcrtc
join test_case tc on tcrtc.case_id = tc.id
where tcrtc.review_id = #{reviewId}
</select>
</mapper>

View File

@ -1,5 +1,6 @@
package io.metersphere.base.mapper.ext; package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.TestCase;
import io.metersphere.controller.request.BaseQueryRequest; import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.track.dto.PlanReportCaseDTO; import io.metersphere.track.dto.PlanReportCaseDTO;
import io.metersphere.track.dto.TestCaseReportStatusResultDTO; import io.metersphere.track.dto.TestCaseReportStatusResultDTO;
@ -68,4 +69,6 @@ public interface ExtTestPlanTestCaseMapper {
Long getPreOrder(@Param("planId")String planId, @Param("baseOrder") Long baseOrder); Long getPreOrder(@Param("planId")String planId, @Param("baseOrder") Long baseOrder);
Long getLastOrder(@Param("planId")String planId, @Param("baseOrder") Long baseOrder); Long getLastOrder(@Param("planId")String planId, @Param("baseOrder") Long baseOrder);
List<TestCase> getTestCaseWithNodeInfo(@Param("planId") String planId);
} }

View File

@ -556,6 +556,13 @@
order by `order` desc limit 1; order by `order` desc limit 1;
</select> </select>
<select id="getTestCaseWithNodeInfo" resultType="io.metersphere.base.domain.TestCase">
select tc.project_id, tc.node_id
from test_plan_test_case tptc
join test_case tc on tptc.case_id = tc.id
where tptc.plan_id = #{planId}
</select>
<sql id="queryVersionCondition"> <sql id="queryVersionCondition">
<if test="request.versionId != null"> <if test="request.versionId != null">
and ${versionTable}.version_id = #{request.versionId} and ${versionTable}.version_id = #{request.versionId}

View File

@ -7,6 +7,7 @@ import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper; import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper; import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseReviewTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper; import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
@ -52,8 +53,6 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
@Resource @Resource
TestPlanMapper testPlanMapper; TestPlanMapper testPlanMapper;
@Resource @Resource
TestPlanTestCaseMapper testPlanTestCaseMapper;
@Resource
ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper; ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper;
@Resource @Resource
ExtTestCaseMapper extTestCaseMapper; ExtTestCaseMapper extTestCaseMapper;
@ -66,6 +65,8 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
@Resource @Resource
TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper; TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper;
@Resource @Resource
ExtTestCaseReviewTestCaseMapper extTestCaseReviewTestCaseMapper;
@Resource
TestCaseReviewMapper testCaseReviewMapper; TestCaseReviewMapper testCaseReviewMapper;
public TestCaseNodeService() { public TestCaseNodeService() {
@ -307,55 +308,64 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
* @return List<TestCaseNodeDTO> * @return List<TestCaseNodeDTO>
*/ */
public List<TestCaseNodeDTO> getNodeByPlanId(String planId) { public List<TestCaseNodeDTO> getNodeByPlanId(String planId) {
List<TestCase> testCases = extTestPlanTestCaseMapper.getTestCaseWithNodeInfo(planId);
Map<String, List<String>> projectNodeMap = getProjectNodeMap(testCases);
return getNodeTreeWithPruningTree(projectNodeMap);
}
public List<TestCaseNodeDTO> getNodeByReviewId(String reviewId) {
List<TestCase> testCases = extTestCaseReviewTestCaseMapper.getTestCaseWithNodeInfo(reviewId);
Map<String, List<String>> projectNodeMap = getProjectNodeMap(testCases);
return getNodeTreeWithPruningTree(projectNodeMap);
}
public List<TestCaseNodeDTO> getNodeTreeWithPruningTree(Map<String, List<String>> projectNodeMap) {
List<TestCaseNodeDTO> list = new ArrayList<>(); List<TestCaseNodeDTO> list = new ArrayList<>();
List<String> projectIds = testPlanProjectService.getProjectIdsByPlanId(planId); projectNodeMap.forEach((k, v) -> {
projectIds.forEach(id -> { Project project = projectMapper.selectByPrimaryKey(k);
Project project = projectMapper.selectByPrimaryKey(id);
if (project != null) { if (project != null) {
String name = project.getName(); String name = project.getName();
List<TestCaseNodeDTO> nodeList = getNodeDTO(id, planId); List<TestCaseNodeDTO> testCaseNodes = getNodeTreeWithPruningTree(k, v);
TestCaseNodeDTO testCaseNodeDTO = new TestCaseNodeDTO(); TestCaseNodeDTO testCaseNodeDTO = new TestCaseNodeDTO();
testCaseNodeDTO.setId(project.getId()); testCaseNodeDTO.setId(project.getId());
testCaseNodeDTO.setName(name); testCaseNodeDTO.setName(name);
testCaseNodeDTO.setLabel(name); testCaseNodeDTO.setLabel(name);
testCaseNodeDTO.setChildren(nodeList); testCaseNodeDTO.setChildren(testCaseNodes);
if (!CollectionUtils.isEmpty(nodeList)) { if (!CollectionUtils.isEmpty(testCaseNodes)) {
list.add(testCaseNodeDTO); list.add(testCaseNodeDTO);
} }
} }
}); });
return list; return list;
} }
public List<TestCaseNodeDTO> getNodeByReviewId(String reviewId) { /**
List<TestCaseNodeDTO> list = new ArrayList<>(); * 获取当前项目下的
ProjectExample example = new ProjectExample(); * @param projectId
example.createCriteria().andWorkspaceIdEqualTo(SessionUtils.getCurrentWorkspaceId()); * @param pruningTreeIds
List<Project> projects = projectMapper.selectByExample(example); * @return
List<String> projectIds = projects.stream().map(Project::getId).collect(Collectors.toList()); */
public List<TestCaseNodeDTO> getNodeTreeWithPruningTree(String projectId, List<String> pruningTreeIds) {
projectIds.forEach(id -> { List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
String name = projectMapper.selectByPrimaryKey(id).getName(); List<TestCaseNodeDTO> nodeTrees = getNodeTrees(testCaseNodes);
Iterator<TestCaseNodeDTO> iterator = nodeTrees.iterator();
TestCaseReviewTestCaseExample testCaseReviewTestCaseExample = new TestCaseReviewTestCaseExample(); while (iterator.hasNext()) {
testCaseReviewTestCaseExample.createCriteria().andReviewIdEqualTo(reviewId); TestCaseNodeDTO rootNode = iterator.next();
List<TestCaseReviewTestCase> testCaseReviewTestCases = testCaseReviewTestCaseMapper.selectByExample(testCaseReviewTestCaseExample); if (pruningTree(rootNode, pruningTreeIds)) {
List<String> caseIds = testCaseReviewTestCases.stream().map(TestCaseReviewTestCase::getCaseId).collect(Collectors.toList()); iterator.remove();
List<TestCaseNodeDTO> nodeList = getReviewNodeDTO(id, caseIds);
if (!CollectionUtils.isEmpty(nodeList)) {
TestCaseNodeDTO testCaseNodeDTO = new TestCaseNodeDTO();
testCaseNodeDTO.setName(name);
testCaseNodeDTO.setLabel(name);
testCaseNodeDTO.setChildren(nodeList);
testCaseNodeDTO.setProjectId(id);
list.add(testCaseNodeDTO);
} }
}); }
return list; return nodeTrees;
}
private Map<String, List<String>> getProjectNodeMap(List<TestCase> testCases) {
Map<String, List<String>> projectNodeMap = new HashMap<>();
for (TestCase testCase : testCases) {
List<String> nodeIds = Optional.ofNullable(projectNodeMap.get(testCase.getProjectId())).orElse(new ArrayList<>());
nodeIds.add(testCase.getNodeId());
projectNodeMap.put(testCase.getProjectId(), nodeIds);
}
return projectNodeMap;
} }
private List<TestCaseNodeDTO> getNodeDTO(String projectId, QueryTestPlanCaseRequest request) { private List<TestCaseNodeDTO> getNodeDTO(String projectId, QueryTestPlanCaseRequest request) {
@ -364,8 +374,6 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
return null; return null;
} }
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
List<String> caseIds = testPlanTestCases.stream() List<String> caseIds = testPlanTestCases.stream()
.map(TestPlanCaseDTO::getCaseId) .map(TestPlanCaseDTO::getCaseId)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -376,79 +384,7 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
.map(TestCase::getNodeId) .map(TestCase::getNodeId)
.collect(Collectors.toList()); .collect(Collectors.toList());
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(testCaseNodes); return getNodeTreeWithPruningTree(projectId, dataNodeIds);
Iterator<TestCaseNodeDTO> iterator = nodeTrees.iterator();
while (iterator.hasNext()) {
TestCaseNodeDTO rootNode = iterator.next();
if (pruningTree(rootNode, dataNodeIds)) {
iterator.remove();
}
}
return nodeTrees;
}
private List<TestCaseNodeDTO> getNodeDTO(String projectId, String planId) {
TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample();
testPlanTestCaseExample.createCriteria().andPlanIdEqualTo(planId);
List<TestPlanTestCase> testPlanTestCases = testPlanTestCaseMapper.selectByExample(testPlanTestCaseExample);
if (testPlanTestCases.isEmpty()) {
return null;
}
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
List<String> caseIds = testPlanTestCases.stream()
.map(TestPlanTestCase::getCaseId)
.collect(Collectors.toList());
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andIdIn(caseIds);
List<String> dataNodeIds = testCaseMapper.selectByExample(testCaseExample).stream()
.map(TestCase::getNodeId)
.collect(Collectors.toList());
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(testCaseNodes);
Iterator<TestCaseNodeDTO> iterator = nodeTrees.iterator();
while (iterator.hasNext()) {
TestCaseNodeDTO rootNode = iterator.next();
if (pruningTree(rootNode, dataNodeIds)) {
iterator.remove();
}
}
return nodeTrees;
}
private List<TestCaseNodeDTO> getReviewNodeDTO(String projectId, List<String> caseIds) {
if (CollectionUtils.isEmpty(caseIds)) {
return null;
}
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andIdIn(caseIds);
List<String> dataNodeIds = testCaseMapper.selectByExample(testCaseExample).stream()
.map(TestCase::getNodeId)
.collect(Collectors.toList());
List<TestCaseNodeDTO> nodeTrees = getNodeTrees(testCaseNodes);
Iterator<TestCaseNodeDTO> iterator = nodeTrees.iterator();
while (iterator.hasNext()) {
TestCaseNodeDTO rootNode = iterator.next();
if (pruningTree(rootNode, dataNodeIds)) {
iterator.remove();
}
}
return nodeTrees;
} }
public List<TestCaseNodeDTO> getAllNodeByPlanId(QueryNodeRequest request) { public List<TestCaseNodeDTO> getAllNodeByPlanId(QueryNodeRequest request) {

View File

@ -522,11 +522,25 @@ public class TestPlanService {
} }
public void testPlanRelevance(PlanCaseRelevanceRequest request) { public void testPlanRelevance(PlanCaseRelevanceRequest request) {
Map<String, String> userMap = new HashMap<>();
boolean isSelectAll = request.getRequest() != null && request.getRequest().isSelectAll();
if (isSelectAll) {
Map<String, TestCase> maintainerMap = extTestCaseMapper.getMaintainerMap(request.getRequest());
for (String k : maintainerMap.keySet()) {
userMap.put(k, maintainerMap.get(k).getMaintainer());
}
} else {
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andIdIn(request.getIds());
List<TestCase> testCaseList = testCaseMapper.selectByExample(testCaseExample);
userMap = testCaseList.stream()
.collect(HashMap::new, (m, v) -> m.put(v.getId(), v.getMaintainer()), HashMap::putAll);
}
ServiceUtils.getSelectAllIds(request, request.getRequest(), SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
(query) -> extTestCaseMapper.selectRelateIdsByQuery(query)); TestPlanTestCaseMapper batchMapper = sqlSession.getMapper(TestPlanTestCaseMapper.class);
List<String> testCaseIds = request.getIds(); List<String> testCaseIds = new ArrayList<>(userMap.keySet());
if (testCaseIds.isEmpty()) { if (testCaseIds.isEmpty()) {
return; return;
@ -535,32 +549,42 @@ public class TestPlanService {
// 尽量保持与用例顺序一致 // 尽量保持与用例顺序一致
Collections.reverse(testCaseIds); Collections.reverse(testCaseIds);
TestCaseExample testCaseExample = new TestCaseExample();
testCaseExample.createCriteria().andIdIn(testCaseIds);
List<TestCase> testCaseList = testCaseMapper.selectByExample(testCaseExample);
Map<String, String> userMap = testCaseList.stream()
.collect(HashMap::new, (m, v) -> m.put(v.getId(), v.getMaintainer()), HashMap::putAll);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestPlanTestCaseMapper batchMapper = sqlSession.getMapper(TestPlanTestCaseMapper.class);
Long nextOrder = ServiceUtils.getNextOrder(request.getPlanId(), extTestPlanTestCaseMapper::getLastOrder); Long nextOrder = ServiceUtils.getNextOrder(request.getPlanId(), extTestPlanTestCaseMapper::getLastOrder);
for (String caseId : testCaseIds) { for (String caseId : testCaseIds) {
TestPlanTestCaseWithBLOBs testPlanTestCase = new TestPlanTestCaseWithBLOBs(); TestPlanTestCaseWithBLOBs testPlanTestCase = new TestPlanTestCaseWithBLOBs();
testPlanTestCase.setId(UUID.randomUUID().toString()); testPlanTestCase.setId(UUID.randomUUID().toString());
testPlanTestCase.setCreateUser(SessionUtils.getUserId()); testPlanTestCase.setCreateUser(SessionUtils.getUserId());
testPlanTestCase.setExecutor(userMap.get(caseId) == null ? SessionUtils.getUserId() : userMap.get(caseId)); String maintainer = Optional.ofNullable(userMap.get(caseId)).orElse(SessionUtils.getUserId());
testPlanTestCase.setExecutor(maintainer);
testPlanTestCase.setCaseId(caseId); testPlanTestCase.setCaseId(caseId);
testPlanTestCase.setCreateTime(System.currentTimeMillis()); testPlanTestCase.setCreateTime(System.currentTimeMillis());
testPlanTestCase.setUpdateTime(System.currentTimeMillis()); testPlanTestCase.setUpdateTime(System.currentTimeMillis());
testPlanTestCase.setPlanId(request.getPlanId()); testPlanTestCase.setPlanId(request.getPlanId());
testPlanTestCase.setStatus(TestPlanStatus.Prepare.name()); testPlanTestCase.setStatus(TestPlanStatus.Prepare.name());
testPlanTestCase.setOrder(nextOrder); testPlanTestCase.setOrder(nextOrder);
nextOrder += 5000; nextOrder += ServiceUtils.ORDER_STEP;
batchMapper.insert(testPlanTestCase); batchMapper.insert(testPlanTestCase);
} }
sqlSession.flushStatements(); sqlSession.flushStatements();
caseTestRelevance(request, testCaseIds);
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getPlanId());
if (StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Prepare.name())
|| StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) {
testPlan.setStatus(TestPlanStatus.Underway.name());
testPlan.setActualStartTime(System.currentTimeMillis()); // 将状态更新为进行中时开始时间也要更新
testPlan.setActualEndTime(null);
testPlanMapper.updateByPrimaryKey(testPlan);
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
public void caseTestRelevance(PlanCaseRelevanceRequest request, List<String> testCaseIds) {
//同步添加关联的接口和测试用例 //同步添加关联的接口和测试用例
if (request.getChecked()) { if (request.getChecked()) {
if (!testCaseIds.isEmpty()) { if (!testCaseIds.isEmpty()) {
@ -652,18 +676,6 @@ public class TestPlanService {
}); });
} }
} }
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getPlanId());
if (StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Prepare.name())
|| StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) {
testPlan.setStatus(TestPlanStatus.Underway.name());
testPlan.setActualStartTime(System.currentTimeMillis()); // 将状态更新为进行中时开始时间也要更新
testPlan.setActualEndTime(null);
testPlanMapper.updateByPrimaryKey(testPlan);
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
} }
public List<TestPlan> recentTestPlans(String projectId) { public List<TestPlan> recentTestPlans(String projectId) {