comtrya_lib/steps/
mod.rs

1use crate::atoms::Atom;
2use crate::steps::finalizers::FlowControl;
3use tracing::error;
4
5pub mod finalizers;
6pub mod initializers;
7
8pub struct Step {
9    pub atom: Box<dyn Atom>,
10    pub initializers: Vec<initializers::FlowControl>,
11    pub finalizers: Vec<finalizers::FlowControl>,
12}
13
14impl Step {
15    pub fn do_initializers_allow_us_to_run(&self) -> bool {
16        self.initializers
17            .iter()
18            .fold(true, |_, flow_control| match flow_control {
19                initializers::FlowControl::Ensure(i) => {
20                    i.initialize().unwrap_or_else(|err| {
21                        error!("Failed to run initializer: {}", err.to_string());
22
23                        // On an error, we can't really determine if this Atom should
24                        // run; so lets play it safe and filter it out too
25                        false
26                    })
27                }
28
29                initializers::FlowControl::SkipIf(i) => {
30                    match i.initialize() {
31                        Ok(true) => {
32                            // Returning false because we should Skip if true, so false
33                            // will filter this out of the atom list
34                            false
35                        }
36                        Ok(false) => true,
37                        Err(err) => {
38                            error!("Failed to run initializer: {}", err.to_string());
39
40                            // On an error, we can't really determine if this Atom should
41                            // run; so lets play it safe and filter it out too
42                            false
43                        }
44                    }
45                }
46            })
47    }
48
49    pub fn do_finalizers_allow_us_to_continue(&self) -> bool {
50        self.finalizers
51            .iter()
52            .fold(true, |_, flow_control| match flow_control {
53                finalizers::FlowControl::StopIf(i) => {
54                    match i.finalize(self.atom.as_ref()) {
55                        Ok(true) => {
56                            // Returning false because we should Skip if true, so false
57                            // will filter this out of the atom list
58                            false
59                        }
60                        Ok(false) => true,
61                        Err(err) => {
62                            error!("Failed to run finalizers: {}", err.to_string());
63
64                            // On an error, we can't really determine if this Atom should
65                            // run; so lets play it safe and filter it out too
66                            false
67                        }
68                    }
69                }
70                FlowControl::Ensure(i) => {
71                    match i.finalize(self.atom.as_ref()) {
72                        Ok(true) => true,
73                        Ok(false) => false,
74                        Err(err) => {
75                            error!("Failed to run finalizers: {}", err.to_string());
76
77                            // On an error, we can't really determine if this Atom should
78                            // run; so lets play it safe and filter it out too
79                            false
80                        }
81                    }
82                }
83            })
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::finalizers::test::EchoFinalizer;
90    use super::finalizers::test::ErrorFinalizer;
91    use super::finalizers::FlowControl as FinalizerFlowControl;
92    use super::initializers::test::Echo as EchoInitializer;
93    use super::initializers::test::Error as ErrorInitializer;
94    use super::initializers::FlowControl as InitializerFlowControl;
95    use crate::atoms::Echo as EchoAtom;
96    use pretty_assertions::assert_eq;
97
98    use super::*;
99
100    #[test]
101    fn initializers_can_control_execution() {
102        let step = Step {
103            atom: Box::new(EchoAtom("hello-world")),
104            initializers: vec![InitializerFlowControl::Ensure(Box::new(EchoInitializer(
105                true,
106            )))],
107            finalizers: vec![],
108        };
109
110        assert_eq!(true, step.do_initializers_allow_us_to_run());
111
112        let step = Step {
113            atom: Box::new(EchoAtom("hello-world")),
114            initializers: vec![InitializerFlowControl::Ensure(Box::new(EchoInitializer(
115                false,
116            )))],
117            finalizers: vec![],
118        };
119
120        assert_eq!(false, step.do_initializers_allow_us_to_run());
121
122        let step = Step {
123            atom: Box::new(EchoAtom("hello-world")),
124            initializers: vec![InitializerFlowControl::SkipIf(Box::new(EchoInitializer(
125                true,
126            )))],
127            finalizers: vec![],
128        };
129
130        assert_eq!(false, step.do_initializers_allow_us_to_run());
131
132        let step = Step {
133            atom: Box::new(EchoAtom("hello-world")),
134            initializers: vec![InitializerFlowControl::SkipIf(Box::new(EchoInitializer(
135                false,
136            )))],
137            finalizers: vec![],
138        };
139
140        assert_eq!(true, step.do_initializers_allow_us_to_run());
141
142        let step = Step {
143            atom: Box::new(EchoAtom("hello-world")),
144            initializers: vec![
145                InitializerFlowControl::SkipIf(Box::new(EchoInitializer(false))),
146                InitializerFlowControl::SkipIf(Box::new(EchoInitializer(true))),
147            ],
148            finalizers: vec![],
149        };
150
151        assert_eq!(false, step.do_initializers_allow_us_to_run());
152    }
153
154    #[test]
155    fn initializers_that_error_block_execution() {
156        let step = Step {
157            atom: Box::new(EchoAtom("hello-world")),
158            initializers: vec![InitializerFlowControl::SkipIf(Box::new(ErrorInitializer()))],
159            finalizers: vec![],
160        };
161
162        assert_eq!(false, step.do_initializers_allow_us_to_run());
163
164        let step = Step {
165            atom: Box::new(EchoAtom("hello-world")),
166            initializers: vec![
167                InitializerFlowControl::SkipIf(Box::new(EchoInitializer(false))),
168                InitializerFlowControl::SkipIf(Box::new(ErrorInitializer())),
169            ],
170            finalizers: vec![],
171        };
172
173        assert_eq!(false, step.do_initializers_allow_us_to_run());
174    }
175
176    #[test]
177    fn finalizers_can_control_execution() {
178        let step = Step {
179            atom: Box::new(EchoAtom("hello-world")),
180            initializers: vec![],
181            finalizers: vec![FinalizerFlowControl::StopIf(Box::new(EchoFinalizer(false)))],
182        };
183
184        assert_eq!(true, step.do_finalizers_allow_us_to_continue());
185
186        let step = Step {
187            atom: Box::new(EchoAtom("hello-world")),
188            initializers: vec![],
189            finalizers: vec![FinalizerFlowControl::StopIf(Box::new(EchoFinalizer(true)))],
190        };
191
192        assert_eq!(false, step.do_finalizers_allow_us_to_continue());
193
194        let step = Step {
195            atom: Box::new(EchoAtom("hello-world")),
196            initializers: vec![],
197            finalizers: vec![
198                FinalizerFlowControl::StopIf(Box::new(EchoFinalizer(false))),
199                FinalizerFlowControl::StopIf(Box::new(EchoFinalizer(true))),
200            ],
201        };
202
203        assert_eq!(false, step.do_finalizers_allow_us_to_continue());
204    }
205
206    #[test]
207    fn finalizers_that_error_block_execution() {
208        let step = Step {
209            atom: Box::new(EchoAtom("hello-world")),
210            initializers: vec![],
211            finalizers: vec![FinalizerFlowControl::StopIf(Box::new(ErrorFinalizer()))],
212        };
213
214        assert_eq!(false, step.do_finalizers_allow_us_to_continue());
215
216        let step = Step {
217            atom: Box::new(EchoAtom("hello-world")),
218            initializers: vec![],
219            finalizers: vec![
220                FinalizerFlowControl::StopIf(Box::new(EchoFinalizer(false))),
221                FinalizerFlowControl::StopIf(Box::new(ErrorFinalizer())),
222            ],
223        };
224
225        assert_eq!(false, step.do_finalizers_allow_us_to_continue());
226    }
227}