99 Stage ,
1010 Workflow ,
1111)
12- from ddeutil .workflow .stages import EmptyStage , UntilStage
12+ from ddeutil .workflow .stages import EmptyStage , RaiseStage , UntilStage
1313
1414from ..utils import MockEvent , dump_yaml_context
1515
@@ -50,6 +50,81 @@ def test_until_stage():
5050 }
5151
5252
53+ def test_until_stage_raise ():
54+ stage = UntilStage .model_validate (
55+ {
56+ "name" : "This is until stage" ,
57+ "item" : 1 ,
58+ "until" : "${{ item }} > 2" ,
59+ "stages" : [
60+ RaiseStage .model_validate (
61+ {"name" : "Raise stage nested" , "raise" : "Raise some error." }
62+ ),
63+ ],
64+ "extras" : {"foo" : "bar" },
65+ }
66+ )
67+ rs : Result = stage .execute (params = {})
68+ assert rs .status == FAILED
69+ assert rs .context == {
70+ "status" : FAILED ,
71+ "until" : {
72+ 1 : {
73+ "status" : FAILED ,
74+ "loop" : 1 ,
75+ "item" : 1 ,
76+ "stages" : {
77+ "1426584094" : {
78+ "outputs" : {},
79+ "errors" : {
80+ "name" : "StageError" ,
81+ "message" : "Raise some error." ,
82+ },
83+ "status" : FAILED ,
84+ }
85+ },
86+ "errors" : {
87+ "name" : "StageError" ,
88+ "message" : "Loop execution was break because its nested-stage, 'Raise stage nested', failed." ,
89+ },
90+ }
91+ },
92+ "errors" : {
93+ "name" : "StageError" ,
94+ "message" : "Loop execution was break because its nested-stage, 'Raise stage nested', failed." ,
95+ },
96+ }
97+
98+ stage = UntilStage .model_validate (
99+ {
100+ "name" : "This is until stage" ,
101+ "item" : 1 ,
102+ "until" : "${{ item }} if ${{ item }} == 1 else 'demo'" ,
103+ "stages" : [
104+ EmptyStage (name = "Empty stage nested" , echo = "1" ),
105+ ],
106+ "extras" : {"foo" : "bar" },
107+ }
108+ )
109+ rs : Result = stage .execute (params = {})
110+ assert rs .status == FAILED
111+ assert rs .context == {
112+ "status" : FAILED ,
113+ "until" : {
114+ 1 : {
115+ "status" : SUCCESS ,
116+ "loop" : 1 ,
117+ "item" : 1 ,
118+ "stages" : {"4735427693" : {"outputs" : {}, "status" : SUCCESS }},
119+ }
120+ },
121+ "errors" : {
122+ "name" : "TypeError" ,
123+ "message" : "Return type of until condition not be `boolean`, getting: 'demo'" ,
124+ },
125+ }
126+
127+
53128def test_until_stage_skipped ():
54129 stage = UntilStage .model_validate (
55130 {
@@ -89,8 +164,6 @@ def test_until_stage_skipped():
89164
90165
91166def test_until_stage_cancel ():
92- event = Event ()
93- event .set ()
94167 stage = UntilStage .model_validate (
95168 {
96169 "name" : "This is until stage" ,
@@ -103,6 +176,8 @@ def test_until_stage_cancel():
103176 "extras" : {"foo" : "bar" },
104177 }
105178 )
179+ event = Event ()
180+ event .set ()
106181 rs : Result = stage .execute (params = {}, event = event )
107182 assert rs .status == CANCEL
108183 assert rs .context == {
@@ -137,6 +212,38 @@ def test_until_stage_cancel():
137212 },
138213 }
139214
215+ event = MockEvent (n = 2 )
216+ rs : Result = stage .execute (params = {}, event = event )
217+ assert rs .status == CANCEL
218+ assert rs .context == {
219+ "status" : CANCEL ,
220+ "until" : {
221+ 1 : {
222+ "status" : CANCEL ,
223+ "loop" : 1 ,
224+ "item" : 1 ,
225+ "stages" : {
226+ "4735427693" : {
227+ "outputs" : {},
228+ "errors" : {
229+ "name" : "StageCancelError" ,
230+ "message" : "Execution was canceled from the event before start parallel." ,
231+ },
232+ "status" : CANCEL ,
233+ }
234+ },
235+ "errors" : {
236+ "name" : "StageCancelError" ,
237+ "message" : "Loop execution was canceled from the event after end loop execution." ,
238+ },
239+ }
240+ },
241+ "errors" : {
242+ "name" : "StageCancelError" ,
243+ "message" : "Loop execution was canceled from the event after end loop execution." ,
244+ },
245+ }
246+
140247
141248def test_until_stage_exec_exceed_loop ():
142249 stage = UntilStage .model_validate (
0 commit comments