enhancement #ICANTH 去除隐式子流程特性

This commit is contained in:
everywhere.z
2025-05-26 20:33:41 +08:00
parent e695648728
commit cc7ca69450
217 changed files with 337 additions and 4143 deletions

View File

@@ -1,58 +0,0 @@
package com.yomahub.liteflow.test.subflow;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.noear.solon.annotation.Import;
import org.noear.solon.annotation.Inject;
import org.noear.solon.test.SolonTest;
import java.util.HashSet;
import java.util.Set;
/**
* 测试隐式调用子流程 单元测试
*
* @author justin.xu
*/
@Import(profiles ="classpath:/subflow/application-implicit.properties")
@SolonTest
public class ImplicitSubFlowELDeclMultiSpringbootTest extends BaseTest {
@Inject
private FlowExecutor flowExecutor;
public static final Set<String> RUN_TIME_SLOT = new HashSet<>();
// 这里GCmp中隐式的调用chain4从而执行了hm
@Test
public void testImplicitSubFlow1() {
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "it's a request");
DefaultContext context = response.getFirstContextBean();
Assertions.assertTrue(response.isSuccess());
Assertions.assertEquals("f==>g==>h==>m", response.getExecuteStepStr());
// 传递了slotIndex则set的size==1
Assertions.assertEquals(1, RUN_TIME_SLOT.size());
// set中第一次设置的requestId和response中的requestId一致
Assertions.assertTrue(RUN_TIME_SLOT.contains(response.getSlot().getRequestId()));
// requestData的取值正确
Assertions.assertEquals("it's implicit subflow.", context.getData("innerRequest"));
}
// 在p里多线程调用q 10次每个q取到的参数都是不同的。
@Test
public void testImplicitSubFlow2() {
LiteflowResponse response = flowExecutor.execute2Resp("c1", "it's a request");
DefaultContext context = response.getFirstContextBean();
Assertions.assertTrue(response.isSuccess());
Set<String> set = context.getData("test");
// requestData的取值正确
Assertions.assertEquals(10, set.size());
}
}

View File

@@ -1,48 +0,0 @@
package com.yomahub.liteflow.test.subflow;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.exception.MultipleParsersException;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.noear.solon.annotation.Import;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import org.noear.solon.test.SolonTest;
/**
* 测试主流程与子流程在不同的配置文件的场景
*
* @author Bryan.Zhang
*/
@Import(profiles ="classpath:/subflow/application-subInDifferentConfig1.properties")
@SolonTest
public class SubflowInDifferentConfigELDeclMultiSpringbootTest extends BaseTest {
@Inject
private FlowExecutor flowExecutor;
// 是否按照流程定义配置执行
@Test
public void testExplicitSubFlow1() {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request");
Assertions.assertTrue(response.isSuccess());
Assertions.assertEquals("a==>b==>b==>a==>e==>d", response.getExecuteStepStr());
}
@Inject
private AppContext context;
// 主要测试有不同的配置类型后会不会报出既定的错误
@Test
public void testExplicitSubFlow2() {
Assertions.assertThrows(MultipleParsersException.class, () -> {
LiteflowConfig config = context.getBean(LiteflowConfig.class);
config.setRuleSource("subflow/flow-main.xml,subflow/flow-sub1.xml,subflow/flow-sub2.yml");
flowExecutor.reloadRule();
});
}
}

View File

@@ -1,32 +0,0 @@
package com.yomahub.liteflow.test.subflow;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.noear.solon.annotation.Import;
import org.noear.solon.annotation.Inject;
import org.noear.solon.test.SolonTest;
/**
* 测试显示调用子流程(json) 单元测试
*
* @author justin.xu
*/
@Import(profiles ="classpath:/subflow/application-json.properties")
@SolonTest
public class SubflowJsonELDeclMultiSpringBootTest extends BaseTest {
@Inject
private FlowExecutor flowExecutor;
// 是否按照流程定义配置执行
@Test
public void testExplicitSubFlow() {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request");
Assertions.assertTrue(response.isSuccess());
Assertions.assertEquals("a==>b==>c==>b==>a==>e==>d", response.getExecuteStepStr());
}
}

View File

@@ -1,32 +0,0 @@
package com.yomahub.liteflow.test.subflow;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.noear.solon.annotation.Import;
import org.noear.solon.annotation.Inject;
import org.noear.solon.test.SolonTest;
/**
* 测试显示调用子流程(xml) 单元测试
*
* @author justin.xu
*/
@Import(profiles ="classpath:/subflow/application-xml.properties")
@SolonTest
public class SubflowXMLELDeclMultiSpringBootTest extends BaseTest {
@Inject
private FlowExecutor flowExecutor;
// 是否按照流程定义配置执行
@Test
public void testExplicitSubFlow() {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request");
Assertions.assertTrue(response.isSuccess());
Assertions.assertEquals("a==>b==>c==>b==>a==>e==>d", response.getExecuteStepStr());
}
}

View File

