From 855dbc60efa5d2539e442208bee06351b531b3c6 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sat, 18 Dec 2021 13:47:01 +0530 Subject: [PATCH] Fixes #8 ``` $ cargo test <--- snip ---> thread panicked while panicking. aborting. Running unittests (target/debug/deps/tests_migrate-7d90f83f506b1b25) ``` gdb revealed that demo::demo_account_works receives a SIGKILL due to a failed test. No idea why it didn't fail the usual way. The part where the test fails hits an endpoint with the wrong datatype payload, it should have failed with a 404 when the status was asserted but it didn't. Fixing that fixed #8. Additionally, all demo user functionality was restructured to include an abort functionality, which can be used to kill the loop that deletes and creates demo user throughout the runtime of the app. --- Cargo.toml | 2 +- src/demo.rs | 112 +++++++++++++++++++++++++++++++++------------------- src/main.rs | 18 +++++++-- 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 45f362c4..7a20ffcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/mCaptcha/mCaptcha" documentation = "https://mcaptcha.org/docs/" license = "AGPLv3 or later version" authors = ["realaravinth "] -edition = "2018" +edition = "2021" default-run = "mcaptcha" build = "build.rs" diff --git a/src/demo.rs b/src/demo.rs index e1965276..17a16176 100644 --- a/src/demo.rs +++ b/src/demo.rs @@ -15,9 +15,11 @@ * along with this program. If not, see . */ use std::time::Duration; +//use std::sync::atomicBool use actix::clock::sleep; use actix::spawn; +use tokio::task::JoinHandle; use crate::api::v1::account::delete::runners::delete_user; use crate::api::v1::account::{username::runners::username_exists, AccountCheckPayload}; @@ -31,52 +33,79 @@ pub const DEMO_USER: &str = "aaronsw"; /// Demo password pub const DEMO_PASSWORD: &str = "password"; -/// register demo user runner -async fn register_demo_user(data: &AppData) -> ServiceResult<()> { - let user_exists_payload = AccountCheckPayload { - val: DEMO_USER.into(), - }; +pub struct DemoUser { + data: AppData, + duration: Duration, + handle: JoinHandle<()>, +} - if !username_exists(&user_exists_payload, data).await?.exists { - let register_payload = Register { - username: DEMO_USER.into(), - password: DEMO_PASSWORD.into(), - confirm_password: DEMO_PASSWORD.into(), - email: None, +impl DemoUser { + pub async fn spawn(data: AppData, duration: Duration) -> ServiceResult { + let handle = Self::run(data.clone(), duration.clone()).await?; + let d = Self { + data, + duration, + handle, }; - log::info!("Registering demo user"); - match register_runner(®ister_payload, data).await { - Err(ServiceError::UsernameTaken) | Ok(_) => Ok(()), - Err(e) => Err(e), + Ok(d) + } + + #[allow(dead_code)] + pub fn abort(&self) { + self.handle.abort(); + } + + /// register demo user runner + async fn register_demo_user(data: &AppData) -> ServiceResult<()> { + let user_exists_payload = AccountCheckPayload { + val: DEMO_USER.into(), + }; + + if !username_exists(&user_exists_payload, &data).await?.exists { + let register_payload = Register { + username: DEMO_USER.into(), + password: DEMO_PASSWORD.into(), + confirm_password: DEMO_PASSWORD.into(), + email: None, + }; + + log::info!("Registering demo user"); + match register_runner(®ister_payload, &data).await { + Err(ServiceError::UsernameTaken) | Ok(_) => Ok(()), + Err(e) => Err(e), + } + } else { + Ok(()) } - } else { + } + + async fn delete_demo_user(data: &AppData) -> ServiceResult<()> { + log::info!("Deleting demo user"); + delete_user(DEMO_USER, &data).await?; Ok(()) } -} -async fn delete_demo_user(data: &AppData) -> ServiceResult<()> { - log::info!("Deleting demo user"); - delete_user(DEMO_USER, data).await?; - Ok(()) -} + pub async fn run( + data: AppData, + duration: Duration, + ) -> ServiceResult> { + Self::register_demo_user(&data).await?; -pub async fn run(data: AppData, duration: Duration) -> ServiceResult<()> { - register_demo_user(&data).await?; - - let fut = async move { - loop { - sleep(duration).await; - if let Err(e) = delete_demo_user(&data).await { - log::error!("Error while deleting demo user: {:?}", e); + let fut = async move { + loop { + sleep(duration).await; + if let Err(e) = Self::delete_demo_user(&data).await { + log::error!("Error while deleting demo user: {:?}", e); + } + if let Err(e) = Self::register_demo_user(&data).await { + log::error!("Error while registering demo user: {:?}", e); + } } - if let Err(e) = register_demo_user(&data).await { - log::error!("Error while registering demo user: {:?}", e); - } - } - }; - spawn(fut); - Ok(()) + }; + let handle = spawn(fut); + Ok(handle) + } } #[cfg(test)] @@ -100,7 +129,7 @@ mod tests { let duration = Duration::from_secs(DURATION); // register works - let _ = register_demo_user(&data).await.unwrap(); + let _ = DemoUser::register_demo_user(&data).await.unwrap(); let payload = AccountCheckPayload { val: DEMO_USER.into(), }; @@ -108,11 +137,11 @@ mod tests { signin(DEMO_USER, DEMO_PASSWORD).await; // deletion works - assert!(super::delete_demo_user(&data).await.is_ok()); + assert!(DemoUser::delete_demo_user(&data).await.is_ok()); assert!(!username_exists(&payload, &data).await.unwrap().exists); // test the runner - run(data, duration).await.unwrap(); + let user = DemoUser::spawn(data, duration).await.unwrap(); let (data_inner, _, signin_resp, token_key) = add_levels_util(DEMO_USER, DEMO_PASSWORD).await; let cookies = get_cookie!(signin_resp); @@ -133,7 +162,7 @@ mod tests { let resp = test::call_service( &app, - post_request!(&token_key, crate::V1_API_ROUTES.captcha.create) + post_request!(&token_key, crate::V1_API_ROUTES.captcha.get) .cookie(cookies) .to_request(), ) @@ -141,5 +170,6 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); let res_levels: Vec = test::read_body_json(resp).await; assert!(res_levels.is_empty()); + user.abort(); } } diff --git a/src/main.rs b/src/main.rs index 310cf24f..7c28ec41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,7 @@ pub use settings::Settings; use static_assets::FileMap; pub use widget::WIDGET_ROUTES; +use crate::demo::DemoUser; pub use crate::middleware::auth::CheckLogin; lazy_static! { @@ -114,10 +115,14 @@ async fn main() -> std::io::Result<()> { sqlx::migrate!("./migrations/").run(&data.db).await.unwrap(); let data = actix_web::web::Data::new(data); + let mut demo_user: Option = None; + if SETTINGS.allow_demo && SETTINGS.allow_registration { - demo::run(data.clone(), Duration::from_secs(60 * 30)) - .await - .unwrap(); + demo_user = Some( + DemoUser::spawn(data.clone(), Duration::from_secs(60 * 30)) + .await + .unwrap(), + ); } println!("Starting server on: http://{}", SETTINGS.server.get_ip()); @@ -141,7 +146,12 @@ async fn main() -> std::io::Result<()> { .bind(SETTINGS.server.get_ip()) .unwrap() .run() - .await + .await?; + + if let Some(demo_user) = demo_user { + demo_user.abort(); + } + Ok(()) } #[cfg(not(tarpaulin_include))]