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.

352 lines
8.7 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
3 years ago
4 years ago
  1. use crate::async_utils::sleep;
  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;
  7. use std::fmt::Debug;
  8. use std::time::Duration;
  9. #[async_trait(?Send)]
  10. pub trait SymbolRunner {
  11. async fn run_symbol<S: Symbol + Debug, L: Logger>(
  12. &self,
  13. symbol: &S,
  14. logger: &L,
  15. force: bool,
  16. ) -> Result<bool, Box<dyn Error>>;
  17. }
  18. #[derive(Debug, Default)]
  19. pub struct ExecuteDidNotReachError;
  20. impl Error for ExecuteDidNotReachError {}
  21. impl fmt::Display for ExecuteDidNotReachError {
  22. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  23. write!(f, "Target not reached after executing symbol")
  24. }
  25. }
  26. #[derive(Clone, Debug, Default)]
  27. pub struct InitializingSymbolRunner;
  28. impl InitializingSymbolRunner {
  29. #[must_use]
  30. pub const fn new() -> Self {
  31. Self
  32. }
  33. async fn exec_symbol<S: Symbol + Debug, L: Logger>(
  34. &self,
  35. symbol: &S,
  36. logger: &L,
  37. ) -> Result<(), Box<dyn Error>> {
  38. logger.info(format!("Executing {:?}", symbol));
  39. symbol.execute().await?;
  40. let target_reached = symbol.target_reached().await?;
  41. logger.trace(format!(
  42. "Symbol reports target_reached: {:?} (should be true)",
  43. target_reached
  44. ));
  45. if target_reached {
  46. Ok(())
  47. } else {
  48. Err(Box::new(ExecuteDidNotReachError))
  49. }
  50. }
  51. }
  52. #[async_trait(?Send)]
  53. impl SymbolRunner for InitializingSymbolRunner {
  54. async fn run_symbol<S: Symbol + Debug, L: Logger>(
  55. &self,
  56. symbol: &S,
  57. logger: &L,
  58. force: bool,
  59. ) -> Result<bool, Box<dyn Error>> {
  60. let executed = if force {
  61. logger.debug("Forcing symbol execution");
  62. self.exec_symbol(symbol, logger).await?;
  63. true
  64. } else {
  65. let target_reached = symbol.target_reached().await?;
  66. if target_reached {
  67. logger.debug(format!("{:?} already reached", symbol));
  68. } else {
  69. logger.trace(format!(
  70. "Symbol reports target_reached: {:?}",
  71. target_reached
  72. ));
  73. self.exec_symbol(symbol, logger).await?;
  74. }
  75. !target_reached
  76. };
  77. Ok(executed)
  78. }
  79. }
  80. #[derive(Clone, Debug)]
  81. pub struct DelayingSymbolRunner<R>(R);
  82. impl<R> DelayingSymbolRunner<R> {
  83. #[must_use]
  84. pub const fn new(symbol_runner: R) -> Self {
  85. Self(symbol_runner)
  86. }
  87. }
  88. #[async_trait(?Send)]
  89. impl<R> SymbolRunner for DelayingSymbolRunner<R>
  90. where
  91. R: SymbolRunner,
  92. {
  93. #[allow(
  94. clippy::cast_sign_loss,
  95. clippy::cast_possible_truncation,
  96. clippy::cast_precision_loss
  97. )]
  98. async fn run_symbol<S: Symbol + Debug, L: Logger>(
  99. &self,
  100. symbol: &S,
  101. logger: &L,
  102. force: bool,
  103. ) -> Result<bool, Box<dyn Error>> {
  104. sleep(Duration::from_millis(
  105. (((std::time::SystemTime::now()
  106. .duration_since(std::time::UNIX_EPOCH)
  107. .unwrap()
  108. .subsec_micros()
  109. % 20) as f32
  110. / 2.0)
  111. .exp()
  112. / 8.0) as u64,
  113. ))
  114. .await;
  115. self.0.run_symbol(symbol, logger, force).await
  116. }
  117. }
  118. #[derive(Clone, Debug, Default)]
  119. pub struct DrySymbolRunner;
  120. impl DrySymbolRunner {
  121. #[must_use]
  122. pub const fn new() -> Self {
  123. Self
  124. }
  125. }
  126. #[async_trait(?Send)]
  127. impl SymbolRunner for DrySymbolRunner {
  128. async fn run_symbol<S: Symbol + Debug, L: Logger>(
  129. &self,
  130. symbol: &S,
  131. logger: &L,
  132. force: bool,
  133. ) -> Result<bool, Box<dyn Error>> {
  134. let would_execute = if force {
  135. logger.info(format!("Would force-execute {:?}", symbol));
  136. true
  137. } else {
  138. let target_reached = symbol.target_reached().await?;
  139. logger.debug(format!(
  140. "Symbol reports target_reached: {:?}",
  141. target_reached
  142. ));
  143. if !target_reached {
  144. logger.info(format!("Would execute {:?}", symbol));
  145. }
  146. !target_reached
  147. };
  148. Ok(would_execute)
  149. }
  150. }
  151. #[derive(Clone, Debug)]
  152. pub struct ReportingSymbolRunner<R>(R);
  153. impl<R> ReportingSymbolRunner<R> {
  154. #[must_use]
  155. pub const fn new(symbol_runner: R) -> Self {
  156. Self(symbol_runner)
  157. }
  158. }
  159. #[async_trait(?Send)]
  160. impl<R> SymbolRunner for ReportingSymbolRunner<R>
  161. where
  162. R: SymbolRunner,
  163. {
  164. async fn run_symbol<S: Symbol + Debug, L: Logger>(
  165. &self,
  166. symbol: &S,
  167. logger: &L,
  168. force: bool,
  169. ) -> Result<bool, Box<dyn Error>> {
  170. logger.debug(format!("Running symbol {:?}", symbol));
  171. let res = self.0.run_symbol(symbol, logger, force).await;
  172. if let Err(ref e) = res {
  173. logger.info(format!("Failed on {:?} with {}, aborting.", symbol, e));
  174. } else {
  175. logger.debug(format!("Successfully finished {:?}", symbol));
  176. }
  177. res
  178. }
  179. }
  180. #[cfg(test)]
  181. mod test {
  182. use super::{DrySymbolRunner, InitializingSymbolRunner, ReportingSymbolRunner, SymbolRunner};
  183. use crate::async_utils::sleep;
  184. use crate::async_utils::{run, try_join};
  185. use crate::loggers::StoringLogger;
  186. use crate::symbols::Symbol;
  187. use async_trait::async_trait;
  188. use std::cell::RefCell;
  189. use std::error::Error;
  190. use std::fmt;
  191. use std::fmt::Debug;
  192. use std::time::Duration;
  193. #[derive(Debug, PartialEq, Clone)]
  194. enum DummySymbolError {
  195. Error(()),
  196. }
  197. impl Error for DummySymbolError {}
  198. impl fmt::Display for DummySymbolError {
  199. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  200. write!(f, "Dummy symbol error")
  201. }
  202. }
  203. #[derive(Debug)]
  204. struct DummySymbol<T, E> {
  205. _target_reached: RefCell<T>,
  206. _execute: RefCell<E>,
  207. }
  208. #[async_trait(?Send)]
  209. impl<
  210. E: Iterator<Item = Result<(), Box<dyn Error>>>,
  211. T: Iterator<Item = Result<bool, Box<dyn Error>>>,
  212. > Symbol for DummySymbol<T, E>
  213. {
  214. async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  215. self._target_reached.borrow_mut().next().unwrap()
  216. }
  217. async fn execute(&self) -> Result<(), Box<dyn Error>> {
  218. self._execute.borrow_mut().next().unwrap()
  219. }
  220. }
  221. impl<
  222. E: Iterator<Item = Result<(), Box<dyn Error>>>,
  223. T: Iterator<Item = Result<bool, Box<dyn Error>>>,
  224. > DummySymbol<T, E>
  225. {
  226. #[must_use]
  227. fn new<
  228. IE: IntoIterator<IntoIter = E, Item = Result<(), Box<dyn Error>>>,
  229. IT: IntoIterator<IntoIter = T, Item = Result<bool, Box<dyn Error>>>,
  230. >(
  231. target_reached: IT,
  232. execute: IE,
  233. ) -> Self {
  234. Self {
  235. _target_reached: RefCell::new(target_reached.into_iter()),
  236. _execute: RefCell::new(execute.into_iter()),
  237. }
  238. }
  239. }
  240. fn run_symbol<S: Symbol + Debug>(s: S) -> Result<bool, Box<dyn Error>> {
  241. run(InitializingSymbolRunner::new().run_symbol(&s, &StoringLogger::new(), false))
  242. }
  243. #[test]
  244. fn nothing_needed_to_be_done() {
  245. let result = run_symbol(DummySymbol::new(vec![Ok(true)], vec![Ok(())]));
  246. assert!(result.is_ok());
  247. }
  248. #[test]
  249. fn everything_is_ok() {
  250. let result = run_symbol(DummySymbol::new(vec![Ok(false), Ok(true)], vec![Ok(())]));
  251. assert!(result.is_ok());
  252. }
  253. #[test]
  254. fn executing_did_not_change_state() {
  255. let result = run_symbol(DummySymbol::new(vec![Ok(false), Ok(false)], vec![Ok(())]));
  256. assert_eq!(
  257. result.unwrap_err().to_string(),
  258. "Target not reached after executing symbol"
  259. );
  260. }
  261. #[test]
  262. fn executing_did_not_work() {
  263. let result = run_symbol(DummySymbol::new(
  264. vec![Ok(false)],
  265. vec![Err(Box::new(DummySymbolError::Error(())) as Box<dyn Error>)],
  266. ));
  267. assert_eq!(result.unwrap_err().to_string(), "Dummy symbol error");
  268. }
  269. #[derive(Debug)]
  270. struct SleeperSymbol;
  271. #[async_trait(?Send)]
  272. impl Symbol for SleeperSymbol {
  273. async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  274. sleep(Duration::from_millis(0)).await;
  275. Ok(true)
  276. }
  277. async fn execute(&self) -> Result<(), Box<dyn Error>> {
  278. unimplemented!();
  279. }
  280. }
  281. #[test]
  282. fn actually_support_parallel_execution() {
  283. run(async {
  284. let s1 = SleeperSymbol;
  285. let s2 = DummySymbol::new(vec![Ok(false), Ok(true)], vec![Ok(())]);
  286. let l1 = StoringLogger::new();
  287. let l2 = StoringLogger::new();
  288. let runner1 = InitializingSymbolRunner::new();
  289. let result = try_join!(
  290. runner1.run_symbol(&s1, &l1, false),
  291. runner1.run_symbol(&s2, &l2, false),
  292. )
  293. .unwrap();
  294. assert_eq!(result, (false, true));
  295. let s2 = DummySymbol::new(vec![Ok(false), Ok(true)], vec![Ok(())]);
  296. let l1 = StoringLogger::new();
  297. let l2 = StoringLogger::new();
  298. let runner2 = DrySymbolRunner::new();
  299. let result = try_join!(
  300. runner2.run_symbol(&s1, &l1, false),
  301. runner2.run_symbol(&s2, &l2, false),
  302. )
  303. .unwrap();
  304. assert_eq!(result, (false, true));
  305. let s2 = DummySymbol::new(vec![Ok(false), Ok(true)], vec![Ok(())]);
  306. let l1 = StoringLogger::new();
  307. let l2 = StoringLogger::new();
  308. let runner3 = ReportingSymbolRunner::new(runner1);
  309. let result = try_join!(
  310. runner3.run_symbol(&s1, &l1, false),
  311. runner3.run_symbol(&s2, &l2, false),
  312. )
  313. .unwrap();
  314. assert_eq!(result, (false, true));
  315. });
  316. }
  317. }