feature #I7HJFX 完成nospring场景下的测试用例编写及测试

This commit is contained in:
zy
2023-07-14 12:07:13 +08:00
parent 9dd4b8898f
commit 8eadf39624
16 changed files with 447 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
package com.yomahub.liteflow.test.parallelLoop;
import com.yomahub.liteflow.exception.LiteFlowException;
/**
* 用户自定义带状态码的异常
*/
public class CustomStatefulException extends LiteFlowException {
public CustomStatefulException(String code, String message) {
super(code, message);
}
}

View File

@@ -0,0 +1,23 @@
package com.yomahub.liteflow.test.parallelLoop;
import cn.hutool.core.util.ObjectUtil;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.thread.ExecutorBuilder;
import java.util.concurrent.ExecutorService;
public class CustomThreadExecutor implements ExecutorBuilder {
@Override
public ExecutorService buildExecutor() {
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
// 只有在非spring的场景下liteflowConfig才会为null
if (ObjectUtil.isNull(liteflowConfig)) {
liteflowConfig = new LiteflowConfig();
}
return buildDefaultExecutor(liteflowConfig.getParallelMaxWorkers(), liteflowConfig.getParallelMaxWorkers(),
liteflowConfig.getParallelQueueLimit(), "customer-loop-thead-");
}
}

View File

@@ -0,0 +1,120 @@
package com.yomahub.liteflow.test.parallelLoop;
import cn.hutool.core.collection.ListUtil;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.FlowExecutorHolder;
import com.yomahub.liteflow.exception.LiteFlowException;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.regex.Pattern;
/**
* nospring环境EL异步循环测试
*
* @author zhhhhy
* @since 2.11.0
*/
public class ParallelLoopTest extends BaseTest {
private static FlowExecutor flowExecutor;
@BeforeAll
public static void init() {
LiteflowConfig config = new LiteflowConfig();
config.setRuleSource("parallelLoop/flow.xml");
config.setParallelMaxWorkers(10);
config.setParallelQueueLimit(1024);
config.setParallelLoopExecutorClass("com.yomahub.liteflow.test.parallelLoop.CustomThreadExecutor");
flowExecutor = FlowExecutorHolder.loadInstance(config);
}
//测试并行FOR循环循环次数直接在el中定义
@Test
public void testParallelLoop1() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
Assertions.assertTrue(response.isSuccess());
}
//测试并行FOR循环循环次数由For组件定义
@Test
public void testParallelLoop2() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
Assertions.assertTrue(response.isSuccess());
}
//测试并行FOR循环中的BREAK组件能够正常发挥作用
@Test
public void testParallelLoop3() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
Assertions.assertTrue(response.isSuccess());
}
//测试并行FOR循环中主线程是否会正常等待所有并行子项完成后再继续执行
@Test
public void testParallelLoop4() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
Assertions.assertTrue(response.isSuccess());
}
@Test
//测试并行FOR循环中某个并行子项抛出异常
public void testParallelLoop5() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
Assertions.assertFalse(response.isSuccess());
Assertions.assertEquals("300", response.getCode());
Assertions.assertNotNull(response.getCause());
Assertions.assertTrue(response.getCause() instanceof LiteFlowException);
Assertions.assertNotNull(response.getSlot());
}
//并行的条件循环
@Test
public void testParallelLoop6() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
Assertions.assertTrue(response.isSuccess());
}
//并行的迭代循环
@Test
public void testParallelLoop7() throws Exception {
List<String> list = ListUtil.toList("1", "2", "3", "4", "5");
LiteflowResponse response = flowExecutor.execute2Resp("chain7", list);
Assertions.assertTrue(response.isSuccess());
}
//测试并行FOR循环中的index
@Test
public void testParallelLoop8() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
DefaultContext context = response.getFirstContextBean();
Assertions.assertTrue(response.isSuccess());
String regex = "(?!.*(.).*\\1)[0-4]{5}"; //匹配不包含重复数字的0-4的5位数字
Pattern pattern = Pattern.compile(regex);
//e1,e2,e3分别并行执行5次因此单个循环的顺序可以是任意的
Assertions.assertTrue(pattern.matcher(context.getData("loop_e1")).matches());
Assertions.assertTrue(pattern.matcher(context.getData("loop_e2")).matches());
Assertions.assertTrue(pattern.matcher(context.getData("loop_e3")).matches());
}
//测试自定义线程池配置是否生效
@Test
public void testParallelLoop9() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
DefaultContext context = response.getFirstContextBean();
Assertions.assertTrue(response.isSuccess());
Assertions.assertTrue(context.getData("threadName").toString().startsWith("customer-loop-thead"));
}
}

View File

@@ -0,0 +1,19 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
public class ACmp extends NodeComponent{
@Override
public void process() {
System.out.println("ACmp executed!");
}
}

View File

@@ -0,0 +1,19 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
public class BCmp extends NodeComponent{
@Override
public void process() {
System.out.println("BCmp executed!");
}
}

View File

@@ -0,0 +1,19 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
public class CCmp extends NodeComponent{
@Override
public void process() {
System.out.println("CCmp executed!");
}
}

View File

@@ -0,0 +1,28 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
public class DCmp extends NodeComponent{
@Override
public void process() {
DefaultContext context = this.getFirstContextBean();
String key = "test";
if (context.hasData(key)) {
int count = context.getData(key);
context.setData(key, ++count);
}
else {
context.setData(key, 1);
}
}
}

View File

@@ -0,0 +1,31 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.parallelLoop.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
public class ECmp extends NodeComponent{
//注意与串行的ECmp相比,并行的ECmp的process方法必须保证线程安全
@Override
public synchronized void process() {
DefaultContext context = this.getFirstContextBean();
String key = StrUtil.format("{}_{}", "loop", this.getTag());
if (context.hasData(key)) {
String loopStr = context.getData(key);
String loopStrReturn = StrUtil.format("{}{}", loopStr, this.getLoopIndex());
context.setData(key, loopStrReturn);
}
else {
context.setData(key, this.getLoopIndex().toString());
}
}
}

View File

@@ -0,0 +1,18 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
public class FCmp extends NodeComponent{
@Override
public void process() {
try {
System.out.println("FCmp start to sleep 5s");
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("FCmp executed!");
}
}

View File

@@ -0,0 +1,16 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.test.exception.CustomStatefulException;
public class GCmp extends NodeComponent{
@Override
public void process() {
if(this.getLoopIndex()==1){
throw new CustomStatefulException("300", "chain execute custom stateful execption");
}
System.out.println("GCmp executed!");
}
}

View File

@@ -0,0 +1,16 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
public class HCmp extends NodeComponent{
@Override
public void process() {
DefaultContext context = this.getFirstContextBean();
context.setData("threadName", Thread.currentThread().getName());
System.out.println("HCmp executed!");
}
}

View File

@@ -0,0 +1,15 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeIteratorComponent;
import java.util.Iterator;
import java.util.List;
public class ITCmp extends NodeIteratorComponent {
@Override
public Iterator<?> processIterator() throws Exception {
List<String> list = this.getRequestData();
return list.iterator();
}
}

View File

@@ -0,0 +1,12 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeForComponent;
public class XCmp extends NodeForComponent {
@Override
public int processFor() throws Exception {
return 3;
}
}

View File

@@ -0,0 +1,17 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeBreakComponent;
import com.yomahub.liteflow.slot.DefaultContext;
public class YCmp extends NodeBreakComponent {
@Override
public boolean processBreak() throws Exception {
DefaultContext context = this.getFirstContextBean();
int count = 0;
if(context.hasData("test")) {
count = context.getData("test");
}
return count > 3;
}
}

View File

@@ -0,0 +1,19 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeWhileComponent;
import com.yomahub.liteflow.slot.DefaultContext;
public class ZCmp extends NodeWhileComponent {
@Override
public boolean processWhile() throws Exception {
DefaultContext context = this.getFirstContextBean();
String key = "test";
if (context.hasData(key)) {
int count = context.getData("test");
return count < 5;
} else {
return true;
}
}
}

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<nodes>
<node id="a" class="com.yomahub.liteflow.test.parallelLoop.cmp.ACmp"/>
<node id="b" class="com.yomahub.liteflow.test.parallelLoop.cmp.BCmp"/>
<node id="c" class="com.yomahub.liteflow.test.parallelLoop.cmp.CCmp"/>
<node id="d" class="com.yomahub.liteflow.test.parallelLoop.cmp.DCmp"/>
<node id="e" class="com.yomahub.liteflow.test.parallelLoop.cmp.ECmp"/>
<node id="f" class="com.yomahub.liteflow.test.parallelLoop.cmp.FCmp"/>
<node id="g" class="com.yomahub.liteflow.test.parallelLoop.cmp.GCmp"/>
<node id="h" class="com.yomahub.liteflow.test.parallelLoop.cmp.HCmp"/>
<node id="it" class="com.yomahub.liteflow.test.parallelLoop.cmp.ITCmp"/>
<node id="x" class="com.yomahub.liteflow.test.parallelLoop.cmp.XCmp"/>
<node id="y" class="com.yomahub.liteflow.test.parallelLoop.cmp.YCmp"/>
<node id="z" class="com.yomahub.liteflow.test.parallelLoop.cmp.ZCmp"/>
</nodes>
<chain name="chain1">
FOR(2).DO(THEN(a,b,c));
</chain>
<chain name="chain2">
FOR(x).parallel(true).DO(THEN(a,b,c));
</chain>
<chain name="chain3">
FOR(100).parallel(true).DO(THEN(a,b,d)).BREAK(y);
</chain>
<chain name="chain4">
FOR(x).parallel(true).DO(THEN(a,b,f));
</chain>
<chain name="chain5">
FOR(x).parallel(true).DO(THEN(a,b,g));
</chain>
<chain name="chain6">
WHILE(z).parallel(true).DO(THEN(a,d));
</chain>
<chain name="chain7">
ITERATOR(it).parallel(true).DO(THEN(a,b));
</chain>
<chain name="chain8">
FOR(5).parallel(true).DO(
WHEN(
THEN(a,e.tag("e1")),
THEN(c,e.tag("e2")),
THEN(b,e.tag("e3"))
)
);
</chain>
<chain name="chain9">
FOR(x).parallel(true).DO(THEN(a,b,h));
</chain>
</flow>