@@ -1,32 +0,0 @@
package com.yomahub.liteflow.test.subflow;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.noear.solon.annotation.Import;
import org.noear.solon.annotation.Inject;
import org.noear.solon.test.SolonTest;
/**
* 测试显示调用子流程(yml) 单元测试
*
* @author justin.xu
*/
@Import(profiles ="classpath:/subflow/application-yml.properties")
@SolonTest
public class SubflowYmlELDeclMultiSpringBootTest extends BaseTest {
@Inject
private FlowExecutor flowExecutor;
// 是否按照流程定义配置执行
@Test
public void testExplicitSubFlowYml() {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a request");
Assertions.assertTrue(response.isSuccess());
Assertions.assertEquals("a==>b==>c==>b==>a==>e==>d", response.getExecuteStepStr());
}
}

View File

@@ -1,37 +0,0 @@
package com.yomahub.liteflow.test.subflow.cmp1;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent
public class CmpConfig1 {
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a")
public void processA(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "b")
public void processB(NodeComponent bindCmp) {
System.out.println("BCmp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "c")
public void processC(NodeComponent bindCmp) {
System.out.println("CCmp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "d")
public void processD(NodeComponent bindCmp) {
System.out.println("DCmp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "e")
public void processE(NodeComponent bindCmp) {
System.out.println("ECmp executed!");
}
}

View File

@@ -1,94 +0,0 @@
package com.yomahub.liteflow.test.subflow.cmp2;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.slot.DefaultContext;
import org.noear.solon.annotation.Inject;
import java.util.HashSet;
import java.util.Set;
import static com.yomahub.liteflow.test.subflow.ImplicitSubFlowELDeclMultiSpringbootTest.RUN_TIME_SLOT;
@LiteflowComponent
public class CmpConfig2 {
@Inject
private FlowExecutor flowExecutor;
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "f")
public void processF(NodeComponent bindCmp) {
RUN_TIME_SLOT.add(bindCmp.getSlot().getRequestId());
System.out.println("Fcomp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "g")
public void processG(NodeComponent bindCmp) throws Exception {
RUN_TIME_SLOT.add(bindCmp.getSlot().getRequestId());
System.out.println("Gcmp executed!");
bindCmp.invoke("chain4", "it's implicit subflow.");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "h")
public void processH(NodeComponent bindCmp) {
String requestData = bindCmp.getSubChainReqData();
DefaultContext context = bindCmp.getFirstContextBean();
context.setData("innerRequest", requestData);
RUN_TIME_SLOT.add(bindCmp.getSlot().getRequestId());
System.out.println("Hcomp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "m")
public void processM(NodeComponent bindCmp) {
RUN_TIME_SLOT.add(bindCmp.getSlot().getRequestId());
System.out.println("Mcomp executed!");
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "p")
public void processP(NodeComponent bindCmp) throws Exception {
int slotIndex = bindCmp.getSlotIndex();
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
try {
flowExecutor.invokeInAsync("c2", "it's implicit subflow " + finalI, slotIndex);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}).start();
}
Thread.sleep(1000);
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "q")
public void processQ(NodeComponent bindCmp) throws Exception {
String requestData = bindCmp.getSubChainReqDataInAsync();
DefaultContext context = bindCmp.getFirstContextBean();
synchronized (this) {
if (context.hasData("test")) {
Set<String> set = context.getData("test");
set.add(requestData);
}
else {
Set<String> set = new HashSet<>();
set.add(requestData);
context.setData("test", set);
}
}
}
}

View File

@@ -1 +0,0 @@
liteflow.rule-source=subflow/flow-main.el.xml,subflow/flow-sub1.el.xml,subflow/flow-sub2.el.xml

View File

@@ -1 +0,0 @@
liteflow.rule-source=subflow/flow-main.el.xml,subflow/flow-sub1.el.xml,subflow/flow-sub2.el.yml

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain3">
THEN(f, g);
</chain>
<chain name="chain4">
THEN(h, m);
</chain>
<chain name="c1">
THEN(p);
</chain>
<chain name="c2">
THEN(q);
</chain>
</flow>

View File

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

View File

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

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain3">
THEN(e, d);
</chain>
</flow>

View File

@@ -1,4 +0,0 @@
flow:
chain:
- name: chain3
value: "THEN(e, d);"

View File

@@ -1,22 +0,0 @@
{
"flow": {
"chain": [
{
"name": "chain3",
"value": "THEN(e,d);"
},
{
"name": "chain2",
"value": "THEN(b, a, chain3);"
},
{
"name": "chain1",
"value": "THEN(a, b, c, chain2);"
},
{
"name": "c",
"value": "THEN(d, e);"
}
]
}
}

View File

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

View File

@@ -1,10 +0,0 @@
flow:
chain:
- name: chain3
value: "THEN(e, d);"
- name: chain1
value: "THEN(a, b, c, chain2);"
- name: c
value: "THEN(d, e);"
- name: chain2
value: "THEN(b, a, chain3);"