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.

389 lines
9.2 KiB

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