A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
4.7 KiB

4 years ago
4 years ago
4 years ago
  1. use super::SymbolRunner;
  2. use crate::loggers::Logger;
  3. use crate::symbols::Symbol;
  4. use async_trait::async_trait;
  5. use std::error::Error;
  6. use std::fmt::Debug;
  7. #[async_trait(?Send)]
  8. pub trait Runnable {
  9. async fn run<R: SymbolRunner, L: Logger>(
  10. &self,
  11. runner: &R,
  12. logger: &L,
  13. force: bool,
  14. ) -> Result<bool, Box<dyn Error>>;
  15. }
  16. #[async_trait(?Send)]
  17. #[allow(clippy::use_self)]
  18. impl<S> Runnable for S
  19. where
  20. Self: Symbol + Debug,
  21. {
  22. async fn run<R: SymbolRunner, L: Logger>(
  23. &self,
  24. runner: &R,
  25. logger: &L,
  26. force: bool,
  27. ) -> Result<bool, Box<dyn Error>> {
  28. runner.run_symbol(self, logger, force).await
  29. }
  30. }
  31. macro_rules! runnable_for_tuple {
  32. ( $($name:ident)* ) => (
  33. #[allow(clippy::let_unit_value)]
  34. #[async_trait(?Send)]
  35. #[allow(non_snake_case)]
  36. impl<$($name: Symbol + Debug,)*> Runnable for ($($name,)*) {
  37. #[allow(unused)]
  38. async fn run<_R: SymbolRunner, _L: Logger>(&self, runner: &_R, logger: &_L, force: bool) -> Result<bool, Box<dyn Error>> {
  39. let ($($name,)*) = self;
  40. let mut result = false;
  41. $(result = runner.run_symbol($name, logger, force || result).await? || result;)*
  42. Ok(result)
  43. }
  44. }
  45. );
  46. }
  47. for_each_tuple!(runnable_for_tuple);
  48. #[cfg(test)]
  49. mod test {
  50. use super::Runnable;
  51. use crate::async_utils::run;
  52. use crate::loggers::{Logger, StoringLogger};
  53. use crate::symbols::Symbol;
  54. use crate::SymbolRunner;
  55. use async_trait::async_trait;
  56. use std::cell::RefCell;
  57. use std::error::Error;
  58. use std::fmt::Debug;
  59. use std::rc::Rc;
  60. #[derive(Debug)]
  61. struct DummySymbol<T, E> {
  62. _target_reached: RefCell<T>,
  63. _execute: RefCell<E>,
  64. }
  65. #[async_trait(?Send)]
  66. impl<
  67. E: Iterator<Item = Result<(), Box<dyn Error>>>,
  68. T: Iterator<Item = Result<bool, Box<dyn Error>>>,
  69. > Symbol for DummySymbol<T, E>
  70. {
  71. async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  72. self._target_reached.borrow_mut().next().unwrap()
  73. }
  74. async fn execute(&self) -> Result<(), Box<dyn Error>> {
  75. self._execute.borrow_mut().next().unwrap()
  76. }
  77. }
  78. impl<
  79. E: Iterator<Item = Result<(), Box<dyn Error>>>,
  80. T: Iterator<Item = Result<bool, Box<dyn Error>>>,
  81. > DummySymbol<T, E>
  82. {
  83. fn new<
  84. IE: IntoIterator<IntoIter = E, Item = Result<(), Box<dyn Error>>>,
  85. IT: IntoIterator<IntoIter = T, Item = Result<bool, Box<dyn Error>>>,
  86. >(
  87. target_reached: IT,
  88. execute: IE,
  89. ) -> Self {
  90. Self {
  91. _target_reached: RefCell::new(target_reached.into_iter()),
  92. _execute: RefCell::new(execute.into_iter()),
  93. }
  94. }
  95. }
  96. struct TestSymbolRunner {
  97. count: Rc<RefCell<usize>>,
  98. }
  99. fn get_runner() -> (Rc<RefCell<usize>>, TestSymbolRunner) {
  100. let count = Rc::new(RefCell::new(0));
  101. let runner = TestSymbolRunner {
  102. count: Rc::clone(&count),
  103. };
  104. (count, runner)
  105. }
  106. #[async_trait(?Send)]
  107. impl SymbolRunner for TestSymbolRunner {
  108. async fn run_symbol<S: Symbol + Debug, L: Logger>(
  109. &self,
  110. symbol: &S,
  111. _logger: &L,
  112. force: bool,
  113. ) -> Result<bool, Box<dyn Error>> {
  114. let run = force || !symbol.target_reached().await?;
  115. if run {
  116. *self.count.borrow_mut() += 1;
  117. }
  118. Ok(run)
  119. }
  120. }
  121. fn run_symbol(
  122. runnable: impl Runnable,
  123. force: bool,
  124. ) -> (Rc<RefCell<usize>>, Result<bool, Box<dyn Error>>) {
  125. let (count, runner) = get_runner();
  126. let res = run(runnable.run(&runner, &StoringLogger::new(), force));
  127. (count, res)
  128. }
  129. #[test]
  130. fn correctly_handles_symbol_tuples() {
  131. let (count, res) = run_symbol(
  132. (
  133. DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
  134. DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
  135. ),
  136. false,
  137. );
  138. res.unwrap();
  139. assert_eq!(*count.borrow(), 2);
  140. let (count, res) = run_symbol(
  141. (
  142. DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
  143. DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
  144. ),
  145. false,
  146. );
  147. res.unwrap();
  148. assert_eq!(*count.borrow(), 1);
  149. // An unreached symbol forces all further symbols
  150. let (count, res) = run_symbol(
  151. (
  152. DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
  153. DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
  154. ),
  155. false,
  156. );
  157. res.unwrap();
  158. assert_eq!(*count.borrow(), 2);
  159. let (count, res) = run_symbol(
  160. (
  161. DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
  162. DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
  163. ),
  164. false,
  165. );
  166. res.unwrap();
  167. assert_eq!(*count.borrow(), 0);
  168. let (count, res) = run_symbol(
  169. (
  170. DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
  171. DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
  172. ),
  173. true,
  174. );
  175. res.unwrap();
  176. assert_eq!(*count.borrow(), 2);
  177. }
  178. }