From af60cc154047d7a5f9e47985db14f31d8b68ed02 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Wed, 3 Dec 2025 22:15:05 +0800 Subject: [PATCH] =?UTF-8?q?test(pipeline):=20=E6=B7=BB=E5=8A=A0=20Pipeline?= =?UTF-8?q?=20=E6=A0=B8=E5=BF=83=E5=8A=9F=E8=83=BD=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加 Pipeline 执行流程测试,验证 Stage 和 Hook 的执行顺序 - 添加失败场景测试,确保 Pipeline 在失败时能正确停止并跳过后续阶段 - 实现 Stage 配置外部开关控制测试,验证可选 Stage 的启用与禁用逻辑 - 创建 RecordingContext 类用于记录执行事件,便于断言生命周期钩子调用 - 构建 SimpleStage 和 OptionalStage 测试辅助类,支持自定义执行逻辑与条件判断 --- .../basic/pipeline/core/PipelineTest.java | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/test/java/com/ycwl/basic/pipeline/core/PipelineTest.java diff --git a/src/test/java/com/ycwl/basic/pipeline/core/PipelineTest.java b/src/test/java/com/ycwl/basic/pipeline/core/PipelineTest.java new file mode 100644 index 00000000..0b111abe --- /dev/null +++ b/src/test/java/com/ycwl/basic/pipeline/core/PipelineTest.java @@ -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 pipeline = new PipelineBuilder("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 pipeline = new PipelineBuilder("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 pipeline = new PipelineBuilder("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 events = new ArrayList<>(); + private final Map 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 getEvents() { + return events; + } + } + + /** + * 简化的 Stage 实现,支持自定义执行逻辑与业务前置条件。 + */ + static class SimpleStage extends AbstractPipelineStage { + private final String name; + private final Function> executor; + private final Predicate condition; + + SimpleStage(String name, Function> executor) { + this(name, executor, ctx -> true); + } + + SimpleStage(String name, + Function> executor, + Predicate 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 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()); + } + } +}