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.

149 lines
3.8 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. use async_trait::async_trait;
  2. use regex::Regex;
  3. use schematics::async_utils::{run, sleep};
  4. use schematics::loggers::{Entry, StoringLogger};
  5. use schematics::resources::{AcmeUser, Cert, Csr, GitCheckout};
  6. use schematics::symbols::Symbol;
  7. use schematics::Setup;
  8. use schematics::SymbolRunner;
  9. use slog::{info, Logger as SlogLogger};
  10. use std::error::Error;
  11. use std::fmt::Debug;
  12. use std::time::Duration;
  13. #[derive(Clone, Debug)]
  14. struct TestSymbolRunner {
  15. run: bool,
  16. }
  17. impl TestSymbolRunner {
  18. fn new(run: bool) -> Self {
  19. Self { run }
  20. }
  21. }
  22. #[async_trait(?Send)]
  23. impl SymbolRunner for TestSymbolRunner {
  24. async fn run_symbol<S: Symbol + Debug>(
  25. &self,
  26. _symbol: &S,
  27. logger: &SlogLogger,
  28. _force: bool,
  29. ) -> Result<bool, Box<dyn Error>> {
  30. info!(logger, "run_symbol");
  31. sleep(Duration::from_millis(0)).await;
  32. Ok(self.run)
  33. }
  34. }
  35. fn test(
  36. count: usize,
  37. body: fn(setup: Setup<TestSymbolRunner, StoringLogger>) -> (),
  38. ) -> Vec<Entry<String>> {
  39. let runner = TestSymbolRunner::new(false);
  40. let logger = StoringLogger::new();
  41. {
  42. let setup = Setup::new(runner, logger.clone());
  43. body(setup);
  44. }
  45. assert_eq!(logger.release(), vec![Entry(3, ".".repeat(count))]);
  46. let runner = TestSymbolRunner::new(true);
  47. let logger = StoringLogger::new();
  48. {
  49. let setup = Setup::new(runner, logger.clone());
  50. body(setup);
  51. }
  52. logger.release()
  53. }
  54. #[test]
  55. fn can_create_an_acme_user() {
  56. let mut result = test(1, |setup| {
  57. assert_eq!((run(setup.add(AcmeUser)).unwrap().0).0, "acme");
  58. });
  59. let entry = result
  60. .pop()
  61. .expect("log is empty but should contain one entry");
  62. assert_eq!(result.len(), 0, "log has more than one entry");
  63. assert_eq!(entry.0, 3, "log entry has wrong level");
  64. let re =
  65. Regex::new(r"^resource: AcmeUser\n \w+ \d{1,2} \d{2}:\d{2}:\d{2}.\d{3} INFO run_symbol\n$")
  66. .unwrap();
  67. assert!(
  68. re.is_match(&entry.1),
  69. "log output {} does not match {}",
  70. entry.1,
  71. re
  72. );
  73. }
  74. #[test]
  75. fn runs_only_once() {
  76. let mut result = test(2, |setup| {
  77. run(async {
  78. assert_eq!(
  79. (setup.add(Csr("somehost")).await.unwrap().0)
  80. .as_ref()
  81. .to_str()
  82. .unwrap(),
  83. "/etc/ssl/local_certs/somehost.csr",
  84. );
  85. assert_eq!(
  86. (setup.add(Csr("somehost")).await.unwrap().0)
  87. .as_ref()
  88. .to_str()
  89. .unwrap(),
  90. "/etc/ssl/local_certs/somehost.csr",
  91. );
  92. });
  93. });
  94. let entry = result
  95. .pop()
  96. .expect("log is empty but should contain entries");
  97. assert_eq!(entry.0, 3, "log entry has wrong level");
  98. assert_eq!(entry.1, ".", "log entry has wrong content");
  99. let entry = result
  100. .pop()
  101. .expect("log is empty but should contain entries");
  102. assert_eq!(entry.0, 3, "log entry has wrong level");
  103. assert_eq!(entry.1.matches("run_symbol").count(), 7); // Key and CSR + 5 dirs
  104. assert_eq!(result.len(), 0, "log has more than one entry");
  105. }
  106. #[test]
  107. fn can_create_an_acme_cert() {
  108. let mut result = test(1, |setup| {
  109. assert_eq!(
  110. (run(setup.add(Cert("somehost"))).unwrap().0)
  111. .as_ref()
  112. .to_str()
  113. .unwrap(),
  114. "/etc/ssl/local_certs/somehost.crt",
  115. );
  116. });
  117. let entry = result
  118. .pop()
  119. .expect("log is empty but should contain one entry");
  120. assert_eq!(entry.0, 3, "log entry has wrong level");
  121. assert_eq!(entry.1.matches("run_symbol").count(), 19);
  122. assert_eq!(result.len(), 0, "log has more than one entry");
  123. }
  124. #[test]
  125. fn can_create_a_git_checkout() {
  126. let mut result = test(1, |setup| {
  127. run(setup.add(GitCheckout(
  128. "/tmp/somepath".into(),
  129. "/tmp/some_src_repo",
  130. "master",
  131. )))
  132. .unwrap();
  133. });
  134. let entry = result
  135. .pop()
  136. .expect("log is empty but should contain one entry");
  137. assert_eq!(entry.0, 3, "log entry has wrong level");
  138. assert_eq!(entry.1.matches("run_symbol").count(), 3);
  139. assert_eq!(result.len(), 0, "log has more than one entry");
  140. }