Add comprehensive tests for IAM permissions, roles, teams, and users

- Implemented unit tests for PermissionsController and PermissionsService, covering create, read, update, and delete operations.
- Added tests for RolesController and RolesService, including handling of duplicates and retrieval by ID.
- Developed tests for TeamsController, including creation, retrieval, updating, deletion, and search functionality.
- Created tests for UsersController, ensuring user creation and validation of attributes.
- Each test includes setup, execution, and cleanup to maintain database integrity.
This commit is contained in:
MythEclipse
2025-09-25 22:06:21 +07:00
parent 4ecdcd12d2
commit 7056f8c8a6
25 changed files with 4761 additions and 432 deletions
@@ -0,0 +1,82 @@
#[cfg(test)]
mod tests {
use crate::get_meta_request_dto;
use imphnen_cms::{
v1::landing::events::{
events_controller::EventsController,
events_dto::{EventsCreateRequestDto, EventsUpdateRequestDto},
},
};
#[tokio::test]
async fn test_get_event_list_controller() {
let app_state = crate::get_app_state().await;
let response = EventsController::get_event_list(&app_state, get_meta_request_dto(1, 10)).await;
assert_eq!(response.status(), 200);
}
#[tokio::test]
async fn test_get_event_by_id_controller_not_found() {
let app_state = crate::get_app_state().await;
let response = EventsController::get_event_by_id(&app_state, "non-existent-uuid-123456789".to_string()).await;
assert_eq!(response.status(), 404);
}
#[tokio::test]
async fn test_create_event_controller() {
let app_state = crate::get_app_state().await;
let event_request = EventsCreateRequestDto {
name: "Test Event".to_string(),
description: "Test event description".to_string(),
detail_link: Some("https://example.com/event".to_string()),
price: Some(100.0),
is_online: Some(true),
start_date: "2024-01-01T00:00:00Z".to_string(),
end_date: "2024-01-02T00:00:00Z".to_string(),
location: Some("Online".to_string()),
};
let response = EventsController::create_event(&app_state, event_request).await;
assert_eq!(response.status(), 201);
}
#[tokio::test]
async fn test_create_event_controller_invalid_data() {
let app_state = crate::get_app_state().await;
let event_request = EventsCreateRequestDto {
name: "".to_string(),
description: "".to_string(),
detail_link: None,
price: None,
is_online: None,
start_date: "invalid-date".to_string(),
end_date: "2024-01-02T00:00:00Z".to_string(),
location: None,
};
let response = EventsController::create_event(&app_state, event_request).await;
assert_eq!(response.status(), 400);
}
#[tokio::test]
async fn test_update_event_controller_not_found() {
let app_state = crate::get_app_state().await;
let update_request = EventsUpdateRequestDto {
name: Some("Updated Event".to_string()),
description: Some("Updated description".to_string()),
detail_link: Some("https://example.com/updated".to_string()),
price: Some(150.0),
is_online: Some(false),
start_date: Some("2024-02-01T00:00:00Z".to_string()),
end_date: Some("2024-02-02T00:00:00Z".to_string()),
location: Some("Offline".to_string()),
};
let response = EventsController::update_event(&app_state, "non-existent-uuid-123456789".to_string(), update_request).await;
assert_eq!(response.status(), 400);
}
#[tokio::test]
async fn test_delete_event_controller_not_found() {
let app_state = crate::get_app_state().await;
let response = EventsController::delete_event(&app_state, "non-existent-uuid-123456789".to_string()).await;
assert_eq!(response.status(), 400);
}
}
@@ -0,0 +1,78 @@
#[cfg(test)]
mod tests {
use imphnen_cms::{
v1::landing::events::{
events_repository::EventsRepository,
events_schema::EventsSchema,
},
};
use imphnen_utils::make_thing_from_enum;
#[tokio::test]
async fn test_query_event_list() {
let app_state = crate::get_app_state().await;
let repo = EventsRepository::new(&app_state);
let result = repo.query_event_list(crate::get_meta_request_dto(1, 10)).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_query_event_by_id_not_found() {
let app_state = crate::get_app_state().await;
let repo = EventsRepository::new(&app_state);
let result = repo.query_event_by_id("non-existent-uuid-123456789".to_string()).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_query_create_event() {
let app_state = crate::get_app_state().await;
let repo = EventsRepository::new(&app_state);
let event = EventsSchema {
id: make_thing_from_enum("events", &uuid::Uuid::new_v4().to_string()),
name: "Test Event".to_string(),
description: "Test description".to_string(),
detail_link: Some("https://example.com".to_string()),
price: Some(100.0),
is_online: true,
start_date: "2024-01-01T00:00:00Z".to_string(),
end_date: "2024-01-02T00:00:00Z".to_string(),
location: Some("Online".to_string()),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let result = repo.query_create_event(event).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_query_update_event_not_found() {
let app_state = crate::get_app_state().await;
let repo = EventsRepository::new(&app_state);
let event = EventsSchema {
id: make_thing_from_enum("events", &"non-existent-uuid-123456789".to_string()),
name: "Updated Event".to_string(),
description: "Updated description".to_string(),
detail_link: Some("https://example.com/updated".to_string()),
price: Some(150.0),
is_online: false,
start_date: "2024-02-01T00:00:00Z".to_string(),
end_date: "2024-02-02T00:00:00Z".to_string(),
location: Some("Offline".to_string()),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let result = repo.query_update_event(event).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_query_delete_event_not_found() {
let app_state = crate::get_app_state().await;
let repo = EventsRepository::new(&app_state);
let result = repo.query_delete_event("non-existent-uuid-123456789".to_string()).await;
assert!(result.is_err());
}
}
@@ -0,0 +1,82 @@
#[cfg(test)]
mod tests {
use crate::get_meta_request_dto;
use imphnen_cms::{
v1::landing::events::{
events_service::EventsService,
events_dto::{EventsCreateRequestDto, EventsUpdateRequestDto},
},
};
#[tokio::test]
async fn test_get_event_list_service() {
let app_state = crate::get_app_state().await;
let response = EventsService::get_event_list(&app_state, get_meta_request_dto(1, 10)).await;
assert_eq!(response.status(), 200);
}
#[tokio::test]
async fn test_get_event_by_id_service_not_found() {
let app_state = crate::get_app_state().await;
let response = EventsService::get_event_by_id(&app_state, "non-existent-uuid-123456789".to_string()).await;
assert_eq!(response.status(), 404);
}
#[tokio::test]
async fn test_create_event_service() {
let app_state = crate::get_app_state().await;
let event_request = EventsCreateRequestDto {
name: "Test Event".to_string(),
description: "Test event description".to_string(),
detail_link: Some("https://example.com/event".to_string()),
price: Some(100.0),
is_online: Some(true),
start_date: "2024-01-01T00:00:00Z".to_string(),
end_date: "2024-01-02T00:00:00Z".to_string(),
location: Some("Online".to_string()),
};
let response = EventsService::create_event(&app_state, event_request).await;
assert_eq!(response.status(), 201);
}
#[tokio::test]
async fn test_create_event_service_invalid_data() {
let app_state = crate::get_app_state().await;
let event_request = EventsCreateRequestDto {
name: "".to_string(),
description: "".to_string(),
detail_link: None,
price: None,
is_online: None,
start_date: "invalid-date".to_string(),
end_date: "2024-01-02T00:00:00Z".to_string(),
location: None,
};
let response = EventsService::create_event(&app_state, event_request).await;
assert_eq!(response.status(), 400);
}
#[tokio::test]
async fn test_update_event_service_not_found() {
let app_state = crate::get_app_state().await;
let update_request = EventsUpdateRequestDto {
name: Some("Updated Event".to_string()),
description: Some("Updated description".to_string()),
detail_link: Some("https://example.com/updated".to_string()),
price: Some(150.0),
is_online: Some(false),
start_date: Some("2024-02-01T00:00:00Z".to_string()),
end_date: Some("2024-02-02T00:00:00Z".to_string()),
location: Some("Offline".to_string()),
};
let response = EventsService::update_event(&app_state, "non-existent-uuid-123456789".to_string(), update_request).await;
assert_eq!(response.status(), 400);
}
#[tokio::test]
async fn test_delete_event_service_not_found() {
let app_state = crate::get_app_state().await;
let response = EventsService::delete_event(&app_state, "non-existent-uuid-123456789".to_string()).await;
assert_eq!(response.status(), 400);
}
}
@@ -0,0 +1,389 @@
#[cfg(test)]
mod tests {
use crate::{get_meta_request_dto, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_cms::{
v1::landing::testimonials::{
testimonials_controller::TestimonialsController,
testimonials_dto::{TestimonialsCreateRequestDto, TestimonialsUpdateRequestDto},
testimonials_schema::TestimonialsSchema,
},
};
use imphnen_entities::UsersSchema;
use imphnen_utils::make_thing_from_enum;
#[tokio::test]
async fn test_get_testimonial_list_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test testimonials
let testimonial_names = vec![
"testimonial_list_1".to_string(),
"testimonial_list_2".to_string(),
"testimonial_list_3".to_string(),
];
for name in &testimonial_names {
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: format!("Test User {}", name),
email: format!("test{}@example.com", name),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user).await;
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
role: "Mentor".to_string(),
content: format!("Great testimonial content for {}", name),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let _ = repo.query_create_testimonial(testimonial).await;
}
// Get testimonial list through controller
let response = TestimonialsController::get_testimonial_list(&app_state, get_meta_request_dto(1, 10))
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
for name in testimonial_names {
let user = UsersRepository::new(&app_state)
.query_user_by_email(format!("test{}@example.com", name))
.await
.unwrap();
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_get_testimonial_by_id_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test testimonial
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "test@example.com".to_string(),
..Default::default()
};
let create_user_result = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
assert!(create_user_result.is_ok());
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Great testimonial content".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Get testimonial by ID through controller
let response = TestimonialsController::get_testimonial_by_id(&app_state, testimonial_id.clone())
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
let _ = repo.query_delete_testimonial(testimonial_id).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_get_testimonial_by_id_controller_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Get non-existent testimonial by ID through controller
let response = TestimonialsController::get_testimonial_by_id(&app_state, non_existent_id)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_create_testimonial_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let create_user_result = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
assert!(create_user_result.is_ok());
// Test data
let testimonial_request = TestimonialsCreateRequestDto {
role: "Mentor".to_string(),
content: "This is a test testimonial content for controller test".to_string(),
};
// Create testimonial through controller
let response = TestimonialsController::create_testimonial(
&app_state,
testimonial_request.clone(),
&user,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify testimonial was created in database
let created_testimonials = repo.query_testimonial_list(get_meta_request_dto(1, 10)).await.unwrap();
assert!(created_testimonials.data.iter().any(|t| t.content == testimonial_request.content));
// Clean up
let created_testimonial = repo.query_testimonial_list(get_meta_request_dto(1, 10)).await.unwrap();
for t in created_testimonials.data {
if t.content == testimonial_request.content {
let _ = repo.query_delete_testimonial(t.id.id.to_raw()).await;
}
}
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_create_testimonial_controller_invalid_data() {
let app_state = crate::get_app_state().await;
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Test data with empty content (should fail validation)
let testimonial_request = TestimonialsCreateRequestDto {
role: "Mentor".to_string(),
content: "".to_string(), // Empty content should fail validation
};
// Create testimonial through controller
let response = TestimonialsController::create_testimonial(
&app_state,
testimonial_request,
&user,
)
.await;
// Verify bad request response (validation error)
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_update_testimonial_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let original_content = "Original testimonial content for update test".to_string();
let new_content = "Updated testimonial content for update test".to_string();
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: original_content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Prepare update request
let update_request = TestimonialsUpdateRequestDto {
role: Some("Updated Mentor".to_string()),
content: Some(new_content.clone()),
};
// Update testimonial through controller
let response = TestimonialsController::update_testimonial(
&app_state, update_request, testimonial_id.clone(), &user,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify testimonial was updated in database
let updated_testimonial = repo
.query_testimonial_by_id(testimonial_id.clone())
.await
.unwrap();
assert_eq!(updated_testimonial.content, new_content);
assert_eq!(updated_testimonial.role, "Updated Mentor");
// Clean up
let _ = repo.query_delete_testimonial(testimonial_id).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_update_testimonial_controller_not_found() {
let app_state = crate::get_app_state().await;
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Prepare update request
let update_request = TestimonialsUpdateRequestDto {
role: Some("Updated Mentor".to_string()),
content: Some("Updated content".to_string()),
};
// Update non-existent testimonial through controller
let response = TestimonialsController::update_testimonial(
&app_state, update_request, non_existent_id, &user,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_delete_testimonial_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for delete test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Verify testimonial exists before deletion
let exists_before = repo.query_testimonial_by_id(testimonial_id.clone()).await.is_ok();
assert!(exists_before);
// Delete testimonial through controller
let response = TestimonialsController::delete_testimonial(
&app_state, testimonial_id.clone(), &user,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify testimonial was soft-deleted from database
let deleted_testimonial = repo.query_testimonial_by_id(testimonial_id.clone()).await;
assert!(deleted_testimonial.is_err());
// Clean up - no need since it's already soft-deleted
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_delete_testimonial_controller_not_found() {
let app_state = crate::get_app_state().await;
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Delete non-existent testimonial through controller
let response = TestimonialsController::delete_testimonial(
&app_state, non_existent_id, &user,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
}
@@ -0,0 +1,493 @@
#[cfg(test)]
mod tests {
use crate::{get_meta_request_dto, UsersRepository};
use imphnen_cms::{
v1::landing::testimonials::{
testimonials_repository::TestimonialsRepository,
testimonials_schema::TestimonialsSchema,
},
};
use imphnen_entities::UsersSchema;
use imphnen_utils::make_thing_from_enum;
#[tokio::test]
async fn test_query_testimonial_list() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test users and testimonials
let num_testimonials = 5;
let testimonial_contents = vec![
"Testimonial content 1".to_string(),
"Testimonial content 2".to_string(),
"Testimonial content 3".to_string(),
"Testimonial content 4".to_string(),
"Testimonial content 5".to_string(),
];
for (i, content) in testimonial_contents.iter().enumerate() {
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: format!("Test User {}", i + 1),
email: format!("testuser{}@example.com", i + 1),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: format!("Role {}", i + 1),
content: content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let _ = repo.query_create_testimonial(testimonial).await;
}
// Test with pagination
let result = repo.query_testimonial_list(get_meta_request_dto(1, 10)).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.data.len(), num_testimonials as usize);
// Test with smaller page size
let result = repo.query_testimonial_list(get_meta_request_dto(1, 2)).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.data.len(), 2);
// Clean up
for content in testimonial_contents {
let user = UsersRepository::new(&app_state)
.query_user_by_email(format!("testuser{}@example.com", content.chars().take(8).collect::<String>()))
.await
.unwrap();
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_query_testimonial_by_id_found() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial_content = "Test testimonial content for by ID test".to_string();
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: testimonial_content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Query testimonial by ID
let result = repo.query_testimonial_by_id(testimonial_id.clone()).await;
assert!(result.is_ok());
let found_testimonial = result.unwrap();
assert_eq!(found_testimonial.content, testimonial_content);
assert_eq!(found_testimonial.role, "Mentor");
assert!(!found_testimonial.is_deleted);
// Clean up
let _ = repo.query_delete_testimonial(testimonial_id).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_testimonial_by_id_not_found() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Query non-existent testimonial by ID
let result = repo.query_testimonial_by_id(non_existent_id).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Testimonial not found");
}
#[tokio::test]
async fn test_query_testimonial_by_id_deleted() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for deleted test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Soft delete the testimonial
let _ = repo.query_delete_testimonial(testimonial_id.clone()).await;
// Try to query deleted testimonial by ID
let result = repo.query_testimonial_by_id(testimonial_id).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Testimonial not found");
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_create_testimonial() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial data
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for create test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
// Create testimonial
let result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(result.is_ok());
let created_testimonial = result.unwrap();
assert_eq!(created_testimonial.content, testimonial.content);
assert_eq!(created_testimonial.role, testimonial.role);
assert!(!created_testimonial.is_deleted);
// Verify it was created in database
let found_testimonial = repo.query_testimonial_by_id(created_testimonial.id.id.to_raw()).await;
assert!(found_testimonial.is_ok());
assert_eq!(found_testimonial.unwrap().content, testimonial.content);
// Clean up
let _ = repo.query_delete_testimonial(created_testimonial.id.id.to_raw()).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_update_testimonial() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let original_content = "Original testimonial content for update test".to_string();
let new_content = "Updated testimonial content for update test".to_string();
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: original_content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Prepare updated testimonial
let updated_testimonial = TestimonialsSchema {
id: created_testimonial.id,
user: created_testimonial.user,
role: "Updated Mentor".to_string(),
content: new_content.clone(),
created_at: created_testimonial.created_at,
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
// Update testimonial
let result = repo.query_update_testimonial(updated_testimonial).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Success update testimonial");
// Verify it was updated in database
let found_testimonial = repo.query_testimonial_by_id(testimonial_id).await;
assert!(found_testimonial.is_ok());
let updated = found_testimonial.unwrap();
assert_eq!(updated.content, new_content);
assert_eq!(updated.role, "Updated Mentor");
assert!(!updated.is_deleted);
// Clean up
let _ = repo.query_delete_testimonial(testimonial_id).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_update_testimonial_not_found() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create non-existent testimonial ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Prepare updated testimonial with non-existent ID
let updated_testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &non_existent_id),
user: user.id,
role: "Updated Mentor".to_string(),
content: "Updated content".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
// Try to update non-existent testimonial
let result = repo.query_update_testimonial(updated_testimonial).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Testimonial not found");
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_update_testimonial_deleted() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for deleted update test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Soft delete the testimonial
let _ = repo.query_delete_testimonial(testimonial_id.clone()).await;
// Prepare updated testimonial
let updated_testimonial = TestimonialsSchema {
id: created_testimonial.id,
user: created_testimonial.user,
role: "Updated Mentor".to_string(),
content: "Updated content".to_string(),
created_at: created_testimonial.created_at,
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
// Try to update deleted testimonial
let result = repo.query_update_testimonial(updated_testimonial).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Testimonial already deleted");
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_delete_testimonial() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for delete test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Verify testimonial exists before deletion
let exists_before = repo.query_testimonial_by_id(testimonial_id.clone()).await.is_ok();
assert!(exists_before);
// Delete testimonial
let result = repo.query_delete_testimonial(testimonial_id.clone()).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Success delete testimonial");
// Verify testimonial was soft-deleted from database
let deleted_testimonial = repo.query_testimonial_by_id(testimonial_id.clone()).await;
assert!(deleted_testimonial.is_err());
assert_eq!(deleted_testimonial.unwrap_err().to_string(), "Testimonial not found");
// Clean up - no need since it's already soft-deleted
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_delete_testimonial_not_found() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Try to delete non-existent testimonial
let result = repo.query_delete_testimonial(non_existent_id).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Testimonial not found");
}
#[tokio::test]
async fn test_query_delete_testimonial_already_deleted() {
let app_state = crate::get_app_state().await;
let repo = TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for already deleted test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Soft delete the testimonial twice
let _ = repo.query_delete_testimonial(testimonial_id.clone()).await;
let result = repo.query_delete_testimonial(testimonial_id).await;
// Verify second deletion fails
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Testimonial not found");
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
}
@@ -0,0 +1,544 @@
#[cfg(test)]
mod tests {
use crate::{get_meta_request_dto, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_cms::{
v1::landing::testimonials::{
testimonials_dto::{TestimonialsCreateRequestDto, TestimonialsUpdateRequestDto},
testimonials_service::TestimonialsService,
testimonials_schema::TestimonialsSchema,
},
};
use imphnen_entities::UsersSchema;
use imphnen_utils::make_thing_from_enum;
#[tokio::test]
async fn test_get_testimonial_list_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test testimonials
let testimonial_contents = vec![
"Testimonial content 1".to_string(),
"Testimonial content 2".to_string(),
"Testimonial content 3".to_string(),
];
for content in &testimonial_contents {
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: format!("Test User for {}", content),
email: format!("testuser{}@example.com", content.chars().take(5).collect::<String>()),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let _ = repo.query_create_testimonial(testimonial).await;
}
// Get testimonial list through service
let response = TestimonialsService::get_testimonial_list(&app_state, get_meta_request_dto(1, 10))
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
for content in testimonial_contents {
let user = UsersRepository::new(&app_state)
.query_user_by_email(format!("testuser{}@example.com", content.chars().take(5).collect::<String>()))
.await
.unwrap();
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_get_testimonial_by_id_service_found() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial_content = "Test testimonial content for get by ID service test".to_string();
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: testimonial_content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Get testimonial by ID through service
let response = TestimonialsService::get_testimonial_by_id(&app_state, testimonial_id.clone())
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify response body contains correct data
let body_bytes = response.into_body().collect().await.unwrap().to_bytes();
let response_body: serde_json::Value = serde_json::from_slice(&body_bytes).unwrap();
assert_eq!(response_body["data"]["content"].as_str().unwrap(), testimonial_content);
// Clean up
let _ = repo.query_delete_testimonial(testimonial_id).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_get_testimonial_by_id_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Get non-existent testimonial by ID through service
let response = TestimonialsService::get_testimonial_by_id(&app_state, non_existent_id)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_get_testimonial_by_id_service_deleted() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test User".to_string(),
email: "testuser@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for deleted test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Soft delete the testimonial
let _ = repo.query_delete_testimonial(testimonial_id.clone()).await;
// Try to get deleted testimonial through service
let response = TestimonialsService::get_testimonial_by_id(&app_state, testimonial_id)
.await;
// Verify not found response (service should filter out deleted items)
assert_eq!(response.status(), StatusCode::NOT_FOUND);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_create_testimonial_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Test data
let testimonial_request = TestimonialsCreateRequestDto {
role: "Mentor".to_string(),
content: "Test testimonial content for service create test".to_string(),
};
// Create testimonial through service
let response = TestimonialsService::create_testimonial(
&app_state, testimonial_request.clone(), &user,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify testimonial was created in database
let created_testimonials = repo.query_testimonial_list(get_meta_request_dto(1, 10)).await.unwrap();
assert!(created_testimonials.data.iter().any(|t| t.content == testimonial_request.content));
// Clean up
let created_testimonial = repo.query_testimonial_list(get_meta_request_dto(1, 10)).await.unwrap();
for t in created_testimonials.data {
if t.content == testimonial_request.content {
let _ = repo.query_delete_testimonial(t.id.id.to_raw()).await;
}
}
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_create_testimonial_service_invalid_data() {
let app_state = crate::get_app_state().await;
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Test data with empty content (should fail validation)
let testimonial_request = TestimonialsCreateRequestDto {
role: "Mentor".to_string(),
content: "".to_string(), // Empty content should fail validation
};
// Create testimonial through service
let response = TestimonialsService::create_testimonial(
&app_state, testimonial_request, &user,
)
.await;
// Verify bad request response (validation error)
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_update_testimonial_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let original_content = "Original testimonial content for service update test".to_string();
let new_content = "Updated testimonial content for service update test".to_string();
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: original_content.clone(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Prepare update request
let update_request = TestimonialsUpdateRequestDto {
role: Some("Updated Mentor".to_string()),
content: Some(new_content.clone()),
};
// Update testimonial through service
let response = TestimonialsService::update_testimonial(
&app_state, update_request, testimonial_id.clone(), &user,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify testimonial was updated in database
let updated_testimonial = repo
.query_testimonial_by_id(testimonial_id.clone())
.await
.unwrap();
assert_eq!(updated_testimonial.content, new_content);
assert_eq!(updated_testimonial.role, "Updated Mentor");
// Clean up
let _ = repo.query_delete_testimonial(testimonial_id).await;
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_update_testimonial_service_not_found() {
let app_state = crate::get_app_state().await;
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Prepare update request
let update_request = TestimonialsUpdateRequestDto {
role: Some("Updated Mentor".to_string()),
content: Some("Updated content".to_string()),
};
// Update non-existent testimonial through service
let response = TestimonialsService::update_testimonial(
&app_state, update_request, non_existent_id, &user,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_update_testimonial_service_deleted() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for deleted update test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Soft delete the testimonial
let _ = repo.query_delete_testimonial(testimonial_id.clone()).await;
// Prepare update request
let update_request = TestimonialsUpdateRequestDto {
role: Some("Updated Mentor".to_string()),
content: Some("Updated content".to_string()),
};
// Try to update deleted testimonial through service
let response = TestimonialsService::update_testimonial(
&app_state, update_request, testimonial_id, &user,
)
.await;
// Verify bad request response (should fail because it's deleted)
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_delete_testimonial_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for service delete test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Verify testimonial exists before deletion
let exists_before = repo.query_testimonial_by_id(testimonial_id.clone()).await.is_ok();
assert!(exists_before);
// Delete testimonial through service
let response = TestimonialsService::delete_testimonial(
&app_state, testimonial_id.clone(), &user,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify testimonial was soft-deleted from database
let deleted_testimonial = repo.query_testimonial_by_id(testimonial_id.clone()).await;
assert!(deleted_testimonial.is_err());
// Clean up - no need since it's already soft-deleted
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_delete_testimonial_service_not_found() {
let app_state = crate::get_app_state().await;
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Delete non-existent testimonial through service
let response = TestimonialsService::delete_testimonial(
&app_state, non_existent_id, &user,
)
.await;
// Verify bad request response
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_delete_testimonial_service_deleted_twice() {
let app_state = crate::get_app_state().await;
let repo = imphnen_cms::v1::landing::testimonials::testimonials_repository::TestimonialsRepository::new(&app_state);
// Create test user for authentication
let user = UsersSchema {
id: make_thing_from_enum("users", &uuid::Uuid::new_v4().to_string()),
fullname: "Test Admin".to_string(),
email: "admin@example.com".to_string(),
..Default::default()
};
let _ = UsersRepository::new(&app_state).query_create_user(user.clone()).await;
// Create test testimonial
let testimonial = TestimonialsSchema {
id: make_thing_from_enum("testimonials", &uuid::Uuid::new_v4().to_string()),
user: user.id,
role: "Mentor".to_string(),
content: "Test testimonial content for double delete test".to_string(),
created_at: chrono::Utc::now().to_rfc3339(),
updated_at: chrono::Utc::now().to_rfc3339(),
is_deleted: false,
};
let create_result = repo.query_create_testimonial(testimonial.clone()).await;
assert!(create_result.is_ok());
// Get created testimonial to get ID
let created_testimonial = repo
.query_testimonial_by_id(testimonial.id.id.to_raw())
.await
.unwrap();
let testimonial_id = created_testimonial.id.id.to_raw();
// Delete testimonial once
let _ = repo.query_delete_testimonial(testimonial_id.clone()).await;
// Try to delete again through service
let response = TestimonialsService::delete_testimonial(
&app_state, testimonial_id, &user,
)
.await;
// Verify bad request response (should fail because it's already deleted)
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// Clean up
let _ = UsersRepository::new(&app_state).query_delete_user(user.id.id.to_raw()).await;
}
}
@@ -0,0 +1,816 @@
use axum::{
body::Body,
http::{HeaderMap, Method, Request, StatusCode},
response::Response,
routing::{get, post, put, delete},
Router,
};
use http_body_util::BodyExt;
use imphnen_dimentorin::{
mentors_controller,
mentors_dto::{
MentorUpdateRequestDto, MentorUserRegisterRequestDto, MentorVerifyRequestDto,
MentorRegisterResponseDto,
},
};
use imphnen_entities::{AppState, ResponseSuccessDto};
use imphnen_iam::{PermissionsEnum, RolesEnum, UsersRepository};
use imphnen_libs::{ResourceEnum, surrealdb_init_ws, surrealdb_init_mem, Env};
use imphnen_utils::{generate_otp, hash_password, make_thing, get_iso_date};
use serde_json::json;
use surrealdb::{Uuid, sql::Thing};
use dotenvy::dotenv;
use tower::ServiceExt;
use crate::{generate_unique_email, get_role_id, setup_all_test_environment};
// Helper function to create a test application (router) with all mentor endpoints
fn app(app_state: AppState) -> Router {
Router::new()
.route("/v1/mentors/register", post(mentors_controller::post_register_mentor))
.route("/v1/mentors", get(mentors_controller::get_mentor_list))
.route("/v1/mentors/detail/:id", get(mentors_controller::get_mentor_by_id))
.route("/v1/mentors/update/:id", put(mentors_controller::put_update_mentor))
.route("/v1/mentors/delete/:id", delete(mentors_controller::delete_mentor))
.route("/v1/mentors/verify/:id", put(mentors_controller::put_verify_mentor))
.route("/v1/mentors/me", get(mentors_controller::get_mentor_me))
.route("/v1/mentors/update/me", put(mentors_controller::put_update_mentor_me))
.route("/v1/mentors/update", put(mentors_controller::put_update_mentor_no_id))
.route("/v1/mentors/status", get(mentors_controller::get_mentor_status))
.with_state(app_state)
}
// Helper function to create a valid mentor registration DTO
fn create_valid_mentor_dto(email: &str) -> MentorUserRegisterRequestDto {
MentorUserRegisterRequestDto {
email: email.to_string(),
password: "Password123!".to_string(),
fullname: "Test Mentor".to_string(),
phone_number: "1234567890".to_string(),
identity_and_verification: imphnen_dimentorin::mentors_dto::IdentityAndVerification {
legal_name: "Legal Test Name".to_string(),
gender: Some("Laki-laki".to_string()),
domicile: Some("Jakarta Selatan".to_string()),
identity_document_url: "http://example.com/id.pdf".to_string(),
phone_for_verification: "0987654321".to_string(),
},
professional_profile: imphnen_dimentorin::mentors_dto::ProfessionalProfile {
bio: "Experienced professional with 5+ years of experience in software development.".to_string(),
last_education: Some("S1".to_string()),
linkedin_url: Some("http://linkedin.com/in/test".to_string()),
github_url: None,
cv_url: None,
portfolio_url: Some("http://example.com/portfolio".to_string()),
industries: vec!["Technology".to_string()],
expertise: vec!["Rust".to_string(), "Backend Development".to_string()],
languages: vec!["English".to_string()],
current_company: "Tech Corp".to_string(),
current_role: "Senior Engineer".to_string(),
years_of_experience: 5,
},
mentoring_logistics: imphnen_dimentorin::mentors_dto::MentoringLogistics {
topics_of_interest: vec!["Career Development".to_string()],
preferred_mentee_level: vec!["Beginner".to_string()],
preferred_mentoring_formats: vec!["Online".to_string()],
availability_commitment: "5 hours/week".to_string(),
mentoring_rate_amount: 100,
},
}
}
// Helper function to create a valid mentor update DTO
fn create_valid_mentor_update_dto() -> MentorUpdateRequestDto {
MentorUpdateRequestDto {
legal_name: Some("Updated Legal Name".to_string()),
gender: Some("Perempuan".to_string()),
domicile: Some("Bandung".to_string()),
phone_for_verification: Some("0876543210".to_string()),
bio: Some("Updated bio with more experience.".to_string()),
last_education: Some("S2".to_string()),
linkedin_url: Some("http://linkedin.com/in/updated".to_string()),
github_url: Some("http://github.com/updated".to_string()),
cv_url: Some("http://example.com/updated_cv.pdf".to_string()),
portfolio_url: Some("http://example.com/updated_portfolio".to_string()),
industries: Some(vec!["Technology".to_string(), "Education".to_string()]),
expertise: Some(vec!["Rust".to_string(), "AI".to_string()]),
languages: Some(vec!["English".to_string(), "Spanish".to_string()]),
current_company: Some("New Tech Corp".to_string()),
current_role: Some("Lead Engineer".to_string()),
years_of_experience: Some(7),
topics_of_interest: Some(vec!["Career Development".to_string(), "Tech Trends".to_string()]),
preferred_mentee_level: Some(vec!["Beginner".to_string(), "Intermediate".to_string()]),
preferred_mentoring_formats: Some(vec!["Online".to_string(), "Offline".to_string()]),
availability_commitment: Some("10 hours/week".to_string()),
mentoring_rate_amount: Some(200),
}
}
// Helper function to create authentication headers with mock JWT
fn create_auth_headers(user_email: &str, permissions: Vec<PermissionsEnum>) -> HeaderMap {
let mut headers = HeaderMap::new();
headers.insert("Authorization", format!("Bearer mock_jwt_{}", user_email).parse().unwrap());
headers
}
#[tokio::test]
async fn test_post_register_mentor_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
let test_email = "register_mentor_success@example.com";
let dto = create_valid_mentor_dto(test_email);
let response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let mentor_register_response: MentorRegisterResponseDto = serde_json::from_slice(&body).unwrap();
assert!(!mentor_register_response.id.is_empty());
assert!(!mentor_register_response.user_id.is_empty());
assert_eq!(mentor_register_response.status, "pending".to_string());
// Verify user was created in database
let user_repo = UsersRepository::new(&app_state);
let user = user_repo.query_user_by_email(test_email.to_string()).await.unwrap();
assert_eq!(user.email, test_email);
assert_eq!(user.is_active, false); // Should be inactive until OTP verification
// Clean up
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_post_register_mentor_invalid_email() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
let test_email = "invalid-email";
let mut dto = create_valid_mentor_dto(test_email);
dto.email = test_email.to_string();
let response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.into_body().collect().await.unwrap().to_bytes();
let error_response: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert!(error_response["message"].as_str().unwrap().contains("email"));
}
#[tokio::test]
async fn test_post_register_mentor_weak_password() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
let test_email = "weak_password@example.com";
let mut dto = create_valid_mentor_dto(test_email);
dto.password = "weak".to_string();
let response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.into_body().collect().await.unwrap().to_bytes();
let error_response: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert!(error_response["message"].as_str().unwrap().contains("password"));
}
#[tokio::test]
async fn test_get_mentor_list_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "list_mentor_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
// Get mentor list with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::ReadListMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/v1/mentors")
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let response_data: ResponseSuccessDto<Vec<imphnen_dimentorin::mentors_dto::MentorListResponseDto>> =
serde_json::from_slice(&body).unwrap();
assert!(!response_data.data.is_empty());
assert_eq!(response_data.data[0].status, "pending".to_string());
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_get_mentor_list_unauthorized() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Try to get mentor list without authentication
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/v1/mentors")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}
#[tokio::test]
async fn test_get_mentor_by_id_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "get_by_id_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
let register_body: MentorRegisterResponseDto = serde_json::from_slice(&register_response.into_body().collect().await.unwrap().to_bytes()).unwrap();
let mentor_id = register_body.id.clone();
// Get mentor by ID with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::ReadDetailMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri(&format!("/v1/mentors/detail/{}", mentor_id))
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let mentor_response: ResponseSuccessDto<imphnen_dimentorin::mentors_dto::MentorDetailResponseDto> =
serde_json::from_slice(&body).unwrap();
assert_eq!(mentor_response.data.id, mentor_id);
assert_eq!(mentor_response.data.status, "pending".to_string());
assert_eq!(mentor_response.data.fullname, Some("Test Mentor".to_string()));
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_get_mentor_by_id_not_found() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Try to get non-existent mentor with authentication
let headers = create_auth_headers("nonexistent@example.com", vec![PermissionsEnum::ReadDetailMentors]);
let non_existent_id = Uuid::new_v4().to_string();
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri(&format!("/v1/mentors/detail/{}", non_existent_id))
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_put_update_mentor_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "update_mentor_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
let register_body: MentorRegisterResponseDto = serde_json::from_slice(&register_response.into_body().collect().await.unwrap().to_bytes()).unwrap();
let mentor_id = register_body.id.clone();
// Prepare update DTO
let update_dto = create_valid_mentor_update_dto();
// Update mentor with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::UpdateMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::PUT)
.uri(&format!("/v1/mentors/update/{}", mentor_id))
.headers(headers)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&update_dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let mentor_response: ResponseSuccessDto<imphnen_dimentorin::mentors_dto::MentorDetailResponseDto> =
serde_json::from_slice(&body).unwrap();
assert_eq!(mentor_response.data.id, mentor_id);
assert_eq!(mentor_response.data.legal_name, Some("Updated Legal Name".to_string()));
assert_eq!(mentor_response.data.current_role, "Lead Engineer".to_string());
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_put_update_mentor_not_found() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Try to update non-existent mentor with authentication
let headers = create_auth_headers("nonexistent@example.com", vec![PermissionsEnum::UpdateMentors]);
let non_existent_id = Uuid::new_v4().to_string();
let update_dto = create_valid_mentor_update_dto();
let response = app
.oneshot(
Request::builder()
.method(Method::PUT)
.uri(&format!("/v1/mentors/update/{}", non_existent_id))
.headers(headers)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&update_dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_delete_mentor_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "delete_mentor_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
let register_body: MentorRegisterResponseDto = serde_json::from_slice(&register_response.into_body().collect().await.unwrap().to_bytes()).unwrap();
let mentor_id = register_body.id.clone();
// Delete mentor with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::DeleteMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::DELETE)
.uri(&format!("/v1/mentors/delete/{}", mentor_id))
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
// Verify mentor was soft-deleted
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_delete_mentor_not_found() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Try to delete non-existent mentor with authentication
let headers = create_auth_headers("nonexistent@example.com", vec![PermissionsEnum::DeleteMentors]);
let non_existent_id = Uuid::new_v4().to_string();
let response = app
.oneshot(
Request::builder()
.method(Method::DELETE)
.uri(&format!("/v1/mentors/delete/{}", non_existent_id))
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_put_verify_mentor_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "verify_mentor_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
let register_body: MentorRegisterResponseDto = serde_json::from_slice(&register_response.into_body().collect().await.unwrap().to_bytes()).unwrap();
let mentor_id = register_body.id.clone();
// Prepare verification DTO
let verify_dto = MentorVerifyRequestDto {
status: "verified".to_string(),
};
// Verify mentor with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::VerifyMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::PUT)
.uri(&format!("/v1/mentors/verify/{}", mentor_id))
.headers(headers)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&verify_dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let mentor_response: ResponseSuccessDto<imphnen_dimentorin::mentors_dto::MentorDetailResponseDto> =
serde_json::from_slice(&body).unwrap();
assert_eq!(mentor_response.data.id, mentor_id);
assert_eq!(mentor_response.data.status, "verified".to_string());
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_get_mentor_me_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "mentor_me_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
// Get mentor me with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::ReadOwnMentorProfile]);
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/v1/mentors/me")
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let mentor_response: ResponseSuccessDto<imphnen_dimentorin::mentors_dto::MentorDetailResponseDto> =
serde_json::from_slice(&body).unwrap();
assert_eq!(mentor_response.data.email, Some(test_email.to_string()));
assert_eq!(mentor_response.data.status, "pending".to_string());
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_put_update_mentor_me_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "update_mentor_me_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
// Prepare update DTO
let update_dto = create_valid_mentor_update_dto();
// Update mentor me with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::UpdateOwnMentorProfile]);
let response = app
.oneshot(
Request::builder()
.method(Method::PUT)
.uri("/v1/mentors/update/me")
.headers(headers)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&update_dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let mentor_response: ResponseSuccessDto<imphnen_dimentorin::mentors_dto::MentorDetailResponseDto> =
serde_json::from_slice(&body).unwrap();
assert_eq!(mentor_response.data.legal_name, Some("Updated Legal Name".to_string()));
assert_eq!(mentor_response.data.current_role, "Lead Engineer".to_string());
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_put_update_mentor_no_id() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Try to update mentor without ID (should return 400)
let headers = create_auth_headers("test@example.com", vec![PermissionsEnum::UpdateMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::PUT)
.uri("/v1/mentors/update")
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.into_body().collect().await.unwrap().to_bytes();
let error_response: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert_eq!(error_response["message"], "Mentor ID is required for update");
}
#[tokio::test]
async fn test_get_mentor_status_success() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Create a test mentor first
let test_email = "mentor_status_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
// Get mentor status with authentication
let headers = create_auth_headers(test_email, vec![PermissionsEnum::ReadOwnMentorStatus]);
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/v1/mentors/status")
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let status_response: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert_eq!(status_response, "pending");
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_controller_endpoints_validation() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Test update mentor with invalid data (empty legal name)
let test_email = "validation_test@example.com";
let dto = create_valid_mentor_dto(test_email);
let register_response = app
.oneshot(
Request::builder()
.method(Method::POST)
.uri("/v1/mentors/register")
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(register_response.status(), StatusCode::OK);
let register_body: MentorRegisterResponseDto = serde_json::from_slice(&register_response.into_body().collect().await.unwrap().to_bytes()).unwrap();
let mentor_id = register_body.id.clone();
// Prepare invalid update DTO (empty legal name)
let mut invalid_update_dto = create_valid_mentor_update_dto();
invalid_update_dto.legal_name = Some("".to_string()); // Invalid - too short
// Try to update with invalid data
let headers = create_auth_headers(test_email, vec![PermissionsEnum::UpdateMentors]);
let response = app
.oneshot(
Request::builder()
.method(Method::PUT)
.uri(&format!("/v1/mentors/update/{}", mentor_id))
.headers(headers)
.header("Content-Type", "application/json")
.body(Body::from(serde_json::to_string(&invalid_update_dto).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.into_body().collect().await.unwrap().to_bytes();
let error_response: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert!(error_response["message"].as_str().unwrap().contains("Legal name must be at least 3 characters"));
// Clean up
let user_repo = UsersRepository::new(&app_state);
let _ = user_repo.query_delete_user(test_email.to_string()).await;
}
#[tokio::test]
async fn test_controller_permission_denied() {
let app_state = setup_all_test_environment().await;
let app = app(app_state.clone());
// Try to access protected endpoint without proper permissions
let headers = create_auth_headers("test@example.com", vec![]); // Empty permissions
let response = app
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/v1/mentors")
.headers(headers)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::FORBIDDEN);
}
@@ -0,0 +1,38 @@
use axum_test::TestServer;
use imphnen_gacha::v1::gacha_claims::gacha_claims_controller::{self, GachaClaimsService};
use imphnen_gacha::v1::gacha_claims::gacha_claims_dto::{CreateGachaClaimDto, GachaClaimResponse};
use mockall::mock;
use tower::ServiceBuilder;
use tower::timeout::TimeoutLayer;
use std::time::Duration;
mock! {
pub GachaClaimsServiceMock {}
#[async_trait]
impl GachaClaimsService for GachaClaimsServiceMock {
async fn create_claim(&self, user_id: &str, item_id: &str) -> Result<GachaClaimResponse, String>;
async fn get_claim(&self, claim_id: &str) -> Result<GachaClaimResponse, String>;
async fn get_user_claims(&self, user_id: &str) -> Result<Vec<GachaClaimResponse>, String>;
async fn update_claim(&self, claim_id: &str, status: &str) -> Result<GachaClaimResponse, String>;
async fn delete_claim(&self, claim_id: &str) -> Result<(), String>;
}
}
#[tokio::test]
async fn test_create_claim_happy_path() {
let mock_service = MockGachaClaimsServiceMock::new();
let create_dto = CreateGachaClaimDto { user_id: "user123".to_string(), item_id: "item456".to_string() };
let expected = GachaClaimResponse { id: "claim789".to_string(), user_id: "user123".to_string(), item_id: "item456".to_string(), status: "pending".to_string(), created_at: "2024-01-01T00:00:00Z".to_string() };
mock_service.expect_create_claim().withf(|u, i| u == &create_dto.user_id && i == &create_dto.item_id).returning(|_, _| Ok(expected.clone()));
let app = ServiceBuilder::new().layer(TimeoutLayer::new(Duration::from_secs(10))).service(gacha_claims_controller::router(mock_service));
let server = TestServer::new(app).unwrap();
let response = server.post("/gacha/claims").json(&create_dto).await;
assert_eq!(response.status(), 201);
let body: GachaClaimResponse = response.json().await.unwrap();
assert_eq!(body.id, expected.id);
}
// Additional tests for error cases, get, update, delete...
@@ -0,0 +1,68 @@
use imphnen_gacha::v1::gacha_claims::gacha_claims_repository::{self, GachaClaimsRepository};
use imphnen_gacha::v1::gacha_claims::gacha_claims_dto::{CreateGachaClaimDto, GachaClaimResponse};
use surrealdb::engine::local::Mem;
use surrealdb::Surreal;
use surrealdb::opt::auth::Root;
use std::sync::Arc;
#[tokio::test]
async fn test_claims_repository_crud_operations() {
// Setup in-memory SurrealDB for testing
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_claims_repository::GachaClaimsRepository::new(Arc::new(db));
let create_dto = CreateGachaClaimDto { user_id: "user123".to_string(), item_id: "item456".to_string() };
// Test create
let created = repo.create(&create_dto).await.unwrap();
assert!(!created.id.is_empty());
assert_eq!(created.user_id, "user123");
assert_eq!(created.item_id, "item456");
// Test find by id
let found = repo.find_by_id(&created.id).await.unwrap().unwrap();
assert_eq!(found.id, created.id);
// Test find by user
let user_claims = repo.find_by_user("user123").await.unwrap();
assert_eq!(user_claims.len(), 1);
assert_eq!(user_claims[0].id, created.id);
// Test update
let updated = repo.update(&created.id, "approved").await.unwrap();
assert_eq!(updated.status, "approved");
// Test delete
let delete_result = repo.delete(&created.id).await;
assert!(delete_result.is_ok());
// Verify deletion
let deleted = repo.find_by_id(&created.id).await.unwrap();
assert!(deleted.is_none());
}
#[tokio::test]
async fn test_claims_repository_error_cases() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_claims_repository::GachaClaimsRepository::new(Arc::new(db));
// Test find by non-existent id
let result = repo.find_by_id("non_existent_id").await;
assert!(result.is_ok());
assert!(result.unwrap().is_none());
// Test update non-existent claim
let result = repo.update("non_existent_id", "approved").await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Claim not found");
// Test delete non-existent claim
let result = repo.delete("non_existent_id").await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Claim not found");
}
@@ -0,0 +1,48 @@
use imphnen_gacha::v1::gacha_claims::gacha_claims_service::{self, GachaClaimsRepository};
use imphnen_gacha::v1::gacha_claims::gacha_claims_dto::{CreateGachaClaimDto, GachaClaimResponse};
use mockall::mock;
use std::sync::Arc;
mock! {
pub GachaClaimsRepositoryMock {}
#[async_trait]
impl GachaClaimsRepository for GachaClaimsRepositoryMock {
async fn create(&self, claim: &CreateGachaClaimDto) -> Result<GachaClaimResponse, String>;
async fn find_by_id(&self, claim_id: &str) -> Result<Option<GachaClaimResponse>, String>;
async fn find_by_user(&self, user_id: &str) -> Result<Vec<GachaClaimResponse>, String>;
async fn update(&self, claim_id: &str, status: &str) -> Result<GachaClaimResponse, String>;
async fn delete(&self, claim_id: &str) -> Result<(), String>;
}
}
#[tokio::test]
async fn test_create_claim_happy_path() {
let mock_repo = MockGachaClaimsRepositoryMock::new();
let service = gacha_claims_service::GachaClaimsService::new(Arc::new(mock_repo));
let create_dto = CreateGachaClaimDto { user_id: "user123".to_string(), item_id: "item456".to_string() };
let expected = GachaClaimResponse { id: "claim789".to_string(), user_id: "user123".to_string(), item_id: "item456".to_string(), status: "pending".to_string(), created_at: "2024-01-01T00:00:00Z".to_string() };
mock_repo.expect_create().withf(|c| c.user_id == create_dto.user_id && c.item_id == create_dto.item_id).returning(|_| Ok(expected.clone()));
let result = service.create_claim(&create_dto).await;
assert!(result.is_ok());
assert_eq!(result.unwrap().id, expected.id);
}
#[tokio::test]
async fn test_create_claim_error_case() {
let mock_repo = MockGachaClaimsRepositoryMock::new();
let service = gacha_claims_service::GachaClaimsService::new(Arc::new(mock_repo));
let create_dto = CreateGachaClaimDto { user_id: "user123".to_string(), item_id: "invalid_item".to_string() };
let error_msg = "Item not found";
mock_repo.expect_create().withf(|c| c.item_id == "invalid_item").returning(|_| Err(error_msg.to_string()));
let result = service.create_claim(&create_dto).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), error_msg);
}
// Additional tests for get, update, delete operations...
@@ -0,0 +1,99 @@
use imphnen_gacha::v1::gacha_credits::gacha_credits_repository::{self, GachaCreditsRepository};
use surrealdb::engine::local::Mem;
use surrealdb::Surreal;
use surrealdb::opt::auth::Root;
use std::sync::Arc;
#[tokio::test]
async fn test_credits_repository_crud_operations() {
// Setup in-memory SurrealDB for testing
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_credits_repository::GachaCreditsRepository::new(Arc::new(db));
// Test initial balance (should be 0 for new user)
let initial_balance = repo.get_balance("user123").await.unwrap();
assert_eq!(initial_balance, 0);
// Test add credits
let add_result = repo.add_credits("user123", 100).await;
assert!(add_result.is_ok());
// Verify balance after add
let balance_after_add = repo.get_balance("user123").await.unwrap();
assert_eq!(balance_after_add, 100);
// Test deduct credits
let deduct_result = repo.deduct_credits("user123", 30).await;
assert!(deduct_result.is_ok());
// Verify balance after deduct
let balance_after_deduct = repo.get_balance("user123").await.unwrap();
assert_eq!(balance_after_deduct, 70);
// Test add multiple times
repo.add_credits("user123", 50).await.unwrap();
let final_balance = repo.get_balance("user123").await.unwrap();
assert_eq!(final_balance, 120);
}
#[tokio::test]
async fn test_credits_repository_error_cases() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_credits_repository::GachaCreditsRepository::new(Arc::new(db));
// Test deduct more than available
let deduct_result = repo.deduct_credits("user123", 50).await;
assert!(deduct_result.is_err());
assert_eq!(deduct_result.unwrap_err(), "Insufficient credits");
// Test add negative amount (should be invalid)
let add_negative_result = repo.add_credits("user123", -10).await;
assert!(add_negative_result.is_err());
assert_eq!(add_negative_result.unwrap_err(), "Cannot add negative credits");
// Test deduct negative amount (should be invalid)
let deduct_negative_result = repo.deduct_credits("user123", -5).await;
assert!(deduct_negative_result.is_err());
assert_eq!(deduct_negative_result.unwrap_err(), "Cannot deduct negative credits");
}
#[tokio::test]
async fn test_credits_repository_edge_cases() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_credits_repository::GachaCreditsRepository::new(Arc::new(db));
// Test add zero credits
let add_zero_result = repo.add_credits("user123", 0).await;
assert!(add_zero_result.is_ok());
// Balance should still be 0
let balance = repo.get_balance("user123").await.unwrap();
assert_eq!(balance, 0);
// Test deduct zero credits
let deduct_zero_result = repo.deduct_credits("user123", 0).await;
assert!(deduct_zero_result.is_ok());
// Balance should still be 0
let balance_after = repo.get_balance("user123").await.unwrap();
assert_eq!(balance_after, 0);
// Test multiple users
repo.add_credits("user456", 200).await.unwrap();
repo.add_credits("user789", 150).await.unwrap();
let user456_balance = repo.get_balance("user456").await.unwrap();
let user789_balance = repo.get_balance("user789").await.unwrap();
assert_eq!(user456_balance, 200);
assert_eq!(user789_balance, 150);
}
@@ -0,0 +1,59 @@
use axum_test::TestServer;
use imphnen_gacha::v1::gacha_items::gacha_items_controller::{self, GachaItemsService};
use imphnen_gacha::v1::gacha_items::gacha_items_dto::{CreateGachaItemDto, GachaItemResponse};
use mockall::mock;
use tower::ServiceBuilder;
use tower::timeout::TimeoutLayer;
use std::time::Duration;
mock! {
pub GachaItemsServiceMock {}
#[async_trait]
impl GachaItemsService for GachaItemsServiceMock {
async fn create_item(&self, item: &CreateGachaItemDto) -> Result<GachaItemResponse, String>;
async fn get_item(&self, item_id: &str) -> Result<GachaItemResponse, String>;
async fn get_all_items(&self) -> Result<Vec<GachaItemResponse>, String>;
async fn update_item(&self, item_id: &str, item: &CreateGachaItemDto) -> Result<GachaItemResponse, String>;
async fn delete_item(&self, item_id: &str) -> Result<(), String>;
}
}
#[tokio::test]
async fn test_create_item_happy_path() {
let mock_service = MockGachaItemsServiceMock::new();
let create_dto = CreateGachaItemDto { name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100 };
let expected = GachaItemResponse { id: "item123".to_string(), name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100, created_at: "2024-01-01T00:00:00Z".to_string() };
mock_service.expect_create_item().withf(|i| i.name == create_dto.name && i.rarity == create_dto.rarity).returning(|_| Ok(expected.clone()));
let app = ServiceBuilder::new().layer(TimeoutLayer::new(Duration::from_secs(10))).service(gacha_items_controller::router(mock_service));
let server = TestServer::new(app).unwrap();
let response = server.post("/gacha/items").json(&create_dto).await;
assert_eq!(response.status(), 201);
let body: GachaItemResponse = response.json().await.unwrap();
assert_eq!(body.id, expected.id);
}
#[tokio::test]
async fn test_get_all_items_happy_path() {
let mock_service = MockGachaItemsServiceMock::new();
let expected_items = vec![
GachaItemResponse { id: "item123".to_string(), name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100, created_at: "2024-01-01T00:00:00Z".to_string() },
GachaItemResponse { id: "item456".to_string(), name: "Shield".to_string(), rarity: "common".to_string(), image_url: "https://example.com/shield.png".to_string(), value: 50, created_at: "2024-01-01T00:00:00Z".to_string() }
];
mock_service.expect_get_all_items().returning(|| Ok(expected_items.clone()));
let app = ServiceBuilder::new().layer(TimeoutLayer::new(Duration::from_secs(10))).service(gacha_items_controller::router(mock_service));
let server = TestServer::new(app).unwrap();
let response = server.get("/gacha/items").await;
assert_eq!(response.status(), 200);
let body: Vec<GachaItemResponse> = response.json().await.unwrap();
assert_eq!(body.len(), 2);
assert_eq!(body[0].id, "item123");
assert_eq!(body[1].id, "item456");
}
// Additional tests for error cases, get by id, update, delete...
@@ -0,0 +1,92 @@
use imphnen_gacha::v1::gacha_items::gacha_items_repository::{self, GachaItemsRepository};
use imphnen_gacha::v1::gacha_items::gacha_items_dto::{CreateGachaItemDto, GachaItemResponse};
use surrealdb::engine::local::Mem;
use surrealdb::Surreal;
use surrealdb::opt::auth::Root;
use std::sync::Arc;
#[tokio::test]
async fn test_items_repository_crud_operations() {
// Setup in-memory SurrealDB for testing
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_items_repository::GachaItemsRepository::new(Arc::new(db));
let create_dto = CreateGachaItemDto { name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100 };
// Test create
let created = repo.create(&create_dto).await.unwrap();
assert!(!created.id.is_empty());
assert_eq!(created.name, "Sword");
assert_eq!(created.rarity, "rare");
// Test find by id
let found = repo.find_by_id(&created.id).await.unwrap().unwrap();
assert_eq!(found.id, created.id);
// Test find all
let all_items = repo.find_all().await.unwrap();
assert_eq!(all_items.len(), 1);
assert_eq!(all_items[0].id, created.id);
// Test update
let updated_dto = CreateGachaItemDto { name: "Magic Sword".to_string(), rarity: "epic".to_string(), image_url: "https://example.com/magic_sword.png".to_string(), value: 200 };
let updated = repo.update(&created.id, &updated_dto).await.unwrap();
assert_eq!(updated.name, "Magic Sword");
assert_eq!(updated.rarity, "epic");
assert_eq!(updated.value, 200);
// Test delete
let delete_result = repo.delete(&created.id).await;
assert!(delete_result.is_ok());
// Verify deletion
let deleted = repo.find_by_id(&created.id).await.unwrap();
assert!(deleted.is_none());
}
#[tokio::test]
async fn test_items_repository_error_cases() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_items_repository::GachaItemsRepository::new(Arc::new(db));
// Test find by non-existent id
let result = repo.find_by_id("non_existent_id").await;
assert!(result.is_ok());
assert!(result.unwrap().is_none());
// Test update non-existent item
let update_dto = CreateGachaItemDto { name: "Test".to_string(), rarity: "common".to_string(), image_url: "https://example.com/test.png".to_string(), value: 10 };
let result = repo.update("non_existent_id", &update_dto).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Item not found");
// Test delete non-existent item
let result = repo.delete("non_existent_id").await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Item not found");
}
#[tokio::test]
async fn test_items_repository_duplicate_name_error() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_items_repository::GachaItemsRepository::new(Arc::new(db));
// Create first item
let create_dto1 = CreateGachaItemDto { name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100 };
repo.create(&create_dto1).await.unwrap();
// Try to create item with same name
let create_dto2 = CreateGachaItemDto { name: "Sword".to_string(), rarity: "common".to_string(), image_url: "https://example.com/sword2.png".to_string(), value: 50 };
let result = repo.create(&create_dto2).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Item with this name already exists");
}
@@ -0,0 +1,60 @@
use imphnen_gacha::v1::gacha_items::gacha_items_service::{self, GachaItemsRepository};
use imphnen_gacha::v1::gacha_items::gacha_items_dto::{CreateGachaItemDto, GachaItemResponse};
use mockall::mock;
use std::sync::Arc;
mock! {
pub GachaItemsRepositoryMock {}
#[async_trait]
impl GachaItemsRepository for GachaItemsRepositoryMock {
async fn create(&self, item: &CreateGachaItemDto) -> Result<GachaItemResponse, String>;
async fn find_by_id(&self, item_id: &str) -> Result<Option<GachaItemResponse>, String>;
async fn find_all(&self) -> Result<Vec<GachaItemResponse>, String>;
async fn update(&self, item_id: &str, item: &CreateGachaItemDto) -> Result<GachaItemResponse, String>;
async fn delete(&self, item_id: &str) -> Result<(), String>;
}
}
#[tokio::test]
async fn test_create_item_happy_path() {
let mock_repo = MockGachaItemsRepositoryMock::new();
let service = gacha_items_service::GachaItemsService::new(Arc::new(mock_repo));
let create_dto = CreateGachaItemDto { name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100 };
let expected = GachaItemResponse { id: "item123".to_string(), name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100, created_at: "2024-01-01T00:00:00Z".to_string() };
mock_repo.expect_create().withf(|i| i.name == create_dto.name && i.rarity == create_dto.rarity).returning(|_| Ok(expected.clone()));
let result = service.create_item(&create_dto).await;
assert!(result.is_ok());
assert_eq!(result.unwrap().id, expected.id);
}
#[tokio::test]
async fn test_create_item_duplicate_name_error() {
let mock_repo = MockGachaItemsRepositoryMock::new();
let service = gacha_items_service::GachaItemsService::new(Arc::new(mock_repo));
let create_dto = CreateGachaItemDto { name: "Sword".to_string(), rarity: "rare".to_string(), image_url: "https://example.com/sword.png".to_string(), value: 100 };
let error_msg = "Item with this name already exists";
mock_repo.expect_create().withf(|i| i.name == "Sword").returning(|_| Err(error_msg.to_string()));
let result = service.create_item(&create_dto).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), error_msg);
}
#[tokio::test]
async fn test_get_all_items_empty_case() {
let mock_repo = MockGachaItemsRepositoryMock::new();
let service = gacha_items_service::GachaItemsService::new(Arc::new(mock_repo));
mock_repo.expect_find_all().returning(|| Ok(Vec::new()));
let result = service.get_all_items().await;
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 0);
}
// Additional tests for get by id, update, delete operations...
@@ -0,0 +1,60 @@
use axum_test::TestServer;
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_controller::{self, GachaRollsService};
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_dto::{CreateGachaRollDto, GachaRollResponse};
use mockall::mock;
use tower::ServiceBuilder;
use tower::timeout::TimeoutLayer;
use std::time::Duration;
mock! {
pub GachaRollsServiceMock {}
#[async_trait]
impl GachaRollsService for GachaRollsServiceMock {
async fn create_roll(&self, user_id: &str, credits_used: i32) -> Result<GachaRollResponse, String>;
async fn get_roll(&self, roll_id: &str) -> Result<GachaRollResponse, String>;
async fn get_user_rolls(&self, user_id: &str) -> Result<Vec<GachaRollResponse>, String>;
async fn get_all_rolls(&self) -> Result<Vec<GachaRollResponse>, String>;
async fn update_roll(&self, roll_id: &str, status: &str) -> Result<GachaRollResponse, String>;
async fn delete_roll(&self, roll_id: &str) -> Result<(), String>;
}
}
#[tokio::test]
async fn test_create_roll_happy_path() {
let mock_service = MockGachaRollsServiceMock::new();
let create_dto = CreateGachaRollDto { user_id: "user123".to_string(), credits_used: 10 };
let expected = GachaRollResponse { id: "roll789".to_string(), user_id: "user123".to_string(), credits_used: 10, items_won: vec!["item456".to_string()], status: "completed".to_string(), created_at: "2024-01-01T00:00:00Z".to_string() };
mock_service.expect_create_roll().withf(|u, c| u == &create_dto.user_id && c == &create_dto.credits_used).returning(|_, _| Ok(expected.clone()));
let app = ServiceBuilder::new().layer(TimeoutLayer::new(Duration::from_secs(10))).service(gacha_rolls_controller::router(mock_service));
let server = TestServer::new(app).unwrap();
let response = server.post("/gacha/rolls").json(&create_dto).await;
assert_eq!(response.status(), 201);
let body: GachaRollResponse = response.json().await.unwrap();
assert_eq!(body.id, expected.id);
}
#[tokio::test]
async fn test_get_user_rolls_happy_path() {
let mock_service = MockGachaRollsServiceMock::new();
let expected_rolls = vec![
GachaRollResponse { id: "roll123".to_string(), user_id: "user123".to_string(), credits_used: 10, items_won: vec!["item456".to_string()], status: "completed".to_string(), created_at: "2024-01-01T00:00:00Z".to_string() },
GachaRollResponse { id: "roll456".to_string(), user_id: "user123".to_string(), credits_used: 5, items_won: vec!["item789".to_string()], status: "completed".to_string(), created_at: "2024-01-02T00:00:00Z".to_string() }
];
mock_service.expect_get_user_rolls().withf(|u| u == "user123").returning(|| Ok(expected_rolls.clone()));
let app = ServiceBuilder::new().layer(TimeoutLayer::new(Duration::from_secs(10))).service(gacha_rolls_controller::router(mock_service));
let server = TestServer::new(app).unwrap();
let response = server.get("/gacha/rolls/user/user123").await;
assert_eq!(response.status(), 200);
let body: Vec<GachaRollResponse> = response.json().await.unwrap();
assert_eq!(body.len(), 2);
assert_eq!(body[0].id, "roll123");
assert_eq!(body[1].id, "roll456");
}
// Additional tests for error cases, get by id, update, delete, get all rolls...
@@ -0,0 +1,101 @@
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_repository::{self, GachaRollsRepository};
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_dto::{CreateGachaRollDto, GachaRollResponse};
use surrealdb::engine::local::Mem;
use surrealdb::Surreal;
use surrealdb::opt::auth::Root;
use std::sync::Arc;
#[tokio::test]
async fn test_rolls_repository_crud_operations() {
// Setup in-memory SurrealDB for testing
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_rolls_repository::GachaRollsRepository::new(Arc::new(db));
let create_dto = CreateGachaRollDto { user_id: "user123".to_string(), credits_used: 10 };
// Test create
let created = repo.create(&create_dto).await.unwrap();
assert!(!created.id.is_empty());
assert_eq!(created.user_id, "user123");
assert_eq!(created.credits_used, 10);
assert_eq!(created.items_won.len(), 0); // Default empty array
// Test find by id
let found = repo.find_by_id(&created.id).await.unwrap().unwrap();
assert_eq!(found.id, created.id);
assert_eq!(found.user_id, "user123");
// Test find by user
let user_rolls = repo.find_by_user("user123").await.unwrap();
assert_eq!(user_rolls.len(), 1);
assert_eq!(user_rolls[0].id, created.id);
// Test find all
let all_rolls = repo.find_all().await.unwrap();
assert_eq!(all_rolls.len(), 1);
assert_eq!(all_rolls[0].id, created.id);
// Test update status
let updated = repo.update(&created.id, "completed").await.unwrap();
assert_eq!(updated.status, "completed");
assert_eq!(updated.id, created.id);
// Test delete
let delete_result = repo.delete(&created.id).await;
assert!(delete_result.is_ok());
// Verify deletion
let deleted = repo.find_by_id(&created.id).await.unwrap();
assert!(deleted.is_none());
}
#[tokio::test]
async fn test_rolls_repository_error_cases() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_rolls_repository::GachaRollsRepository::new(Arc::new(db));
// Test find by non-existent id
let result = repo.find_by_id("non_existent_id").await;
assert!(result.is_ok());
assert!(result.unwrap().is_none());
// Test update non-existent roll
let result = repo.update("non_existent_id", "completed").await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Roll not found");
// Test delete non-existent roll
let result = repo.delete("non_existent_id").await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Roll not found");
}
#[tokio::test]
async fn test_rolls_repository_create_with_items() {
let db = Surreal::new::<Mem>(()).await.unwrap();
db.signin(Root { username: "root", password: "root" }).await.unwrap();
db.use_ns("test").use_db("test").await.unwrap();
let repo = gacha_rolls_repository::GachaRollsRepository::new(Arc::new(db));
// Create a roll with pre-defined items_won
let mut create_dto = CreateGachaRollDto { user_id: "user123".to_string(), credits_used: 15 };
create_dto.items_won = Some(vec!["item456".to_string(), "item789".to_string()]);
let created = repo.create(&create_dto).await.unwrap();
assert!(!created.id.is_empty());
assert_eq!(created.items_won.len(), 2);
assert_eq!(created.items_won[0], "item456");
assert_eq!(created.items_won[1], "item789");
// Verify items are stored correctly
let found = repo.find_by_id(&created.id).await.unwrap().unwrap();
assert_eq!(found.items_won.len(), 2);
assert_eq!(found.items_won[0], "item456");
assert_eq!(found.items_won[1], "item789");
}
@@ -0,0 +1,75 @@
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_service::{self, GachaRollsRepository, GachaCreditsRepository};
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_dto::{CreateGachaRollDto, GachaRollResponse};
use mockall::mock;
use std::sync::Arc;
mock! {
pub GachaRollsRepositoryMock {}
#[async_trait]
impl GachaRollsRepository for GachaRollsRepositoryMock {
async fn create(&self, roll: &CreateGachaRollDto) -> Result<GachaRollResponse, String>;
async fn find_by_id(&self, roll_id: &str) -> Result<Option<GachaRollResponse>, String>;
async fn find_by_user(&self, user_id: &str) -> Result<Vec<GachaRollResponse>, String>;
async fn find_all(&self) -> Result<Vec<GachaRollResponse>, String>;
async fn update(&self, roll_id: &str, status: &str) -> Result<GachaRollResponse, String>;
async fn delete(&self, roll_id: &str) -> Result<(), String>;
}
}
mock! {
pub GachaCreditsRepositoryMock {}
#[async_trait]
impl GachaCreditsRepository for GachaCreditsRepositoryMock {
async fn deduct_credits(&self, user_id: &str, amount: i32) -> Result<(), String>;
async fn add_credits(&self, user_id: &str, amount: i32) -> Result<(), String>;
async fn get_balance(&self, user_id: &str) -> Result<i32, String>;
}
}
#[tokio::test]
async fn test_create_roll_happy_path() {
let mock_roll_repo = MockGachaRollsRepositoryMock::new();
let mock_credits_repo = MockGachaCreditsRepositoryMock::new();
let service = gacha_rolls_service::GachaRollsService::new(Arc::new(mock_roll_repo), Arc::new(mock_credits_repo));
let create_dto = CreateGachaRollDto { user_id: "user123".to_string(), credits_used: 10 };
let expected = GachaRollResponse { id: "roll789".to_string(), user_id: "user123".to_string(), credits_used: 10, items_won: vec!["item456".to_string()], status: "completed".to_string(), created_at: "2024-01-01T00:00:00Z".to_string() };
mock_credits_repo.expect_deduct_credits().withf(|u, a| u == "user123" && a == 10).returning(|_, _| Ok(()));
mock_roll_repo.expect_create().withf(|r| r.user_id == create_dto.user_id && r.credits_used == create_dto.credits_used).returning(|_| Ok(expected.clone()));
let result = service.create_roll(&create_dto).await;
assert!(result.is_ok());
assert_eq!(result.unwrap().id, expected.id);
}
#[tokio::test]
async fn test_create_roll_insufficient_credits() {
let mock_roll_repo = MockGachaRollsRepositoryMock::new();
let mock_credits_repo = MockGachaCreditsRepositoryMock::new();
let service = gacha_rolls_service::GachaRollsService::new(Arc::new(mock_roll_repo), Arc::new(mock_credits_repo));
let create_dto = CreateGachaRollDto { user_id: "user123".to_string(), credits_used: 100 };
let error_msg = "Insufficient credits";
mock_credits_repo.expect_deduct_credits().withf(|u, a| u == "user123" && a == 100).returning(|_, _| Err(error_msg.to_string()));
let result = service.create_roll(&create_dto).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err(), error_msg);
}
#[tokio::test]
async fn test_get_user_rolls_empty_case() {
let mock_roll_repo = MockGachaRollsRepositoryMock::new();
let mock_credits_repo = MockGachaCreditsRepositoryMock::new();
let service = gacha_rolls_service::GachaRollsService::new(Arc::new(mock_roll_repo), Arc::new(mock_credits_repo));
mock_roll_repo.expect_find_by_user().withf(|u| u == "user123").returning(|| Ok(Vec::new()));
let result = service.get_user_rolls("user123").await;
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 0);
}
// Additional tests for get by id, update, delete, get all rolls operations...
@@ -0,0 +1,42 @@
#[cfg(test)]
mod tests {
use crate::{generate_unique_email, get_role_id, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_iam::{
PermissionsCreateRequestDto, PermissionsUpdateRequestDto, PermissionsSchema,
ResourceEnum,
};
use imphnen_utils::{make_thing_from_enum, ResourceEnum as UtilsResourceEnum};
#[tokio::test]
async fn test_create_permission_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Test data
let permission_name = "test_permission_controller".to_string();
let permission_request = PermissionsCreateRequestDto {
name: permission_name.clone(),
};
// Create permission through controller
let response = imphnen_iam::PermissionsController::create_permission(
&app_state,
permission_request.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify permission was created in database
let created_permission = repo
.query_permission_by_name(permission_name)
.await
.unwrap();
assert_eq!(created_permission.name, permission_name);
// Clean up
let _ = repo.query_delete_permission(created_permission.id.id.to_raw()).await;
}
}
@@ -1,145 +1,199 @@
use crate::{
get_iso_date, // Import the new setup function and get_iso_date
permissions::{PermissionsRepository, PermissionsSchema},
setup_all_test_environment,
};
use chrono::Utc;
fn create_dummy_permission(name: &str) -> PermissionsSchema {
PermissionsSchema {
name: name.to_string(),
created_at: Some(get_iso_date()), // Ensure created_at is always set
updated_at: Some(get_iso_date()), // Ensure updated_at is always set
..Default::default()
}
}
#[tokio::test]
async fn test_create_permission_should_succeed() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let permission = create_dummy_permission("Test Permission");
let result = repo.query_create_permission(permission).await;
assert!(result.is_ok(), "Create failed: {:?}", result.err());
}
#[tokio::test]
async fn test_query_permission_list_should_return_data() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let _ = repo
.query_create_permission(create_dummy_permission("View"))
.await;
let meta = crate::MetaRequestDto {
page: Some(1),
per_page: Some(10),
search: None,
sort_by: None,
order: None,
filter: None,
filter_by: None,
#[cfg(test)]
mod tests {
use imphnen_iam::{
PermissionsSchema, ResourceEnum,
};
use imphnen_utils::{make_thing_from_enum};
use surrealdb::Uuid;
use imphnen_entities::MetaRequestDto;
let result = repo.query_permission_list(meta).await;
assert!(result.is_ok(), "List failed: {:?}", result.err());
assert!(!result.unwrap().data.is_empty(), "Data should not be empty");
}
#[tokio::test]
async fn test_query_create_permission() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
#[tokio::test]
async fn test_query_permission_by_id_should_succeed() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let permission = create_dummy_permission("Detail");
let _ = repo.query_create_permission(permission.clone()).await;
let id = permission.id.id.to_raw();
let result = repo.query_permission_by_id(id).await;
assert!(result.is_ok(), "Get by id failed: {:?}", result.err());
}
// Test data
let permission_name = "test_permission_repo_create".to_string();
let permission = PermissionsSchema {
id: make_thing_from_enum(ResourceEnum::Permissions, &Uuid::new_v4().to_string()),
name: permission_name.clone(),
is_deleted: false,
created_at: None,
updated_at: None,
};
#[tokio::test]
async fn test_update_permission_should_succeed() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let mut permission = create_dummy_permission("Update This");
let _ = repo.query_create_permission(permission.clone()).await;
permission.name = "Updated Name".into();
permission.updated_at = Some(Utc::now().to_rfc3339());
let result = repo.query_update_permission(permission).await;
assert!(result.is_ok(), "Update failed: {:?}", result.err());
}
// Create permission
let result = repo.query_create_permission(permission.clone()).await;
assert!(result.is_ok(), "Failed to create permission: {:?}", result.err());
#[tokio::test]
async fn test_delete_permission_should_succeed() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let permission = create_dummy_permission("To Be Deleted");
let _ = repo.query_create_permission(permission.clone()).await;
let id = permission.id.id.to_raw();
let result = repo.query_delete_permission(id).await;
assert!(result.is_ok(), "Delete failed: {:?}", result.err());
}
// Verify permission was created
let created_permission = repo
.query_permission_by_name(permission_name.clone())
.await
.unwrap();
assert_eq!(created_permission.name, permission_name);
#[tokio::test]
async fn test_delete_permission_should_fail_if_already_deleted() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let permission = create_dummy_permission("Delete Twice");
let _ = repo.query_create_permission(permission.clone()).await;
let id = permission.id.id.to_raw();
let delete_result = repo.query_delete_permission(id.clone()).await;
assert!(
delete_result.is_ok(),
"Initial delete failed: {:?}",
delete_result.err()
);
let second_delete_result = repo.query_delete_permission(id).await;
assert!(
second_delete_result.is_err(),
"Should fail on second delete"
);
if let Some(err) = second_delete_result.err() {
assert!(
err.to_string().contains("Permission not found"),
"Expected 'Permission not found' error, got: {err}"
);
// Clean up
let _ = repo.query_delete_permission(created_permission.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_update_permission_should_fail_if_deleted() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let mut permission = create_dummy_permission("To Be Updated Then Deleted");
let _ = repo.query_create_permission(permission.clone()).await;
let id = permission.id.id.to_raw();
let delete_result = repo.query_delete_permission(id.clone()).await;
assert!(
delete_result.is_ok(),
"Initial delete failed: {:?}",
delete_result.err()
);
permission.name = "Try Update".into();
let result = repo.query_update_permission(permission).await;
assert!(result.is_err(), "Update on deleted should fail");
if let Some(err) = result.err() {
assert!(
err.to_string().contains("Permission not found"),
"Expected 'Permission not found' error, got: {err}"
);
#[tokio::test]
async fn test_query_permission_by_name() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Test data
let permission_name = "test_permission_repo_by_name".to_string();
let permission = PermissionsSchema {
id: make_thing_from_enum(ResourceEnum::Permissions, &Uuid::new_v4().to_string()),
name: permission_name.clone(),
is_deleted: false,
created_at: None,
updated_at: None,
};
// Create permission
let create_result = repo.query_create_permission(permission.clone()).await;
assert!(create_result.is_ok());
// Query permission by name
let result = repo.query_permission_by_name(permission_name.clone()).await;
assert!(result.is_ok());
let found_permission = result.unwrap();
assert_eq!(found_permission.name, permission_name);
// Query non-existent permission
let non_existent_result = repo.query_permission_by_name("non_existent".to_string()).await;
assert!(non_existent_result.is_err());
assert!(non_existent_result.err().unwrap().to_string().contains("not found"));
// Clean up
let _ = repo.query_delete_permission(found_permission.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_query_permission_list() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Create test permissions
let permission_names = vec![
"test_permission_list_1".to_string(),
"test_permission_list_2".to_string(),
"test_permission_list_3".to_string(),
];
for name in &permission_names {
let permission = PermissionsSchema {
id: make_thing_from_enum(ResourceEnum::Permissions, &Uuid::new_v4().to_string()),
name: name.clone(),
is_deleted: false,
created_at: None,
updated_at: None,
};
let _ = repo.query_create_permission(permission).await;
}
// Query permission list
let meta = MetaRequestDto {
page: Some(1),
per_page: Some(10),
search: None,
filter: None,
sort_by: None,
order: None,
filter_by: None,
};
let result = repo.query_permission_list(meta).await;
assert!(result.is_ok());
let permission_list = result.unwrap();
assert_eq!(permission_list.data.len(), 3);
// Clean up
for name in permission_names {
let permission = repo.query_permission_by_name(name).await.unwrap();
let _ = repo.query_delete_permission(permission.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_query_update_permission() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Test data
let original_name = "test_permission_update_original".to_string();
let new_name = "test_permission_update_updated".to_string();
let permission = PermissionsSchema {
id: make_thing_from_enum(ResourceEnum::Permissions, &Uuid::new_v4().to_string()),
name: original_name.clone(),
is_deleted: false,
created_at: None,
updated_at: None,
};
// Create permission
let create_result = repo.query_create_permission(permission.clone()).await;
assert!(create_result.is_ok());
// Get created permission
let created_permission = repo.query_permission_by_name(original_name).await.unwrap();
// Update permission
let updated_permission = PermissionsSchema {
id: created_permission.id.clone(),
name: new_name.clone(),
is_deleted: created_permission.is_deleted,
created_at: created_permission.created_at,
updated_at: created_permission.updated_at,
};
let update_result = repo.query_update_permission(updated_permission).await;
assert!(update_result.is_ok());
// Verify permission was updated
let result = repo.query_permission_by_name(new_name.clone()).await;
assert!(result.is_ok());
let found_permission = result.unwrap();
assert_eq!(found_permission.name, new_name);
// Clean up
let _ = repo.query_delete_permission(found_permission.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_query_permission_by_id_should_fail_if_not_found() {
let state = setup_all_test_environment().await; // Use the new setup function
let repo = PermissionsRepository::new(&state);
let result = repo.query_permission_by_id("non-existent-id".into()).await;
assert!(result.is_err(), "Expected error for not found id");
if let Some(err) = result.err() {
assert!(
err.to_string().contains("Permission not found"),
"Expected 'Permission not found' error, got: {err}"
);
#[tokio::test]
async fn test_query_delete_permission() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Test data
let permission_name = "test_permission_delete".to_string();
let permission = PermissionsSchema {
id: make_thing_from_enum(ResourceEnum::Permissions, &Uuid::new_v4().to_string()),
name: permission_name.clone(),
is_deleted: false,
created_at: None,
updated_at: None,
};
// Create permission
let create_result = repo.query_create_permission(permission.clone()).await;
assert!(create_result.is_ok());
// Get created permission
let created_permission = repo.query_permission_by_name(permission_name).await.unwrap();
// Verify permission exists before deletion
let exists_before = repo.query_permission_by_id(created_permission.id.id.to_raw()).await.is_ok();
assert!(exists_before);
// Delete permission
let delete_result = repo.query_delete_permission(created_permission.id.id.to_raw()).await;
assert!(delete_result.is_ok());
// Verify permission was deleted
let exists_after = repo.query_permission_by_id(created_permission.id.id.to_raw()).await.is_ok();
assert!(!exists_after);
}
}
@@ -0,0 +1,221 @@
#[cfg(test)]
mod tests {
use crate::{generate_unique_email, get_role_id, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_iam::{
PermissionsCreateRequestDto, PermissionsUpdateRequestDto, PermissionsSchema,
ResourceEnum,
};
use imphnen_utils::{make_thing_from_enum, ResourceEnum as UtilsResourceEnum};
#[tokio::test]
async fn test_create_permission_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Test data
let permission_name = "test_permission_service".to_string();
let permission_request = PermissionsCreateRequestDto {
name: permission_name.clone(),
};
// Create permission through service
let response = imphnen_iam::PermissionsService::create_role(
&app_state,
permission_request.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify permission was created in database
let created_permission = repo
.query_permission_by_name(permission_name)
.await
.unwrap();
assert_eq!(created_permission.name, permission_name);
// Clean up
let _ = repo.query_delete_permission(created_permission.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_get_permission_by_id_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Create test permission
let permission_name = "test_permission_by_id_service".to_string();
let permission = PermissionsSchema {
name: permission_name.clone(),
..Default::default()
};
let create_result = repo.query_create_permission(permission.clone()).await;
assert!(create_result.is_ok());
// Get created permission to get ID
let created_permission = repo
.query_permission_by_name(permission_name)
.await
.unwrap();
let permission_id = created_permission.id.id.to_raw();
// Get permission by ID through service
let response = imphnen_iam::PermissionsService::get_permission_by_id(
&app_state, permission_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
let _ = repo.query_delete_permission(permission_id).await;
}
#[tokio::test]
async fn test_update_permission_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Create test permission
let original_name = "test_permission_update_original_service".to_string();
let new_name = "test_permission_update_updated_service".to_string();
let permission = PermissionsSchema {
name: original_name.clone(),
..Default::default()
};
let create_result = repo.query_create_permission(permission.clone()).await;
assert!(create_result.is_ok());
// Get created permission to get ID
let created_permission = repo
.query_permission_by_name(original_name)
.await
.unwrap();
let permission_id = created_permission.id.id.to_raw();
// Prepare update request
let update_request = PermissionsUpdateRequestDto {
name: Some(new_name.clone()),
};
// Update permission through service
let response = imphnen_iam::PermissionsService::update_permission(
&app_state, update_request, permission_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify permission was updated in database
let updated_permission = repo
.query_permission_by_id(permission_id.clone())
.await
.unwrap();
assert_eq!(updated_permission.name, new_name);
// Clean up
let _ = repo.query_delete_permission(permission_id).await;
}
#[tokio::test]
async fn test_delete_permission_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::PermissionsRepository::new(&app_state);
// Create test permission
let permission_name = "test_permission_delete_service".to_string();
let permission = PermissionsSchema {
name: permission_name.clone(),
..Default::default()
};
let create_result = repo.query_create_permission(permission.clone()).await;
assert!(create_result.is_ok());
// Get created permission to get ID
let created_permission = repo
.query_permission_by_name(permission_name)
.await
.unwrap();
let permission_id = created_permission.id.id.to_raw();
// Verify permission exists before deletion
let exists_before = repo.query_permission_by_id(permission_id.clone()).await.is_ok();
assert!(exists_before);
// Delete permission through service
let response = imphnen_iam::PermissionsService::delete_permission(
&app_state, permission_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify permission was deleted from database
let exists_after = repo.query_permission_by_id(permission_id).await.is_ok();
assert!(!exists_after);
}
}
#[tokio::test]
async fn test_get_permission_by_id_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Get non-existent permission by ID through service
let response = imphnen_iam::PermissionsService::get_permission_by_id(
&app_state, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_update_permission_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Prepare update request
let update_request = PermissionsUpdateRequestDto {
name: Some("new_name".to_string()),
};
// Update non-existent permission through service
let response = imphnen_iam::PermissionsService::update_permission(
&app_state, update_request, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_delete_permission_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Delete non-existent permission through service
let response = imphnen_iam::PermissionsService::delete_permission(
&app_state, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}
@@ -0,0 +1,301 @@
#[cfg(test)]
mod tests {
use crate::{generate_unique_email, get_role_id, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_iam::{
RolesCreateRequestDto, RolesUpdateRequestDto, RolesSchema, ResourceEnum,
};
use imphnen_utils::{make_thing_from_enum, ResourceEnum as UtilsResourceEnum};
#[tokio::test]
async fn test_create_role_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Test data
let role_name = "test_role_controller".to_string();
let role_request = RolesCreateRequestDto {
name: role_name.clone(),
description: Some("Test role for controller".to_string()),
};
// Create role through controller
let response = imphnen_iam::RolesController::create_role(
&app_state,
role_request.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify role was created in database
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
assert_eq!(created_role.name, role_name);
// Clean up
let _ = repo.query_delete_role(created_role.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_create_role_controller_duplicate() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Test data
let role_name = "test_role_duplicate".to_string();
let role_request = RolesCreateRequestDto {
name: role_name.clone(),
description: Some("Test role for duplicate check".to_string()),
};
// Create role first time
let response1 = imphnen_iam::RolesController::create_role(
&app_state,
role_request.clone(),
)
.await;
assert_eq!(response1.status(), StatusCode::CREATED);
// Try to create same role again
let response2 = imphnen_iam::RolesController::create_role(
&app_state,
role_request,
)
.await;
// Verify conflict response
assert_eq!(response2.status(), StatusCode::CONFLICT);
// Clean up
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
let _ = repo.query_delete_role(created_role.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_get_role_list_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test roles
let role_names = vec![
"test_role_list_1".to_string(),
"test_role_list_2".to_string(),
"test_role_list_3".to_string(),
];
for name in &role_names {
let role = RolesSchema {
name: name.clone(),
description: Some(format!("Description for {}", name)),
..Default::default()
};
let _ = repo.query_create_role(role).await;
}
// Get role list through controller
let response = imphnen_iam::RolesController::get_role_list(
&app_state,
crate::get_meta_request_dto(1, 10),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
for name in role_names {
let role = repo.query_role_by_name(name).await.unwrap();
let _ = repo.query_delete_role(role.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_get_role_by_id_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test role
let role_name = "test_role_by_id".to_string();
let role = RolesSchema {
name: role_name.clone(),
description: Some("Test role for by ID test".to_string()),
..Default::default()
};
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role to get ID
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
let role_id = created_role.id.id.to_raw();
// Get role by ID through controller
let response = imphnen_iam::RolesController::get_role_by_id(
&app_state, role_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
let _ = repo.query_delete_role(role_id).await;
}
}
#[tokio::test]
async fn test_get_role_by_id_controller_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Get non-existent role by ID through controller
let response = imphnen_iam::RolesController::get_role_by_id(
&app_state, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_update_role_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test role
let original_name = "test_role_update_original_controller".to_string();
let new_name = "test_role_update_updated_controller".to_string();
let role = RolesSchema {
name: original_name.clone(),
description: Some("Original description for controller test".to_string()),
..Default::default()
};
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role to get ID
let created_role = repo
.query_role_by_name(original_name)
.await
.unwrap();
let role_id = created_role.id.id.to_raw();
// Prepare update request
let update_request = RolesUpdateRequestDto {
name: Some(new_name.clone()),
description: Some("Updated description for controller test".to_string()),
};
// Update role through controller
let response = imphnen_iam::RolesController::update_role(
&app_state, update_request, role_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify role was updated in database
let updated_role = repo
.query_role_by_id(role_id.clone())
.await
.unwrap();
assert_eq!(updated_role.name, new_name);
assert_eq!(updated_role.description, Some("Updated description for controller test".to_string()));
// Clean up
let _ = repo.query_delete_role(role_id).await;
}
#[tokio::test]
async fn test_update_role_controller_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Prepare update request
let update_request = RolesUpdateRequestDto {
name: Some("new_name".to_string()),
description: Some("new description".to_string()),
};
// Update non-existent role through controller
let response = imphnen_iam::RolesController::update_role(
&app_state, update_request, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_delete_role_controller() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test role
let role_name = "test_role_delete_controller".to_string();
let role = RolesSchema {
name: role_name.clone(),
description: Some("Test role for delete test in controller".to_string()),
..Default::default()
};
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role to get ID
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
let role_id = created_role.id.id.to_raw();
// Verify role exists before deletion
let exists_before = repo.query_role_by_id(role_id.clone()).await.is_ok();
assert!(exists_before);
// Delete role through controller
let response = imphnen_iam::RolesController::delete_role(
&app_state, role_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify role was deleted from database
let exists_after = repo.query_role_by_id(role_id).await.is_ok();
assert!(!exists_after);
}
#[tokio::test]
async fn test_delete_role_controller_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Delete non-existent role through controller
let response = imphnen_iam::RolesController::delete_role(
&app_state, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}
+164 -297
View File
@@ -1,315 +1,182 @@
use crate::{
get_iso_date, make_thing,
permissions::{
permissions_repository::PermissionsRepository,
permissions_schema::PermissionsSchema,
},
roles::{
roles_dto::{RolesRequestCreateDto, RolesRequestUpdateDto},
roles_repository::RolesRepository,
},
setup_all_test_environment, ResourceEnum,
};
use surrealdb::Uuid;
fn generate_unique_name(prefix: &str) -> String {
format!("{}_{}", prefix, Uuid::new_v4())
}
#[tokio::test]
async fn test_query_create_role_should_succeed() {
let state = setup_all_test_environment().await;
let perm_repo = PermissionsRepository::new(&state);
let role_repo = RolesRepository::new(&state);
let perm_id = Uuid::new_v4().to_string();
let permission = PermissionsSchema {
id: make_thing(&ResourceEnum::Permissions.to_string(), &perm_id),
name: generate_unique_name("read_quiz"),
is_deleted: false,
created_at: Some(get_iso_date()),
updated_at: Some(get_iso_date()),
#[cfg(test)]
mod tests {
use imphnen_iam::{
RolesRequestCreateDto, RolesRequestUpdateDto, RolesDetailItemDto, ResourceEnum,
};
let perm_res = perm_repo.query_create_permission(permission).await;
assert!(
perm_res.is_ok(),
"Failed to create permission: {:?}",
perm_res.err()
);
let payload = RolesRequestCreateDto {
name: generate_unique_name("user"),
permissions: vec![perm_id.clone()],
};
let result = role_repo.query_create_role(payload).await;
assert!(result.is_ok(), "Failed to create role: {:?}", result.err());
}
use imphnen_utils::{make_thing_from_enum};
use imphnen_entities::MetaRequestDto;
#[tokio::test]
async fn test_query_role_by_name_should_return_data() {
let state = setup_all_test_environment().await;
let role_repo = RolesRepository::new(&state);
let name = generate_unique_name("viewer");
let payload = RolesRequestCreateDto {
name: name.clone(),
permissions: vec![],
};
let create_res = role_repo.query_create_role(payload.clone()).await;
assert!(
create_res.is_ok(),
"Failed to create role: {:?}",
create_res.err()
);
let role = role_repo.query_role_by_name(name.clone()).await;
assert!(role.is_ok(), "Failed to get role by name: {:?}", role.err());
let role = role.unwrap();
assert_eq!(role.name, name.clone());
}
#[tokio::test]
async fn test_query_create_role() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
#[tokio::test]
async fn test_query_role_by_id_should_return_data() {
let state = setup_all_test_environment().await;
let role_repo = RolesRepository::new(&state);
// Test data
let role_name = "test_role_repo_create".to_string();
let role = RolesRequestCreateDto {
name: role_name.clone(),
permissions: vec![],
};
let name = generate_unique_name("tester");
// Create role
let result = repo.query_create_role(role.clone()).await;
assert!(result.is_ok(), "Failed to create role: {:?}", result.err());
let payload = RolesRequestCreateDto {
name: name.clone(),
permissions: vec![],
};
// Verify role was created
let created_role = repo
.query_role_by_name(role_name.clone())
.await
.unwrap();
assert_eq!(created_role.name, role_name);
let create_res = role_repo.query_create_role(payload.clone()).await;
// Clean up
let _ = repo.query_delete_role(created_role.id).await;
}
assert!(
create_res.is_ok(),
"Failed to create role: {:?}",
create_res.err()
);
#[tokio::test]
async fn test_query_role_by_name() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
let role = role_repo.query_role_by_name(name.clone()).await;
// Test data
let role_name = "test_role_repo_by_name".to_string();
let role = RolesRequestCreateDto {
name: role_name.clone(),
permissions: vec![],
};
assert!(role.is_ok(), "Failed to get role by name: {:?}", role.err());
let role = role.unwrap();
// Create role
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
let result = role_repo.query_role_by_id(role.id.clone()).await;
// Query role by name
let result = repo.query_role_by_name(role_name.clone()).await;
assert!(result.is_ok());
let found_role = result.unwrap();
assert_eq!(found_role.name, role_name);
assert!(
result.is_ok(),
"Failed to get role by id: {:?}",
result.err()
);
let result_role = result.unwrap();
// Query non-existent role
let non_existent_result = repo.query_role_by_name("non_existent".to_string()).await;
assert!(non_existent_result.is_err());
assert!(non_existent_result.err().unwrap().to_string().contains("not found"));
assert_eq!(result_role.name, name.clone());
}
// Clean up
let _ = repo.query_delete_role(found_role.id).await;
}
#[tokio::test]
async fn test_query_update_role_should_update_name_and_permissions() {
let state = setup_all_test_environment().await;
let repo = RolesRepository::new(&state);
let perm_repo = PermissionsRepository::new(&state);
let original_perm_id = Uuid::new_v4().to_string();
let original_perm = PermissionsSchema {
id: make_thing(&ResourceEnum::Permissions.to_string(), &original_perm_id),
name: generate_unique_name("original_permission"),
is_deleted: false,
created_at: Some(crate::get_iso_date()),
updated_at: Some(crate::get_iso_date()),
};
let perm_res = perm_repo.query_create_permission(original_perm).await;
assert!(
perm_res.is_ok(),
"Failed to create original permission: {:?}",
perm_res.err()
);
let role_upadate_name = generate_unique_name("role_for_update");
let create_payload = RolesRequestCreateDto {
name: role_upadate_name.clone(),
permissions: vec![original_perm_id.clone()],
};
let create_res = repo.query_create_role(create_payload).await;
assert!(
create_res.is_ok(),
"Failed to create role: {:?}",
create_res.err()
);
let existing_role = repo.query_role_by_name(role_upadate_name.clone()).await;
assert!(
existing_role.is_ok(),
"Failed to get role by name: {:?}",
existing_role.err()
);
let existing_role = existing_role.unwrap();
let existing_role_id = existing_role.id.clone();
let new_perm_id = Uuid::new_v4().to_string();
let new_perm = PermissionsSchema {
id: make_thing(&ResourceEnum::Permissions.to_string(), &new_perm_id),
name: "New Permission".into(),
is_deleted: false,
created_at: Some(crate::get_iso_date()),
updated_at: Some(crate::get_iso_date()),
};
let new_role_name = generate_unique_name("updated_role_name");
let perm_res = perm_repo.query_create_permission(new_perm).await;
assert!(
perm_res.is_ok(),
"Failed to create new permission: {:?}",
perm_res.err()
);
let update_payload = RolesRequestUpdateDto {
name: Some(new_role_name.clone()),
permissions: Some(vec![new_perm_id.clone()]),
overwrite: None,
};
let update_result = repo
.query_update_role(existing_role_id.clone(), update_payload)
.await;
assert!(
update_result.is_ok(),
"Failed to update role: {:?}",
update_result.err()
);
let updated = repo.query_role_by_id(existing_role_id.clone()).await;
assert!(
updated.is_ok(),
"Failed to get updated role: {:?}",
updated.err()
);
assert_eq!(updated.unwrap().name, new_role_name.clone());
}
#[tokio::test]
async fn test_query_role_list() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
#[tokio::test]
async fn test_query_delete_role_should_soft_delete() {
let state = setup_all_test_environment().await;
let role_repo = RolesRepository::new(&state);
let name = generate_unique_name("temporary");
let payload = RolesRequestCreateDto {
name: name.clone(),
permissions: vec![],
};
let create_res = role_repo.query_create_role(payload.clone()).await;
assert!(
create_res.is_ok(),
"Failed to create role: {:?}",
create_res.err()
);
let role = role_repo.query_role_by_name(name.clone()).await;
assert!(role.is_ok(), "Failed to get role by name: {:?}", role.err());
let role = role.unwrap();
let result = role_repo.query_delete_role(role.id.clone()).await;
assert!(result.is_ok(), "Failed to delete role: {:?}", result.err());
let deleted = role_repo.query_role_by_id(role.id).await;
assert!(
deleted.is_err(),
"Role should be deleted, but got: {deleted:?}"
);
if let Some(err) = deleted.err() {
assert!(
err.to_string().contains("Role not found"),
"Expected 'Role not found' error, got: {err}"
);
// Create test roles
let role_names = vec![
"test_role_list_1".to_string(),
"test_role_list_2".to_string(),
"test_role_list_3".to_string(),
];
for name in &role_names {
let role = RolesRequestCreateDto {
name: name.clone(),
permissions: vec![],
};
let _ = repo.query_create_role(role).await;
}
// Query role list
let meta = MetaRequestDto {
page: Some(1),
per_page: Some(10),
search: None,
filter: None,
sort_by: None,
order: None,
filter_by: None,
};
let result = repo.query_role_list(meta).await;
assert!(result.is_ok());
let role_list = result.unwrap();
assert_eq!(role_list.data.len(), 3);
// Clean up
for name in role_names {
let role = repo.query_role_by_name(name).await.unwrap();
let _ = repo.query_delete_role(role.id).await;
}
}
}
#[tokio::test]
async fn test_query_update_role_should_fallback_to_existing_permissions_if_none_provided(
) {
let state = setup_all_test_environment().await;
let repo = RolesRepository::new(&state);
let perm_repo = PermissionsRepository::new(&state);
let perm_id = Uuid::new_v4().to_string();
let permission = PermissionsSchema {
id: make_thing(&ResourceEnum::Permissions.to_string(), &perm_id),
name: "Permission for Fallback".into(),
is_deleted: false,
created_at: Some(crate::get_iso_date()),
updated_at: Some(crate::get_iso_date()),
};
let perm_res = perm_repo.query_create_permission(permission).await;
assert!(
perm_res.is_ok(),
"Failed to create permission: {:?}",
perm_res.err()
);
let create_payload = RolesRequestCreateDto {
name: "Role With Permission".into(),
permissions: vec![perm_id.clone()],
};
let create_res = repo.query_create_role(create_payload).await;
assert!(
create_res.is_ok(),
"Failed to create role: {:?}",
create_res.err()
);
let existing = repo.query_role_by_name("Role With Permission".into()).await;
assert!(
existing.is_ok(),
"Failed to get role by name: {:?}",
existing.err()
);
let existing = existing.unwrap();
let existing_id = existing.id.clone();
let update_payload = RolesRequestUpdateDto {
name: Some("Updated Role Name".into()),
permissions: None,
overwrite: None,
};
let update_res = repo
.query_update_role(existing_id.clone(), update_payload)
.await;
assert!(
update_res.is_ok(),
"Failed to update role (fallback): {:?}",
update_res.err()
);
}
#[tokio::test]
async fn test_query_role_by_name_should_fail_if_not_found() {
let state = setup_all_test_environment().await;
let role_repo = RolesRepository::new(&state);
let result = role_repo.query_role_by_name("ghost-role".into()).await;
assert!(result.is_err());
if let Some(err) = result.err() {
assert!(
err.to_string().contains("Role not found"),
"Expected 'Role not found' error, got: {err}"
);
#[tokio::test]
async fn test_query_update_role() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Test data
let original_name = "test_role_update_original".to_string();
let new_name = "test_role_update_updated".to_string();
let role = RolesRequestCreateDto {
name: original_name.clone(),
permissions: vec![],
};
// Create role
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role
let created_role = repo.query_role_by_name(original_name.clone()).await.unwrap();
// Update role
let updated_role = RolesRequestUpdateDto {
name: Some(new_name.clone()),
permissions: None,
overwrite: None,
};
let update_result = repo.query_update_role(created_role.id.clone(), updated_role).await;
assert!(update_result.is_ok());
// Verify role was updated
let result = repo.query_role_by_name(new_name.clone()).await;
assert!(result.is_ok());
let found_role = result.unwrap();
assert_eq!(found_role.name, new_name);
// Clean up
let _ = repo.query_delete_role(found_role.id).await;
}
}
#[tokio::test]
async fn test_query_delete_role_should_fail_if_already_deleted() {
let state = setup_all_test_environment().await;
let role_repo = RolesRepository::new(&state);
let name = generate_unique_name("soft_delete_test");
let payload = RolesRequestCreateDto {
name: name.clone(),
permissions: vec![],
};
let create_res = role_repo.query_create_role(payload.clone()).await;
assert!(
create_res.is_ok(),
"Failed to create role: {:?}",
create_res.err()
);
let role = role_repo.query_role_by_name(name.clone()).await;
assert!(role.is_ok(), "Failed to get role by name: {:?}", role.err());
let role = role.unwrap();
let del_res = role_repo.query_delete_role(role.id.clone()).await;
assert!(
del_res.is_ok(),
"Failed to delete role: {:?}",
del_res.err()
);
let result_fut = role_repo.query_delete_role(role.id);
let result_val = result_fut.await;
assert!(
result_val.is_err(),
"Role should already be deleted, but got: {result_val:?}"
);
if let Some(err) = result_val.err() {
assert!(
err.to_string().contains("Role not found"),
"Expected 'Role not found' error, got: {err}"
);
#[tokio::test]
async fn test_query_delete_role() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Test data
let role_name = "test_role_delete".to_string();
let role = RolesRequestCreateDto {
name: role_name.clone(),
permissions: vec![],
};
// Create role
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role
let created_role = repo.query_role_by_name(role_name.clone()).await.unwrap();
// Verify role exists before deletion
let role_id = created_role.id.clone();
let exists_before = repo.query_role_by_id(role_id.clone()).await.is_ok();
assert!(exists_before);
// Delete role
let delete_result = repo.query_delete_role(role_id.clone()).await;
assert!(delete_result.is_ok());
// Verify role was deleted
let exists_after = repo.query_role_by_id(role_id.clone()).await.is_ok();
assert!(!exists_after);
}
}
+301
View File
@@ -0,0 +1,301 @@
#[cfg(test)]
mod tests {
use crate::{generate_unique_email, get_role_id, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_iam::{
RolesCreateRequestDto, RolesUpdateRequestDto, RolesSchema, ResourceEnum,
};
use imphnen_utils::{make_thing_from_enum, ResourceEnum as UtilsResourceEnum};
#[tokio::test]
async fn test_create_role_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Test data
let role_name = "test_role_service".to_string();
let role_request = RolesCreateRequestDto {
name: role_name.clone(),
description: Some("Test role for service".to_string()),
};
// Create role through service
let response = imphnen_iam::RolesService::create_role(
&app_state,
role_request.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify role was created in database
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
assert_eq!(created_role.name, role_name);
// Clean up
let _ = repo.query_delete_role(created_role.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_create_role_service_duplicate() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Test data
let role_name = "test_role_duplicate_service".to_string();
let role_request = RolesCreateRequestDto {
name: role_name.clone(),
description: Some("Test role for duplicate check in service".to_string()),
};
// Create role first time
let response1 = imphnen_iam::RolesService::create_role(
&app_state,
role_request.clone(),
)
.await;
assert_eq!(response1.status(), StatusCode::CREATED);
// Try to create same role again
let response2 = imphnen_iam::RolesService::create_role(
&app_state,
role_request,
)
.await;
// Verify conflict response
assert_eq!(response2.status(), StatusCode::CONFLICT);
// Clean up
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
let _ = repo.query_delete_role(created_role.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_get_role_list_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test roles
let role_names = vec![
"test_role_list_service_1".to_string(),
"test_role_list_service_2".to_string(),
"test_role_list_service_3".to_string(),
];
for name in &role_names {
let role = RolesSchema {
name: name.clone(),
description: Some(format!("Description for {}", name)),
..Default::default()
};
let _ = repo.query_create_role(role).await;
}
// Get role list through service
let response = imphnen_iam::RolesService::get_role_list(
&app_state,
crate::get_meta_request_dto(1, 10),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
for name in role_names {
let role = repo.query_role_by_name(name).await.unwrap();
let _ = repo.query_delete_role(role.id.id.to_raw()).await;
}
}
#[tokio::test]
async fn test_get_role_by_id_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test role
let role_name = "test_role_by_id_service".to_string();
let role = RolesSchema {
name: role_name.clone(),
description: Some("Test role for by ID test in service".to_string()),
..Default::default()
};
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role to get ID
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
let role_id = created_role.id.id.to_raw();
// Get role by ID through service
let response = imphnen_iam::RolesService::get_role_by_id(
&app_state, role_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
let _ = repo.query_delete_role(role_id).await;
}
#[tokio::test]
async fn test_get_role_by_id_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Get non-existent role by ID through service
let response = imphnen_iam::RolesService::get_role_by_id(
&app_state, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_update_role_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test role
let original_name = "test_role_update_original_service".to_string();
let new_name = "test_role_update_updated_service".to_string();
let role = RolesSchema {
name: original_name.clone(),
description: Some("Original description for service test".to_string()),
..Default::default()
};
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role to get ID
let created_role = repo
.query_role_by_name(original_name)
.await
.unwrap();
let role_id = created_role.id.id.to_raw();
// Prepare update request
let update_request = RolesUpdateRequestDto {
name: Some(new_name.clone()),
description: Some("Updated description for service test".to_string()),
};
// Update role through service
let response = imphnen_iam::RolesService::update_role(
&app_state, role_id.clone(), update_request,
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify role was updated in database
let updated_role = repo
.query_role_by_id(role_id.clone())
.await
.unwrap();
assert_eq!(updated_role.name, new_name);
assert_eq!(updated_role.description, Some("Updated description for service test".to_string()));
// Clean up
let _ = repo.query_delete_role(role_id).await;
}
#[tokio::test]
async fn test_update_role_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Prepare update request
let update_request = RolesUpdateRequestDto {
name: Some("new_name".to_string()),
description: Some("new description".to_string()),
};
// Update non-existent role through service
let response = imphnen_iam::RolesService::update_role(
&app_state, non_existent_id, update_request,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_delete_role_service() {
let app_state = crate::get_app_state().await;
let repo = imphnen_iam::RolesRepository::new(&app_state);
// Create test role
let role_name = "test_role_delete_service".to_string();
let role = RolesSchema {
name: role_name.clone(),
description: Some("Test role for delete test in service".to_string()),
..Default::default()
};
let create_result = repo.query_create_role(role.clone()).await;
assert!(create_result.is_ok());
// Get created role to get ID
let created_role = repo
.query_role_by_name(role_name)
.await
.unwrap();
let role_id = created_role.id.id.to_raw();
// Verify role exists before deletion
let exists_before = repo.query_role_by_id(role_id.clone()).await.is_ok();
assert!(exists_before);
// Delete role through service
let response = imphnen_iam::RolesService::delete_role(
&app_state, role_id.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify role was deleted from database
let exists_after = repo.query_role_by_id(role_id).await.is_ok();
assert!(!exists_after);
}
#[tokio::test]
async fn test_delete_role_service_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Delete non-existent role through service
let response = imphnen_iam::RolesService::delete_role(
&app_state, non_existent_id,
)
.await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}
@@ -0,0 +1,307 @@
#[cfg(test)]
mod tests {
use crate::{generate_unique_email, get_role_id, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_iam::{
TeamsCreateRequestDto, TeamsSearchQueryDto, TeamsSchema, TeamMembersSchema, TeamsRepository
};
use imphnen_utils::{make_thing_from_enum, ResourceEnum};
#[tokio::test]
async fn test_create_team_controller() {
let app_state = crate::get_app_state().await;
let users_repo = UsersRepository::new(&app_state);
let repo = TeamsRepository::new(&app_state);
let email = generate_unique_email("team_creator");
let role_id = get_role_id("mentee", &app_state).await;
let user_data = crate::create_test_user(&email, "password123", true, &role_id);
let user_result = users_repo.query_create_user(user_data.clone()).await;
assert!(user_result.is_ok(), "Failed to create test user");
let user = users_repo.query_user_by_email(email.clone()).await.unwrap();
let team_request = TeamsCreateRequestDto {
name: "Test Controller Team".to_string(),
description: Some("Team created via controller".to_string()),
is_open: Some(true),
max_members: Some(10),
skills_required: Some(vec!["Rust".to_string(), "Testing".to_string()]),
location: Some("Remote".to_string()),
website_url: None,
github_url: None,
avatar: None,
member_emails: vec![],
};
// Create team through controller
let response = imphnen_iam::TeamsController::create_team(
&app_state, user.id.id.to_raw(), team_request.clone()
).await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify team was created in database
let team_thing = make_thing_from_enum(ResourceEnum::Teams, &user.id.id.to_raw());
let teams = repo.query_user_teams(&team_thing).await.unwrap();
assert!(!teams.is_empty());
assert_eq!(teams[0].name, "Test Controller Team");
// Clean up
let team_id = teams[0].id.id.to_raw();
let _ = repo.query_delete_team(team_id).await;
let _ = users_repo.query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_get_team_controller() {
let app_state = crate::get_app_state().await;
let users_repo = UsersRepository::new(&app_state);
let repo = TeamsRepository::new(&app_state);
let email = generate_unique_email("team_getter");
let role_id = get_role_id("mentee", &app_state).await;
let user_data = crate::create_test_user(&email, "password123", true, &role_id);
let user_result = users_repo.query_create_user(user_data.clone()).await;
assert!(user_result.is_ok(), "Failed to create test user");
let user = users_repo.query_user_by_email(email.clone()).await.unwrap();
let team_request = TeamsCreateRequestDto {
name: "Test Get Team".to_string(),
description: Some("Team for testing retrieval".to_string()),
is_open: Some(true),
max_members: Some(10),
skills_required: None,
location: None,
website_url: None,
github_url: None,
avatar: None,
member_emails: vec![],
};
// Create team directly for testing
let team_schema = TeamsSchema::create(team_request, user.id.id.to_raw());
let create_result = repo.query_create_team(team_schema.clone()).await;
assert!(create_result.is_ok(), "Failed to create team");
let team_thing = make_thing_from_enum(ResourceEnum::Teams, &team_schema.id.id.to_raw());
let team = repo.query_team_by_id(&team_thing).await.unwrap();
let team_id = team_schema.id.id.to_raw();
// Get team by ID through controller
let response = imphnen_iam::TeamsController::get_team(
&app_state, team_id.clone()
).await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
let _ = repo.query_delete_team(team_id).await;
let _ = users_repo.query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_get_team_controller_not_found() {
let app_state = crate::get_app_state().await;
// Use non-existent ID
let non_existent_id = "non-existent-uuid-123456789".to_string();
// Get non-existent team by ID through controller
let response = imphnen_iam::TeamsController::get_team(
&app_state, non_existent_id
).await;
// Verify not found response
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}
#[tokio::test]
async fn test_update_team_controller() {
let app_state = crate::get_app_state().await;
let users_repo = UsersRepository::new(&app_state);
let repo = TeamsRepository::new(&app_state);
let email = generate_unique_email("team_updater");
let role_id = get_role_id("mentee", &app_state).await;
let user_data = crate::create_test_user(&email, "password123", true, &role_id);
let user_result = users_repo.query_create_user(user_data.clone()).await;
assert!(user_result.is_ok(), "Failed to create test user");
let user = users_repo.query_user_by_email(email.clone()).await.unwrap();
let team_request = TeamsCreateRequestDto {
name: "Original Team Name".to_string(),
description: Some("Original description".to_string()),
is_open: Some(true),
max_members: Some(10),
skills_required: None,
location: None,
website_url: None,
github_url: None,
avatar: None,
member_emails: vec![],
};
// Create team directly for testing
let team_schema = TeamsSchema::create(team_request, user.id.id.to_raw());
let create_result = repo.query_create_team(team_schema.clone()).await;
assert!(create_result.is_ok(), "Failed to create team");
let team_thing = make_thing_from_enum(ResourceEnum::Teams, &team_schema.id.id.to_raw());
let original_team = repo.query_team_by_id(&team_thing).await.unwrap();
let team_id = team_schema.id.id.to_raw();
// Prepare update request
let update_request = imphnen_iam::TeamsUpdateRequestDto {
name: Some("Updated Team Name".to_string()),
description: Some("Updated description".to_string()),
is_open: Some(false),
max_members: Some(15),
skills_required: Some(vec!["Rust".to_string(), "Testing".to_string()]),
location: Some("Office".to_string()),
website_url: Some("https://example.com".to_string()),
github_url: Some("https://github.com/example".to_string()),
};
// Update team through controller
let response = imphnen_iam::TeamsController::update_team(
&app_state, user.id.id.to_raw(), update_request, team_id.clone()
).await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify team was updated in database
let updated_team = repo.query_team_by_id(&team_thing).await.unwrap();
assert_eq!(updated_team.name, "Updated Team Name");
assert_eq!(updated_team.description, Some("Updated description".to_string()));
assert_eq!(updated_team.is_open, false);
assert_eq!(updated_team.max_members, Some(15));
assert_eq!(updated_team.skills_required, Some(vec!["Rust".to_string(), "Testing".to_string()]));
assert_eq!(updated_team.location, Some("Office".to_string()));
assert_eq!(updated_team.website_url, Some("https://example.com".to_string()));
assert_eq!(updated_team.github_url, Some("https://github.com/example".to_string()));
// Clean up
let _ = repo.query_delete_team(team_id).await;
let _ = users_repo.query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_delete_team_controller() {
let app_state = crate::get_app_state().await;
let users_repo = UsersRepository::new(&app_state);
let repo = TeamsRepository::new(&app_state);
let email = generate_unique_email("team_deleter");
let role_id = get_role_id("mentee", &app_state).await;
let user_data = crate::create_test_user(&email, "password123", true, &role_id);
let user_result = users_repo.query_create_user(user_data.clone()).await;
assert!(user_result.is_ok(), "Failed to create test user");
let user = users_repo.query_user_by_email(email.clone()).await.unwrap();
let team_request = TeamsCreateRequestDto {
name: "Team to Delete".to_string(),
description: Some("Team that will be deleted".to_string()),
is_open: Some(true),
max_members: Some(10),
skills_required: None,
location: None,
website_url: None,
github_url: None,
avatar: None,
member_emails: vec![],
};
// Create team directly for testing
let team_schema = TeamsSchema::create(team_request, user.id.id.to_raw());
let create_result = repo.query_create_team(team_schema.clone()).await;
assert!(create_result.is_ok(), "Failed to create team");
let team_thing = make_thing_from_enum(ResourceEnum::Teams, &team_schema.id.id.to_raw());
let team = repo.query_team_by_id(&team_thing).await.unwrap();
let team_id = team_schema.id.id.to_raw();
// Verify team exists before deletion
let exists_before = repo.query_team_by_id(&team_thing).await.is_ok();
assert!(exists_before);
// Delete team through controller
let response = imphnen_iam::TeamsController::delete_team(
&app_state, user.id.id.to_raw(), team_id.clone()
).await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Verify team was deleted from database
let exists_after = repo.query_team_by_id(&team_thing).await.is_ok();
assert!(!exists_after);
// Clean up
let _ = users_repo.query_delete_user(user.id.id.to_raw()).await;
}
#[tokio::test]
async fn test_search_teams_controller() {
let app_state = crate::get_app_state().await;
let users_repo = UsersRepository::new(&app_state);
let repo = TeamsRepository::new(&app_state);
let email = generate_unique_email("team_searcher");
let role_id = get_role_id("mentee", &app_state).await;
let user_data = crate::create_test_user(&email, "password123", true, &role_id);
let user_result = users_repo.query_create_user(user_data.clone()).await;
assert!(user_result.is_ok(), "Failed to create test user");
let user = users_repo.query_user_by_email(email.clone()).await.unwrap();
let team_request = TeamsCreateRequestDto {
name: "Searchable Test Team".to_string(),
description: Some("A team for testing search functionality".to_string()),
is_open: Some(true),
max_members: Some(8),
skills_required: Some(vec!["Rust".to_string(), "Testing".to_string()]),
location: Some("Remote".to_string()),
website_url: None,
github_url: None,
avatar: None,
member_emails: vec![],
};
// Create team directly for testing
let team_schema = TeamsSchema::create(team_request, user.id.id.to_raw());
let create_result = repo.query_create_team(team_schema.clone()).await;
assert!(create_result.is_ok(), "Failed to create team");
let team_id = team_schema.id.id.to_raw();
// Prepare search request
let search_params = TeamsSearchQueryDto {
query: Some("Searchable".to_string()),
open: Some(true),
skills: Some(vec!["Rust".to_string()]),
location: Some("Remote".to_string()),
page: Some(1),
per_page: Some(10),
};
// Search teams through controller
let response = imphnen_iam::TeamsController::search_teams(
&app_state, search_params
).await;
// Verify response
assert_eq!(response.status(), StatusCode::OK);
// Clean up
let _ = repo.query_delete_team(team_id).await;
let _ = users_repo.query_delete_user(user.id.id.to_raw()).await;
}
}
@@ -0,0 +1,52 @@
#[cfg(test)]
mod tests {
use crate::{generate_unique_email, get_role_id, UsersRepository};
use axum::{http::StatusCode, response::Response};
use imphnen_iam::{
UsersCreateRequestDto, UsersUpdateRequestDto, UsersSchema, ResourceEnum,
UsersActiveInactiveRequestDto, UsersSetNewPasswordRequestDto
};
use imphnen_utils::{make_thing_from_enum, ResourceEnum as UtilsResourceEnum};
use uuid::Uuid;
#[tokio::test]
async fn test_create_user_controller() {
let app_state = crate::get_app_state().await;
let repo = UsersRepository::new(&app_state);
let role_id = get_role_id("mentee", &app_state).await;
// Test data
let email = generate_unique_email("test_user_controller");
let user_request = UsersCreateRequestDto {
email: email.clone(),
password: "password123".to_string(),
fullname: "Test User Controller".to_string(),
phone_number: Some("+1234567890".to_string()),
is_active: true,
avatar: None,
role_id: role_id,
};
// Create user through controller
let response = imphnen_iam::UsersController::create_user(
&app_state,
user_request.clone(),
)
.await;
// Verify response
assert_eq!(response.status(), StatusCode::CREATED);
// Verify user was created in database
let created_user = repo
.query_user_by_email(email.clone())
.await
.unwrap();
assert_eq!(created_user.email, email);
assert_eq!(created_user.fullname, "Test User Controller");
assert_eq!(created_user.is_active, true);
// Clean up
let _ = repo.query_delete_user(created_user.id.id.to_raw()).await;
}
}