wfe_core/primitives/
if_step.rs1use async_trait::async_trait;
2use serde_json::json;
3
4use crate::models::ExecutionResult;
5use crate::traits::step::{StepBody, StepExecutionContext};
6
7#[derive(Default)]
9pub struct IfStep {
10 pub condition: bool,
11}
12
13#[async_trait]
14impl StepBody for IfStep {
15 async fn run(&mut self, context: &StepExecutionContext<'_>) -> crate::Result<ExecutionResult> {
16 let children_active = context
17 .persistence_data
18 .and_then(|d| d.get("children_active"))
19 .and_then(|v| v.as_bool())
20 .unwrap_or(false);
21
22 if children_active {
23 let mut scope = context.execution_pointer.scope.clone();
25 scope.push(context.execution_pointer.id.clone());
26
27 if context.workflow.is_branch_complete(&scope) {
28 Ok(ExecutionResult::next())
29 } else {
30 Ok(ExecutionResult::persist(json!({"children_active": true})))
31 }
32 } else {
33 if self.condition {
35 Ok(ExecutionResult::branch(
36 vec![json!(null)],
37 Some(json!({"children_active": true})),
38 ))
39 } else {
40 Ok(ExecutionResult::next())
41 }
42 }
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use crate::models::{ExecutionPointer, PointerStatus};
50 use crate::primitives::test_helpers::*;
51
52 #[tokio::test]
53 async fn condition_true_first_run_branches() {
54 let mut step = IfStep { condition: true };
55 let pointer = ExecutionPointer::new(0);
56 let wf_step = default_step();
57 let workflow = default_workflow();
58 let ctx = make_context(&pointer, &wf_step, &workflow);
59
60 let result = step.run(&ctx).await.unwrap();
61 assert!(!result.proceed);
62 assert_eq!(result.branch_values, Some(vec![json!(null)]));
63 assert_eq!(result.persistence_data, Some(json!({"children_active": true})));
64 }
65
66 #[tokio::test]
67 async fn condition_false_first_run_proceeds() {
68 let mut step = IfStep { condition: false };
69 let pointer = ExecutionPointer::new(0);
70 let wf_step = default_step();
71 let workflow = default_workflow();
72 let ctx = make_context(&pointer, &wf_step, &workflow);
73
74 let result = step.run(&ctx).await.unwrap();
75 assert!(result.proceed);
76 assert!(result.branch_values.is_none());
77 }
78
79 #[tokio::test]
80 async fn children_active_and_complete_proceeds() {
81 let mut step = IfStep { condition: true };
82 let mut pointer = ExecutionPointer::new(0);
83 pointer.persistence_data = Some(json!({"children_active": true}));
84
85 let wf_step = default_step();
86
87 let mut workflow = default_workflow();
89 let mut child = ExecutionPointer::new(1);
90 child.scope = vec![pointer.id.clone()];
91 child.status = PointerStatus::Complete;
92 workflow.execution_pointers.push(child);
93
94 let ctx = make_context(&pointer, &wf_step, &workflow);
95
96 let result = step.run(&ctx).await.unwrap();
97 assert!(result.proceed);
98 }
99
100 #[tokio::test]
101 async fn children_active_and_incomplete_persists() {
102 let mut step = IfStep { condition: true };
103 let mut pointer = ExecutionPointer::new(0);
104 pointer.persistence_data = Some(json!({"children_active": true}));
105
106 let wf_step = default_step();
107
108 let mut workflow = default_workflow();
110 let mut child = ExecutionPointer::new(1);
111 child.scope = vec![pointer.id.clone()];
112 child.status = PointerStatus::Running;
113 workflow.execution_pointers.push(child);
114
115 let ctx = make_context(&pointer, &wf_step, &workflow);
116
117 let result = step.run(&ctx).await.unwrap();
118 assert!(!result.proceed);
119 assert_eq!(result.persistence_data, Some(json!({"children_active": true})));
120 }
121}