Commit bd2558c0 authored by chenjianxing's avatar chenjianxing Committed by jianxing
Browse files

fix: 关系图保存时检测环并且合并图

parent 03d3dceb
dev feat_api_custom_field feat_custom_field feat_environment_group feat_environment_group_copy feat_timing_clean feat_vc feat_vc_testtrack fix_lyh_v1.17 master pr@dev@feat@四种协议test、case页面优化 pr@dev@feat_add_issueremark pr@dev@feat_sync pr@dev@feat_工作空间多项目环境组合 pr@dev@feat_性能测试版本对比页面修改_自动执行 pr@dev@feat_接口测试_文档结构断言 pr@dev@fix pr@dev@fix_scenario_load_test pr@dev@fix_sql版本冲突 pr@dev@fix_从公共用例库移除_再编辑用例发现无法加到公共用例库了 pr@dev@fix_代码扫描图标不显示 pr@dev@fix_修复环境设置中编辑下模块和路径匹配时模块和路径允许为空的缺陷 pr@dev@fix_修改db版本号 pr@dev@fix_功能用例版本切换 pr@dev@fix_场景导入按钮失效 pr@dev@fix_应用管理没有自动保存 pr@dev@fix_接口case优化 pr@dev@fix_接口测试_复制接口 pr@dev@fix_接口测试_安全漏洞 pr@dev@fix_接口测试_引用问题 pr@dev@fix_接口用例在定义后面 pr@dev@fix_接口详情-变更历史无变更详情日志 pr@dev@fix_操作日志_增删改查除系统设置中的操作均无法跳转 pr@dev@fix_新增测试阶段字段在筛选列表中未更新 pr@dev@fix_测试跟踪_功能用例_公共用例库_选择修改用例责任人后,新的责任人仍不可编辑和删除该用例 pr@dev@fix_用例评审_测试计划_关注人支持多选 pr@dev@fix_被引用的数据删除显示重复 pr@dev@refactor_menu_pos pr@dev@refactor_获取场景报告接口效率优化 pr@dev@内置函数构造器优化增加mock数据说明示例及场景变量 pr@master@fix_代码扫描图标不显示 pr@v1.14@fix_接口测试_复制接口 pr@v1.14@fix_用例评审_测试计划_关注人支持多选 pr@v1.15@fix_sync pr@v1.16@fix_scenario_load pr@v1.16@fix_接口测试_安全漏洞 pr@v1.16@fix_接口测试_引用问题 pr@v1.16@fix_接口详情-变更历史无变更详情日志 pr@v1.16@fix_测试跟踪_功能用例_公共用例库_选择修改用例责任人后,新的责任人仍不可编辑和删除该用例 pr@v1.16@refactor_获取场景报告接口效率优化 pr@v1.17@feat_我的工作台加版本筛选 pr@v1.17@fix pr@v1.17@fix_功能用例版本切换 pr@v1.17@fix_新增测试阶段字段在筛选列表中未更新 pr@v1.18@fix_修复环境设置中编辑下模块和路径匹配时模块和路径允许为空的缺陷 refactor_environment_group refactor_project_setting refactor_ws_notice_template repr@dev_master_v1.16@ repr@dev_v1.14@@fix_【接口定义】-添加mock函数时值生成优化+页面翻译“return” repr@dev_v1.14@f7409212@fix_接口测试_CSV优化 repr@dev_v1.14_v1.16@fc598de402cffa8744ee656948f715c31e7d58a2@refactor_场景资源池执行添加日志打印 repr@dev_v1.16@1abe60fc@fix_接口测试_循环控制器 repr@dev_v1.16@22a21ac3@fix_接口测试_自动化步骤 repr@dev_v1.16@5d8ba4eb@fix_接口详情-变更历史无变更详情日志 repr@dev_v1.16@6de996ff@fix_接口定义_开启过多时环境与接口名称重叠 repr@dev_v1.16@a009bb38@fix_接口测试_场景执行 repr@dev_v1.16@e15672af3dc95618192ee81aedbefffdfd377b8a@fix_代码扫描图标不显示 repr@dev_v1.16@e43c11a7@fix_应用管理没有保存 repr@dev_v1.16@e43c11a7@fix_应用管理没有自动保存 repr@dev_v1.16_v1.17@430a1864ffe9800240f4fbd9b0c92991305c0baa@fix_脑图创建的用例导出状态和责任人为空 repr@dev_v1.16_v1.17@91c1b2a7@fix_接口测试_插件步骤 repr@dev_v1.17@0d05cd92d9a1b005aac8c07594625f3cda8319080d05cd92d9a1b005aac8c07594625f3cda831908@feat_测试跟踪用例版本相关 repr@dev_v1.17@0d05cd92d9a1b005aac8c07594625f3cda831908@fix_功能用例版本管理回收站 repr@dev_v1.18@abc86b09@fix_lyh_dev repr@devev_v1.16@31e9453dccbf5b363f72b9a2c4d6b1f40d9e92f5@fix_tapd不显示图片 repr@v1.16@fix_JSONPATH断言等有200个字符限制 repr@v1.16_dev@09a4129d@fix_接口测试_调试状态 repr@v1.16_dev@11eb4bc6@feat_error_report repr@v1.16_dev@6a89622f@fix_接口测试_JSON校验处理 repr@v1.16_dev@d5cf72dc@fix_接口测试_场景报告 repr@v1.16_dev@e2e90011@fix_testplan_用例执行 repr@v1.16_dev@ef78a7eb@fix_xpack_code repr@v1.16_v1.17_dev@bfb01376@fix_bugs_import_api repr@v1.16_v1.17_dev@dd1880fa@fix_bugs_0118 seleniumdocker获取报告图表 ui v1.14 v1.15 v1.16 v1.17 v1.18 工作空间多项目环境组合 v1.18.2-rc2 v1.18.2-rc1 v1.18.2-rc0 v1.18.2-arm64 v1.18.1 v1.18.0 v1.17.3 v1.17.2 v1.17.1 v1.17.0 v1.16.6 v1.16.5 v1.16.4 v1.16.3 v1.16.2 v1.16.1 v1.16.0 v1.15.4 v1.15.3 v1.15.2 v1.15.1 v1.15.0 v1.14.7 v1.14.6 v1.14.5 v1.14.4 v1.14.3 v1.14.2 v1.14.1 v1.14.0 v1.14.0-rc3 v1.14.0-rc2 v1.14.0-rc1
No related merge requests found
Showing with 116 additions and 30 deletions
+116 -30
package io.metersphere.base.mapper.ext;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtRelationshipEdgeMapper {
List<String> getGraphIdsByNodeIds(@Param("ids") List<String> ids);
}
<?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.ExtRelationshipEdgeMapper">
<select id="getGraphIdsByNodeIds" resultType="java.lang.String">
select distinct graph_id
from relationship_edge
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>
</select>
</mapper>
......@@ -563,7 +563,7 @@
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
and test_case.status != 'Trash';
and (test_case.status != 'Trash' or test_case.status is NULL);
</select>
<update id="deleteToGc">
......
......@@ -4,6 +4,8 @@ package io.metersphere.service;
import io.metersphere.base.domain.RelationshipEdge;
import io.metersphere.base.domain.RelationshipEdgeExample;
import io.metersphere.base.mapper.RelationshipEdgeMapper;
import io.metersphere.base.mapper.ext.ExtRelationshipEdgeMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.RelationshipEdgeRequest;
import org.apache.commons.collections.CollectionUtils;
......@@ -15,9 +17,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -31,6 +31,8 @@ public class RelationshipEdgeService {
@Resource
private RelationshipEdgeMapper relationshipEdgeMapper;
@Resource
private ExtRelationshipEdgeMapper extRelationshipEdgeMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
public void delete(String sourceId, String targetId) {
......@@ -95,29 +97,51 @@ public class RelationshipEdgeService {
return relationshipEdgeMapper.selectByExample(example);
}
/**
* 保存新的边
* 校验是否存在环
* 同时将两个不连通的图合并成一个图
* @param request
*/
public void saveBatch(RelationshipEdgeRequest request) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
RelationshipEdgeMapper batchMapper = sqlSession.getMapper(RelationshipEdgeMapper.class);
String graphId = getGraphId(request);
// todo 检验是否有环
String graphId = UUID.randomUUID().toString();
List<RelationshipEdge> relationshipEdges = getEdgesBySaveRequest(request);
Set<String> addEdgesIds = new HashSet<>();
if (CollectionUtils.isNotEmpty(request.getTargetIds())) {
for (String targetId : request.getTargetIds()) {
request.getTargetIds().forEach(targetId -> {
RelationshipEdge edge = getNewRelationshipEdge(graphId, request.getId(), targetId, request.getType());
batchMapper.insert(edge);
}
relationshipEdges.add(edge);
addEdgesIds.add(edge.getSourceId() + edge.getTargetId());
});
}
if (CollectionUtils.isNotEmpty(request.getSourceIds())) {
for (String sourceId : request.getSourceIds()) {
request.getSourceIds().forEach(sourceId -> {
RelationshipEdge edge = getNewRelationshipEdge(graphId, sourceId, request.getId(), request.getType());
batchMapper.insert(edge);
}
relationshipEdges.add(edge);
addEdgesIds.add(edge.getSourceId() + edge.getTargetId());
});
}
// 判断是否有环, 两个方向都搜索一遍
if (directedCycle(request.getId(), relationshipEdges, new HashSet<>(), true) ||
directedCycle(request.getId(), relationshipEdges, new HashSet<>(), false)) {
MSException.throwException("关联后存在循环依赖,请检查依赖关系");
};
relationshipEdges.forEach(item -> {
if (addEdgesIds.contains(item.getSourceId() + item.getTargetId())) {
batchMapper.insert(item);
} else {
item.setGraphId(graphId); // 把原来图的id设置成合并后新的图的id
batchMapper.updateByPrimaryKey(item);
}
});
sqlSession.flushStatements();
}
......@@ -133,15 +157,11 @@ public class RelationshipEdgeService {
}
/**
* 获取当前节点所在图的id
* 查找要关联的边所在图的所有的边
* @param request
* @return
*/
private String getGraphId(RelationshipEdgeRequest request) {
// 判断这些顶点是否已经和其他顶点连通
// 连通的话,加到同一个图中,否则新建一个图,即 graphId
String graphId = UUID.randomUUID().toString();
public List<RelationshipEdge> getEdgesBySaveRequest(RelationshipEdgeRequest request) {
List<String> graphNodes = new ArrayList<>();
graphNodes.add(request.getId());
if (request.getTargetIds() != null) {
......@@ -150,18 +170,58 @@ public class RelationshipEdgeService {
if (request.getSourceIds() != null) {
graphNodes.addAll(request.getSourceIds());
}
List<String> graphIds = extRelationshipEdgeMapper.getGraphIdsByNodeIds(graphNodes);
if (CollectionUtils.isEmpty(graphIds)) {
return new ArrayList<>();
}
RelationshipEdgeExample example = new RelationshipEdgeExample();
example.createCriteria()
.andSourceIdIn(graphNodes);
example.or(
example.createCriteria()
.andTargetIdIn(graphNodes)
);
List<RelationshipEdge> relationshipEdges = relationshipEdgeMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(relationshipEdges)) {
return relationshipEdges.get(0).getGraphId();
.andGraphIdIn(graphIds);
return relationshipEdgeMapper.selectByExample(example);
}
/**
* 给定一点,深度搜索该连通图中是否存在环
* @param id
* @param edges
* @param markSet
* @param isForwardDirection
* @return
*/
public boolean directedCycle(String id, List<RelationshipEdge> edges, Set<String> markSet, Boolean isForwardDirection) {
if (markSet.contains(id)) {
// 如果已经访问过该节点,则说明存在环
return true;
}
return graphId;
markSet.add(id);
ArrayList<String> nextLevelNodes = new ArrayList();
for (RelationshipEdge relationshipEdge : edges) {
if (isForwardDirection) {// 正向则搜索 sourceId 是当前节点的边
if (id.equals(relationshipEdge.getSourceId())) {
nextLevelNodes.add(relationshipEdge.getTargetId());
}
} else {
if (id.equals(relationshipEdge.getTargetId())) {
nextLevelNodes.add(relationshipEdge.getSourceId());
}
}
}
for (String nextNode : nextLevelNodes) {
if (directedCycle(nextNode, edges, markSet, isForwardDirection)) {
return true;
};
}
// 关键,递归完这一条路径要把这个标记去掉,否则会误判为有环
// 比如 1->3, 1->2->3 , 3 经过多次但是无环
markSet.remove(id);
return false;
}
/**
......
......@@ -446,7 +446,6 @@ export default {
activated() {
this.getTemplateField();
this.condition.filters = {reviewStatus: ["Prepare", "Pass", "UnPass"]};
this.condition.filters = {status: ["Prepare" , "Underway" , "Completed"]}
let ids = this.$route.params.ids;
if (ids) {
this.condition.ids = ids;
......@@ -458,7 +457,7 @@ export default {
selectNodeIds() {
this.page.currentPage = 1;
if(!this.trashEnable){
this.condition.filters.status = ["Prepare" , "Underway" , "Completed"];
this.condition.filters.status = [];
}
initCondition(this.condition, false);
this.initTableData();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment