#
mcaptcha/
demo.rs

    1// Copyright (C) 2022  Aravinth Manivannan <realaravinth@batsense.net>
    2// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
    3//
    4// SPDX-License-Identifier: AGPL-3.0-or-later
    5
    6use std::time::Duration;
    7//use std::sync::atomicBool
    8
    9use actix::clock::sleep;
    10use actix::spawn;
    11use tokio::sync::oneshot::{channel, error::TryRecvError, Receiver, Sender};
    12use tokio::task::JoinHandle;
    13
    14use crate::api::v1::account::delete::runners::delete_user;
    15use crate::api::v1::account::{username::runners::username_exists, AccountCheckPayload};
    16use crate::api::v1::auth::runners::{register_runner, Register};
    17use crate::*;
    18
    19use errors::*;
    20
    21/// Demo username
    22pub const DEMO_USER: &str = "aaronsw";
    23/// Demo password
    24pub const DEMO_PASSWORD: &str = "password";
    25
    26pub struct DemoUser {
    27    tx: Sender<()>,
    28}
    29
    30impl DemoUser {
    31    pub async fn spawn(
    32        data: AppData,
    33        duration: u32,
    34    ) -> ServiceResult<(Self, JoinHandle<()>)> {
    35        let (tx, rx) = channel();
    36        let handle = Self::run(data, duration, rx).await?;
    37        let d = Self { tx };
    38
    39        Ok((d, handle))
    40    }
    41
    42    #[allow(dead_code)]
    43    pub fn abort(mut self) {
    44        self.tx.send(());
    45    }
    46
    47    /// register demo user runner
    48    async fn register_demo_user(data: &AppData) -> ServiceResult<()> {
    49        let user_exists_payload = AccountCheckPayload {
    50            val: DEMO_USER.into(),
    51        };
    52
    53        if !username_exists(&user_exists_payload, data).await?.exists {
    54            let register_payload = Register {
    55                username: DEMO_USER.into(),
    56                password: DEMO_PASSWORD.into(),
    57                confirm_password: DEMO_PASSWORD.into(),
    58                email: None,
    59            };
    60
    61            log::info!("Registering demo user");
    62            match register_runner(&register_payload, data).await {
    63                Err(ServiceError::UsernameTaken) | Ok(_) => Ok(()),
    64                Err(e) => Err(e),
    65            }
    66        } else {
    67            Ok(())
    68        }
    69    }
    70
    71    async fn delete_demo_user(data: &AppData) -> ServiceResult<()> {
    72        log::info!("Deleting demo user");
    73        delete_user(DEMO_USER, data).await?;
    74        Ok(())
    75    }
    76
    77    pub async fn run(
    78        data: AppData,
    79        duration: u32,
    80        mut rx: Receiver<()>,
    81    ) -> ServiceResult<JoinHandle<()>> {
    82        Self::register_demo_user(&data).await?;
    83
    84        fn can_run(rx: &mut Receiver<()>) -> bool {
    85            match rx.try_recv() {
    86                Err(TryRecvError::Empty) => true,
    87                _ => false,
    88            }
    89        }
    90
    91        let mut exit = false;
    92        let fut = async move {
    93            loop {
    94                if exit {
    95                    break;
    96                }
    97                for _ in 0..duration {
    98                    if can_run(&mut rx) {
    99                        sleep(Duration::new(1, 0)).await;
    100                        continue;
    101                    } else {
    102                        exit = true;
    103                        break;
    104                    }
    105                }
    106
    107                if let Err(e) = Self::delete_demo_user(&data).await {
    108                    log::error!("Error while deleting demo user: {:?}", e);
    109                }
    110
    111                if let Err(e) = Self::register_demo_user(&data).await {
    112                    log::error!("Error while registering demo user: {:?}", e);
    113                }
    114            }
    115        };
    116        let handle = spawn(fut);
    117        Ok(handle)
    118    }
    119}
    120
    121#[cfg(test)]
    122mod tests {
    123
    124    use actix_web::test;
    125    use libmcaptcha::defense::Level;
    126
    127    use super::*;
    128    use crate::tests::*;
    129
    130    const DURATION: u64 = 25;
    131
    132    #[actix_rt::test]
    133    async fn demo_account_works_pg() {
    134        let data = crate::tests::pg::get_data().await;
    135        demo_account_works(data).await;
    136    }
    137
    138    #[actix_rt::test]
    139    async fn demo_account_works_maria() {
    140        let data = crate::tests::maria::get_data().await;
    141        demo_account_works(data).await;
    142    }
    143
    144    async fn demo_account_works(data_inner: ArcData) {
    145        let data_inner = &data_inner;
    146        let data = AppData::new(data_inner.clone());
    147        crate::tests::delete_user(data_inner, DEMO_USER).await;
    148        let duration = Duration::from_secs(DURATION);
    149
    150        // register works
    151        DemoUser::register_demo_user(&data).await.unwrap();
    152        let payload = AccountCheckPayload {
    153            val: DEMO_USER.into(),
    154        };
    155        assert!(username_exists(&payload, &data).await.unwrap().exists);
    156        signin(data_inner, DEMO_USER, DEMO_PASSWORD).await;
    157
    158        // deletion works
    159        assert!(DemoUser::delete_demo_user(&data).await.is_ok());
    160        assert!(!username_exists(&payload, &data).await.unwrap().exists);
    161
    162        // test the runner
    163        let user = DemoUser::spawn(data, DURATION as u32).await.unwrap();
    164        let (_, signin_resp, token_key) =
    165            add_levels_util(data_inner, DEMO_USER, DEMO_PASSWORD).await;
    166        let cookies = get_cookie!(signin_resp);
    167        let app = get_app!(data_inner).await;
    168
    169        let resp = test::call_service(
    170            &app,
    171            post_request!(&token_key, crate::V1_API_ROUTES.captcha.get)
    172                .cookie(cookies.clone())
    173                .to_request(),
    174        )
    175        .await;
    176        assert_eq!(resp.status(), StatusCode::OK);
    177        let res_levels: Vec<Level> = test::read_body_json(resp).await;
    178        assert!(!res_levels.is_empty());
    179
    180        sleep(Duration::from_secs(DURATION * 2)).await;
    181
    182        let resp = test::call_service(
    183            &app,
    184            post_request!(&token_key, crate::V1_API_ROUTES.captcha.get)
    185                .cookie(cookies)
    186                .to_request(),
    187        )
    188        .await;
    189        assert_eq!(resp.status(), StatusCode::OK);
    190        let res_levels: Vec<Level> = test::read_body_json(resp).await;
    191        assert!(res_levels.is_empty());
    192        user.0.abort();
    193        user.1.await.unwrap();
    194    }
    195}