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 chat;
|
||||||
pub mod routing;
|
pub mod routing;
|
||||||
|
pub mod routing_operations;
|
||||||
pub mod test;
|
pub mod test;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ pub struct AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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;
|
let chats = self.chats.lock().await;
|
||||||
for i in 0..chats.len() {
|
for i in 0..chats.len() {
|
||||||
if chats[i].room_id == *room_id {
|
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 serde::Deserialize;
|
||||||
use tower_http::cors::CorsLayer;
|
use tower_http::cors::CorsLayer;
|
||||||
|
|
||||||
use crate::{
|
use crate::{routing_operations, AppState};
|
||||||
chat::{Chat, Message},
|
|
||||||
AppState,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ReceivedMessage {
|
struct ReceivedMessage {
|
||||||
|
@ -37,46 +34,18 @@ async fn alive() -> impl IntoResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive_message(
|
async fn receive_message(
|
||||||
State(mut state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(received_message): Json<ReceivedMessage>,
|
Json(received_message): Json<ReceivedMessage>,
|
||||||
) {
|
) {
|
||||||
let sender = received_message.username;
|
let sender = received_message.username;
|
||||||
let data = received_message.message;
|
let data = received_message.message;
|
||||||
let room_id = received_message.room_id;
|
let room_id = received_message.room_id;
|
||||||
let message = Message::new(sender, data);
|
routing_operations::receive_message(sender, data, room_id, &state).await;
|
||||||
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,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_message(
|
async fn send_message(
|
||||||
Path(room_id): Path<String>,
|
Path(room_id): Path<String>,
|
||||||
State(mut state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
match state.is_chat_exists(&room_id).await {
|
routing_operations::send_message(room_id, state).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()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
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