test_collector/
test_runner.rs1use std::any::Any;
2use std::panic;
3use std::panic::AssertUnwindSafe;
4use std::time::Instant;
5use futures::FutureExt;
6use test_collector_utils::IntegrationTestMeta;
7use crate::{TestEnvironment, TestResult, TestResults};
8use crate::logger::{log_error_static_info, log_error_test, log_static_info, log_test};
9
10pub struct TestRunner<T: TestEnvironment> {
11 test_environment: T,
12}
13
14impl<T: TestEnvironment> TestRunner<T> {
15 pub fn new(test_environment: T) -> TestRunner<T> {
16 TestRunner {
17 test_environment
18 }
19 }
20
21 pub fn run_safe(mut self) -> TestResults {
22 log_static_info(format_args!("Next step is to start test environment"));
23 let spin_up_started_at = Instant::now();
24 self.test_environment = self.test_environment.start();
25 let start_up_duration = spin_up_started_at.elapsed();
26 log_static_info(format_args!("Test environment was started within {:?}", start_up_duration));
27 log_static_info(format_args!("***"));
28
29 log_static_info(format_args!("Next step is to run tests"));
30 let tests_started_at = Instant::now();
31 let (success_tests, failed_tests) = self.run_tests();
32 let tests_duration = tests_started_at.elapsed();
33 log_static_info(format_args!("All tests finished within {:?}", tests_duration));
34 log_static_info(format_args!("***"));
35
36 log_static_info(format_args!("Next step is to stop test environment"));
37 let teardown_started_at = Instant::now();
38 self.test_environment = self.test_environment.stop();
39 let stop_duration = teardown_started_at.elapsed();
40 log_static_info(format_args!("Test environment was stopped, within {:?}", stop_duration));
41 log_static_info(format_args!("***"));
42
43 let overall_duration = spin_up_started_at.elapsed();
44 log_static_info(format_args!("Overall duration {:?}", overall_duration));
45
46 return TestResults {
47 success_tests,
48 failed_tests,
49 start_up_duration,
50 tests_duration,
51 stop_duration,
52 };
53 }
54
55 pub fn run(self) {
56 let result = self.run_safe();
57 let success_test_number = result.success_tests.len();
58 let failed_test_number =result.failed_tests.len();
59 log_static_info(format_args!("Successful test {}. Failed tests {}",
60 success_test_number,
61 failed_test_number,
62 ));
63 for test in result.success_tests {
64 log_static_info(format_args!("Test [{}] ....... PASSED", test.name));
65 }
66 for test in result.failed_tests {
67 log_error_static_info(format_args!("Test [{}] ....... FAILED", test.name));
68 }
69 if failed_test_number > 0 {
70 panic!("Some tests are Failing");
71 }
72 }
73
74 fn run_tests(&self) -> (Vec<TestResult>, Vec<TestResult>) {
75 let number_of_tests = inventory::iter::<IntegrationTestMeta>.into_iter().count();
76 log_static_info(format_args!("Found {} tests", number_of_tests));
77 let mut successful_tests: Vec<TestResult> = Vec::new();
78 let mut failed_tests: Vec<TestResult> = Vec::new();
79 for test in inventory::iter::<IntegrationTestMeta> {
80 log_test(format_args!("Running Before Each Test for: [{}]", test.name));
81 self.test_environment.before_each_test();
82 let result = self.run_test(test);
83 if result.success {
84 successful_tests.push(result);
85 } else {
86 failed_tests.push(result);
87 }
88 log_test(format_args!("Running After Each Test for: [{}]", test.name));
89 self.test_environment.after_each_test();
90 }
91 (successful_tests, failed_tests)
92 }
93
94 fn run_test(&self, test: &IntegrationTestMeta) -> TestResult {
95 let test_started = Instant::now();
96 log_test(format_args!("Running Test: [{}]", test.name));
97 let result = self.run_test_safe(test);
98 let test_duration = test_started.elapsed();
99 let success = match result {
100 Ok(_) => {
101 log_test(format_args!("Test [{}] PASSED. Duration {:?}", test.name, test_duration));
102 true
103 }
104 Err(e) => {
105 let error: Result<Box<&'static str>, Box<dyn Any + Send>> = e.downcast();
106 if error.is_ok() {
107 let error: Box<&'static str> = error.unwrap();
108 log_error_test(format_args!("Test [{}] finished with ERROR. Duration {:?} \n {:?}",
109 test.name, test_duration, error));
110 } else {
111 log_error_test(format_args!("Test [{}] FAILED. Duration {:?}",
112 test.name, test_duration));
113 }
114
115 false
116 }
117 };
118 TestResult {
119 name: test.name.clone(),
120 success,
121 duration: test_duration,
122 }
123 }
124
125 fn run_test_safe(&self, test: &IntegrationTestMeta) -> Result<(), Box<dyn Any + Send>> {
126 if test.sync_fn.is_some() {
127 panic::catch_unwind(test.sync_fn.unwrap())
128 } else {
129 let async_test = (test.async_fn.as_ref().unwrap())();
130 let catch_panic_wrapper = AssertUnwindSafe(async_test).catch_unwind();
131 self.test_environment.block_on(catch_panic_wrapper)
132 }
133 }
134}