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.

202 lines
5.5 KiB

8 years ago
  1. use std::error::Error;
  2. use std::fmt;
  3. use std::io::Write;
  4. use loggers::Logger;
  5. use symbols::Symbol;
  6. #[derive(Debug,PartialEq)]
  7. pub enum SymbolRunError<E: Error> {
  8. Symbol(E),
  9. ExecuteDidNotReach(())
  10. }
  11. impl<E: Error> Error for SymbolRunError<E> {
  12. fn description(&self) -> &str {
  13. match self {
  14. &SymbolRunError::Symbol(_) => "Symbol execution error",
  15. &SymbolRunError::ExecuteDidNotReach(_) => "Target not reached after executing symbol"
  16. }
  17. }
  18. fn cause(&self) -> Option<&Error> {
  19. match self {
  20. &SymbolRunError::Symbol(ref e) => Some(e),
  21. &SymbolRunError::ExecuteDidNotReach(_) => None
  22. }
  23. }
  24. }
  25. impl<E: Error> fmt::Display for SymbolRunError<E> {
  26. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  27. match self {
  28. &SymbolRunError::Symbol(ref e) => write!(f, "{}", e),
  29. &SymbolRunError::ExecuteDidNotReach(_) => write!(f, "{}", self.description())
  30. }
  31. }
  32. }
  33. impl<E: Error> From<E> for SymbolRunError<E> {
  34. fn from(err: E) -> SymbolRunError<E> {
  35. SymbolRunError::Symbol(err)
  36. }
  37. }
  38. pub trait SymbolRunner {
  39. fn run_symbol<S: Symbol + fmt::Display>(&self, logger: &mut Logger, symbol: &S) -> Result<(), SymbolRunError<S::Error>>
  40. where S::Error: Error;
  41. }
  42. pub struct InitializingSymbolRunner;
  43. impl SymbolRunner for InitializingSymbolRunner {
  44. fn run_symbol<S: Symbol + fmt::Display>(&self, logger: &mut Logger, symbol: &S) -> Result<(), SymbolRunError<S::Error>>
  45. where S::Error: Error
  46. {
  47. let target_reached = try!(symbol.target_reached());
  48. if target_reached {
  49. logger.write(format!("{} already reached", symbol).as_str());
  50. } else {
  51. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  52. logger.write(format!("Executing {}", symbol).as_str());
  53. try!(symbol.execute());
  54. let target_reached = try!(symbol.target_reached());
  55. logger.debug(format!("Symbol reports target_reached: {:?} (should be true)", target_reached).as_str());
  56. if !target_reached {
  57. return Err(SymbolRunError::ExecuteDidNotReach(()));
  58. }
  59. }
  60. Ok(())
  61. }
  62. }
  63. pub struct DrySymbolRunner;
  64. impl SymbolRunner for DrySymbolRunner {
  65. fn run_symbol<S: Symbol + fmt::Display>(&self, logger: &mut Logger, symbol: &S) -> Result<(), SymbolRunError<S::Error>>
  66. where S::Error: Error
  67. {
  68. let target_reached = try!(symbol.target_reached());
  69. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  70. if !target_reached {
  71. logger.write(format!("Would execute {}", symbol).as_str());
  72. }
  73. Ok(())
  74. }
  75. }
  76. // FIXME: Add ExpectingSymbolRunner
  77. #[cfg(test)]
  78. mod test {
  79. use std::cell::RefCell;
  80. use std::error::Error;
  81. use std::fmt;
  82. use loggers::Logger;
  83. use symbols::Symbol;
  84. use schema::SymbolRunner;
  85. use schema::InitializingSymbolRunner;
  86. use schema::SymbolRunError;
  87. #[derive(Debug, PartialEq, Clone)]
  88. enum DummySymbolError {
  89. Error(())
  90. }
  91. impl Error for DummySymbolError {
  92. fn description(&self) -> &str {
  93. return "Description";
  94. }
  95. }
  96. impl fmt::Display for DummySymbolError {
  97. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  98. write!(f, "Dummy symbol error")
  99. }
  100. }
  101. #[derive(Debug)]
  102. struct DummySymbol {
  103. _target_reacheds: Vec<Result<bool, DummySymbolError>>,
  104. _cur_target_reached: RefCell<usize>,
  105. _execute: Result<(), DummySymbolError>,
  106. }
  107. impl Symbol for DummySymbol {
  108. type Error = DummySymbolError;
  109. fn target_reached(&self) -> Result<bool, Self::Error> {
  110. let mut cur = self._cur_target_reached.borrow_mut();
  111. let ret = self._target_reacheds[*cur].clone();
  112. *cur = *cur + 1;
  113. ret
  114. }
  115. fn execute(&self) -> Result<(), Self::Error> { self._execute.clone() }
  116. }
  117. impl fmt::Display for DummySymbol {
  118. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  119. write!(f, "Dummy symbol")
  120. }
  121. }
  122. impl DummySymbol {
  123. fn new(target_reached: Vec<Result<bool, DummySymbolError>>,
  124. execute: Result<(), DummySymbolError>) -> DummySymbol {
  125. DummySymbol { _target_reacheds: target_reached, _cur_target_reached: RefCell::new(0), _execute: execute }
  126. }
  127. }
  128. struct DummyLogger {
  129. log: Vec<String>
  130. }
  131. impl DummyLogger {
  132. fn new() -> DummyLogger {
  133. DummyLogger { log: Vec::new() }
  134. }
  135. }
  136. impl Logger for DummyLogger {
  137. fn write(&mut self, line: &str) {
  138. self.log.push(From::from(line));
  139. }
  140. fn debug(&mut self, line: &str) {
  141. self.log.push(From::from(line));
  142. }
  143. }
  144. #[test]
  145. fn nothing_needed_to_be_done() {
  146. let result: Result<(), SymbolRunError<DummySymbolError>> = InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(true)], Ok(())) );
  147. assert_eq!(
  148. result,
  149. Ok(())
  150. );
  151. }
  152. #[test]
  153. fn everything_is_ok() {
  154. let result: Result<(), SymbolRunError<DummySymbolError>> = InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(false), Ok(true)], Ok(())) );
  155. assert_eq!(
  156. result,
  157. Ok(())
  158. );
  159. }
  160. #[test]
  161. fn executing_did_not_change_state() {
  162. let result: Result<(), SymbolRunError<DummySymbolError>> = InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(false), Ok(false)], Ok(())));
  163. assert_eq!(
  164. result,
  165. Err(SymbolRunError::ExecuteDidNotReach(()))
  166. );
  167. }
  168. #[test]
  169. fn executing_did_not_work() {
  170. assert_eq!(
  171. InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(false)], Err(DummySymbolError::Error(()))) ),
  172. Err(SymbolRunError::Symbol(DummySymbolError::Error(())))
  173. );
  174. }
  175. }