test: ✅ add tests
refactor: ♻️ routing_operations
This commit is contained in:
parent
e67aee396f
commit
da2b65e7dc
4 changed files with 152 additions and 41 deletions
|
@ -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<usize> {
|
||||
pub async fn is_chat_exists(&self, room_id: &String) -> Option<usize> {
|
||||
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;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AppState>,
|
||||
State(state): State<AppState>,
|
||||
Json(received_message): Json<ReceivedMessage>,
|
||||
) {
|
||||
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<String>,
|
||||
State(mut state): State<AppState>,
|
||||
State(state): State<AppState>,
|
||||
) -> 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
|
||||
}
|
||||
|
|
50
src/routing_operations.rs
Normal file
50
src/routing_operations.rs
Normal file
|
@ -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()),
|
||||
}
|
||||
}
|
95
src/test.rs
95
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue