diff --git a/data/auth.sqlite b/data/auth.sqlite index 93a57fc..debfb36 100644 Binary files a/data/auth.sqlite and b/data/auth.sqlite differ diff --git a/markbase-core/tests/user_share_integration.rs b/markbase-core/tests/user_share_integration.rs new file mode 100644 index 0000000..c2ec62a --- /dev/null +++ b/markbase-core/tests/user_share_integration.rs @@ -0,0 +1,188 @@ +use std::path::PathBuf; +use markbase_core::provider::{DataProvider, User, SqliteProvider}; + +#[cfg(test)] +mod integration_tests { + use super::*; + + fn create_test_provider() -> SqliteProvider { + // Use existing auth database for testing (relative to project root) + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let db_path = format!("{}/../data/auth.sqlite", manifest_dir); + SqliteProvider::new(&db_path).unwrap() + } + + #[tokio::test] + async fn test_user_workflow() { + let provider = create_test_provider(); + + // Use unique username to avoid conflicts + let unique_name = format!("testuser_{}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs()); + + // 1. Create user + let user = User { + username: unique_name.clone(), + password_hash: "".to_string(), + home_dir: PathBuf::from("/tmp/testuser"), + uid: 1000, + gid: 1000, + permissions: "read,write".to_string(), + status: 1, + }; + + provider.create_user(&user, "testpassword123").unwrap(); + + // 2. Check user exists + let loaded_user = provider.get_user(&unique_name).unwrap().unwrap(); + assert_eq!(loaded_user.username, unique_name); + assert_eq!(loaded_user.home_dir, PathBuf::from("/tmp/testuser")); + assert_eq!(loaded_user.status, 1); + + // 3. Verify password + assert!(provider.check_password(&unique_name, "testpassword123").unwrap()); + assert!(!provider.check_password(&unique_name, "wrongpassword").unwrap()); + + // 4. Get home directory + let home_dir = provider.get_home_dir(&unique_name).unwrap().unwrap(); + assert_eq!(home_dir, "/tmp/testuser"); + + // 5. Update user + let updated_user = User { + username: unique_name.clone(), + password_hash: "".to_string(), + home_dir: PathBuf::from("/tmp/testuser_updated"), + uid: 1001, + gid: 1001, + permissions: "read".to_string(), + status: 1, + }; + + provider.update_user(&updated_user, None).unwrap(); + + let loaded_user = provider.get_user(&unique_name).unwrap().unwrap(); + assert_eq!(loaded_user.home_dir, PathBuf::from("/tmp/testuser_updated")); + assert_eq!(loaded_user.uid, 1001); + + // 6. Reset password + provider.reset_password(&unique_name, "newpassword456").unwrap(); + assert!(provider.check_password(&unique_name, "newpassword456").unwrap()); + assert!(!provider.check_password(&unique_name, "testpassword123").unwrap()); + + // 7. List users + let users = provider.list_users().unwrap(); + assert!(users.len() >= 1); + assert!(users.iter().any(|u| u.username == unique_name)); + + // 8. Delete user + provider.delete_user(&unique_name).unwrap(); + assert!(provider.get_user(&unique_name).unwrap().is_none()); + } + + #[tokio::test] + async fn test_multiple_users() { + let provider = create_test_provider(); + + // Use unique usernames to avoid conflicts + let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + let users_data = vec![ + (format!("alice_{}", timestamp), "/tmp/alice_home", "alicepass"), + (format!("bob_{}", timestamp), "/tmp/bob_home", "bobpass"), + (format!("charlie_{}", timestamp), "/tmp/charlie_home", "charliepass"), + ]; + + for (username, home_dir, password) in &users_data { + let user = User { + username: username.clone(), + password_hash: "".to_string(), + home_dir: PathBuf::from(home_dir), + uid: 1000, + gid: 1000, + permissions: "read,write".to_string(), + status: 1, + }; + + provider.create_user(&user, password).unwrap(); + } + + // 2. List all users + let loaded_users = provider.list_users().unwrap(); + assert!(loaded_users.len() >= 3); + + // 3. Verify each user + for (username, home_dir, password) in &users_data { + let user = provider.get_user(username).unwrap().unwrap(); + assert_eq!(user.home_dir, PathBuf::from(home_dir)); + assert!(provider.check_password(username, password).unwrap()); + } + + // 4. Cleanup + for (username, _, _) in &users_data { + provider.delete_user(username).unwrap(); + } + + let remaining_users = provider.list_users().unwrap(); + assert!(!remaining_users.iter().any(|u| users_data.iter().any(|(name, _, _)| name == &u.username))); + } + + #[tokio::test] + async fn test_user_permissions() { + let provider = create_test_provider(); + + // Use unique usernames to avoid conflicts + let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + + // 1. Create admin user + let admin = User { + username: format!("admin_{}", timestamp), + password_hash: "".to_string(), + home_dir: PathBuf::from("/tmp/admin_home"), + uid: 1000, + gid: 1000, + permissions: "read,write,delete,admin".to_string(), + status: 1, + }; + + provider.create_user(&admin, "adminpass").unwrap(); + + // 2. Create regular user + let regular = User { + username: format!("regular_{}", timestamp), + password_hash: "".to_string(), + home_dir: PathBuf::from("/tmp/regular_home"), + uid: 1001, + gid: 1001, + permissions: "read".to_string(), + status: 1, + }; + + provider.create_user(®ular, "regularpass").unwrap(); + + // 3. Verify permissions + let admin_user = provider.get_user(&format!("admin_{}", timestamp)).unwrap().unwrap(); + assert!(admin_user.permissions.contains("admin")); + + let regular_user = provider.get_user(&format!("regular_{}", timestamp)).unwrap().unwrap(); + assert!(regular_user.permissions.contains("read")); + assert!(!regular_user.permissions.contains("admin")); + + // 4. Update regular user permissions + let updated_regular = User { + username: format!("regular_{}", timestamp), + password_hash: "".to_string(), + home_dir: PathBuf::from("/tmp/regular_home"), + uid: 1001, + gid: 1001, + permissions: "read,write".to_string(), + status: 1, + }; + + provider.update_user(&updated_regular, None).unwrap(); + + let regular_user = provider.get_user(&format!("regular_{}", timestamp)).unwrap().unwrap(); + assert!(regular_user.permissions.contains("write")); + + // 5. Cleanup + provider.delete_user(&format!("admin_{}", timestamp)).unwrap(); + provider.delete_user(&format!("regular_{}", timestamp)).unwrap(); + } +} \ No newline at end of file