Skip to content

Commit 4868d18

Browse files
committed
🧪 tests: update testcase for make coverage on stages module.
1 parent 990899c commit 4868d18

4 files changed

Lines changed: 199 additions & 15 deletions

File tree

src/ddeutil/workflow/audits.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,11 @@
2626
get_audit_model: Factory function for creating audit instances
2727
2828
Example:
29-
```python
30-
from ddeutil.workflow.audits import get_audit_model
3129
32-
# Create file-based Audit
33-
audit = get_audit_model(run_id="run-123")
34-
audit.info("Workflow execution started")
35-
audit.success("Workflow completed successfully")
36-
```
30+
>>> from ddeutil.workflow.audits import get_audit_model
31+
>>> audit = get_audit_model(run_id="run-123")
32+
>>> audit.info("Workflow execution started")
33+
>>> audit.success("Workflow completed successfully")
3734
3835
Note:
3936
Audit instances are automatically configured based on the workflow
@@ -228,7 +225,8 @@ def save(
228225
"""
229226
raise NotImplementedError("Audit should implement `save` method.")
230227

231-
def compress_data(self, data: str) -> bytes:
228+
@staticmethod
229+
def compress_data(data: str) -> bytes:
232230
"""Compress audit data for storage efficiency.
233231
234232
Args:
@@ -239,7 +237,8 @@ def compress_data(self, data: str) -> bytes:
239237
"""
240238
return zlib.compress(data.encode("utf-8"))
241239

242-
def decompress_data(self, data: bytes) -> str:
240+
@staticmethod
241+
def decompress_data(data: bytes) -> str:
243242
"""Decompress audit data.
244243
245244
Args:
@@ -493,7 +492,7 @@ def cleanup_old_audits(self, max_age_days: int = 30) -> int:
493492
return cleaned_count
494493

495494

496-
class SQLiteAudit(BaseAudit):
495+
class SQLiteAudit(BaseAudit): # pragma: no cov
497496
"""SQLite Audit model for database-based audit storage.
498497
499498
This class inherits from BaseAudit and implements SQLite database storage

tests/stages/test_stage_case.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_case_stage_exec(test_path):
3636
],
3737
},
3838
],
39-
}
39+
},
4040
)
4141
rs: Result = stage.execute({"params": {"name": "bar"}})
4242
assert rs.status == SUCCESS
@@ -110,6 +110,7 @@ def test_case_stage_exec_raise():
110110
],
111111
},
112112
],
113+
"extras": {"foo": "bar"},
113114
}
114115
)
115116
# NOTE: Raise because else condition does not set.
@@ -125,6 +126,43 @@ def test_case_stage_exec_raise():
125126
},
126127
}
127128

129+
stage: Stage = CaseStage.model_validate(
130+
{
131+
"name": "Stage raise not has else condition",
132+
"id": "raise-else",
133+
"case": "${{ params.name }}",
134+
"match": [
135+
{
136+
"case": "bar",
137+
"stages": [
138+
{
139+
"name": "Raise stage",
140+
"raise": "Raise with ${{ params.name }}",
141+
}
142+
],
143+
},
144+
],
145+
"extras": {"foo": "bar"},
146+
}
147+
)
148+
rs: Result = stage.execute({"params": {"name": "bar"}})
149+
assert rs.status == FAILED
150+
assert rs.context == {
151+
"status": FAILED,
152+
"case": "bar",
153+
"stages": {
154+
"4045646338": {
155+
"outputs": {},
156+
"errors": {"name": "StageError", "message": "Raise with bar"},
157+
"status": FAILED,
158+
}
159+
},
160+
"errors": {
161+
"name": "StageError",
162+
"message": "Case-Stage was break because it has a sub stage, Raise stage, failed without raise error.",
163+
},
164+
}
165+
128166

129167
def test_case_stage_exec_cancel():
130168
stage: Stage = CaseStage.model_validate(
@@ -158,6 +196,19 @@ def test_case_stage_exec_cancel():
158196
},
159197
}
160198

199+
event = MockEvent(n=1)
200+
rs: Result = stage.execute({"params": {"name": "bar"}}, event=event)
201+
assert rs.status == CANCEL
202+
assert rs.context == {
203+
"status": CANCEL,
204+
"case": "bar",
205+
"stages": {},
206+
"errors": {
207+
"name": "StageError",
208+
"message": "Case-Stage was canceled from event that had set before stage case execution.",
209+
},
210+
}
211+
161212

162213
def test_case_stage_exec_skipped():
163214
stage: Stage = CaseStage.model_validate(

tests/stages/test_stage_until.py

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
Stage,
1010
Workflow,
1111
)
12-
from ddeutil.workflow.stages import EmptyStage, UntilStage
12+
from ddeutil.workflow.stages import EmptyStage, RaiseStage, UntilStage
1313

1414
from ..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+
53128
def test_until_stage_skipped():
54129
stage = UntilStage.model_validate(
55130
{
@@ -89,8 +164,6 @@ def test_until_stage_skipped():
89164

90165

91166
def 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

141248
def test_until_stage_exec_exceed_loop():
142249
stage = UntilStage.model_validate(

tests/test_audits.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,34 @@
33
from unittest import mock
44

55
import pytest
6-
from ddeutil.workflow.audits import FileAudit
6+
from ddeutil.workflow.audits import BaseAudit, FileAudit
77
from ddeutil.workflow.conf import Config
8+
from pydantic import ValidationError
9+
10+
11+
@mock.patch.multiple(BaseAudit, __abstractmethods__=set())
12+
def test_base_audit():
13+
audit = BaseAudit.model_validate(
14+
{
15+
"name": "wf-scheduling",
16+
"type": "manual",
17+
"release": datetime(2024, 1, 1, 1),
18+
"run_id": "558851633820240817184358131811",
19+
}
20+
)
21+
cp_data = audit.compress_data("foo")
22+
assert audit.decompress_data(cp_data) == "foo"
23+
24+
with pytest.raises(ValidationError):
25+
BaseAudit.model_validate(
26+
{
27+
"name": "wf-scheduling",
28+
"type": "manual",
29+
"release": datetime(2024, 1, 1, 1),
30+
"run_id": "558851633820240817184358131811",
31+
"extras": "foo",
32+
}
33+
)
834

935

1036
@mock.patch.object(Config, "enable_write_audit", False)
@@ -20,6 +46,7 @@ def test_conf_log_file():
2046
"parent_run_id": None,
2147
"run_id": "558851633820240817184358131811",
2248
"update": datetime.now(),
49+
"extras": None,
2350
},
2451
)
2552
log.save(excluded=None)

0 commit comments

Comments
 (0)