enhancement #I821F1 增加测试案例,调整注释
This commit is contained in:
parent
7fdb5829f5
commit
ca9449f531
|
@ -216,53 +216,77 @@ public class FlowExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查 chain 的有效性,同时重新构建 FlowBus 的 chain,将调用的子 chain 连起来
|
* 检查 chain 的有效性,同时重新构建 FlowBus 的 chain,将其子 chain 引用连起来
|
||||||
* @throws CyclicDependencyException
|
* @throws CyclicDependencyException
|
||||||
*/
|
*/
|
||||||
private void checkValidOfChain() {
|
private void checkValidOfChain() {
|
||||||
|
|
||||||
// 存储已经构建完的有效的 chain 对应 Id
|
// 存储已经构建完的有效的 chain 对应 Id
|
||||||
Set<String> validChainIdSet = new HashSet<>();
|
Set<String> validChainIdSet = new HashSet<>();
|
||||||
|
|
||||||
// 遍历所有解析的 chain
|
// 遍历所有解析的 chain
|
||||||
for (Chain rootChain : FlowBus.getChainMap().values()) {
|
for (Chain rootChain : FlowBus.getChainMap().values()) {
|
||||||
|
|
||||||
// 不存在 validChainIdSet 中的 chain,说明还未检查
|
// 不存在 validChainIdSet 中的 chain,说明还未检查
|
||||||
if (!validChainIdSet.contains(rootChain.getChainId())) {
|
if (!validChainIdSet.contains(rootChain.getChainId())) {
|
||||||
|
|
||||||
// 与 rootChain 相关联的 chain 的 ID
|
// 与 rootChain 相关联的 chain 的 ID
|
||||||
Set<String> associatedChainIdSet = new HashSet<>();
|
Set<String> associatedChainIdSet = new HashSet<>();
|
||||||
|
|
||||||
// 检查 chain 的有效性,是否存在死循环情况
|
// 检查 chain 的有效性,是否存在死循环情况
|
||||||
checkValidOfChain(rootChain, associatedChainIdSet);
|
checkValidOfChain(rootChain, associatedChainIdSet);
|
||||||
|
|
||||||
// 检查完当前 chain 后,能走到这里说明当前相关的 chain 是有效的
|
// 检查完当前 chain 后,能走到这里说明当前相关的 chain 是有效的
|
||||||
validChainIdSet.addAll(associatedChainIdSet);
|
validChainIdSet.addAll(associatedChainIdSet);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查 chain 的有效性
|
* 检查 chain 的有效性
|
||||||
* @param currentChain 当前遍历到的 chain 节点
|
* @param currentChain 当前遍历到的 chain 节点
|
||||||
|
* @param associatedChainIdSet 与 rootChain 相关联的 chainId 集合
|
||||||
* @throws CyclicDependencyException
|
* @throws CyclicDependencyException
|
||||||
*/
|
*/
|
||||||
private void checkValidOfChain(Chain currentChain, Set<String> associatedChainIdSet) {
|
private void checkValidOfChain(Chain currentChain, Set<String> associatedChainIdSet) {
|
||||||
// 判断 completedChainIdSet 中是否已经存在对应的 chain
|
|
||||||
|
// 判断 associatedChainIdSet 中是否已经存在对应的 chain
|
||||||
if (associatedChainIdSet.add(currentChain.getChainId())) {
|
if (associatedChainIdSet.add(currentChain.getChainId())) {
|
||||||
|
|
||||||
// Set 中不存在则说明可能是父 chain 或者子 chain 未引用自身,又或者子 chain 未引用其父 chain,继续判断其子 chain
|
// Set 中不存在则说明可能是父 chain 或者子 chain 未引用自身,又或者子 chain 未引用其父 chain,继续判断其子 chain
|
||||||
for (Condition condition : currentChain.getConditionList()) {
|
for (Condition condition : currentChain.getConditionList()) {
|
||||||
|
|
||||||
// 遍历所有 executable 列表
|
// 遍历所有 executable 列表
|
||||||
for (Executable executable : condition.getExecutableList()) {
|
for (Executable executable : condition.getExecutableList()) {
|
||||||
|
|
||||||
// 只需判断 chain,因为只有 chain 才会存在死循环依赖情况
|
// 只需判断 chain,因为只有 chain 才会存在死循环依赖情况
|
||||||
if (executable instanceof Chain) {
|
if (executable instanceof Chain) {
|
||||||
|
|
||||||
// 能执行到此处,必能从 FlowBus 中获取到对应的 chain,故无需做非空判断
|
// 能执行到此处,必能从 FlowBus 中获取到对应的 chain,故无需做非空判断
|
||||||
Chain childrenChain = FlowBus.getChainMap().get(executable.getId());
|
Chain childrenChain = FlowBus.getChainMap().get(executable.getId());
|
||||||
|
|
||||||
// 递归检查 chain 有效性
|
// 递归检查 chain 有效性
|
||||||
checkValidOfChain(childrenChain, associatedChainIdSet);
|
checkValidOfChain(childrenChain, associatedChainIdSet);
|
||||||
|
|
||||||
// 重新构建 chain 的 condition 列表
|
// 重新构建 chain 的 condition 列表
|
||||||
((Chain) executable).setConditionList(childrenChain.getConditionList());
|
((Chain) executable).setConditionList(childrenChain.getConditionList());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
String errorMessage = StrUtil.format("There is a circular dependency in the chain[{}], please check carefully.", currentChain.getChainId());
|
||||||
|
|
||||||
|
LOG.error(errorMessage);
|
||||||
|
|
||||||
// chain 重复,说明子 chain 中引用了自身或其父 chain,存在死循环情况
|
// chain 重复,说明子 chain 中引用了自身或其父 chain,存在死循环情况
|
||||||
throw new CyclicDependencyException(StrUtil.format("There is a circular dependency in the chain[{}], please check carefully.", currentChain.getChainId()));
|
throw new CyclicDependencyException(errorMessage);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 此方法就是从原有的配置源主动拉取新的进行刷新
|
// 此方法就是从原有的配置源主动拉取新的进行刷新
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
package com.yomahub.liteflow.test.subflow.endlessLopp;
|
||||||
|
|
||||||
|
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||||
|
import com.yomahub.liteflow.exception.CyclicDependencyException;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||||
|
import com.yomahub.liteflow.test.BaseTest;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试多文件情况下 chain 死循环逻辑
|
||||||
|
*
|
||||||
|
* @author luo yi
|
||||||
|
* @since 2.11.1
|
||||||
|
*/
|
||||||
|
public class FlowInDifferentConfigTest extends BaseTest {
|
||||||
|
|
||||||
|
// 测试 chain 死循环
|
||||||
|
@Test
|
||||||
|
public void testChainEndlessLoop() {
|
||||||
|
Assertions.assertThrows(CyclicDependencyException.class, () -> {
|
||||||
|
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||||
|
config.setRuleSource("subflow/endlessLoop/flow-main.el.xml,subflow/endlessLoop/flow-sub1.el.xml");
|
||||||
|
FlowExecutorHolder.loadInstance(config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.yomahub.liteflow.test.subflow.endlessLopp;
|
||||||
|
|
||||||
|
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||||
|
import com.yomahub.liteflow.exception.CyclicDependencyException;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||||
|
import com.yomahub.liteflow.test.BaseTest;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试 json 文件情况下 chain 死循环逻辑
|
||||||
|
*
|
||||||
|
* @author luo yi
|
||||||
|
* @since 2.11.1
|
||||||
|
*/
|
||||||
|
public class FlowJsonTest extends BaseTest {
|
||||||
|
|
||||||
|
// 测试 chain 死循环
|
||||||
|
@Test
|
||||||
|
public void testChainEndlessLoop() {
|
||||||
|
Assertions.assertThrows(CyclicDependencyException.class, () -> {
|
||||||
|
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||||
|
config.setRuleSource("subflow/endlessLoop/flow.el.json");
|
||||||
|
FlowExecutorHolder.loadInstance(config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.yomahub.liteflow.test.subflow.endlessLopp;
|
||||||
|
|
||||||
|
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||||
|
import com.yomahub.liteflow.exception.CyclicDependencyException;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||||
|
import com.yomahub.liteflow.test.BaseTest;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试 xml 文件情况下 chain 死循环逻辑
|
||||||
|
*
|
||||||
|
* @author luo yi
|
||||||
|
* @since 2.11.1
|
||||||
|
*/
|
||||||
|
public class FlowXMLTest extends BaseTest {
|
||||||
|
|
||||||
|
// 测试 chain 死循环
|
||||||
|
@Test
|
||||||
|
public void testChainEndlessLoop() {
|
||||||
|
Assertions.assertThrows(CyclicDependencyException.class, () -> {
|
||||||
|
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||||
|
config.setRuleSource("subflow/endlessLoop/flow.el.xml");
|
||||||
|
FlowExecutorHolder.loadInstance(config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.yomahub.liteflow.test.subflow.endlessLopp;
|
||||||
|
|
||||||
|
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||||
|
import com.yomahub.liteflow.exception.CyclicDependencyException;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||||
|
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||||
|
import com.yomahub.liteflow.test.BaseTest;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试 yml 文件情况下 chain 死循环逻辑
|
||||||
|
*
|
||||||
|
* @author luo yi
|
||||||
|
* @since 2.11.1
|
||||||
|
*/
|
||||||
|
public class FlowYMLTest extends BaseTest {
|
||||||
|
|
||||||
|
// 测试 chain 死循环
|
||||||
|
@Test
|
||||||
|
public void testChainEndlessLoop() {
|
||||||
|
Assertions.assertThrows(CyclicDependencyException.class, () -> {
|
||||||
|
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||||
|
config.setRuleSource("subflow/endlessLoop/flow.el.yml");
|
||||||
|
FlowExecutorHolder.loadInstance(config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<flow>
|
||||||
|
<nodes>
|
||||||
|
<node id="a" class="com.yomahub.liteflow.test.subflow.cmp1.ACmp"/>
|
||||||
|
<node id="b" class="com.yomahub.liteflow.test.subflow.cmp1.BCmp"/>
|
||||||
|
<node id="c" class="com.yomahub.liteflow.test.subflow.cmp1.CCmp"/>
|
||||||
|
<node id="d" class="com.yomahub.liteflow.test.subflow.cmp1.DCmp"/>
|
||||||
|
<node id="e" class="com.yomahub.liteflow.test.subflow.cmp1.ECmp"/>
|
||||||
|
<node id="f" class="com.yomahub.liteflow.test.subflow.cmp2.FCmp"/>
|
||||||
|
<node id="g" class="com.yomahub.liteflow.test.subflow.cmp2.GCmp"/>
|
||||||
|
<node id="h" class="com.yomahub.liteflow.test.subflow.cmp2.HCmp"/>
|
||||||
|
<node id="m" class="com.yomahub.liteflow.test.subflow.cmp2.MCmp"/>
|
||||||
|
</nodes>
|
||||||
|
<chain name="chain1">
|
||||||
|
THEN(a, b, chain2);
|
||||||
|
</chain>
|
||||||
|
</flow>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<flow>
|
||||||
|
<chain name="chain2">
|
||||||
|
THEN(b, a, chain1);
|
||||||
|
</chain>
|
||||||
|
</flow>
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"flow": {
|
||||||
|
"nodes": {
|
||||||
|
"node": [
|
||||||
|
{
|
||||||
|
"id": "a",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp1.ACmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp1.BCmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp1.CCmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp1.DCmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp1.ECmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp2.FCmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "g",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp2.GCmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "h",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp2.HCmp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M",
|
||||||
|
"class": "com.yomahub.liteflow.test.subflow.cmp2.MCmp"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"chain": [
|
||||||
|
{
|
||||||
|
"name": "chain7",
|
||||||
|
"value": "THEN(a, chain8);"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "chain8",
|
||||||
|
"value": "THEN(b, chain9);"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "chain9",
|
||||||
|
"value": "WHEN(c, chain7);"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<flow>
|
||||||
|
<nodes>
|
||||||
|
<node id="a" class="com.yomahub.liteflow.test.subflow.cmp1.ACmp"/>
|
||||||
|
<node id="b" class="com.yomahub.liteflow.test.subflow.cmp1.BCmp"/>
|
||||||
|
<node id="c" class="com.yomahub.liteflow.test.subflow.cmp1.CCmp"/>
|
||||||
|
<node id="d" class="com.yomahub.liteflow.test.subflow.cmp1.DCmp"/>
|
||||||
|
<node id="e" class="com.yomahub.liteflow.test.subflow.cmp1.ECmp"/>
|
||||||
|
<node id="f" class="com.yomahub.liteflow.test.subflow.cmp2.FCmp"/>
|
||||||
|
<node id="g" class="com.yomahub.liteflow.test.subflow.cmp2.GCmp"/>
|
||||||
|
<node id="h" class="com.yomahub.liteflow.test.subflow.cmp2.HCmp"/>
|
||||||
|
<node id="m" class="com.yomahub.liteflow.test.subflow.cmp2.MCmp"/>
|
||||||
|
</nodes>
|
||||||
|
<chain name="chain1">
|
||||||
|
THEN(a, chain2);
|
||||||
|
</chain>
|
||||||
|
|
||||||
|
<chain name="chain2">
|
||||||
|
THEN(b, chain3);
|
||||||
|
</chain>
|
||||||
|
|
||||||
|
<chain name="chain3">
|
||||||
|
THEN(c, chain1);
|
||||||
|
</chain>
|
||||||
|
</flow>
|
|
@ -0,0 +1,28 @@
|
||||||
|
flow:
|
||||||
|
nodes:
|
||||||
|
node:
|
||||||
|
- id: a
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp1.ACmp
|
||||||
|
- id: b
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp1.BCmp
|
||||||
|
- id: c
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp1.CCmp
|
||||||
|
- id: d
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp1.DCmp
|
||||||
|
- id: e
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp1.ECmp
|
||||||
|
- id: f
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp2.FCmp
|
||||||
|
- id: g
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp2.GCmp
|
||||||
|
- id: h
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp2.HCmp
|
||||||
|
- id: h
|
||||||
|
class: com.yomahub.liteflow.test.subflow.cmp2.MCmp
|
||||||
|
chain:
|
||||||
|
- name: chain4
|
||||||
|
value: "THEN(a, chain5);"
|
||||||
|
- name: chain5
|
||||||
|
value: "THEN(b, chain6);"
|
||||||
|
- name: chain6
|
||||||
|
value: "THEN(c, chain5);"
|
Loading…
Reference in New Issue