enhancement #I821F1 增加测试案例,调整注释

This commit is contained in:
luoyi 2023-09-22 23:38:58 +08:00
parent 7fdb5829f5
commit ca9449f531
10 changed files with 279 additions and 3 deletions

View File

@ -216,53 +216,77 @@ public class FlowExecutor {
}
/**
* 检查 chain 的有效性同时重新构建 FlowBus chain调用的子 chain 连起来
* 检查 chain 的有效性同时重新构建 FlowBus chain其子 chain 引用连起来
* @throws CyclicDependencyException
*/
private void checkValidOfChain() {
// 存储已经构建完的有效的 chain 对应 Id
Set<String> validChainIdSet = new HashSet<>();
// 遍历所有解析的 chain
for (Chain rootChain : FlowBus.getChainMap().values()) {
// 不存在 validChainIdSet 中的 chain说明还未检查
if (!validChainIdSet.contains(rootChain.getChainId())) {
// rootChain 相关联的 chain ID
Set<String> associatedChainIdSet = new HashSet<>();
// 检查 chain 的有效性是否存在死循环情况
checkValidOfChain(rootChain, associatedChainIdSet);
// 检查完当前 chain 能走到这里说明当前相关的 chain 是有效的
validChainIdSet.addAll(associatedChainIdSet);
}
}
}
/**
* 检查 chain 的有效性
* @param currentChain 当前遍历到的 chain 节点
* @param associatedChainIdSet rootChain 相关联的 chainId 集合
* @throws CyclicDependencyException
*/
private void checkValidOfChain(Chain currentChain, Set<String> associatedChainIdSet) {
// 判断 completedChainIdSet 中是否已经存在对应的 chain
// 判断 associatedChainIdSet 中是否已经存在对应的 chain
if (associatedChainIdSet.add(currentChain.getChainId())) {
// Set 中不存在则说明可能是父 chain 或者子 chain 未引用自身又或者子 chain 未引用其父 chain继续判断其子 chain
for (Condition condition : currentChain.getConditionList()) {
// 遍历所有 executable 列表
for (Executable executable : condition.getExecutableList()) {
// 只需判断 chain因为只有 chain 才会存在死循环依赖情况
if (executable instanceof Chain) {
// 能执行到此处必能从 FlowBus 中获取到对应的 chain故无需做非空判断
Chain childrenChain = FlowBus.getChainMap().get(executable.getId());
// 递归检查 chain 有效性
checkValidOfChain(childrenChain, associatedChainIdSet);
// 重新构建 chain condition 列表
((Chain) executable).setConditionList(childrenChain.getConditionList());
}
}
}
} else {
String errorMessage = StrUtil.format("There is a circular dependency in the chain[{}], please check carefully.", currentChain.getChainId());
LOG.error(errorMessage);
// 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);
}
}
// 此方法就是从原有的配置源主动拉取新的进行刷新

View File

@ -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);
});
}
}

View File

@ -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);
});
}
}

View File

@ -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);
});
}
}

View File

@ -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);
});
}
}

View File

@ -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>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain2">
THEN(b, a, chain1);
</chain>
</flow>

View File

@ -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);"
}
]
}
}

View File

@ -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>

View File

@ -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);"