You've already forked FrameTour-BE
test(pipeline): 添加 Pipeline 核心功能测试
- 增加 Pipeline 执行流程测试,验证 Stage 和 Hook 的执行顺序 - 添加失败场景测试,确保 Pipeline 在失败时能正确停止并跳过后续阶段 - 实现 Stage 配置外部开关控制测试,验证可选 Stage 的启用与禁用逻辑 - 创建 RecordingContext 类用于记录执行事件,便于断言生命周期钩子调用 - 构建 SimpleStage 和 OptionalStage 测试辅助类,支持自定义执行逻辑与条件判断
This commit is contained in:
169
src/test/java/com/ycwl/basic/pipeline/core/PipelineTest.java
Normal file
169
src/test/java/com/ycwl/basic/pipeline/core/PipelineTest.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package com.ycwl.basic.pipeline.core;
|
||||
|
||||
import com.ycwl.basic.pipeline.annotation.StageConfig;
|
||||
import com.ycwl.basic.pipeline.enums.StageOptionalMode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PipelineTest {
|
||||
|
||||
@Test
|
||||
void execute_shouldRunStagesAndHooks() {
|
||||
RecordingContext context = new RecordingContext();
|
||||
|
||||
SimpleStage stage1 = new SimpleStage("stage1", ctx -> {
|
||||
SimpleStage dynamic = new SimpleStage("stage1_dynamic", c -> StageResult.success());
|
||||
return StageResult.successWithNext("add dynamic", dynamic);
|
||||
});
|
||||
SimpleStage stage2 = new SimpleStage("stage2", ctx -> StageResult.success());
|
||||
|
||||
Pipeline<RecordingContext> pipeline = new PipelineBuilder<RecordingContext>("recording")
|
||||
.addStage(stage1)
|
||||
.addStage(stage2)
|
||||
.build();
|
||||
|
||||
boolean result = pipeline.execute(context);
|
||||
|
||||
assertTrue(result);
|
||||
assertEquals(
|
||||
List.of("before", "stage1", "stage1_dynamic", "stage2", "after", "cleanup"),
|
||||
context.getEvents()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void execute_shouldStopOnFailureAndSkipAfterHook() {
|
||||
RecordingContext context = new RecordingContext();
|
||||
|
||||
SimpleStage ok = new SimpleStage("ok", ctx -> StageResult.success());
|
||||
SimpleStage fail = new SimpleStage("fail", ctx -> StageResult.failed("boom"));
|
||||
SimpleStage neverRun = new SimpleStage("never", ctx -> StageResult.success());
|
||||
|
||||
Pipeline<RecordingContext> pipeline = new PipelineBuilder<RecordingContext>("failing")
|
||||
.addStage(ok)
|
||||
.addStage(fail)
|
||||
.addStage(neverRun)
|
||||
.build();
|
||||
|
||||
boolean result = pipeline.execute(context);
|
||||
|
||||
assertFalse(result);
|
||||
assertEquals(
|
||||
List.of("before", "ok", "fail", "cleanup"),
|
||||
context.getEvents()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void stageConfigShouldRespectExternalSwitch() {
|
||||
RecordingContext context = new RecordingContext();
|
||||
context.setStageState("optional_stage", false);
|
||||
|
||||
OptionalStage optional = new OptionalStage();
|
||||
Pipeline<RecordingContext> pipeline = new PipelineBuilder<RecordingContext>("optional")
|
||||
.addStage(optional)
|
||||
.build();
|
||||
|
||||
boolean result = pipeline.execute(context);
|
||||
|
||||
assertTrue(result);
|
||||
assertEquals(
|
||||
List.of("before", "after", "cleanup"),
|
||||
context.getEvents()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录执行轨迹的 Context,便于断言 Pipeline 生命周期钩子与 Stage 执行顺序。
|
||||
*/
|
||||
static class RecordingContext implements PipelineContext {
|
||||
private final List<String> events = new ArrayList<>();
|
||||
private final Map<String, Boolean> stageStates = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void beforePipeline() {
|
||||
events.add("before");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPipeline() {
|
||||
events.add("after");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
events.add("cleanup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStageEnabled(String stageId, boolean defaultEnabled) {
|
||||
return stageStates.getOrDefault(stageId, defaultEnabled);
|
||||
}
|
||||
|
||||
void setStageState(String stageId, boolean enabled) {
|
||||
stageStates.put(stageId, enabled);
|
||||
}
|
||||
|
||||
List<String> getEvents() {
|
||||
return events;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的 Stage 实现,支持自定义执行逻辑与业务前置条件。
|
||||
*/
|
||||
static class SimpleStage extends AbstractPipelineStage<RecordingContext> {
|
||||
private final String name;
|
||||
private final Function<RecordingContext, StageResult<RecordingContext>> executor;
|
||||
private final Predicate<RecordingContext> condition;
|
||||
|
||||
SimpleStage(String name, Function<RecordingContext, StageResult<RecordingContext>> executor) {
|
||||
this(name, executor, ctx -> true);
|
||||
}
|
||||
|
||||
SimpleStage(String name,
|
||||
Function<RecordingContext, StageResult<RecordingContext>> executor,
|
||||
Predicate<RecordingContext> condition) {
|
||||
this.name = name;
|
||||
this.executor = executor;
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldExecuteByBusinessLogic(RecordingContext context) {
|
||||
return condition.test(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StageResult<RecordingContext> doExecute(RecordingContext context) {
|
||||
context.getEvents().add(name);
|
||||
return executor.apply(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 带 StageConfig 的 Stage,用于验证 SUPPORT 模式下的开关控制。
|
||||
*/
|
||||
@StageConfig(stageId = "optional_stage", optionalMode = StageOptionalMode.SUPPORT, defaultEnabled = true)
|
||||
static class OptionalStage extends SimpleStage {
|
||||
|
||||
OptionalStage() {
|
||||
super("optional", ctx -> StageResult.success());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user