fix(测试跟踪): 功能用例默认模块多次创建的问题
This commit is contained in:
parent
2b2069581f
commit
d424ef28bc
|
@ -4,21 +4,21 @@ import io.metersphere.base.domain.TestCaseNode;
|
||||||
import io.metersphere.commons.constants.OperLogConstants;
|
import io.metersphere.commons.constants.OperLogConstants;
|
||||||
import io.metersphere.commons.constants.OperLogModule;
|
import io.metersphere.commons.constants.OperLogModule;
|
||||||
import io.metersphere.commons.constants.PermissionConstants;
|
import io.metersphere.commons.constants.PermissionConstants;
|
||||||
|
import io.metersphere.dto.TestCaseNodeDTO;
|
||||||
import io.metersphere.log.annotation.MsAuditLog;
|
import io.metersphere.log.annotation.MsAuditLog;
|
||||||
import io.metersphere.log.annotation.MsRequestLog;
|
import io.metersphere.log.annotation.MsRequestLog;
|
||||||
|
import io.metersphere.plan.request.function.QueryTestPlanCaseRequest;
|
||||||
import io.metersphere.request.testcase.DragNodeRequest;
|
import io.metersphere.request.testcase.DragNodeRequest;
|
||||||
import io.metersphere.request.testcase.QueryNodeRequest;
|
import io.metersphere.request.testcase.QueryNodeRequest;
|
||||||
import io.metersphere.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.request.testcase.QueryTestCaseRequest;
|
||||||
import io.metersphere.plan.request.function.QueryTestPlanCaseRequest;
|
|
||||||
import io.metersphere.request.testreview.QueryCaseReviewRequest;
|
import io.metersphere.request.testreview.QueryCaseReviewRequest;
|
||||||
import io.metersphere.dto.TestCaseNodeDTO;
|
|
||||||
import io.metersphere.service.BaseCheckPermissionService;
|
import io.metersphere.service.BaseCheckPermissionService;
|
||||||
import io.metersphere.service.TestCaseNodeService;
|
import io.metersphere.service.TestCaseNodeService;
|
||||||
import io.metersphere.service.wapper.CheckPermissionService;
|
import io.metersphere.service.wapper.CheckPermissionService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
package io.metersphere.listener;
|
package io.metersphere.listener;
|
||||||
|
|
||||||
import io.metersphere.base.domain.ModuleNode;
|
|
||||||
import io.metersphere.base.domain.Project;
|
import io.metersphere.base.domain.Project;
|
||||||
import io.metersphere.base.domain.TestCaseNodeExample;
|
|
||||||
import io.metersphere.base.mapper.ProjectMapper;
|
import io.metersphere.base.mapper.ProjectMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtModuleNodeMapper;
|
import io.metersphere.base.mapper.ext.ExtModuleNodeMapper;
|
||||||
import io.metersphere.commons.constants.KafkaTopicConstants;
|
import io.metersphere.commons.constants.KafkaTopicConstants;
|
||||||
import io.metersphere.commons.constants.ProjectModuleDefaultNodeEnum;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.service.TestCaseNodeService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
import org.springframework.kafka.annotation.KafkaListener;
|
import org.springframework.kafka.annotation.KafkaListener;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ProjectCreatedListener {
|
public class ProjectCreatedListener {
|
||||||
public static final String CONSUME_ID = "test_track_project-created";
|
public static final String CONSUME_ID = "test_track_project-created";
|
||||||
|
@ -24,6 +19,8 @@ public class ProjectCreatedListener {
|
||||||
private ExtModuleNodeMapper extModuleNodeMapper;
|
private ExtModuleNodeMapper extModuleNodeMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ProjectMapper projectMapper;
|
private ProjectMapper projectMapper;
|
||||||
|
@Resource
|
||||||
|
private TestCaseNodeService testCaseNodeService;
|
||||||
|
|
||||||
@KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.PROJECT_CREATED_TOPIC, groupId = "${spring.application.name}")
|
@KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.PROJECT_CREATED_TOPIC, groupId = "${spring.application.name}")
|
||||||
public void consume(ConsumerRecord<?, String> record) {
|
public void consume(ConsumerRecord<?, String> record) {
|
||||||
|
@ -37,23 +34,7 @@ public class ProjectCreatedListener {
|
||||||
if (project == null) {
|
if (project == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 创建功能用例默认模块
|
||||||
// 防止重复创建功能用例默认节点
|
testCaseNodeService.createDefaultNode(projectId);
|
||||||
TestCaseNodeExample example = new TestCaseNodeExample();
|
|
||||||
example.createCriteria()
|
|
||||||
.andProjectIdEqualTo(projectId).andNameEqualTo(ProjectModuleDefaultNodeEnum.TEST_CASE_DEFAULT_NODE.getNodeName());
|
|
||||||
List<ModuleNode> moduleNodes = extModuleNodeMapper.selectByExample(ProjectModuleDefaultNodeEnum.TEST_CASE_DEFAULT_NODE.getTableName(), example);
|
|
||||||
if (moduleNodes.size() == 0) {
|
|
||||||
ModuleNode record = new ModuleNode();
|
|
||||||
record.setId(UUID.randomUUID().toString());
|
|
||||||
record.setCreateUser(project.getCreateUser());
|
|
||||||
record.setPos(1.0);
|
|
||||||
record.setLevel(1);
|
|
||||||
record.setCreateTime(System.currentTimeMillis());
|
|
||||||
record.setUpdateTime(System.currentTimeMillis());
|
|
||||||
record.setProjectId(projectId);
|
|
||||||
record.setName(ProjectModuleDefaultNodeEnum.TEST_CASE_DEFAULT_NODE.getNodeName());
|
|
||||||
extModuleNodeMapper.insert(ProjectModuleDefaultNodeEnum.TEST_CASE_DEFAULT_NODE.getTableName(), record);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
|
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtTestReviewCaseMapper;
|
import io.metersphere.base.mapper.ext.ExtTestReviewCaseMapper;
|
||||||
import io.metersphere.commons.constants.MicroServiceName;
|
import io.metersphere.commons.constants.MicroServiceName;
|
||||||
|
import io.metersphere.commons.constants.ProjectModuleDefaultNodeEnum;
|
||||||
import io.metersphere.commons.constants.TestCaseConstants;
|
import io.metersphere.commons.constants.TestCaseConstants;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.*;
|
import io.metersphere.commons.utils.*;
|
||||||
|
@ -36,6 +37,8 @@ import org.apache.ibatis.session.ExecutorType;
|
||||||
import org.apache.ibatis.session.SqlSession;
|
import org.apache.ibatis.session.SqlSession;
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
import org.mybatis.spring.SqlSessionUtils;
|
import org.mybatis.spring.SqlSessionUtils;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
@ -69,6 +72,10 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
|
||||||
TestPlanProjectService testPlanProjectService;
|
TestPlanProjectService testPlanProjectService;
|
||||||
@Resource
|
@Resource
|
||||||
TestPlanService testPlanService;
|
TestPlanService testPlanService;
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
private static final String TEST_CASE_DEFAULT_NODE_CREATE_KEY = "TEST_CASE:DEFAULT_NODE:CREATE";
|
||||||
|
|
||||||
public TestCaseNodeService() {
|
public TestCaseNodeService() {
|
||||||
super(TestCaseNodeDTO.class);
|
super(TestCaseNodeDTO.class);
|
||||||
|
@ -122,25 +129,12 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseNode getDefaultNode(String projectId) {
|
public TestCaseNode checkDefaultNode(String projectId) {
|
||||||
TestCaseNodeExample example = new TestCaseNodeExample();
|
TestCaseNode defaultNode = getDefaultNode(projectId);
|
||||||
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo("未规划用例").andParentIdIsNull();
|
if (defaultNode == null) {
|
||||||
List<TestCaseNode> list = testCaseNodeMapper.selectByExample(example);
|
return this.createDefaultNode(projectId);
|
||||||
if (CollectionUtils.isEmpty(list)) {
|
|
||||||
NodeNumDTO record = new NodeNumDTO();
|
|
||||||
record.setId(UUID.randomUUID().toString());
|
|
||||||
record.setCreateUser(SessionUtils.getUserId());
|
|
||||||
record.setName("未规划用例");
|
|
||||||
record.setPos(1.0);
|
|
||||||
record.setLevel(1);
|
|
||||||
record.setCreateTime(System.currentTimeMillis());
|
|
||||||
record.setUpdateTime(System.currentTimeMillis());
|
|
||||||
record.setProjectId(projectId);
|
|
||||||
testCaseNodeMapper.insert(record);
|
|
||||||
record.setCaseNum(0);
|
|
||||||
return record;
|
|
||||||
} else {
|
} else {
|
||||||
return list.get(0);
|
return defaultNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +216,7 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
|
||||||
request.setQueryUi(queryUi);
|
request.setQueryUi(queryUi);
|
||||||
this.setRequestWeekParam(request);
|
this.setRequestWeekParam(request);
|
||||||
// 判断当前项目下是否有默认模块,没有添加默认模块
|
// 判断当前项目下是否有默认模块,没有添加默认模块
|
||||||
this.getDefaultNode(projectId);
|
this.checkDefaultNode(projectId);
|
||||||
request.setProjectId(projectId);
|
request.setProjectId(projectId);
|
||||||
request.setUserId(SessionUtils.getUserId());
|
request.setUserId(SessionUtils.getUserId());
|
||||||
request.setNodeIds(null);
|
request.setNodeIds(null);
|
||||||
|
@ -291,8 +285,10 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
|
||||||
|
|
||||||
public List<TestCaseNodeDTO> getTrashCaseNode(String projectId, QueryTestCaseRequest request) {
|
public List<TestCaseNodeDTO> getTrashCaseNode(String projectId, QueryTestCaseRequest request) {
|
||||||
// 初始化回收站中模块被删除的用例, 挂在默认未规划模块, 获取回收站模块节点数据
|
// 初始化回收站中模块被删除的用例, 挂在默认未规划模块, 获取回收站模块节点数据
|
||||||
TestCaseNode defaultNode = this.getDefaultNode(projectId);
|
TestCaseNode defaultNode = this.checkDefaultNode(projectId);
|
||||||
|
if (defaultNode != null) {
|
||||||
extTestCaseMapper.updateNoModuleTrashNodeToDefault(projectId, defaultNode.getId(), defaultNode.getName());
|
extTestCaseMapper.updateNoModuleTrashNodeToDefault(projectId, defaultNode.getId(), defaultNode.getName());
|
||||||
|
}
|
||||||
request.setProjectId(projectId);
|
request.setProjectId(projectId);
|
||||||
request.setNodeIds(null);
|
request.setNodeIds(null);
|
||||||
ServiceUtils.setBaseQueryRequestCustomMultipleFields(request);
|
ServiceUtils.setBaseQueryRequestCustomMultipleFields(request);
|
||||||
|
@ -761,4 +757,49 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NodeNumDTO createDefaultNode(String projectId) {
|
||||||
|
// 加锁, 防止并发创建
|
||||||
|
RLock lock = redissonClient.getLock(TEST_CASE_DEFAULT_NODE_CREATE_KEY + ":" + projectId);
|
||||||
|
if (lock.tryLock()) {
|
||||||
|
try {
|
||||||
|
// 双重检查, 判断是否已经存在默认节点
|
||||||
|
if (getDefaultNode(projectId) != null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建默认节点, 只执行一次
|
||||||
|
NodeNumDTO record = new NodeNumDTO();
|
||||||
|
record.setId(UUID.randomUUID().toString());
|
||||||
|
record.setCreateUser(SessionUtils.getUserId());
|
||||||
|
record.setName(ProjectModuleDefaultNodeEnum.TEST_CASE_DEFAULT_NODE.getNodeName());
|
||||||
|
record.setPos(1.0);
|
||||||
|
record.setLevel(1);
|
||||||
|
record.setCreateTime(System.currentTimeMillis());
|
||||||
|
record.setUpdateTime(System.currentTimeMillis());
|
||||||
|
record.setProjectId(projectId);
|
||||||
|
testCaseNodeMapper.insert(record);
|
||||||
|
record.setCaseNum(0);
|
||||||
|
return record;
|
||||||
|
}catch (Exception e){
|
||||||
|
LogUtil.error(e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestCaseNode getDefaultNode(String projectId) {
|
||||||
|
TestCaseNodeExample example = new TestCaseNodeExample();
|
||||||
|
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(ProjectModuleDefaultNodeEnum.TEST_CASE_DEFAULT_NODE.getNodeName()).andParentIdIsNull();
|
||||||
|
List<TestCaseNode> defaultNodes = testCaseNodeMapper.selectByExample(example);
|
||||||
|
if (CollectionUtils.isEmpty(defaultNodes)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return defaultNodes.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue