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.

193 lines
4.7 KiB

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