feat(用例评审): 新增用例评审模块功能

This commit is contained in:
guoyuqi 2023-11-22 18:46:32 +08:00 committed by 刘瑞斌
parent 25acb2b894
commit 2a51b922c6
17 changed files with 1349 additions and 5 deletions

View File

@ -218,6 +218,19 @@ public class PermissionConstants {
/*------ end: FUNCTIONAL_CASE ------*/
/*------ start: CASE_REVIEW ------*/
public static final String CASE_REVIEW_READ = "CASE_REVIEW:READ";
public static final String CASE_REVIEW_READ_ADD = "CASE_REVIEW:READ+ADD";
public static final String CASE_REVIEW_READ_UPDATE = "CASE_REVIEW:READ+UPDATE";
public static final String CASE_REVIEW_READ_DELETE = "CASE_REVIEW:READ+DELETE";
public static final String CASE_REVIEW_READ_COMMENT = "CASE_REVIEW:READ+COMMENT";
public static final String CASE_REVIEW_READ_EXPORT = "CASE_REVIEW:READ+EXPORT";
public static final String CASE_REVIEW_READ_IMPORT = "CASE_REVIEW:READ+IMPORT";
/*------ end: FUNCTIONAL_CASE ------*/
/*------ start: API_DEBUG ------*/

View File

@ -0,0 +1,6 @@
package io.metersphere.functional.constants;
public enum CaseReviewPassRule {
SINGLE,
MULTIPLE
}

View File

@ -0,0 +1,8 @@
package io.metersphere.functional.constants;
public enum CaseReviewStatus {
PREPARED,
UNDERWAY,
COMPLETED,
ARCHIVED;
}

View File

@ -0,0 +1,5 @@
package io.metersphere.functional.constants;
public enum DemandPlatform {
LOCAL;
}

View File

@ -0,0 +1,62 @@
package io.metersphere.functional.controller;
import io.metersphere.functional.request.CaseReviewModuleCreateRequest;
import io.metersphere.functional.request.CaseReviewModuleUpdateRequest;
import io.metersphere.functional.service.CaseReviewModuleService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "用例管理-用例评审-模块")
@RestController
@RequestMapping("/case/review/module")
public class CaseReviewModuleController {
@Resource
private CaseReviewModuleService caseReviewModuleService;
@GetMapping("/tree/{projectId}")
@Operation(summary = "用例管理-用例评审-模块-获取模块树")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ)
public List<BaseTreeNode> getTree(@PathVariable String projectId) {
return caseReviewModuleService.getTree(projectId);
}
@PostMapping("/add")
@Operation(summary = "用例管理-用例评审-模块-添加模块")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_ADD)
public void add(@RequestBody @Validated CaseReviewModuleCreateRequest request) {
caseReviewModuleService.add(request, SessionUtils.getUserId());
}
@PostMapping("/update")
@Operation(summary = "用例管理-用例评审-模块-修改模块")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE)
public void list(@RequestBody @Validated CaseReviewModuleUpdateRequest request) {
caseReviewModuleService.update(request, SessionUtils.getUserId());
}
@PostMapping("/move")
@Operation(summary = "用例管理-用例评审-模块-移动模块")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE)
public void moveNode(@Validated @RequestBody NodeMoveRequest request) {
caseReviewModuleService.moveNode(request, SessionUtils.getUserId());
}
@GetMapping("/delete/{moduleId}")
@Operation(summary = "用例管理-用例评审-模块-删除模块")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_DELETE)
public void deleteNode(@PathVariable String moduleId) {
caseReviewModuleService.deleteModule(moduleId);
}
}

View File

@ -0,0 +1,16 @@
package io.metersphere.functional.mapper;
import io.metersphere.functional.domain.CaseReview;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author wx
*/
public interface ExtCaseReviewMapper {
List<CaseReview> checkCaseByModuleIds(@Param("moduleIds") List<String> deleteIds);
}

View File

@ -0,0 +1,17 @@
<?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.functional.mapper.ExtCaseReviewMapper">
<select id="checkCaseByModuleIds" resultType="io.metersphere.functional.domain.CaseReview">
SELECT
id, name, module_id, create_user
FROM
case_review
WHERE
module_id IN
<foreach collection="moduleIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -0,0 +1,27 @@
package io.metersphere.functional.mapper;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.system.dto.sdk.BaseModule;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtCaseReviewModuleMapper {
List<BaseTreeNode> selectBaseByProjectId(@Param("projectId")String projectId);
List<BaseTreeNode> selectBaseByIds(@Param("ids") List<String> ids);
List<String> selectChildrenIdsByParentIds(@Param("ids") List<String> deleteIds);
List<String> selectChildrenIdsSortByPos(String parentId);
Long getMaxPosByParentId(String parentId);
BaseModule selectBaseModuleById(String dragNodeId);
BaseModule selectModuleByParentIdAndPosOperator(NodeSortQueryParam nodeSortQueryParam);
List<BaseTreeNode> selectIdAndParentIdByProjectId(String projectId);
}

View File

@ -0,0 +1,64 @@
<?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.functional.mapper.ExtCaseReviewModuleMapper">
<select id="selectBaseByProjectId" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT id, name, parent_id AS parentId, 'module' AS type
FROM case_review_module
WHERE project_id = #{projectId}
ORDER BY pos
</select>
<select id="selectBaseByIds" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT id, name, parent_id AS parentId, 'module' AS type
FROM case_review_module
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
ORDER BY pos
</select>
<select id="selectModuleByParentIdAndPosOperator"
parameterType="io.metersphere.project.dto.NodeSortQueryParam"
resultType="io.metersphere.system.dto.sdk.BaseModule">
SELECT id, name, pos, project_Id, parent_id
FROM case_review_module
WHERE parent_id = #{parentId}
<if test="operator == 'moreThan'">
AND pos &gt; #{pos}
</if>
<if test="operator == 'lessThan'">
AND pos &lt; #{pos}
</if>
ORDER BY pos
<if test="operator == 'lessThan' or operator == 'latest'">
DESC
</if>
LIMIT 1
</select>
<select id="selectChildrenIdsByParentIds" resultType="java.lang.String">
SELECT id FROM case_review_module WHERE parent_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="getMaxPosByParentId" resultType="java.lang.Long">
SELECT max(pos)
FROM case_review_module
WHERE parent_id = #{0}
</select>
<select id="selectChildrenIdsSortByPos" resultType="java.lang.String">
SELECT id FROM case_review_module WHERE parent_id = #{0}
ORDER BY pos ASC
</select>
<select id="selectBaseModuleById" resultType="io.metersphere.system.dto.sdk.BaseModule">
SELECT id, name, pos, project_Id, parent_id
FROM case_review_module
WHERE id = #{0}
</select>
<select id="selectIdAndParentIdByProjectId" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT id, parent_id AS parentId
FROM case_review_module
WHERE project_id = #{0}
</select>
</mapper>

View File

@ -0,0 +1,33 @@
package io.metersphere.functional.request;
import io.metersphere.sdk.constants.ModuleConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author guoyuqi
*/
@Data
public class CaseReviewModuleCreateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{project.id.not_blank}")
private String projectId;
@Schema(description = "模块名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{file_module.name.not_blank}")
private String name;
@Schema(description = "父模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{parent.node.not_blank}")
private String parentId = ModuleConstants.ROOT_NODE_PARENT_ID;
}

View File

@ -0,0 +1,28 @@
package io.metersphere.functional.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author guoyuqi
*/
@Data
public class CaseReviewModuleUpdateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{file_module.id.not_blank}")
private String id;
@Schema(description = "模块名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{file_module.name.not_blank}")
private String name;
}

View File

@ -1,5 +0,0 @@
package io.metersphere.functional.result;
public enum DemandPlatform {
LOCAL;
}

View File

@ -0,0 +1,243 @@
/**
* @filename:CaseReviewModuleServiceImpl 2023年5月17日
* @project ms V3.x
* Copyright(c) 2018 wx Co. Ltd.
* All right reserved.
*/
package io.metersphere.functional.service;
import io.metersphere.functional.domain.*;
import io.metersphere.functional.mapper.*;
import io.metersphere.functional.request.CaseReviewModuleCreateRequest;
import io.metersphere.functional.request.CaseReviewModuleUpdateRequest;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortDTO;
import io.metersphere.project.service.ModuleTreeService;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class CaseReviewModuleService extends ModuleTreeService {
@Resource
private CaseReviewModuleMapper caseReviewModuleMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ExtCaseReviewModuleMapper extCaseReviewModuleMapper;
@Resource
private ExtCaseReviewMapper extCaseReviewMapper;
@Resource
private DeleteCaseReviewService deleteCaseReviewService;
@Resource
private OperationLogService operationLogService;
public List<BaseTreeNode> getTree(String projectId) {
List<BaseTreeNode> fileModuleList = extCaseReviewModuleMapper.selectBaseByProjectId(projectId);
return super.buildTreeAndCountResource(fileModuleList, true, Translator.get("default.module"));
}
public void add(CaseReviewModuleCreateRequest request, String userId) {
CaseReviewModule caseReviewModule = new CaseReviewModule();
caseReviewModule.setId(IDGenerator.nextStr());
caseReviewModule.setName(request.getName());
caseReviewModule.setParentId(request.getParentId());
caseReviewModule.setProjectId(request.getProjectId());
this.checkDataValidity(caseReviewModule);
caseReviewModule.setCreateTime(System.currentTimeMillis());
caseReviewModule.setUpdateTime(caseReviewModule.getCreateTime());
caseReviewModule.setPos(this.countPos(request.getParentId()));
caseReviewModule.setCreateUser(userId);
caseReviewModule.setUpdateUser(userId);
caseReviewModuleMapper.insert(caseReviewModule);
}
public void update(CaseReviewModuleUpdateRequest request, String userId) {
CaseReviewModule updateModule = caseReviewModuleMapper.selectByPrimaryKey(request.getId());
if (updateModule == null) {
throw new MSException(Translator.get("case_module.not.exist"));
}
updateModule.setName(request.getName());
this.checkDataValidity(updateModule);
updateModule.setUpdateTime(System.currentTimeMillis());
updateModule.setUpdateUser(userId);
updateModule.setCreateUser(null);
updateModule.setCreateTime(null);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
}
public void moveNode(NodeMoveRequest request, String userId) {
NodeSortDTO nodeSortDTO = super.getNodeSortDTO(request,
extCaseReviewModuleMapper::selectBaseModuleById,
extCaseReviewModuleMapper::selectModuleByParentIdAndPosOperator);
CaseReviewModuleExample example = new CaseReviewModuleExample();
example.createCriteria().andParentIdEqualTo(nodeSortDTO.getParent().getId()).andIdEqualTo(request.getDragNodeId());
//节点换到了别的节点下,要先更新parent节点再计算sort
if (caseReviewModuleMapper.countByExample(example) == 0) {
CaseReviewModule caseReviewModule = new CaseReviewModule();
caseReviewModule.setId(request.getDragNodeId());
caseReviewModule.setParentId(nodeSortDTO.getParent().getId());
caseReviewModule.setUpdateUser(userId);
caseReviewModule.setUpdateTime(System.currentTimeMillis());
caseReviewModuleMapper.updateByPrimaryKeySelective(caseReviewModule);
}
super.sort(nodeSortDTO);
}
public void deleteModule(String moduleId) {
CaseReviewModule deleteModule = caseReviewModuleMapper.selectByPrimaryKey(moduleId);
if (deleteModule != null) {
List<CaseReview> caseReviews = this.deleteModuleByIds(Collections.singletonList(moduleId), new ArrayList<>(), deleteModule.getProjectId());
batchDelLog(caseReviews, deleteModule.getProjectId());
}
}
public void batchDelLog(List<CaseReview> caseReviews, String projectId) {
List<LogDTO> dtoList = new ArrayList<>();
caseReviews.forEach(item -> {
LogDTO dto = new LogDTO(
projectId,
"",
item.getId(),
item.getCreateUser(),
OperationLogType.DELETE.name(),
OperationLogModule.CASE_REVIEW,
item.getName());
dto.setPath("/case/review/module/delete/");
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(item));
dtoList.add(dto);
});
operationLogService.batchAdd(dtoList);
}
public List<CaseReview> deleteModuleByIds(List<String>deleteIds, List<CaseReview>caseReviews, String projectId){
if (CollectionUtils.isEmpty(deleteIds)) {
return caseReviews;
}
CaseReviewModuleExample caseReviewModuleExample = new CaseReviewModuleExample();
caseReviewModuleExample.createCriteria().andIdIn(deleteIds);
caseReviewModuleMapper.deleteByExample(caseReviewModuleExample);
List<CaseReview> caseReviewList = extCaseReviewMapper.checkCaseByModuleIds(deleteIds);
if (CollectionUtils.isNotEmpty(caseReviewList)) {
caseReviews.addAll(caseReviewList);
}
deleteCaseReviewService.deleteCaseReviewResource(deleteIds, projectId);
List<String> childrenIds = extCaseReviewModuleMapper.selectChildrenIdsByParentIds(deleteIds);
if (CollectionUtils.isNotEmpty(childrenIds)) {
deleteModuleByIds(childrenIds, caseReviews, projectId);
}
return caseReviews;
}
private Long countPos(String parentId) {
Long maxPos = extCaseReviewModuleMapper.getMaxPosByParentId(parentId);
if (maxPos == null) {
return LIMIT_POS;
} else {
return maxPos + LIMIT_POS;
}
}
/**
* 查找当前项目下模块每个节点对应的资源统计
*
*/
public Map<String, Long> getModuleCountMap(String projectId, List<ModuleCountDTO> moduleCountDTOList) {
//构建模块树并计算每个节点下的所有数量包含子节点
List<BaseTreeNode> treeNodeList = this.getTreeOnlyIdsAndResourceCount(projectId, moduleCountDTOList);
//通过广度遍历的方式构建返回值
return super.getIdCountMapByBreadth(treeNodeList);
}
public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(String projectId, List<ModuleCountDTO> moduleCountDTOList) {
//节点内容只有Id和parentId
List<BaseTreeNode> fileModuleList = extCaseReviewModuleMapper.selectIdAndParentIdByProjectId(projectId);
return super.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get("default.module"));
}
/**
* 检查数据的合法性
*/
private void checkDataValidity(CaseReviewModule caseReviewModule) {
CaseReviewModuleExample example = new CaseReviewModuleExample();
if (!StringUtils.equals(caseReviewModule.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
//检查父ID是否存在
example.createCriteria().andIdEqualTo(caseReviewModule.getParentId());
if (caseReviewModuleMapper.countByExample(example) == 0) {
throw new MSException(Translator.get("parent.node.not_blank"));
}
example.clear();
if (StringUtils.isNotBlank(caseReviewModule.getProjectId())) {
//检查项目ID是否和父节点ID一致
example.createCriteria().andProjectIdEqualTo(caseReviewModule.getProjectId()).andIdEqualTo(caseReviewModule.getParentId());
if (caseReviewModuleMapper.countByExample(example) == 0) {
throw new MSException(Translator.get("project.cannot.match.parent"));
}
example.clear();
}
}
example.createCriteria().andParentIdEqualTo(caseReviewModule.getParentId()).andNameEqualTo(caseReviewModule.getName()).andIdNotEqualTo(caseReviewModule.getId());
if (caseReviewModuleMapper.countByExample(example) > 0) {
throw new MSException(Translator.get("node.name.repeat"));
}
example.clear();
}
@Override
public void updatePos(String id, long pos) {
CaseReviewModule updateModule = new CaseReviewModule();
updateModule.setPos(pos);
updateModule.setId(id);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
}
@Override
public void refreshPos(String parentId) {
List<String> childrenIdSortByPos = extCaseReviewModuleMapper.selectChildrenIdsSortByPos(parentId);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
CaseReviewModuleMapper batchUpdateMapper = sqlSession.getMapper(CaseReviewModuleMapper.class);
for (int i = 0; i < childrenIdSortByPos.size(); i++) {
String nodeId = childrenIdSortByPos.get(i);
CaseReviewModule updateModule = new CaseReviewModule();
updateModule.setId(nodeId);
updateModule.setPos((i + 1) * LIMIT_POS);
batchUpdateMapper.updateByPrimaryKeySelective(updateModule);
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}

View File

@ -0,0 +1,59 @@
package io.metersphere.functional.service;
import io.metersphere.functional.domain.*;
import io.metersphere.functional.mapper.*;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author guoyuqi
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class DeleteCaseReviewService {
@Resource
private CaseReviewMapper caseReviewMapper;
@Resource
private CaseReviewUserMapper caseReviewUserMapper;
@Resource
private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper;
@Resource
private CaseReviewFunctionalCaseArchiveMapper caseReviewFunctionalCaseArchiveMapper;
@Resource
private CaseReviewFollowerMapper caseReviewFollowerMapper;
@Resource
private CaseReviewHistoryMapper caseReviewHistoryMapper;
public void deleteCaseReviewResource(List<String> ids, String projectId) {
//TODO 删除各种关联关系 1.关联用例(功能/接口/场景/ui/性能) 2.评审和评审人 3. 归档的用例 4. 关注人 5.评审历史 6. 操作记录
//1.刪除评审与功能用例关联关系
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdIn(ids);
caseReviewFunctionalCaseMapper.deleteByExample(caseReviewFunctionalCaseExample);
//2. 删除评审和评审人
CaseReviewUserExample caseReviewUserExample = new CaseReviewUserExample();
caseReviewUserExample.createCriteria().andReviewIdIn(ids);
caseReviewUserMapper.deleteByExample(caseReviewUserExample);
//3. 删除归档的用例
CaseReviewFunctionalCaseArchiveExample archiveExample = new CaseReviewFunctionalCaseArchiveExample();
archiveExample.createCriteria().andReviewIdIn(ids);
caseReviewFunctionalCaseArchiveMapper.deleteByExample(archiveExample);
//4.删除关注人
CaseReviewFollowerExample caseReviewFollowerExample = new CaseReviewFollowerExample();
caseReviewFollowerExample.createCriteria().andReviewIdIn(ids);
caseReviewFollowerMapper.deleteByExample(caseReviewFollowerExample);
//5.删除评审历史
CaseReviewHistoryExample caseReviewHistoryExample = new CaseReviewHistoryExample();
caseReviewHistoryExample.createCriteria().andReviewIdIn(ids);
caseReviewHistoryMapper.deleteByExample(caseReviewHistoryExample);
//TODO: 6.删除操作记录
//删除评审
CaseReviewExample caseReviewExample = new CaseReviewExample();
caseReviewExample.createCriteria().andIdIn(ids).andProjectIdEqualTo(projectId);
caseReviewMapper.deleteByExample(caseReviewExample);
}
}

View File

@ -0,0 +1,764 @@
package io.metersphere.functional.controller;
import io.metersphere.functional.constants.CaseReviewPassRule;
import io.metersphere.functional.constants.CaseReviewStatus;
import io.metersphere.functional.domain.CaseReview;
import io.metersphere.functional.domain.CaseReviewModule;
import io.metersphere.functional.domain.CaseReviewModuleExample;
import io.metersphere.functional.mapper.CaseReviewMapper;
import io.metersphere.functional.mapper.CaseReviewModuleMapper;
import io.metersphere.functional.request.CaseReviewModuleCreateRequest;
import io.metersphere.functional.request.CaseReviewModuleUpdateRequest;
import io.metersphere.functional.service.CaseReviewModuleService;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
public class CaseReviewModuleControllerTests extends BaseTest {
private static Project project;
private static final String URL_MODULE_TREE = "/case/review/module/tree/";
private static final String URL_MODULE_TREE_ADD = "/case/review/module/add";
private static final String URL_MODULE_TREE_UPDATE = "/case/review/module/update";
private static List<BaseTreeNode> preliminaryTreeNodes = new ArrayList<>();
private static final String URL_MODULE_TREE_MOVE = "/case/review/module/move";
private static final String URL_MODULE_TREE_DELETE = "/case/review/module/delete/";
@Resource
private CaseReviewModuleService caseReviewModuleService;
@Resource
private CaseReviewModuleMapper caseReviewModuleMapper;
@Resource
private CaseReviewMapper caseReviewMapper;
@Resource
private ProjectMapper projectMapper;
@BeforeEach
public void initTestData() {
if (project == null) {
Project initProject = new Project();
initProject.setId(IDGenerator.nextStr());
initProject.setNum(null);
initProject.setOrganizationId("100001");
initProject.setName("caseReviewModuleTestProject");
initProject.setDescription("caseReviewModuleTestProject");
initProject.setCreateUser("admin");
initProject.setUpdateUser("admin");
initProject.setCreateTime(System.currentTimeMillis());
initProject.setUpdateTime(System.currentTimeMillis());
initProject.setEnable(true);
initProject.setModuleSetting("[\"apiTest\",\"uiTest\"]");
projectMapper.insertSelective(initProject);
project = projectMapper.selectByPrimaryKey(initProject.getId());
}
}
@Test
@Order(1)
public void emptyDataTest() throws Exception {
//空数据下检查模块树
List<BaseTreeNode> treeNodes = this.getCaseReviewModuleTreeNode();
//检查有没有默认节点
boolean hasNode = false;
for (BaseTreeNode baseTreeNode : treeNodes) {
if (StringUtils.equals(baseTreeNode.getId(), ModuleConstants.DEFAULT_NODE_ID)) {
hasNode = true;
}
Assertions.assertNotNull(baseTreeNode.getParentId());
}
Assertions.assertTrue(hasNode);
}
@Test
@Order(2)
public void addModuleTestSuccess() throws Exception {
//根目录下创建节点(a1
CaseReviewModuleCreateRequest request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1");
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
String returnId = mvcResult.getResponse().getContentAsString();
Assertions.assertNotNull(returnId);
List<BaseTreeNode> treeNodes = this.getCaseReviewModuleTreeNode();
BaseTreeNode a1Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
if (StringUtils.equals(baseTreeNode.getName(), request.getName())) {
a1Node = baseTreeNode;
}
Assertions.assertNotNull(baseTreeNode.getParentId());
}
Assertions.assertNotNull(a1Node);
//根目录下创建节点a2和a3在a1下创建子节点a1-b1
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a2");
this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
request.setName("a3");
this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-b1");
request.setParentId(a1Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
treeNodes = this.getCaseReviewModuleTreeNode();
BaseTreeNode a1b1Node = null;
BaseTreeNode a2Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode childNode : baseTreeNode.getChildren()) {
if (StringUtils.equals(childNode.getName(), "a1-b1")) {
a1b1Node = childNode;
}
Assertions.assertNotNull(childNode.getParentId());
}
} else if (StringUtils.equals(baseTreeNode.getName(), "a2")) {
a2Node = baseTreeNode;
}
}
Assertions.assertNotNull(a2Node);
Assertions.assertNotNull(a1b1Node);
//a1节点下可以继续添加a1节点
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1");
request.setParentId(a1Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
//继续创建a1下继续创建a1-a1-b1,
treeNodes = this.getCaseReviewModuleTreeNode();
BaseTreeNode a1ChildNode = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode childNode : baseTreeNode.getChildren()) {
Assertions.assertNotNull(childNode.getParentId());
if (StringUtils.equals(childNode.getName(), "a1")) {
a1ChildNode = childNode;
}
}
}
}
Assertions.assertNotNull(a1ChildNode);
//a1的子节点a1下继续创建节点a1-a1-c1
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-a1-c1");
request.setParentId(a1ChildNode.getId());
this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
treeNodes = this.getCaseReviewModuleTreeNode();
BaseTreeNode a1a1c1Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode secondNode : baseTreeNode.getChildren()) {
Assertions.assertNotNull(secondNode.getParentId());
if (StringUtils.equals(secondNode.getName(), "a1") && CollectionUtils.isNotEmpty(secondNode.getChildren())) {
for (BaseTreeNode thirdNode : secondNode.getChildren()) {
Assertions.assertNotNull(thirdNode.getParentId());
if (StringUtils.equals(thirdNode.getName(), "a1-a1-c1")) {
a1a1c1Node = thirdNode;
}
}
}
}
}
}
Assertions.assertNotNull(a1a1c1Node);
//子节点a1-b1下继续创建节点a1-b1-c1
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-b1-c1");
request.setParentId(a1b1Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_TREE_ADD, request);
treeNodes = this.getCaseReviewModuleTreeNode();
BaseTreeNode a1b1c1Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode secondNode : baseTreeNode.getChildren()) {
if (StringUtils.equals(secondNode.getName(), "a1-b1") && CollectionUtils.isNotEmpty(secondNode.getChildren())) {
for (BaseTreeNode thirdNode : secondNode.getChildren()) {
if (StringUtils.equals(thirdNode.getName(), "a1-b1-c1")) {
a1b1c1Node = thirdNode;
}
}
}
}
}
}
Assertions.assertNotNull(a1b1c1Node);
preliminaryTreeNodes = treeNodes;
}
@Test
@Order(3)
public void addModuleTestError() throws Exception {
this.preliminaryData();
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1");
assert a1Node != null;
//参数校验
CaseReviewModuleCreateRequest request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().isBadRequest());
request = new CaseReviewModuleCreateRequest();
request.setName("none");
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().isBadRequest());
request = new CaseReviewModuleCreateRequest();
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().isBadRequest());
request = new CaseReviewModuleCreateRequest();
request.setParentId(null);
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().isBadRequest());
//父节点ID不存在的
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("ParentIsUUID");
request.setParentId(IDGenerator.nextStr());
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().is5xxServerError());
//添加重复的a1节点
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1");
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().is5xxServerError());
//a1节点下添加重复的a1-b1节点
request = new CaseReviewModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-b1");
request.setParentId(a1Node.getId());
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().is5xxServerError());
//子节点的项目ID和父节点的不匹配
request = new CaseReviewModuleCreateRequest();
request.setProjectId(IDGenerator.nextStr());
request.setName("RandomUUID");
request.setParentId(a1Node.getId());
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().is5xxServerError());
//项目ID和父节点的不匹配
request = new CaseReviewModuleCreateRequest();
request.setProjectId("100001100001");
request.setName("RandomUUID");
request.setParentId(a1Node.getId());
this.requestPost(URL_MODULE_TREE_ADD, request).andExpect(status().is5xxServerError());
}
public static BaseTreeNode getNodeByName(List<BaseTreeNode> preliminaryTreeNodes, String nodeName) {
for (BaseTreeNode firstLevelNode : preliminaryTreeNodes) {
if (StringUtils.equals(firstLevelNode.getName(), nodeName)) {
return firstLevelNode;
}
if (CollectionUtils.isNotEmpty(firstLevelNode.getChildren())) {
for (BaseTreeNode secondLevelNode : firstLevelNode.getChildren()) {
if (StringUtils.equals(secondLevelNode.getName(), nodeName)) {
return secondLevelNode;
}
if (CollectionUtils.isNotEmpty(secondLevelNode.getChildren())) {
for (BaseTreeNode thirdLevelNode : secondLevelNode.getChildren()) {
if (StringUtils.equals(thirdLevelNode.getName(), nodeName)) {
return thirdLevelNode;
}
}
}
}
}
}
return null;
}
@Test
@Order(4)
public void updateModuleTestSuccess() throws Exception {
if (CollectionUtils.isEmpty(preliminaryTreeNodes)) {
this.addModuleTestSuccess();
}
//更改名称
BaseTreeNode a1Node = null;
for (BaseTreeNode node : preliminaryTreeNodes) {
if (StringUtils.equals(node.getName(), "a1")) {
for (BaseTreeNode a1ChildrenNode : node.getChildren()) {
if (StringUtils.equals(a1ChildrenNode.getName(), "a1")) {
a1Node = a1ChildrenNode;
}
}
}
}
assert a1Node != null;
CaseReviewModuleUpdateRequest updateRequest = new CaseReviewModuleUpdateRequest();
updateRequest.setId(a1Node.getId());
updateRequest.setName("a1-a1");
this.requestPostWithOkAndReturn(URL_MODULE_TREE_UPDATE, updateRequest);
preliminaryTreeNodes = this.getCaseReviewModuleTreeNode();
}
@Test
@Order(5)
public void updateModuleTestError() throws Exception {
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1-a1");
assert a1Node != null;
//反例-参数校验
CaseReviewModuleUpdateRequest updateRequest = new CaseReviewModuleUpdateRequest();
this.requestPost(URL_MODULE_TREE_UPDATE, updateRequest).andExpect(status().isBadRequest());
//id不存在
updateRequest = new CaseReviewModuleUpdateRequest();
updateRequest.setId(IDGenerator.nextStr());
updateRequest.setName(IDGenerator.nextStr());
this.requestPost(URL_MODULE_TREE_UPDATE, updateRequest).andExpect(status().is5xxServerError());
//名称重复 a1-a1改为a1-b1
updateRequest = new CaseReviewModuleUpdateRequest();
updateRequest.setId(a1Node.getId());
updateRequest.setName("a1-b1");
this.requestPost(URL_MODULE_TREE_UPDATE, updateRequest).andExpect(status().is5xxServerError());
}
@Test
@Order(6)
public void moveTest() throws Exception {
this.preliminaryData();
/*
*默认节点
|
·a1 +
| |
| ·a1-b1 +
| | |
| | ·a1-b1-c1
| |
| *a1-a1 +创建的时候是a1通过修改改为a1-a1
| |
| ·a1-a1-c1
|
·a2
|
·a3
*/
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = getNodeByName(preliminaryTreeNodes, "a2");
BaseTreeNode a3Node = getNodeByName(preliminaryTreeNodes, "a3");
BaseTreeNode a1a1Node = getNodeByName(preliminaryTreeNodes, "a1-a1");
BaseTreeNode a1b1Node = getNodeByName(preliminaryTreeNodes, "a1-b1");
//父节点内移动-移动到首位 a1挪到a3后面
NodeMoveRequest request = new NodeMoveRequest();
{
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a3Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1Node.getId(), null, false);
}
//父节点内移动-移动到末位 在上面的基础上a1挪到a2上面
{
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a1Node.getId(), a2Node.getId(), null, false);
}
//父节点内移动-移动到中位 a1移动到a2-a3中间
{
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a1Node.getId(), a3Node.getId(), false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a1Node.getId(), a2Node.getId(), null, false);
}
//跨节点移动-移动到首位 a3移动到a1-b1前面然后移动回来;
{
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1b1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1b1Node.getId(), null, false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到末尾 a3移动到a1-a1后面然后移动回来;
{
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1a1Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a1a1Node.getId(), a3Node.getId(), null, false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到中位 a3移动到a1-b1和a1-a1中间然后移动回来;
{
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1b1Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a1b1Node.getId(), a3Node.getId(), a1a1Node.getId(), false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//父节点内移动-a3移动到首位pos小于2是否触发计算函数 先手动更改a1的pos为2然后移动a3到a1前面
{
//更改pos
CaseReviewModule updateModule = new CaseReviewModule();
updateModule.setId(a1Node.getId());
updateModule.setPos(2L);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1Node.getId(), null, true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//父节点内移动-移动到中位前后节点pos差不大于2是否触发计算函数在上面的 a3-a1-a2的基础上 先手动更改a1pos为3*64a2的pos为3*64+2然后移动a3到a1和a2中间
{
//更改pos
CaseReviewModule updateModule = new CaseReviewModule();
updateModule.setId(a1Node.getId());
updateModule.setPos(3 * 64L);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
updateModule.setId(a2Node.getId());
updateModule.setPos(3 * 64 + 2L);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a1Node.getId(), a3Node.getId(), a2Node.getId(), true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到首位pos小于2是否触发计算函数先手动更改a1-b1的pos为2然后移动a3到a1-b1前面最后再移动回来
{
//更改pos
CaseReviewModule updateModule = new CaseReviewModule();
updateModule.setId(a1b1Node.getId());
updateModule.setPos(2L);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1b1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1b1Node.getId(), null, true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到中位前后节点pos差不大于2是否触发计算函数先手动更改a1-a1的pos为a1-b1+2然后移动a3到a1-a1前面最后再移动回来
{
//更改pos
CaseReviewModule updateModule = new CaseReviewModule();
updateModule.setId(a1b1Node.getId());
updateModule.setPos(3 * 64L);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
updateModule.setId(a1a1Node.getId());
updateModule.setPos(3 * 64 + 2L);
caseReviewModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1a1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a1b1Node.getId(), a3Node.getId(), a1a1Node.getId(), true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//移动到没有子节点的节点下 a3移动到a2下
{
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(0);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
CaseReviewModule a3Module = caseReviewModuleMapper.selectByPrimaryKey(a3Node.getId());
Assertions.assertEquals(a3Module.getParentId(), a2Node.getId());
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_TREE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
}
@Test
@Order(7)
public void moveTestError() throws Exception {
this.preliminaryData();
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = getNodeByName(preliminaryTreeNodes, "a2");
//drag节点为空
NodeMoveRequest request = new NodeMoveRequest();
request.setDragNodeId(null);
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().isBadRequest());
//drag节点不存在
request = new NodeMoveRequest();
request.setDragNodeId(IDGenerator.nextStr());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().is5xxServerError());
//drop节点为空
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(null);
request.setDropPosition(1);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().isBadRequest());
//drop节点不存在
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(IDGenerator.nextStr());
request.setDropPosition(1);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().is5xxServerError());
//position为0的时候节点不存在
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(IDGenerator.nextStr());
request.setDropPosition(0);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().is5xxServerError());
//dragNode和dropNode一样
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().is5xxServerError());
//position不是-1 0 1
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(4);
this.requestPost(URL_MODULE_TREE_MOVE, request).andExpect(status().is5xxServerError());
}
@Test
@Order(8)
public void deleteModuleTestSuccess() throws Exception {
this.preliminaryData();
// 删除没有用例的节点a1-b1-c1 检查是否级联删除根节点
BaseTreeNode a1b1Node = getNodeByName(this.getCaseReviewModuleTreeNode(), "a1-b1");
assert a1b1Node != null;
this.requestGetWithOk(URL_MODULE_TREE_DELETE+a1b1Node.getId());
this.checkModuleIsEmpty(a1b1Node.getId());
// 删除有用例的节点 a1-a1 检查是否级联删除根节点
//创建数据
BaseTreeNode a1a1Node = getNodeByName(this.getCaseReviewModuleTreeNode(), "a1-a1");
CaseReview name = createCaseReview(a1a1Node, "name");
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(name.getId());
Assertions.assertNotNull(caseReview);
this.requestGetWithOk(URL_MODULE_TREE_DELETE+a1a1Node.getId());
this.checkModuleIsEmpty(a1a1Node.getId());
CaseReview caseReviewDel = caseReviewMapper.selectByPrimaryKey(name.getId());
Assertions.assertNotNull(caseReviewDel);
//删除不存在的节点
this.requestGetWithOk(URL_MODULE_TREE_DELETE+IDGenerator.nextNum());
// 测试删除根节点
this.requestGetWithOk(URL_MODULE_TREE_DELETE+ModuleConstants.DEFAULT_NODE_ID);
//service层判断测试删除空集合
caseReviewModuleService.deleteModuleByIds(new ArrayList<>(),new ArrayList<>(), project.getId());
checkLog(caseReview.getId(), OperationLogType.DELETE, URL_MODULE_TREE_DELETE);
}
private CaseReview createCaseReview(BaseTreeNode a1a1Node, String name) {
CaseReview caseReview = new CaseReview();
caseReview.setId(IDGenerator.nextStr());
caseReview.setName(name);
caseReview.setModuleId(a1a1Node.getId());
caseReview.setProjectId(project.getId());
caseReview.setStatus(CaseReviewStatus.PREPARED.toString());
caseReview.setReviewPassRule(CaseReviewPassRule.SINGLE.toString());
caseReview.setCreateUser("gyq");
caseReview.setCreateTime(System.currentTimeMillis());
caseReview.setUpdateUser("gyq");
caseReview.setUpdateTime(System.currentTimeMillis());
caseReviewMapper.insertSelective(caseReview);
return caseReview;
}
private void checkModuleIsEmpty(String id) {
CaseReviewModuleExample example = new CaseReviewModuleExample();
example.createCriteria().andParentIdEqualTo(id);
Assertions.assertEquals(caseReviewModuleMapper.countByExample(example), 0);
}
private List<BaseTreeNode> getCaseReviewModuleTreeNode() throws Exception {
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get(URL_MODULE_TREE+"/"+project.getId()).header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, project.getId())
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
String returnData = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class);
}
private void preliminaryData() throws Exception {
if (CollectionUtils.isEmpty(preliminaryTreeNodes)) {
/*
这里需要获取修改过的树的结构期望的最终结构是这样的*为测试用例中挂载文件的节点 · 为空节点
*默认节点
|
·a1 +
| |
| ·a1-b1 +
| | |
| | ·a1-b1-c1
| |
| *a1-a1 +创建的时候是a1通过修改改为a1-a1
| | |
| | ·a1-a1-c1(用于测试文件移动)
|
·a2
|
·a3
*/
this.updateModuleTestSuccess();
}
}
private void checkModulePos(String firstNode, String secondNode, String thirdNode, boolean isRecalculate) {
CaseReviewModule firstModule = caseReviewModuleMapper.selectByPrimaryKey(firstNode);
CaseReviewModule secondModule = caseReviewModuleMapper.selectByPrimaryKey(secondNode);
CaseReviewModule thirdModule = null;
Assertions.assertTrue(firstModule.getPos() < secondModule.getPos());
if (StringUtils.isNotBlank(thirdNode)) {
thirdModule = caseReviewModuleMapper.selectByPrimaryKey(thirdNode);
Assertions.assertTrue(secondModule.getPos() < thirdModule.getPos());
}
if (isRecalculate) {
int limitPos = 64;
Assertions.assertEquals(0, firstModule.getPos() % limitPos);
Assertions.assertEquals(0, secondModule.getPos() % limitPos);
if (thirdModule != null) {
Assertions.assertEquals(0, thirdModule.getPos() % limitPos);
}
}
}
}

View File

@ -247,6 +247,7 @@ public class FunctionalCaseDemandControllerTests extends BaseTest {
DemandDTO demandDTO2 = new DemandDTO();
demandDTO2.setDemandId("100002");
demandDTO2.setDemandName("手动加入Tapd1");
demandDTO2.setDemandUrl("https://www.tapd.cn/55049933/prong/stories/view/1155049933001012783");
demandList.add(demandDTO2);
DemandDTO demandDTO3 = new DemandDTO();
demandDTO3.setDemandId("100003");

View File

@ -100,6 +100,9 @@ public class OperationLogModule {
//用例
public static final String FUNCTIONAL_CASE = "FUNCTIONAL_CASE";
public static final String CASE_REVIEW = "CASE_REVIEW";
//接口调试
public static final String API_DEBUG = "API_DEBUG";
//接口管理-环境