From da2b65e7dc0e17d575b84f3a928ac6a6aa7d1e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Mon, 27 May 2024 01:33:30 +0300 Subject: [PATCH] test: :white_check_mark: add tests refactor: :recycle: routing_operations --- src/lib.rs | 7 +-- src/routing.rs | 41 +++-------------- src/routing_operations.rs | 50 +++++++++++++++++++++ src/test.rs | 95 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 41 deletions(-) create mode 100644 src/routing_operations.rs diff --git a/src/lib.rs b/src/lib.rs index 1dbdcb2..805032e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ use tokio::sync::Mutex; pub mod chat; pub mod routing; +pub mod routing_operations; pub mod test; pub mod utils; @@ -24,7 +25,7 @@ pub struct AppState { } impl AppState { - pub async fn is_chat_exists(&mut self, room_id: &String) -> Option { + pub async fn is_chat_exists(&self, room_id: &String) -> Option { let chats = self.chats.lock().await; for i in 0..chats.len() { if chats[i].room_id == *room_id { @@ -52,10 +53,6 @@ impl AppState { } } } - // if chats[chat_index].last_interaction < current - chat_cleaning_timeout as u64 { - // chats.remove(chat_index); - // return; - // } } } } diff --git a/src/routing.rs b/src/routing.rs index 8d5b9f4..f4e30b1 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -8,10 +8,7 @@ use axum::{ use serde::Deserialize; use tower_http::cors::CorsLayer; -use crate::{ - chat::{Chat, Message}, - AppState, -}; +use crate::{routing_operations, AppState}; #[derive(Debug, Deserialize)] struct ReceivedMessage { @@ -37,46 +34,18 @@ async fn alive() -> impl IntoResponse { } async fn receive_message( - State(mut state): State, + State(state): State, Json(received_message): Json, ) { let sender = received_message.username; let data = received_message.message; let room_id = received_message.room_id; - let message = Message::new(sender, data); - match state.is_chat_exists(&room_id).await { - Some(index) => { - let mut chats = state.chats.lock().await; - chats[index].add_message(message, state.max_message_counter); - } - None => { - let mut new_chat = Chat::new(room_id); - new_chat.add_message(message, state.max_message_counter); - let mut chats = state.chats.lock().await; - let room_id = new_chat.room_id.clone(); - chats.push(new_chat); - drop(chats); - tokio::spawn(AppState::chat_destroyer( - state.chats.clone(), - room_id, - state.chat_cleaning_timeout, - )); - } - } + routing_operations::receive_message(sender, data, room_id, &state).await; } async fn send_message( Path(room_id): Path, - State(mut state): State, + State(state): State, ) -> impl IntoResponse { - match state.is_chat_exists(&room_id).await { - Some(index) => { - let chats = state.chats.lock().await; - ( - StatusCode::OK, - serde_json::to_string(&chats[index]).unwrap(), - ) - } - None => (StatusCode::BAD_REQUEST, serde_json::to_string("").unwrap()), - } + routing_operations::send_message(room_id, state).await } diff --git a/src/routing_operations.rs b/src/routing_operations.rs new file mode 100644 index 0000000..ebbac0e --- /dev/null +++ b/src/routing_operations.rs @@ -0,0 +1,50 @@ +use axum::http::StatusCode; + +use crate::{ + chat::{Chat, Message}, + AppState, +}; + +pub async fn receive_message( + sender: impl ToString, + data: impl ToString, + room_id: impl ToString, + state: &AppState, +) { + let message = Message::new(sender.to_string(), data.to_string()); + match state.is_chat_exists(&room_id.to_string()).await { + Some(index) => { + let mut chats = state.chats.lock().await; + chats[index].add_message(message, state.max_message_counter); + } + None => { + let mut new_chat = Chat::new(room_id.to_string()); + new_chat.add_message(message, state.max_message_counter); + let mut chats = state.chats.lock().await; + let room_id = new_chat.room_id.clone(); + chats.push(new_chat); + drop(chats); + tokio::spawn(AppState::chat_destroyer( + state.chats.clone(), + room_id, + state.chat_cleaning_timeout, + )); + } + } +} + +pub async fn send_message( + room_id: impl ToString, + state: AppState, +) -> (axum::http::StatusCode, std::string::String) { + match state.is_chat_exists(&room_id.to_string()).await { + Some(index) => { + let chats = state.chats.lock().await; + ( + StatusCode::OK, + serde_json::to_string(&chats[index]).unwrap(), + ) + } + None => (StatusCode::BAD_REQUEST, serde_json::to_string("").unwrap()), + } +} diff --git a/src/test.rs b/src/test.rs index 8b13789..7237d0a 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1 +1,96 @@ +#[cfg(test)] +use crate::{routing_operations::receive_message, AppState}; +#[cfg(test)] +use std::sync::Arc; +#[cfg(test)] +use std::time::Duration; +#[cfg(test)] +use tokio::sync::Mutex; +#[tokio::test] +async fn new_message_no_chat() { + let state = AppState { + chats: Arc::new(Mutex::new(vec![])), + max_message_counter: 5, + chat_cleaning_timeout: 10, + }; + receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 1); +} + +#[tokio::test] +async fn new_message_with_chat() { + let state = AppState { + chats: Arc::new(Mutex::new(vec![])), + max_message_counter: 5, + chat_cleaning_timeout: 10, + }; + receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 1); + drop(chats); + + receive_message("Tahinli", "Hi Again", "Tahinli-Chat", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 2); +} + +#[tokio::test] +async fn chat_auto_deletion_with_timeout() { + let state = AppState { + chats: Arc::new(Mutex::new(vec![])), + max_message_counter: 5, + chat_cleaning_timeout: 1, + }; + receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 1); + drop(chats); + + tokio::time::sleep(Duration::from_secs(2)).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 0); +} + +#[tokio::test] +async fn message_auto_deletion_with_counter() { + let state = AppState { + chats: Arc::new(Mutex::new(vec![])), + max_message_counter: 1, + chat_cleaning_timeout: 10, + }; + receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 1); + drop(chats); + + receive_message("Tahinli", "Hi", "Tahinli-Chat", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 1); +} + +#[tokio::test] +async fn create_multiple_chats() { + let state = AppState { + chats: Arc::new(Mutex::new(vec![])), + max_message_counter: 1, + chat_cleaning_timeout: 10, + }; + receive_message("Tahinli", "Hi", "Tahinli-Chat-1", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 1); + assert_eq!(chats[0].messages.len(), 1); + drop(chats); + + receive_message("Tahinli", "Hi", "Tahinli-Chat-2", &state).await; + let chats = state.chats.lock().await; + assert_eq!(chats.len(), 2); + assert_eq!(chats[1].messages.len(), 1); +}