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