feat(功能用例): 用例详情添加关联/取消关联前后置接口&部分逻辑和接口通用
This commit is contained in:
parent
29fb6dd00e
commit
4bc05648fc
|
@ -21,10 +21,7 @@ import jakarta.annotation.Resource;
|
|||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -76,4 +73,10 @@ public class FunctionalCaseRelationshipController {
|
|||
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
|
||||
return PageUtils.setPageInfo(page, functionalCaseRelationshipEdgeService.getFunctionalCasePage(request));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
public void delete(@PathVariable("id") String id) {
|
||||
functionalCaseRelationshipEdgeService.delete(id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.functional.mapper;
|
|||
|
||||
import io.metersphere.functional.dto.FunctionalCaseRelationshipDTO;
|
||||
import io.metersphere.functional.request.RelationshipRequest;
|
||||
import io.metersphere.system.dto.RelationshipEdgeDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -12,4 +13,10 @@ public interface ExtFunctionalCaseRelationshipEdgeMapper {
|
|||
List<String> getGraphIds(@Param("ids") List<String> ids);
|
||||
|
||||
List<FunctionalCaseRelationshipDTO> list(@Param("request") RelationshipRequest request, @Param("sort") String sort);
|
||||
|
||||
RelationshipEdgeDTO getGraphId(@Param("id") String id);
|
||||
|
||||
List<RelationshipEdgeDTO> getEdgeByGraphId(@Param("graphId") String graphId);
|
||||
|
||||
void update(@Param("ids") List<String> ids, @Param("graphId") String graphId);
|
||||
}
|
||||
|
|
|
@ -57,4 +57,23 @@
|
|||
fcre.create_time desc
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getGraphId" resultType="io.metersphere.system.dto.RelationshipEdgeDTO" parameterType="java.lang.String">
|
||||
select source_id sourceId, target_id targetId, graph_id graphId from functional_case_relationship_edge where id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="getEdgeByGraphId" parameterType="java.lang.String" resultType="io.metersphere.system.dto.RelationshipEdgeDTO">
|
||||
select source_id sourceId, target_id targetId from functional_case_relationship_edge where graph_id = #{graphId}
|
||||
</select>
|
||||
|
||||
<update id="update">
|
||||
update functional_case_relationship_edge set graph_id = #{graphId} where (source_id in
|
||||
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>
|
||||
or target_id in
|
||||
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>)
|
||||
</update>
|
||||
</mapper>
|
|
@ -14,9 +14,9 @@ import io.metersphere.functional.mapper.ExtFunctionalCaseRelationshipEdgeMapper;
|
|||
import io.metersphere.functional.mapper.FunctionalCaseRelationshipEdgeMapper;
|
||||
import io.metersphere.functional.request.RelationshipAddRequest;
|
||||
import io.metersphere.functional.request.RelationshipRequest;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.dto.RelationshipEdgeDTO;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.utils.RelationshipEdgeUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
|
@ -83,27 +83,14 @@ public class FunctionalCaseRelationshipEdgeService {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
HashSet<String> nodeIds = new HashSet<>();
|
||||
nodeIds.addAll(edgeList.stream().map(FunctionalCaseRelationshipEdge::getSourceId).collect(Collectors.toSet()));
|
||||
nodeIds.addAll(edgeList.stream().map(FunctionalCaseRelationshipEdge::getTargetId).collect(Collectors.toSet()));
|
||||
// 判断是否有环
|
||||
HashSet<String> visitedSet = new HashSet<>();
|
||||
nodeIds.forEach(nodeId -> {
|
||||
if (!visitedSet.contains(nodeId) && directedCycle(nodeId, edgeList, new HashSet<>(), visitedSet)) {
|
||||
throw new MSException(Translator.get("cycle_relationship"));
|
||||
}
|
||||
;
|
||||
});
|
||||
List<RelationshipEdgeDTO> edgeDTOS = edgeList.stream().map(column -> new RelationshipEdgeDTO(column.getSourceId(), column.getTargetId())).collect(Collectors.toList());
|
||||
RelationshipEdgeUtils.checkEdge(edgeDTOS);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
FunctionalCaseRelationshipEdgeMapper batchMapper = sqlSession.getMapper(FunctionalCaseRelationshipEdgeMapper.class);
|
||||
|
||||
edgeList.forEach(item -> {
|
||||
if (addEdgesIds.contains(item.getSourceId() + item.getTargetId())) {
|
||||
if (batchMapper.selectByPrimaryKey(item.getId()) == null) {
|
||||
batchMapper.insert(item);
|
||||
} else {
|
||||
item.setGraphId(graphId); // 把原来图的id设置成合并后新的图的id
|
||||
batchMapper.updateByPrimaryKey(item);
|
||||
}
|
||||
} else {
|
||||
item.setGraphId(graphId); // 把原来图的id设置成合并后新的图的id
|
||||
|
@ -134,45 +121,6 @@ public class FunctionalCaseRelationshipEdgeService {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 给定一点,深度搜索该连通图中是否存在环
|
||||
*
|
||||
* @param id
|
||||
* @param edges
|
||||
* @param markSet 标记该路径上经过的节点
|
||||
* @param visitedSet 标记访问过的节点
|
||||
* @return
|
||||
*/
|
||||
public boolean directedCycle(String id, List<FunctionalCaseRelationshipEdge> edges, Set<String> markSet, Set<String> visitedSet) {
|
||||
|
||||
if (markSet.contains(id)) {
|
||||
// 如果已经访问过该节点,则说明存在环
|
||||
return true;
|
||||
}
|
||||
|
||||
markSet.add(id);
|
||||
visitedSet.add(id);
|
||||
|
||||
ArrayList<String> nextLevelNodes = new ArrayList();
|
||||
for (FunctionalCaseRelationshipEdge relationshipEdge : edges) {
|
||||
if (id.equals(relationshipEdge.getSourceId())) {
|
||||
nextLevelNodes.add(relationshipEdge.getTargetId());
|
||||
}
|
||||
}
|
||||
|
||||
for (String nextNode : nextLevelNodes) {
|
||||
if (directedCycle(nextNode, edges, markSet, visitedSet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 关键,递归完这一条路径要把这个标记去掉,否则会误判为有环
|
||||
// 比如 1->3, 1->2->3 , 3 经过多次但是无环
|
||||
markSet.remove(id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已经存在的依赖关系图
|
||||
*
|
||||
|
@ -229,4 +177,11 @@ public class FunctionalCaseRelationshipEdgeService {
|
|||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public void delete(String id) {
|
||||
RelationshipEdgeUtils.updateGraphId(id, extFunctionalCaseRelationshipEdgeMapper::getGraphId, extFunctionalCaseRelationshipEdgeMapper::getEdgeByGraphId, extFunctionalCaseRelationshipEdgeMapper::update);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ public class FunctionalCaseRelationshipControllerTests extends BaseTest {
|
|||
public static final String RELATE_PAGE = "/functional/case/relationship/relate/page";
|
||||
public static final String ADD = "/functional/case/relationship/add";
|
||||
public static final String PAGE = "/functional/case/relationship/page";
|
||||
public static final String DELETE = "/functional/case/relationship/delete/";
|
||||
|
||||
|
||||
@Test
|
||||
|
@ -86,6 +87,12 @@ public class FunctionalCaseRelationshipControllerTests extends BaseTest {
|
|||
// 返回请求正常
|
||||
Assertions.assertNotNull(postResultHolder);
|
||||
|
||||
|
||||
//增加覆盖率
|
||||
request.setId("wx_relationship_1");
|
||||
request.setType("POST");
|
||||
request.setSelectIds(List.of("wx_relationship_6"));
|
||||
this.requestPostWithOkAndReturn(ADD, request);
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,5 +129,23 @@ public class FunctionalCaseRelationshipControllerTests extends BaseTest {
|
|||
request.setId("wx_relationship_1");
|
||||
request.setType("POST");
|
||||
this.requestPostWithOkAndReturn(PAGE, request);
|
||||
request.setId("test1111");
|
||||
request.setType("POST");
|
||||
this.requestPostWithOkAndReturn(PAGE, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testDelete() throws Exception {
|
||||
MvcResult postResult = this.requestGetWithOkAndReturn(DELETE + "relationship_1");
|
||||
// 获取返回值
|
||||
String postReturnData = postResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder postResultHolder = JSON.parseObject(postReturnData, ResultHolder.class);
|
||||
// 返回请求正常
|
||||
Assertions.assertNotNull(postResultHolder);
|
||||
|
||||
//异常覆盖
|
||||
assertErrorCode(this.requestGet(DELETE + "test"), MsHttpResultCode.FAILED);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package io.metersphere.system.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
public class RelationshipEdgeDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String sourceId;
|
||||
private String targetId;
|
||||
private String graphId;
|
||||
|
||||
|
||||
public RelationshipEdgeDTO(String sourceId, String targetId) {
|
||||
this.sourceId = sourceId;
|
||||
this.targetId = targetId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package io.metersphere.system.utils;
|
||||
|
||||
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.dto.RelationshipEdgeDTO;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RelationshipEdgeUtils {
|
||||
|
||||
public static void checkEdge(List<RelationshipEdgeDTO> edgeDTOS) {
|
||||
HashSet<String> nodeIds = new HashSet<>();
|
||||
nodeIds.addAll(edgeDTOS.stream().map(RelationshipEdgeDTO::getSourceId).collect(Collectors.toSet()));
|
||||
nodeIds.addAll(edgeDTOS.stream().map(RelationshipEdgeDTO::getTargetId).collect(Collectors.toSet()));
|
||||
// 判断是否有环
|
||||
HashSet<String> visitedSet = new HashSet<>();
|
||||
nodeIds.forEach(nodeId -> {
|
||||
if (!visitedSet.contains(nodeId) && directedCycle(nodeId, edgeDTOS, new HashSet<>(), visitedSet)) {
|
||||
throw new MSException(Translator.get("cycle_relationship"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定一点,深度搜索该连通图中是否存在环
|
||||
*
|
||||
* @param id
|
||||
* @param edges
|
||||
* @param markSet 标记该路径上经过的节点
|
||||
* @param visitedSet 标记访问过的节点
|
||||
* @return
|
||||
*/
|
||||
public static boolean directedCycle(String id, List<RelationshipEdgeDTO> edges, Set<String> markSet, Set<String> visitedSet) {
|
||||
|
||||
if (markSet.contains(id)) {
|
||||
// 如果已经访问过该节点,则说明存在环
|
||||
return true;
|
||||
}
|
||||
|
||||
markSet.add(id);
|
||||
visitedSet.add(id);
|
||||
|
||||
ArrayList<String> nextLevelNodes = new ArrayList();
|
||||
for (RelationshipEdgeDTO relationshipEdge : edges) {
|
||||
if (id.equals(relationshipEdge.getSourceId())) {
|
||||
nextLevelNodes.add(relationshipEdge.getTargetId());
|
||||
}
|
||||
}
|
||||
|
||||
for (String nextNode : nextLevelNodes) {
|
||||
if (directedCycle(nextNode, edges, markSet, visitedSet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 关键,递归完这一条路径要把这个标记去掉,否则会误判为有环
|
||||
// 比如 1->3, 1->2->3 , 3 经过多次但是无环
|
||||
markSet.remove(id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static void updateGraphId(String id, Function<String, RelationshipEdgeDTO> getGraphIdFunc, Function<String, List<RelationshipEdgeDTO>> getEdgeByGraphIdFunc, BiConsumer<List, String> updateFunc) {
|
||||
RelationshipEdgeDTO edge = getGraphIdFunc.apply(id);
|
||||
if (edge == null) {
|
||||
throw new MSException(Translator.get("relationship_not_exist"));
|
||||
}
|
||||
List<RelationshipEdgeDTO> edges = getEdgeByGraphIdFunc.apply(edge.getGraphId());
|
||||
|
||||
// 去掉要删除的边
|
||||
edges = edges.stream()
|
||||
.filter(i -> !i.getSourceId().equals(edge.getSourceId()) && !i.getTargetId().equals(edge.getTargetId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<String> nodes = new HashSet<>();
|
||||
Set<String> markSet = new HashSet<>();
|
||||
nodes.addAll(edges.stream().map(RelationshipEdgeDTO::getSourceId).collect(Collectors.toSet()));
|
||||
nodes.addAll(edges.stream().map(RelationshipEdgeDTO::getTargetId).collect(Collectors.toSet()));
|
||||
|
||||
dfsForMark(edge.getSourceId(), edges, markSet, true);
|
||||
dfsForMark(edge.getSourceId(), edges, markSet, false);
|
||||
|
||||
// 如果连通的点减少,说明形成了两个不连通子图,重新设置graphId
|
||||
if (markSet.size() != nodes.size()) {
|
||||
List<String> updateIds = new ArrayList<>(markSet);
|
||||
updateFunc.accept(updateIds, UUID.randomUUID().toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历标记经过的节点
|
||||
*
|
||||
* @param node
|
||||
* @param edges
|
||||
* @param markSet
|
||||
* @param isForwardDirection
|
||||
*/
|
||||
public static void dfsForMark(String node, List<RelationshipEdgeDTO> edges, Set<String> markSet, boolean isForwardDirection) {
|
||||
markSet.add(node);
|
||||
|
||||
Set<String> nextLevelNodes = new HashSet<>();
|
||||
|
||||
for (RelationshipEdgeDTO edge : edges) {
|
||||
if (isForwardDirection) {
|
||||
if (node.equals(edge.getSourceId())) {
|
||||
nextLevelNodes.add(edge.getTargetId());
|
||||
}
|
||||
} else {
|
||||
if (node.equals(edge.getTargetId())) {
|
||||
nextLevelNodes.add(edge.getSourceId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextLevelNodes.forEach(nextNode -> {
|
||||
if (!markSet.contains(nextNode)) {
|
||||
dfsForMark(nextNode, edges, markSet, true);
|
||||
dfsForMark(nextNode, edges, markSet, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue