From a7a01a8e868f8e90e9dedc0c8da7a84d06bf3c11 Mon Sep 17 00:00:00 2001 From: Warren Date: Wed, 24 Jun 2026 06:31:25 +0800 Subject: [PATCH] Add user/share management integration tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integration Tests: - test_user_workflow: Create, update, reset password, delete user - test_multiple_users: Create multiple users, verify list, cleanup - test_user_permissions: Admin vs regular user permissions Test Features: - Unique usernames (timestamp-based) to avoid conflicts - Using existing data/auth.sqlite database - Cleanup after each test - Password verification - Permission checking Test Coverage: - create_user() + bcrypt password hashing - get_user() + user data verification - check_password() + correct/wrong password tests - update_user() + home_dir, uid, permissions update - reset_password() + password change verification - list_users() + multiple users list - delete_user() + cleanup verification Build: ✅ markbase-core Tests: 3 passed, 0 failed --- data/auth.sqlite | Bin 81920 -> 81920 bytes markbase-core/tests/user_share_integration.rs | 188 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 markbase-core/tests/user_share_integration.rs diff --git a/data/auth.sqlite b/data/auth.sqlite index 93a57fc75512cab820822f35a26f4b76565e71f9..debfb36f088bfd7dc1a42d12742d386b9e8e1371 100644 GIT binary patch delta 1056 zcmZuvOHUI~6zK`yTybTEwwvS2L%%}>MumDc z4?CR3u@1M5bg&+K#Nf~mSX_2mm+X#tMqB5mI;Z=+uJ`~Ia!*IQtbLwl&T5(qX*njQ zErtw689G6G1NUbVA&v%z;4meVVT(pFzoqgtKS#4%lBE-u1;itR4CVEEW_nCdrgcWn z9c8ozYDhoAIQ@M?gA-jwv(sjAM@Ta6CBx5WgHx@Yy^?^ln8{ec%h3T*1ULdmv#G2V zHi_vQi{*PGA^(4hpN|_UM=0i+oaps2b~j6o%=TNT`5lq#)%cY}USHM&ud0U}&F8csBh-&T?)%c>m%YBGVm=oQk!<(Rbx*45K z@3K0{R*G`?*fDKKc)lZOvh^7I2Ti8Yd7ar79|#*KI7-qYhP$9dE=@uBUR{b~CjN7E z9Z%HkDcVY@MIvh!j%(zY__6RZ+rt04`@0cgaYu@$41rSk7KiWQG5i3(!5z3;G(l6> z0H0O?Jzkvt--RMRA)@VUDCd4`RDve_-w_b&*Fgh*u@%H7vBtmGw%%G%ff}4ai#5e1 z=7?1#sKf&_6D5}UoVJdDD+LoYx;OBq94K)qcLlK_;dSZWWR!xSI6x1O*QnnS{PximEF)|mr7E#;{&9W@pvOWkpNH7~S`K0bUyG^L o;F@adwL*t!aMc!?0zt2m84)VgLXD delta 318 zcmZo@U~On%ogmG4bE1qh9FnfyXVVe>;NHYP?xAoDl7)erk7 zj)}&bU&*pEf;f$J6OAT+ll!d-q2SAL75TS<#@6fAS)I zOUX^V%(6_m`MIfiB}J7Sn>m?9nNm`7^Eoz7{-Uq2SukNI|Kzjw;sTpknK_v_HZw4= zfEmcL{+P0xzxe<6=W9W71OwM*#)ALyn+~uDFt>2~Y-Yc}$q4kC4cBI$+dEj8TR0DF zW`6(@64=18`M}G1QO3B*4*xeY1O2l3%m4rUjQ6&G;b(-<@{9rk%mTdkr?VR{Dgq7J M&b$4-Eu$h60FS_C*8l(j 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