use super::*;
use crate::session::{insert_test_session, insert_test_user};
use crate::test_utils::init_test_environment;
use chrono::Utc;
use serial_test::serial;
async fn create_test_admin_with_session(
user_id: &str,
account: &str,
label: &str,
) -> Result<String, Box<dyn std::error::Error>> {
insert_test_user(
UserId::new(user_id.to_string()).expect("Valid user ID"),
account,
label,
true,
)
.await?;
let session_id = format!("test-session-{user_id}");
let csrf_token = "test-csrf-token";
insert_test_session(
SessionId::new(session_id.clone()).expect("Valid session ID"),
UserId::new(user_id.to_string()).expect("Valid user ID"),
csrf_token,
3600,
)
.await?;
Ok(session_id)
}
async fn create_test_user_in_db(
id: &str,
is_admin: bool,
) -> Result<User, Box<dyn std::error::Error>> {
let now = Utc::now();
let user = User {
sequence_number: None,
id: id.to_string(),
account: format!("{id}@example.com"),
label: format!("Test User {id}"),
is_admin,
created_at: now,
updated_at: now,
};
let saved_user = UserStore::upsert_user(user.clone())
.await
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
Ok(saved_user)
}
async fn delete_user_if_exists_and_not_first(user_id: &str) -> Result<(), CoordinationError> {
if let Ok(Some(user)) =
UserStore::get_user(UserId::new(user_id.to_string()).expect("Valid user ID")).await
{
if user.sequence_number != Some(1) {
UserStore::delete_user(UserId::new(user_id.to_string()).expect("Valid user ID"))
.await?;
}
}
Ok(())
}
#[serial]
#[tokio::test]
async fn test_get_all_users() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin_user_id = format!("test-admin-{timestamp}");
let user1_id = format!("test-user-1-{timestamp}");
let user2_id = format!("test-user-2-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Test Admin",
)
.await
.expect("Failed to create admin session");
create_test_user_in_db(&user1_id, false)
.await
.expect("Failed to create test user 1");
create_test_user_in_db(&user2_id, false)
.await
.expect("Failed to create test user 2");
let users =
get_all_users(SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"))
.await
.expect("Failed to get all users");
let user_ids: Vec<String> = users.iter().map(|u| u.id.clone()).collect();
assert!(
user_ids.contains(&admin_user_id),
"Admin user should be in the result"
);
assert!(
user_ids.contains(&user1_id),
"User 1 should be in the result"
);
assert!(
user_ids.contains(&user2_id),
"User 2 should be in the result"
);
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
delete_user_if_exists_and_not_first(&user1_id).await.ok();
delete_user_if_exists_and_not_first(&user2_id).await.ok();
}
#[serial]
#[tokio::test]
async fn test_get_user() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin_user_id = format!("test-admin-get-{timestamp}");
let target_user_id = format!("test-get-user-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Test Admin",
)
.await
.expect("Failed to create admin session");
let _created_user = create_test_user_in_db(&target_user_id, false)
.await
.expect("Failed to create test user");
let user_option = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await
.expect("Failed to get user");
assert!(user_option.is_some(), "User should be found");
let user = user_option.unwrap();
assert_eq!(user.id, target_user_id, "User ID should match");
assert_eq!(
user.account,
format!("{target_user_id}@example.com"),
"User account should match"
);
assert_eq!(
user.label,
format!("Test User {target_user_id}"),
"User label should match"
);
let non_existent_user_id = format!("non-existent-user-{timestamp}");
let non_existent_user_option = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(non_existent_user_id.clone()).expect("Valid non-existent user ID"),
)
.await
.expect("Failed to get non-existent user");
assert!(
non_existent_user_option.is_none(),
"Non-existent user should not be found"
);
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
delete_user_if_exists_and_not_first(&target_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_delete_user_account_admin() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin_user_id = format!("test-admin-delete-{timestamp}");
let user_to_delete_id = format!("test-user-to-delete-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Test Admin",
)
.await
.expect("Failed to create admin session");
create_test_user_in_db(&user_to_delete_id, false)
.await
.expect("Failed to create test user");
let user_before = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(user_to_delete_id.clone()).expect("Valid user to delete ID"),
)
.await
.expect("Failed to get user");
assert!(user_before.is_some(), "User should exist before deletion");
let result = delete_user_account_admin(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(user_to_delete_id.clone()).expect("Valid user to delete ID"),
)
.await;
assert!(result.is_ok(), "Expected successful user deletion");
let user_after = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(user_to_delete_id.clone()).expect("Valid user to delete ID"),
)
.await
.expect("Failed to get user after deletion");
assert!(user_after.is_none(), "User should not exist after deletion");
let non_existent_user_id = format!("non-existent-user-{timestamp}");
let result = delete_user_account_admin(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(non_existent_user_id.clone()).expect("Valid non-existent user ID"),
)
.await;
assert!(
result.is_err(),
"Deleting non-existent user should return an error"
);
match result {
Err(CoordinationError::ResourceNotFound {
resource_type,
resource_id,
}) => {
assert_eq!(
resource_type, "User",
"Error should indicate resource type as User"
);
assert_eq!(
resource_id, non_existent_user_id,
"Error should include the correct user ID"
);
}
_ => panic!("Expected ResourceNotFound error, got {result:?}"),
}
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_update_user_admin_status_success() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin_user_id = format!("admin-user-{timestamp}");
let target_user_id = format!("target-user-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Test Admin",
)
.await
.expect("Failed to create admin session");
create_test_user_in_db(&target_user_id, false)
.await
.expect("Failed to create target user");
let user_before = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await
.expect("Failed to get target user")
.expect("Target user should exist");
assert!(
!user_before.has_admin_privileges(),
"Target user should not have admin privileges initially"
);
let updated_user = update_user_admin_status(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
true,
)
.await
.expect("Failed to update user admin status");
assert!(
updated_user.has_admin_privileges(),
"User should have admin privileges after update"
);
let user_after = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await
.expect("Failed to get target user after update")
.expect("Target user should still exist");
assert!(
user_after.has_admin_privileges(),
"Target user should have admin privileges in the database"
);
let updated_user = update_user_admin_status(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
false,
)
.await
.expect("Failed to update user admin status back");
assert!(
!updated_user.has_admin_privileges(),
"User should not have admin privileges after second update"
);
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
delete_user_if_exists_and_not_first(&target_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_update_user_admin_status_requires_admin() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let non_admin_user_id = format!("non-admin-user-{timestamp}");
let target_user_id = format!("target-user-2-{timestamp}");
insert_test_user(
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
&format!("{non_admin_user_id}@example.com"),
"Non Admin",
false,
)
.await
.expect("Failed to create non-admin user");
let non_admin_session_id = format!("test-session-{non_admin_user_id}");
insert_test_session(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
"csrf-token",
3600,
)
.await
.expect("Failed to create non-admin session");
create_test_user_in_db(&target_user_id, false)
.await
.expect("Failed to create target user");
let result = update_user_admin_status(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
true,
)
.await;
assert!(
result.is_err(),
"Non-admin should not be allowed to update admin status"
);
match result {
Err(CoordinationError::Unauthorized) => {}
_ => panic!("Expected Unauthorized error, got {result:?}"),
}
let admin_user_id = format!("temp-admin-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Temp Admin",
)
.await
.expect("Failed to create temp admin session");
let user_after = get_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await
.expect("Failed to get target user after failed update")
.expect("Target user should still exist");
assert!(
!user_after.has_admin_privileges(),
"Target user's admin privileges should not have changed"
);
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
delete_user_if_exists_and_not_first(&target_user_id)
.await
.ok();
delete_user_if_exists_and_not_first(&non_admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_demote_first_user_prevented() {
init_test_environment().await;
let first_user_session_id = "test-session-first-user-demote";
insert_test_session(
SessionId::new(first_user_session_id.to_string()).expect("Valid session ID"),
UserId::new("first-user".to_string()).expect("Valid user ID"),
"test-csrf-token",
3600,
)
.await
.expect("Failed to create session for first user");
let result = update_user_admin_status(
SessionId::new(first_user_session_id.to_string()).expect("Valid session ID"),
UserId::new("first-user".to_string()).expect("Valid user ID"),
false,
)
.await;
assert!(
result.is_err(),
"Should not be able to demote the first user"
);
match result {
Err(CoordinationError::Conflict(msg)) => {
assert!(
msg.contains("Cannot demote the first user"),
"Error message should mention first user demotion, got: {msg}"
);
}
_ => panic!("Expected Conflict error about first user, got {result:?}"),
}
}
#[serial]
#[tokio::test]
async fn test_demote_first_user_prevented_even_with_other_admins() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let other_admin_id = format!("other-admin-demote-first-{timestamp}");
create_test_user_in_db(&other_admin_id, true)
.await
.expect("Failed to create other admin");
let other_admin_session_id = format!("session-other-admin-{timestamp}");
insert_test_session(
SessionId::new(other_admin_session_id.clone()).expect("Valid session ID"),
UserId::new(other_admin_id.clone()).expect("Valid user ID"),
"test-csrf-token",
3600,
)
.await
.expect("Failed to create session for other admin");
let result = update_user_admin_status(
SessionId::new(other_admin_session_id).expect("Valid session ID"),
UserId::new("first-user".to_string()).expect("Valid user ID"),
false,
)
.await;
assert!(
result.is_err(),
"Should not be able to demote the first user even when other admins exist"
);
match result {
Err(CoordinationError::Conflict(msg)) => {
assert!(
msg.contains("Cannot demote the first user"),
"Error message should mention first user demotion, got: {msg}"
);
}
_ => panic!("Expected Conflict error about first user, got {result:?}"),
}
delete_user_if_exists_and_not_first(&other_admin_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_demote_admin_allowed_when_others_exist() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin1_id = format!("admin1-demote-{timestamp}");
let admin2_id = format!("admin2-demote-{timestamp}");
let admin_session_id =
create_test_admin_with_session(&admin1_id, &format!("{admin1_id}@example.com"), "Admin 1")
.await
.expect("Failed to create admin 1 session");
create_test_user_in_db(&admin2_id, true)
.await
.expect("Failed to create admin 2");
let result = update_user_admin_status(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(admin2_id.clone()).expect("Valid admin2 user ID"),
false,
)
.await;
assert!(
result.is_ok(),
"Should be able to demote admin when other admins exist, got: {result:?}"
);
let updated_user = result.unwrap();
assert!(
!updated_user.is_admin,
"Demoted user should no longer be admin"
);
delete_user_if_exists_and_not_first(&admin1_id).await.ok();
delete_user_if_exists_and_not_first(&admin2_id).await.ok();
}
#[serial]
#[tokio::test]
async fn test_delete_passkey_credential_admin_requires_admin() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let non_admin_user_id = format!("non-admin-user-passkey-{timestamp}");
insert_test_user(
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
&format!("{non_admin_user_id}@example.com"),
"Non Admin",
false,
)
.await
.expect("Failed to create non-admin user");
let non_admin_session_id = format!("test-session-{non_admin_user_id}");
insert_test_session(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
"csrf-token",
3600,
)
.await
.expect("Failed to create non-admin session");
let result = delete_passkey_credential_admin(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
CredentialId::new("credential1".to_string()).expect("Valid test credential ID"),
)
.await;
assert!(result.is_err());
match result {
Err(CoordinationError::Unauthorized) => {}
_ => panic!("Expected Unauthorized error, got: {result:?}"),
}
delete_user_if_exists_and_not_first(&non_admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_delete_oauth2_account_admin_requires_admin() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let non_admin_user_id = format!("non-admin-user-oauth2-{timestamp}");
insert_test_user(
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
&format!("{non_admin_user_id}@example.com"),
"Non Admin",
false,
)
.await
.expect("Failed to create non-admin user");
let non_admin_session_id = format!("test-session-{non_admin_user_id}");
insert_test_session(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
"csrf-token",
3600,
)
.await
.expect("Failed to create non-admin session");
let result = delete_oauth2_account_admin(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
ProviderUserId::new("provider_user_id".to_string()).expect("Valid test provider user ID"),
)
.await;
assert!(result.is_err());
match result {
Err(CoordinationError::Unauthorized) => {}
_ => panic!("Expected Unauthorized error, got: {result:?}"),
}
delete_user_if_exists_and_not_first(&non_admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_get_all_active_sessions_requires_admin() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let non_admin_user_id = format!("non-admin-all-sessions-{timestamp}");
insert_test_user(
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
&format!("{non_admin_user_id}@example.com"),
"Non Admin",
false,
)
.await
.expect("Failed to create non-admin user");
let non_admin_session_id = format!("test-session-{non_admin_user_id}");
insert_test_session(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
"csrf-token",
3600,
)
.await
.expect("Failed to create non-admin session");
let result = get_all_active_sessions(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
)
.await;
assert!(result.is_err());
match result {
Err(CoordinationError::Unauthorized) => {}
_ => panic!("Expected Unauthorized error, got: {result:?}"),
}
delete_user_if_exists_and_not_first(&non_admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_force_logout_user_requires_admin() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let non_admin_user_id = format!("non-admin-force-logout-{timestamp}");
let target_user_id = format!("target-force-logout-{timestamp}");
insert_test_user(
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
&format!("{non_admin_user_id}@example.com"),
"Non Admin",
false,
)
.await
.expect("Failed to create non-admin user");
let non_admin_session_id = format!("test-session-{non_admin_user_id}");
insert_test_session(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(non_admin_user_id.clone()).expect("Valid non-admin user ID"),
"csrf-token",
3600,
)
.await
.expect("Failed to create non-admin session");
let result = force_logout_user(
SessionId::new(non_admin_session_id.clone()).expect("Valid non-admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await;
assert!(result.is_err());
match result {
Err(CoordinationError::Unauthorized) => {}
_ => panic!("Expected Unauthorized error, got: {result:?}"),
}
delete_user_if_exists_and_not_first(&non_admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_get_all_active_sessions_success() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin_user_id = format!("admin-all-sessions-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Test Admin",
)
.await
.expect("Failed to create admin session");
let sessions = get_all_active_sessions(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
)
.await
.expect("Failed to get all active sessions");
assert!(
sessions.contains_key(&admin_user_id),
"Admin user should have at least one session"
);
assert!(
*sessions.get(&admin_user_id).unwrap_or(&0) >= 1,
"Admin user should have at least 1 active session"
);
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_force_logout_user_success() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin_user_id = format!("admin-force-logout-success-{timestamp}");
let target_user_id = format!("target-logout-success-{timestamp}");
let admin_session_id = create_test_admin_with_session(
&admin_user_id,
&format!("{admin_user_id}@example.com"),
"Test Admin",
)
.await
.expect("Failed to create admin session");
insert_test_user(
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
&format!("{target_user_id}@example.com"),
"Target User",
false,
)
.await
.expect("Failed to create target user");
let target_session_id = format!("test-session-{target_user_id}");
insert_test_session(
SessionId::new(target_session_id.clone()).expect("Valid target session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
"csrf-token-target",
3600,
)
.await
.expect("Failed to create target session");
let terminated_count = force_logout_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await
.expect("Failed to force logout user");
assert_eq!(
terminated_count, 1,
"Exactly 1 session should have been terminated"
);
let terminated_count_again = force_logout_user(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(target_user_id.clone()).expect("Valid target user ID"),
)
.await
.expect("Failed to force logout user again");
assert_eq!(
terminated_count_again, 0,
"No sessions should remain after force logout"
);
delete_user_if_exists_and_not_first(&admin_user_id)
.await
.ok();
delete_user_if_exists_and_not_first(&target_user_id)
.await
.ok();
}
#[serial]
#[tokio::test]
async fn test_delete_last_admin_prevented() {
init_test_environment().await;
let first_user_session_id = "test-session-first-user-delete";
insert_test_session(
SessionId::new(first_user_session_id.to_string()).expect("Valid session ID"),
UserId::new("first-user".to_string()).expect("Valid user ID"),
"test-csrf-token",
3600,
)
.await
.expect("Failed to create session for first user");
let result = delete_user_account_admin(
SessionId::new(first_user_session_id.to_string()).expect("Valid session ID"),
UserId::new("first-user".to_string()).expect("Valid user ID"),
)
.await;
assert!(
result.is_err(),
"Should not be able to delete the last admin"
);
match result {
Err(CoordinationError::Conflict(msg)) => {
assert!(
msg.contains("Cannot delete the last admin user"),
"Error message should mention last admin deletion, got: {msg}"
);
}
_ => panic!("Expected Conflict error about last admin, got {result:?}"),
}
}
#[serial]
#[tokio::test]
async fn test_delete_admin_allowed_when_others_exist() {
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin1_id = format!("admin1-delete-ok-{timestamp}");
let admin2_id = format!("admin2-delete-ok-{timestamp}");
let admin_session_id =
create_test_admin_with_session(&admin1_id, &format!("{admin1_id}@example.com"), "Admin 1")
.await
.expect("Failed to create admin 1 session");
create_test_user_in_db(&admin2_id, true)
.await
.expect("Failed to create admin 2");
let result = delete_user_account_admin(
SessionId::new(admin_session_id.clone()).expect("Valid admin session ID"),
UserId::new(admin2_id.clone()).expect("Valid admin2 user ID"),
)
.await;
assert!(
result.is_ok(),
"Should be able to delete admin when other admins exist, got: {result:?}"
);
let deleted_user = UserStore::get_user(UserId::new(admin2_id.clone()).expect("Valid user ID"))
.await
.expect("Failed to query user");
assert!(
deleted_user.is_none(),
"Deleted admin user should no longer exist"
);
delete_user_if_exists_and_not_first(&admin1_id).await.ok();
}
#[serial]
#[tokio::test]
async fn test_last_admin_protected_after_first_user_deleted() {
use crate::test_utils::restore_first_user_after_deletion;
init_test_environment().await;
let timestamp = chrono::Utc::now().timestamp_millis();
let admin2_id = format!("admin2-post-first-delete-{timestamp}");
let admin2_session_id =
create_test_admin_with_session(&admin2_id, &format!("{admin2_id}@example.com"), "Admin 2")
.await
.expect("Failed to create admin 2 session");
let delete_result = delete_user_account_admin(
SessionId::new(admin2_session_id.clone()).expect("Valid session ID"),
UserId::new("first-user".to_string()).expect("Valid user ID"),
)
.await;
assert!(
delete_result.is_ok(),
"Should be able to delete first-user when other admin exists, got: {delete_result:?}"
);
let first_user =
UserStore::get_user(UserId::new("first-user".to_string()).expect("Valid user ID"))
.await
.expect("Failed to query user");
assert!(first_user.is_none(), "First user should be deleted");
let delete_last_result = delete_user_account_admin(
SessionId::new(admin2_session_id.clone()).expect("Valid session ID"),
UserId::new(admin2_id.clone()).expect("Valid user ID"),
)
.await;
assert!(
delete_last_result.is_err(),
"Should not be able to delete the last admin after first-user is gone"
);
match delete_last_result {
Err(CoordinationError::Conflict(msg)) => {
assert!(
msg.contains("Cannot delete the last admin user"),
"Expected last admin deletion error, got: {msg}"
);
}
_ => panic!("Expected Conflict error about last admin, got {delete_last_result:?}"),
}
let demote_result = update_user_admin_status(
SessionId::new(admin2_session_id.clone()).expect("Valid session ID"),
UserId::new(admin2_id.clone()).expect("Valid user ID"),
false,
)
.await;
assert!(
demote_result.is_err(),
"Should not be able to demote the last admin after first-user is gone"
);
match demote_result {
Err(CoordinationError::Conflict(msg)) => {
assert!(
msg.contains("Cannot demote the last admin user"),
"Expected last admin demotion error, got: {msg}"
);
}
_ => panic!("Expected Conflict error about last admin demotion, got {demote_result:?}"),
}
restore_first_user_after_deletion().await;
delete_user_if_exists_and_not_first(&admin2_id).await.ok();
}