1mod common;
2mod functional;
3mod robust;
4
5use colored::*;
6use futures::future::BoxFuture;
7use quorum_core::startup;
8use std::time::Duration;
9
10type FunctionalTestFn = fn() -> BoxFuture<'static, Result<TestResult, String>>;
12type RobustnessTestFn = fn() -> BoxFuture<'static, Result<RobustnessTestResult, String>>;
13
14pub struct TestResult {
15 pub endpoint_time: Duration,
16}
17
18pub struct RobustnessTestResult {
19 pub endpoint_time: Duration,
20}
21
22pub async fn run_all_tests() {
23 println!("\n{}", "Running Tests...".yellow().bold());
24
25 run_functional_tests().await;
26 run_robust_tests().await;
27}
28
29async fn run_functional_tests() {
30 println!("\n{}", "Running Functional Tests...".cyan().bold());
31
32 let tests: Vec<(&str, FunctionalTestFn)> = vec![
33 ("Auth signup with email + password test", || {
34 Box::pin(functional::auth_tests::test_signup_email())
35 }),
36 ("Auth signup with username + password test", || {
37 Box::pin(functional::auth_tests::test_signup_username())
38 }),
39 ("Auth login with email test", || {
40 Box::pin(functional::auth_tests::test_login_email())
41 }),
42 ("Auth login with username test", || {
43 Box::pin(functional::auth_tests::test_login_username())
44 }),
45 ("Auth refresh token test", || {
46 Box::pin(functional::auth_tests::test_refresh_token())
47 }),
48 ("Auth logout test", || {
49 Box::pin(functional::auth_tests::test_logout())
50 }),
51 ("Auth delete user account with email test", || {
52 Box::pin(functional::auth_tests::test_delete_user_account_email())
53 }),
54 ("Auth delete user account with username test", || {
55 Box::pin(functional::auth_tests::test_delete_user_account_username())
56 }),
57 ("Auth update user profile test", || {
58 Box::pin(functional::auth_tests::test_update_user_profile())
59 }),
60 ];
61
62 run_test_suite(&tests).await;
63}
64
65async fn run_robust_tests() {
66 println!("\n{}", "Running Robustness Tests...".magenta().bold());
67
68 let tests: Vec<(&str, RobustnessTestFn)> = vec![
69 ("Signup with short username", || {
70 Box::pin(robust::auth_tests::test_signup_short_username())
71 }),
72 ("Signup with long username", || {
73 Box::pin(robust::auth_tests::test_signup_long_username())
74 }),
75 ("Signup with empty password", || {
76 Box::pin(robust::auth_tests::test_signup_empty_password())
77 }),
78 ("Signup with short password", || {
79 Box::pin(robust::auth_tests::test_signup_short_password())
80 }),
81 ("Signup with long password", || {
82 Box::pin(robust::auth_tests::test_signup_long_password())
83 }),
84 ("Signup with invalid email", || {
85 Box::pin(robust::auth_tests::test_signup_invalid_email())
86 }),
87 ("Signup with duplicate username", || {
88 Box::pin(robust::auth_tests::test_signup_duplicate_username())
89 }),
90 ("Login with wrong password", || {
91 Box::pin(robust::auth_tests::test_login_wrong_password())
92 }),
93 ("Login with nonexistent user", || {
94 Box::pin(robust::auth_tests::test_login_nonexistent_user())
95 }),
96 ("Login with empty username", || {
97 Box::pin(robust::auth_tests::test_login_empty_username())
98 }),
99 ("Refresh with invalid token", || {
100 Box::pin(robust::auth_tests::test_refresh_invalid_token())
101 }),
102 ("Refresh with empty token", || {
103 Box::pin(robust::auth_tests::test_refresh_empty_token())
104 }),
105 ("Delete with wrong password", || {
106 Box::pin(robust::auth_tests::test_delete_wrong_password())
107 }),
108 ("Get user data with wrong password", || {
109 Box::pin(robust::auth_tests::test_get_user_data_wrong_password())
110 }),
111 ("Logout with invalid token", || {
112 Box::pin(robust::auth_tests::test_logout_invalid_token())
113 }),
114 ("Updating profile username with an empty field", || {
115 Box::pin(robust::auth_tests::test_update_profile_empty_username())
116 }),
117 ];
118
119 run_robustness_suite(&tests).await;
120}
121
122async fn run_test_suite(tests: &[(&str, FunctionalTestFn)]) {
123 let mut failed_tests = Vec::new();
124
125 for (i, (test_name, test_fn)) in tests.iter().enumerate() {
126 let timer = startup::create_timer();
127 let is_last = i == tests.len() - 1;
128
129 match test_fn().await {
130 Ok(result) => {
131 if is_last {
132 startup::print_final_step(test_name, true, result.endpoint_time);
133 } else {
134 startup::print_step(test_name, true, result.endpoint_time);
135 }
136 }
137 Err(e) => {
138 let elapsed = startup::elapsed(timer);
139 if is_last {
140 startup::print_final_step(test_name, false, elapsed);
141 } else {
142 startup::print_step(test_name, false, elapsed);
143 }
144 failed_tests.push((test_name.to_string(), e));
145 }
146 }
147 }
148
149 if !failed_tests.is_empty() {
150 println!(
151 "\n{}",
152 format!("{} test(s) failed:", failed_tests.len())
153 .red()
154 .bold()
155 );
156 for (name, error) in &failed_tests {
157 println!("{}", format!(" ✗ {}", name).red());
158 let error_lines: Vec<&str> = error.lines().collect();
159 for (idx, line) in error_lines.iter().enumerate() {
160 if idx == error_lines.len() - 1 {
161 println!(" {} {}", "└─".red(), line.dimmed());
162 } else {
163 println!(" {} {}", "├─".red(), line.dimmed());
164 }
165 }
166 }
167 }
168}
169
170async fn run_robustness_suite(tests: &[(&str, RobustnessTestFn)]) {
172 let mut issue_tests = Vec::new();
173
174 for (i, (test_name, test_fn)) in tests.iter().enumerate() {
175 let timer = startup::create_timer();
176 let is_last = i == tests.len() - 1;
177
178 match test_fn().await {
179 Ok(result) => {
180 if is_last {
181 startup::print_final_step(test_name, true, result.endpoint_time);
182 } else {
183 startup::print_step(test_name, true, result.endpoint_time);
184 }
185 }
186 Err(e) => {
187 let elapsed = startup::elapsed(timer);
188 if is_last {
189 startup::print_final_step(test_name, false, elapsed);
190 } else {
191 startup::print_step(test_name, false, elapsed);
192 }
193 issue_tests.push((test_name.to_string(), e));
194 }
195 }
196 }
197
198 if !issue_tests.is_empty() {
199 println!(
200 "\n{}",
201 format!("{} test(s) with unexpected behavior:", issue_tests.len())
202 .yellow()
203 .bold()
204 );
205 for (name, error) in &issue_tests {
206 println!("{}", format!(" ⚠ {}", name).yellow());
207 let error_lines: Vec<&str> = error.lines().collect();
208 for (idx, line) in error_lines.iter().enumerate() {
209 if idx == error_lines.len() - 1 {
210 println!(" {} {}", "└─".yellow(), line.dimmed());
211 } else {
212 println!(" {} {}", "├─".yellow(), line.dimmed());
213 }
214 }
215 }
216 }
217}