test_collector/
test_runner.rs

1use 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}