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

This commit is contained in:
zy
2023-07-14 12:33:38 +08:00
parent 8eadf39624
commit e5f6ed87c1
17 changed files with 476 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,114 @@
package com.yomahub.liteflow.test.parallelLoop;
import cn.hutool.core.collection.ListUtil;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.exception.LiteFlowException;
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.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import javax.annotation.Resource;
import java.util.List;
import java.util.regex.Pattern;
/**
* springboot环境EL异步循环测试
*
* @author zhhhhy
* @since 2.11.0
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:/parallelLoop/application.xml")
public class ParallelLoopELSpringTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//测试并行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,21 @@
/**
* <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 org.springframework.stereotype.Component;
@Component("a")
public class ACmp extends NodeComponent{
@Override
public void process() {
System.out.println("ACmp executed!");
}
}

View File

@@ -0,0 +1,21 @@
/**
* <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 org.springframework.stereotype.Component;
@Component("b")
public class BCmp extends NodeComponent{
@Override
public void process() {
System.out.println("BCmp executed!");
}
}

View File

@@ -0,0 +1,21 @@
/**
* <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 org.springframework.stereotype.Component;
@Component("c")
public class CCmp extends NodeComponent{
@Override
public void process() {
System.out.println("CCmp executed!");
}
}

View File

@@ -0,0 +1,30 @@
/**
* <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;
import org.springframework.stereotype.Component;
@Component("d")
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,33 @@
/**
* <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;
import org.springframework.stereotype.Component;
@Component("e")
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,20 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
@Component("f")
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,18 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.test.exception.CustomStatefulException;
import org.springframework.stereotype.Component;
@Component("g")
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,18 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
import org.springframework.stereotype.Component;
@Component("h")
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,17 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeIteratorComponent;
import org.springframework.stereotype.Component;
import java.util.Iterator;
import java.util.List;
@Component("it")
public class ITCmp extends NodeIteratorComponent {
@Override
public Iterator<?> processIterator() throws Exception {
List<String> list = this.getRequestData();
return list.iterator();
}
}

View File

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

View File

@@ -0,0 +1,19 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeBreakComponent;
import com.yomahub.liteflow.slot.DefaultContext;
import org.springframework.stereotype.Component;
@Component("y")
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,21 @@
package com.yomahub.liteflow.test.parallelLoop.cmp;
import com.yomahub.liteflow.core.NodeWhileComponent;
import com.yomahub.liteflow.slot.DefaultContext;
import org.springframework.stereotype.Component;
@Component("z")
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,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.yomahub.liteflow.test.parallelLoop.cmp" />
<bean id="springAware" class="com.yomahub.liteflow.spi.spring.SpringAware"/>
<bean class="com.yomahub.liteflow.spring.ComponentScanner"/>
<bean id="liteflowConfig" class="com.yomahub.liteflow.property.LiteflowConfig">
<property name="ruleSource" value="parallelLoop/flow.xml"/>
<property name="parallelMaxWorkers" value="10"/>
<property name="parallelQueueLimit" value="1024"/>
<property name="parallelLoopExecutorClass" value="com.yomahub.liteflow.test.parallelLoop.CustomThreadExecutor"/>
</bean>
<bean id="flowExecutor" class="com.yomahub.liteflow.core.FlowExecutor">
<constructor-arg name="liteflowConfig" ref="liteflowConfig"/>
</bean>
</beans>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
FOR(2).parallel(true).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>