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.

168 lines
4.1 KiB

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