summaryrefslogtreecommitdiff
path: root/crates/vcs_data/vcs_data_test/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/vcs_data/vcs_data_test/src')
-rw-r--r--crates/vcs_data/vcs_data_test/src/lib.rs27
-rw-r--r--crates/vcs_data/vcs_data_test/src/test_local_workspace_setup_and_account_management.rs248
-rw-r--r--crates/vcs_data/vcs_data_test/src/test_sheet_creation_management_and_persistence.rs307
-rw-r--r--crates/vcs_data/vcs_data_test/src/test_vault_setup_and_member_register.rs67
-rw-r--r--crates/vcs_data/vcs_data_test/src/test_virtual_file_creation_and_update.rs162
5 files changed, 811 insertions, 0 deletions
diff --git a/crates/vcs_data/vcs_data_test/src/lib.rs b/crates/vcs_data/vcs_data_test/src/lib.rs
new file mode 100644
index 0000000..8ad03e1
--- /dev/null
+++ b/crates/vcs_data/vcs_data_test/src/lib.rs
@@ -0,0 +1,27 @@
+use std::{env::current_dir, path::PathBuf};
+
+use tokio::fs;
+
+#[cfg(test)]
+pub mod test_vault_setup_and_member_register;
+
+#[cfg(test)]
+pub mod test_virtual_file_creation_and_update;
+
+#[cfg(test)]
+pub mod test_local_workspace_setup_and_account_management;
+
+#[cfg(test)]
+pub mod test_sheet_creation_management_and_persistence;
+
+pub async fn get_test_dir(area: &str) -> Result<PathBuf, std::io::Error> {
+ let dir = current_dir()?.join(".temp").join("test").join(area);
+ if !dir.exists() {
+ std::fs::create_dir_all(&dir)?;
+ } else {
+ // Regenerate existing directory
+ fs::remove_dir_all(&dir).await?;
+ fs::create_dir_all(&dir).await?;
+ }
+ Ok(dir)
+}
diff --git a/crates/vcs_data/vcs_data_test/src/test_local_workspace_setup_and_account_management.rs b/crates/vcs_data/vcs_data_test/src/test_local_workspace_setup_and_account_management.rs
new file mode 100644
index 0000000..2718d01
--- /dev/null
+++ b/crates/vcs_data/vcs_data_test/src/test_local_workspace_setup_and_account_management.rs
@@ -0,0 +1,248 @@
+use std::io::Error;
+
+use cfg_file::config::ConfigFile;
+use vcs_data::{
+ constants::{CLIENT_FILE_README, CLIENT_FILE_WORKSPACE, USER_FILE_KEY, USER_FILE_MEMBER},
+ data::{
+ local::{LocalWorkspace, config::LocalConfig},
+ member::Member,
+ user::UserDirectory,
+ },
+};
+
+use crate::get_test_dir;
+
+#[tokio::test]
+async fn test_local_workspace_setup_and_account_management() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("local_workspace_account_management").await?;
+
+ // Setup local workspace
+ LocalWorkspace::setup_local_workspace(dir.clone()).await?;
+
+ // Check if the following files are created in `dir`:
+ // Files: CLIENT_FILE_WORKSPACE, CLIENT_FILE_README
+ assert!(dir.join(CLIENT_FILE_WORKSPACE).exists());
+ assert!(dir.join(CLIENT_FILE_README).exists());
+
+ // Get local workspace
+ let config = LocalConfig::read_from(dir.join(CLIENT_FILE_WORKSPACE)).await?;
+ let Some(_local_workspace) = LocalWorkspace::init(config, &dir) else {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ "Local workspace not found!",
+ ));
+ };
+
+ // Create user directory from workspace path
+ let Some(user_directory) = UserDirectory::from_path(&dir) else {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ "User directory not found!",
+ ));
+ };
+
+ // Test account registration
+ let member_id = "test_account";
+ let member = Member::new(member_id);
+
+ // Register account
+ user_directory.register_account(member.clone()).await?;
+
+ // Check if the account config file exists
+ assert!(
+ dir.join(USER_FILE_MEMBER.replace("{self_id}", member_id))
+ .exists()
+ );
+
+ // Test account retrieval
+ let retrieved_member = user_directory.account(&member_id.to_string()).await?;
+ assert_eq!(retrieved_member.id(), member.id());
+
+ // Test account IDs listing
+ let account_ids = user_directory.account_ids()?;
+ assert!(account_ids.contains(&member_id.to_string()));
+
+ // Test accounts listing
+ let accounts = user_directory.accounts().await?;
+ assert_eq!(accounts.len(), 1);
+ assert_eq!(accounts[0].id(), member.id());
+
+ // Test account existence check
+ assert!(user_directory.account_cfg(&member_id.to_string()).is_some());
+
+ // Test private key check (should be false initially)
+ assert!(!user_directory.has_private_key(&member_id.to_string()));
+
+ // Test account update
+ let mut updated_member = member.clone();
+ updated_member.set_metadata("email", "test@example.com");
+ user_directory
+ .update_account(updated_member.clone())
+ .await?;
+
+ // Verify update
+ let updated_retrieved = user_directory.account(&member_id.to_string()).await?;
+ assert_eq!(
+ updated_retrieved.metadata("email"),
+ Some(&"test@example.com".to_string())
+ );
+
+ // Test account removal
+ user_directory.remove_account(&member_id.to_string())?;
+
+ // Check if the account config file no longer exists
+ assert!(
+ !dir.join(USER_FILE_MEMBER.replace("{self_id}", member_id))
+ .exists()
+ );
+
+ // Check if account is no longer in the list
+ let account_ids_after_removal = user_directory.account_ids()?;
+ assert!(!account_ids_after_removal.contains(&member_id.to_string()));
+
+ Ok(())
+}
+
+#[tokio::test]
+async fn test_account_private_key_management() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("account_private_key_management").await?;
+
+ // Create user directory
+ let Some(user_directory) = UserDirectory::from_path(&dir) else {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ "User directory not found!",
+ ));
+ };
+
+ // Register account
+ let member_id = "test_account_with_key";
+ let member = Member::new(member_id);
+ user_directory.register_account(member).await?;
+
+ // Create a dummy private key file for testing
+ let private_key_path = dir.join(USER_FILE_KEY.replace("{self_id}", member_id));
+ std::fs::create_dir_all(private_key_path.parent().unwrap())?;
+ std::fs::write(&private_key_path, "dummy_private_key_content")?;
+
+ // Test private key existence check
+ assert!(user_directory.has_private_key(&member_id.to_string()));
+
+ // Test private key path retrieval
+ assert!(
+ user_directory
+ .account_private_key(&member_id.to_string())
+ .is_some()
+ );
+
+ // Remove account (should also remove private key)
+ user_directory.remove_account(&member_id.to_string())?;
+
+ // Check if private key file is also removed
+ assert!(!private_key_path.exists());
+
+ Ok(())
+}
+
+#[tokio::test]
+async fn test_multiple_account_management() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("multiple_account_management").await?;
+
+ // Create user directory
+ let Some(user_directory) = UserDirectory::from_path(&dir) else {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ "User directory not found!",
+ ));
+ };
+
+ // Register multiple accounts
+ let account_names = vec!["alice", "bob", "charlie"];
+
+ for name in &account_names {
+ user_directory.register_account(Member::new(*name)).await?;
+ }
+
+ // Test account IDs listing
+ let account_ids = user_directory.account_ids()?;
+ assert_eq!(account_ids.len(), 3);
+
+ for name in &account_names {
+ assert!(account_ids.contains(&name.to_string()));
+ }
+
+ // Test accounts listing
+ let accounts = user_directory.accounts().await?;
+ assert_eq!(accounts.len(), 3);
+
+ // Remove one account
+ user_directory.remove_account(&"bob".to_string())?;
+
+ // Verify removal
+ let account_ids_after_removal = user_directory.account_ids()?;
+ assert_eq!(account_ids_after_removal.len(), 2);
+ assert!(!account_ids_after_removal.contains(&"bob".to_string()));
+ assert!(account_ids_after_removal.contains(&"alice".to_string()));
+ assert!(account_ids_after_removal.contains(&"charlie".to_string()));
+
+ Ok(())
+}
+
+#[tokio::test]
+async fn test_account_registration_duplicate_prevention() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("account_duplicate_prevention").await?;
+
+ // Create user directory
+ let Some(user_directory) = UserDirectory::from_path(&dir) else {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ "User directory not found!",
+ ));
+ };
+
+ // Register account
+ let member_id = "duplicate_test";
+ user_directory
+ .register_account(Member::new(member_id))
+ .await?;
+
+ // Try to register same account again - should fail
+ let result = user_directory
+ .register_account(Member::new(member_id))
+ .await;
+ assert!(result.is_err());
+
+ Ok(())
+}
+
+#[tokio::test]
+async fn test_nonexistent_account_operations() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("nonexistent_account_operations").await?;
+
+ // Create user directory
+ let Some(user_directory) = UserDirectory::from_path(&dir) else {
+ return Err(Error::new(
+ std::io::ErrorKind::NotFound,
+ "User directory not found!",
+ ));
+ };
+
+ // Try to read non-existent account - should fail
+ let result = user_directory.account(&"nonexistent".to_string()).await;
+ assert!(result.is_err());
+
+ // Try to update non-existent account - should fail
+ let result = user_directory
+ .update_account(Member::new("nonexistent"))
+ .await;
+ assert!(result.is_err());
+
+ // Try to remove non-existent account - should succeed (idempotent)
+ let result = user_directory.remove_account(&"nonexistent".to_string());
+ assert!(result.is_ok());
+
+ // Check private key for non-existent account - should be false
+ assert!(!user_directory.has_private_key(&"nonexistent".to_string()));
+
+ Ok(())
+}
diff --git a/crates/vcs_data/vcs_data_test/src/test_sheet_creation_management_and_persistence.rs b/crates/vcs_data/vcs_data_test/src/test_sheet_creation_management_and_persistence.rs
new file mode 100644
index 0000000..461d465
--- /dev/null
+++ b/crates/vcs_data/vcs_data_test/src/test_sheet_creation_management_and_persistence.rs
@@ -0,0 +1,307 @@
+use std::io::Error;
+
+use cfg_file::config::ConfigFile;
+use vcs_data::{
+ constants::{SERVER_FILE_SHEET, SERVER_FILE_VAULT},
+ data::{
+ member::{Member, MemberId},
+ sheet::{InputRelativePathBuf, SheetName},
+ vault::{Vault, config::VaultConfig, virtual_file::VirtualFileId},
+ },
+};
+
+use crate::get_test_dir;
+
+#[tokio::test]
+async fn test_sheet_creation_management_and_persistence() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("sheet_management").await?;
+
+ // Setup vault
+ Vault::setup_vault(dir.clone()).await?;
+
+ // Get vault
+ let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?;
+ let Some(vault) = Vault::init(config, &dir) else {
+ return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!"));
+ };
+
+ // Add a member to use as sheet holder
+ let member_id: MemberId = "test_member".to_string();
+ vault
+ .register_member_to_vault(Member::new(&member_id))
+ .await?;
+
+ // Test 1: Create a new sheet
+ let sheet_name: SheetName = "test_sheet".to_string();
+ let sheet = vault.create_sheet(&sheet_name, &member_id).await?;
+
+ // Verify sheet properties
+ assert_eq!(sheet.holder(), &member_id);
+ assert_eq!(sheet.holder(), &member_id);
+ assert!(sheet.inputs().is_empty());
+ assert!(sheet.mapping().is_empty());
+
+ // Verify sheet file was created
+ const SHEET_NAME_PARAM: &str = "{sheet-name}";
+ let sheet_path = dir.join(SERVER_FILE_SHEET.replace(SHEET_NAME_PARAM, &sheet_name));
+ assert!(sheet_path.exists());
+
+ // Test 2: Add input packages to the sheet
+ let input_name = "source_files".to_string();
+
+ // First add mapping entries that will be used to generate the input package
+ let mut sheet = vault.sheet(&sheet_name).await?;
+
+ // Add mapping entries for the files
+ let main_rs_path = vcs_data::data::sheet::SheetPathBuf::from("src/main.rs");
+ let lib_rs_path = vcs_data::data::sheet::SheetPathBuf::from("src/lib.rs");
+ let main_rs_id = VirtualFileId::new();
+ let lib_rs_id = VirtualFileId::new();
+
+ sheet
+ .add_mapping(main_rs_path.clone(), main_rs_id.clone())
+ .await?;
+ sheet
+ .add_mapping(lib_rs_path.clone(), lib_rs_id.clone())
+ .await?;
+
+ // Use output_mappings to generate the InputPackage
+ let paths = vec![main_rs_path, lib_rs_path];
+ let input_package = sheet.output_mappings(input_name.clone(), &paths)?;
+ sheet.add_input(input_package)?;
+
+ // Verify input was added
+ assert_eq!(sheet.inputs().len(), 1);
+ let added_input = &sheet.inputs()[0];
+ assert_eq!(added_input.name, input_name);
+ assert_eq!(added_input.files.len(), 2);
+ assert_eq!(
+ added_input.files[0].0,
+ InputRelativePathBuf::from("source_files/main.rs")
+ );
+ assert_eq!(
+ added_input.files[1].0,
+ InputRelativePathBuf::from("source_files/lib.rs")
+ );
+
+ // Test 3: Add mapping entries
+ let mapping_path = vcs_data::data::sheet::SheetPathBuf::from("output/build.exe");
+ let virtual_file_id = VirtualFileId::new();
+
+ sheet
+ .add_mapping(mapping_path.clone(), virtual_file_id.clone())
+ .await?;
+
+ // Verify mapping was added
+ assert_eq!(sheet.mapping().len(), 3);
+ assert_eq!(sheet.mapping().get(&mapping_path), Some(&virtual_file_id));
+
+ // Test 4: Persist sheet to disk
+ sheet.persist().await?;
+
+ // Verify persistence by reloading the sheet
+ let reloaded_sheet = vault.sheet(&sheet_name).await?;
+ assert_eq!(reloaded_sheet.holder(), &member_id);
+ assert_eq!(reloaded_sheet.inputs().len(), 1);
+ assert_eq!(reloaded_sheet.mapping().len(), 3);
+
+ // Test 5: Remove input package
+ let mut sheet_for_removal = vault.sheet(&sheet_name).await?;
+ let removed_input = sheet_for_removal.deny_input(&input_name);
+ assert!(removed_input.is_some());
+ let removed_input = removed_input.unwrap();
+ assert_eq!(removed_input.name, input_name);
+ assert_eq!(removed_input.files.len(), 2);
+ assert_eq!(sheet_for_removal.inputs().len(), 0);
+
+ // Test 6: Remove mapping entry
+ let _removed_virtual_file_id = sheet_for_removal.remove_mapping(&mapping_path).await;
+ // Don't check the return value since it depends on virtual file existence
+ assert_eq!(sheet_for_removal.mapping().len(), 2);
+
+ // Test 7: List all sheets in vault
+ let sheet_names = vault.sheet_names()?;
+ assert_eq!(sheet_names.len(), 2);
+ assert!(sheet_names.contains(&sheet_name));
+ assert!(sheet_names.contains(&"ref".to_string()));
+
+ let all_sheets = vault.sheets().await?;
+ assert_eq!(all_sheets.len(), 2);
+ // One sheet should be the test sheet, the other should be the ref sheet with host as holder
+ let test_sheet_holder = all_sheets
+ .iter()
+ .find(|s| s.holder() == &member_id)
+ .map(|s| s.holder())
+ .unwrap();
+ let ref_sheet_holder = all_sheets
+ .iter()
+ .find(|s| s.holder() == &"host".to_string())
+ .map(|s| s.holder())
+ .unwrap();
+ assert_eq!(test_sheet_holder, &member_id);
+ assert_eq!(ref_sheet_holder, &"host".to_string());
+
+ // Test 8: Safe deletion (move to trash)
+ vault.delete_sheet_safely(&sheet_name).await?;
+
+ // Verify sheet is not in normal listing but can be restored
+ let sheet_names_after_deletion = vault.sheet_names()?;
+ assert_eq!(sheet_names_after_deletion.len(), 1);
+ assert_eq!(sheet_names_after_deletion[0], "ref");
+
+ // Test 9: Restore sheet from trash
+ let restored_sheet = vault.sheet(&sheet_name).await?;
+ assert_eq!(restored_sheet.holder(), &member_id);
+ assert_eq!(restored_sheet.holder(), &member_id);
+
+ // Verify sheet is back in normal listing
+ let sheet_names_after_restore = vault.sheet_names()?;
+ assert_eq!(sheet_names_after_restore.len(), 2);
+ assert!(sheet_names_after_restore.contains(&sheet_name));
+ assert!(sheet_names_after_restore.contains(&"ref".to_string()));
+
+ // Test 10: Permanent deletion
+ vault.delete_sheet(&sheet_name).await?;
+
+ // Verify sheet is permanently gone
+ let sheet_names_final = vault.sheet_names()?;
+ assert_eq!(sheet_names_final.len(), 1);
+ assert_eq!(sheet_names_final[0], "ref");
+
+ // Attempt to access deleted sheet should fail
+ let result = vault.sheet(&sheet_name).await;
+ assert!(result.is_err());
+
+ // Clean up: Remove member
+ vault.remove_member_from_vault(&member_id)?;
+
+ Ok(())
+}
+
+#[tokio::test]
+async fn test_sheet_error_conditions() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("sheet_error_conditions").await?;
+
+ // Setup vault
+ Vault::setup_vault(dir.clone()).await?;
+
+ // Get vault
+ let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?;
+ let Some(vault) = Vault::init(config, &dir) else {
+ return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!"));
+ };
+
+ // Test 1: Create sheet with non-existent member should fail
+ let non_existent_member: MemberId = "non_existent_member".to_string();
+ let sheet_name: SheetName = "test_sheet".to_string();
+
+ let result = vault.create_sheet(&sheet_name, &non_existent_member).await;
+ assert!(result.is_err());
+
+ // Add a member first
+ let member_id: MemberId = "test_member".to_string();
+ vault
+ .register_member_to_vault(Member::new(&member_id))
+ .await?;
+
+ // Test 2: Create duplicate sheet should fail
+ vault.create_sheet(&sheet_name, &member_id).await?;
+ let result = vault.create_sheet(&sheet_name, &member_id).await;
+ assert!(result.is_err());
+
+ // Test 3: Delete non-existent sheet should fail
+ let non_existent_sheet: SheetName = "non_existent_sheet".to_string();
+ let result = vault.delete_sheet(&non_existent_sheet).await;
+ assert!(result.is_err());
+
+ // Test 4: Safe delete non-existent sheet should fail
+ let result = vault.delete_sheet_safely(&non_existent_sheet).await;
+ assert!(result.is_err());
+
+ // Test 5: Restore non-existent sheet from trash should fail
+ let result = vault.restore_sheet(&non_existent_sheet).await;
+ assert!(result.is_err());
+
+ // Clean up
+ vault.remove_member_from_vault(&member_id)?;
+
+ Ok(())
+}
+
+#[tokio::test]
+async fn test_sheet_data_serialization() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("sheet_serialization").await?;
+
+ // Test serialization by creating a sheet through the vault
+ // Setup vault
+ Vault::setup_vault(dir.clone()).await?;
+
+ // Get vault
+ let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?;
+ let Some(vault) = Vault::init(config, &dir) else {
+ return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!"));
+ };
+
+ // Add a member
+ let member_id: MemberId = "test_member".to_string();
+ vault
+ .register_member_to_vault(Member::new(&member_id))
+ .await?;
+
+ // Create a sheet
+ let sheet_name: SheetName = "test_serialization_sheet".to_string();
+ let mut sheet = vault.create_sheet(&sheet_name, &member_id).await?;
+
+ // Add some inputs
+ let input_name = "source_files".to_string();
+ let _files = vec![
+ (
+ InputRelativePathBuf::from("src/main.rs"),
+ VirtualFileId::new(),
+ ),
+ (
+ InputRelativePathBuf::from("src/lib.rs"),
+ VirtualFileId::new(),
+ ),
+ ];
+ // First add mapping entries
+ let main_rs_path = vcs_data::data::sheet::SheetPathBuf::from("src/main.rs");
+ let lib_rs_path = vcs_data::data::sheet::SheetPathBuf::from("src/lib.rs");
+ let main_rs_id = VirtualFileId::new();
+ let lib_rs_id = VirtualFileId::new();
+
+ sheet
+ .add_mapping(main_rs_path.clone(), main_rs_id.clone())
+ .await?;
+ sheet
+ .add_mapping(lib_rs_path.clone(), lib_rs_id.clone())
+ .await?;
+
+ // Use output_mappings to generate the InputPackage
+ let paths = vec![main_rs_path, lib_rs_path];
+ let input_package = sheet.output_mappings(input_name.clone(), &paths)?;
+ sheet.add_input(input_package)?;
+
+ // Add some mappings
+ let build_exe_id = VirtualFileId::new();
+
+ sheet
+ .add_mapping(
+ vcs_data::data::sheet::SheetPathBuf::from("output/build.exe"),
+ build_exe_id,
+ )
+ .await?;
+
+ // Persist the sheet
+ sheet.persist().await?;
+
+ // Verify the sheet file was created
+ const SHEET_NAME_PARAM: &str = "{sheet-name}";
+ let sheet_path = dir.join(SERVER_FILE_SHEET.replace(SHEET_NAME_PARAM, &sheet_name));
+ assert!(sheet_path.exists());
+
+ // Clean up
+ vault.remove_member_from_vault(&member_id)?;
+
+ Ok(())
+}
diff --git a/crates/vcs_data/vcs_data_test/src/test_vault_setup_and_member_register.rs b/crates/vcs_data/vcs_data_test/src/test_vault_setup_and_member_register.rs
new file mode 100644
index 0000000..80ae39e
--- /dev/null
+++ b/crates/vcs_data/vcs_data_test/src/test_vault_setup_and_member_register.rs
@@ -0,0 +1,67 @@
+use std::io::Error;
+
+use cfg_file::config::ConfigFile;
+use vcs_data::{
+ constants::{
+ SERVER_FILE_MEMBER_INFO, SERVER_FILE_README, SERVER_FILE_VAULT, SERVER_PATH_MEMBER_PUB,
+ SERVER_PATH_MEMBERS, SERVER_PATH_SHEETS, SERVER_PATH_VF_ROOT,
+ },
+ data::{
+ member::Member,
+ vault::{Vault, config::VaultConfig},
+ },
+};
+
+use crate::get_test_dir;
+
+#[tokio::test]
+async fn test_vault_setup_and_member_register() -> Result<(), std::io::Error> {
+ let dir = get_test_dir("member_register").await?;
+
+ // Setup vault
+ Vault::setup_vault(dir.clone()).await?;
+
+ // Check if the following files and directories are created in `dir`:
+ // Files: SERVER_FILE_VAULT, SERVER_FILE_README
+ // Directories: SERVER_PATH_SHEETS,
+ // SERVER_PATH_MEMBERS,
+ // SERVER_PATH_MEMBER_PUB,
+ // SERVER_PATH_VIRTUAL_FILE_ROOT
+ assert!(dir.join(SERVER_FILE_VAULT).exists());
+ assert!(dir.join(SERVER_FILE_README).exists());
+ assert!(dir.join(SERVER_PATH_SHEETS).exists());
+ assert!(dir.join(SERVER_PATH_MEMBERS).exists());
+ assert!(dir.join(SERVER_PATH_MEMBER_PUB).exists());
+ assert!(dir.join(SERVER_PATH_VF_ROOT).exists());
+
+ // Get vault
+ let config = VaultConfig::read_from(dir.join(SERVER_FILE_VAULT)).await?;
+ let Some(vault) = Vault::init(config, &dir) else {
+ return Err(Error::new(std::io::ErrorKind::NotFound, "Vault not found!"));
+ };
+
+ // Add member
+ let member_id = "test_member";
+ vault
+ .register_member_to_vault(Member::new(member_id))
+ .await?;
+
+ const ID_PARAM: &str = "{member_id}";
+
+ // Check if the member info file exists
+ assert!(
+ dir.join(SERVER_FILE_MEMBER_INFO.replace(ID_PARAM, member_id))
+ .exists()
+ );
+
+ // Remove member
+ vault.remove_member_from_vault(&member_id.to_string())?;
+
+ // Check if the member info file not exists
+ assert!(
+ !dir.join(SERVER_FILE_MEMBER_INFO.replace(ID_PARAM, member_id))
+ .exists()
+ );
+
+ Ok(())
+}
diff --git a/crates/vcs_data/vcs_data_test/src/test_virtual_file_creation_and_update.rs b/crates/vcs_data/vcs_data_test/src/test_virtual_file_creation_and_update.rs
new file mode 100644
index 0000000..7e30dad
--- /dev/null
+++ b/crates/vcs_data/vcs_data_test/src/test_virtual_file_creation_and_update.rs
@@ -0,0 +1,162 @@
+use std::time::Duration;
+
+use cfg_file::config::ConfigFile;
+use tcp_connection_test::{
+ handle::{ClientHandle, ServerHandle},
+ target::TcpServerTarget,
+ target_configure::ServerTargetConfig,
+};
+use tokio::{
+ join,
+ time::{sleep, timeout},
+};
+use vcs_data::{
+ constants::SERVER_FILE_VAULT,
+ data::{
+ member::Member,
+ vault::{Vault, config::VaultConfig, virtual_file::VirtualFileVersionDescription},
+ },
+};
+
+use crate::get_test_dir;
+
+struct VirtualFileCreateClientHandle;
+struct VirtualFileCreateServerHandle;
+
+impl ClientHandle<VirtualFileCreateServerHandle> for VirtualFileCreateClientHandle {
+ async fn process(mut instance: tcp_connection::instance::ConnectionInstance) {
+ let dir = get_test_dir("virtual_file_creation_and_update_2")
+ .await
+ .unwrap();
+ // Create first test file for virtual file creation
+ let test_content_1 = b"Test file content for virtual file creation";
+ let temp_file_path_1 = dir.join("test_virtual_file_1.txt");
+
+ tokio::fs::write(&temp_file_path_1, test_content_1)
+ .await
+ .unwrap();
+
+ // Send the first file to server for virtual file creation
+ instance.write_file(&temp_file_path_1).await.unwrap();
+
+ // Create second test file for virtual file update
+ let test_content_2 = b"Updated test file content for virtual file";
+ let temp_file_path_2 = dir.join("test_virtual_file_2.txt");
+
+ tokio::fs::write(&temp_file_path_2, test_content_2)
+ .await
+ .unwrap();
+
+ // Send the second file to server for virtual file update
+ instance.write_file(&temp_file_path_2).await.unwrap();
+ }
+}
+
+impl ServerHandle<VirtualFileCreateClientHandle> for VirtualFileCreateServerHandle {
+ async fn process(mut instance: tcp_connection::instance::ConnectionInstance) {
+ let dir = get_test_dir("virtual_file_creation_and_update")
+ .await
+ .unwrap();
+
+ // Setup vault
+ Vault::setup_vault(dir.clone()).await.unwrap();
+
+ // Read vault
+ let Some(vault) = Vault::init(
+ VaultConfig::read_from(dir.join(SERVER_FILE_VAULT))
+ .await
+ .unwrap(),
+ &dir,
+ ) else {
+ panic!("No vault found!");
+ };
+
+ // Register member
+ let member_id = "test_member";
+ vault
+ .register_member_to_vault(Member::new(member_id))
+ .await
+ .unwrap();
+
+ // Create visual file
+ let virtual_file_id = vault
+ .create_virtual_file_from_connection(&mut instance, &member_id.to_string())
+ .await
+ .unwrap();
+
+ // Grant edit right to member
+ vault
+ .grant_virtual_file_edit_right(&member_id.to_string(), &virtual_file_id)
+ .await
+ .unwrap();
+
+ // Update visual file
+ vault
+ .update_virtual_file_from_connection(
+ &mut instance,
+ &member_id.to_string(),
+ &virtual_file_id,
+ &"2".to_string(),
+ VirtualFileVersionDescription {
+ creator: member_id.to_string(),
+ description: "Update".to_string(),
+ },
+ )
+ .await
+ .unwrap();
+ }
+}
+
+#[tokio::test]
+async fn test_virtual_file_creation_and_update() -> Result<(), std::io::Error> {
+ let host = "localhost:5009";
+
+ // Server setup
+ let Ok(server_target) = TcpServerTarget::<
+ VirtualFileCreateClientHandle,
+ VirtualFileCreateServerHandle,
+ >::from_domain(host)
+ .await
+ else {
+ panic!("Test target built failed from a domain named `{}`", host);
+ };
+
+ // Client setup
+ let Ok(client_target) = TcpServerTarget::<
+ VirtualFileCreateClientHandle,
+ VirtualFileCreateServerHandle,
+ >::from_domain(host)
+ .await
+ else {
+ panic!("Test target built failed from a domain named `{}`", host);
+ };
+
+ let future_server = async move {
+ // Only process once
+ let configured_server = server_target.server_cfg(ServerTargetConfig::default().once());
+
+ // Listen here
+ let _ = configured_server.listen().await;
+ };
+
+ let future_client = async move {
+ // Wait for server start
+ let _ = sleep(Duration::from_secs_f32(1.5)).await;
+
+ // Connect here
+ let _ = client_target.connect().await;
+ };
+
+ let test_timeout = Duration::from_secs(15);
+
+ timeout(test_timeout, async { join!(future_client, future_server) })
+ .await
+ .map_err(|_| {
+ std::io::Error::new(
+ std::io::ErrorKind::TimedOut,
+ format!("Test timed out after {:?}", test_timeout),
+ )
+ })?;
+
+ Ok(())
+}