From 1364db3f9453e9c30576e00002c70bea87145240 Mon Sep 17 00:00:00 2001 From: kristof Date: Thu, 3 Apr 2025 13:58:44 +0200 Subject: [PATCH] ... --- herodb/readme.md | 5 + herodb/src/core/db.rs | 342 ------------- herodb/src/zaz/mod.rs | 3 + herodb/src/zaz/tests/db_integration_test.rs | 537 ++++---------------- herodb/src/zaz/tests/mod.rs | 6 + herodb/src/zaz/tests/model_db_test.rs | 13 +- 6 files changed, 122 insertions(+), 784 deletions(-) create mode 100644 herodb/readme.md create mode 100644 herodb/src/zaz/tests/mod.rs diff --git a/herodb/readme.md b/herodb/readme.md new file mode 100644 index 0000000..cc7c647 --- /dev/null +++ b/herodb/readme.md @@ -0,0 +1,5 @@ + + +```bash +cargo test zaz::tests -- --test-threads=1 +``` \ No newline at end of file diff --git a/herodb/src/core/db.rs b/herodb/src/core/db.rs index e7d1d2e..4c7f70c 100644 --- a/herodb/src/core/db.rs +++ b/herodb/src/core/db.rs @@ -424,345 +424,3 @@ impl DB { } } } - -// Test module with mocked models -#[cfg(test)] -mod tests { - use super::*; - use chrono::Utc; - use tempfile::tempdir; - use serde::{Deserialize, Serialize}; - - // Test model - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - struct TestUser { - id: u32, - name: String, - email: String, - } - - impl TestUser { - fn new(id: u32, name: String, email: String) -> Self { - Self { id, name, email } - } - } - - impl Storable for TestUser {} - - impl SledModel for TestUser { - fn get_id(&self) -> String { - self.id.to_string() - } - - fn db_prefix() -> &'static str { - "test_user" - } - } - - #[test] - fn test_db_builder() { - // Create a temporary directory for the test - let dir = tempdir().expect("Failed to create temp dir"); - - // Create a DB with the builder - let db = DBBuilder::new(dir.path()) - .register_model::() - .build() - .expect("Failed to build DB"); - - // Create a test user - let user = TestUser::new(1, "Test User".to_string(), "test@example.com".to_string()); - - // Set the user - db.set(&user).expect("Failed to set user"); - - // Get the user - let retrieved: TestUser = db.get(&user.id.to_string()).expect("Failed to get user"); - - // Check that it matches - assert_eq!(user, retrieved); - } - - #[test] - fn test_dynamic_registration() { - // Create a temporary directory for the test - let dir = tempdir().expect("Failed to create temp dir"); - - // Create an empty DB - let mut db = DB::new(dir.path()).expect("Failed to create DB"); - - // Register the TestUser model - db.register::().expect("Failed to register TestUser"); - - // Create a test user - let user = TestUser::new(2, "Dynamic User".to_string(), "dynamic@example.com".to_string()); - - // Set the user - db.set(&user).expect("Failed to set user"); - - // Get the user - let retrieved: TestUser = db.get(&user.id.to_string()).expect("Failed to get user"); - - // Check that it matches - assert_eq!(user, retrieved); - } -} - -// The as_type function is no longer needed with our type-map based implementation - -#[cfg(test)] -mod tests { - use super::*; - use chrono::Utc; - use tempfile::tempdir; - - #[test] - fn test_read_your_writes() { - // Create a temporary directory for the test - let dir = tempdir().expect("Failed to create temp dir"); - let db = DB::new(dir.path()).expect("Failed to create DB"); - - // Create a user - let user = User::new( - 10, - "Original User".to_string(), - "original@example.com".to_string(), - "password".to_string(), - "Original Corp".to_string(), - "User".to_string(), - ); - - // Insert the user directly (no transaction) - db.set(&user).expect("Failed to insert user"); - - // Begin a transaction - db.begin_transaction().expect("Failed to begin transaction"); - - // Verify we can read the original user - let original = db.get::(&user.id.to_string()).expect("Failed to get original user"); - assert_eq!(original.name, "Original User"); - - // Create a modified user with the same ID - let modified_user = User::new( - 10, - "Modified User".to_string(), - "modified@example.com".to_string(), - "new_password".to_string(), - "Modified Corp".to_string(), - "Admin".to_string(), - ); - - // Update the user in the transaction - db.set(&modified_user).expect("Failed to update user in transaction"); - - // Verify we can read our own writes within the transaction - let in_transaction = db.get::(&user.id.to_string()).expect("Failed to get user from transaction"); - assert_eq!(in_transaction.name, "Modified User"); - assert_eq!(in_transaction.email, "modified@example.com"); - - // Create a new user that only exists in the transaction - let new_user = User::new( - 20, - "Transaction Only User".to_string(), - "tx@example.com".to_string(), - "password".to_string(), - "TX Corp".to_string(), - "Admin".to_string(), - ); - - // Add the new user in the transaction - db.set(&new_user).expect("Failed to add new user in transaction"); - - // Verify we can read the new user within the transaction - let new_in_tx = db.get::(&new_user.id.to_string()).expect("Failed to get new user from transaction"); - assert_eq!(new_in_tx.name, "Transaction Only User"); - - // Delete a user in the transaction and verify it appears deleted within the transaction - db.delete::(&user.id.to_string()).expect("Failed to delete user in transaction"); - match db.get::(&user.id.to_string()) { - Err(SledDBError::NotFound(_)) => (), // Expected result - Ok(_) => panic!("User should appear deleted within transaction"), - Err(e) => panic!("Unexpected error: {}", e), - } - - // Rollback the transaction - db.rollback_transaction().expect("Failed to rollback transaction"); - - // Verify the original user is still available and unchanged after rollback - let after_rollback = db.get::(&user.id.to_string()).expect("Failed to get user after rollback"); - assert_eq!(after_rollback.name, "Original User"); - - // Verify the transaction-only user doesn't exist after rollback - assert!(db.get::(&new_user.id.to_string()).is_err()); - } - - #[test] - fn test_transactions() { - // Create a temporary directory for the test - let dir = tempdir().expect("Failed to create temp dir"); - let db = DB::new(dir.path()).expect("Failed to create DB"); - - // Create a sample user and company for testing - let user = User::new( - 1, - "Transaction Test User".to_string(), - "tx@example.com".to_string(), - "password".to_string(), - "Test Corp".to_string(), - "Admin".to_string(), - ); - - let incorporation_date = Utc::now(); - let company = Company::new( - 1, - "Transaction Test Corp".to_string(), - "TX123".to_string(), - incorporation_date, - "12-31".to_string(), - "tx@corp.com".to_string(), - "123-456-7890".to_string(), - "www.testcorp.com".to_string(), - "123 Test St".to_string(), - BusinessType::Global, - "Tech".to_string(), - "A test company for transactions".to_string(), - CompanyStatus::Active, - ); - - // Test successful transaction (multiple operations committed at once) - { - // Start a transaction - db.begin_transaction().expect("Failed to begin transaction"); - assert!(db.has_active_transaction()); - - // Perform multiple operations within the transaction - db.set(&user).expect("Failed to add user to transaction"); - db.set(&company).expect("Failed to add company to transaction"); - - // Commit the transaction - db.commit_transaction().expect("Failed to commit transaction"); - assert!(!db.has_active_transaction()); - - // Verify both operations were applied - let retrieved_user: User = db.get(&user.id.to_string()).expect("Failed to get user after commit"); - let retrieved_company: Company = db.get(&company.id.to_string()).expect("Failed to get company after commit"); - - assert_eq!(user.name, retrieved_user.name); - assert_eq!(company.name, retrieved_company.name); - } - - // Test transaction rollback - { - // Create another user that should not be persisted - let temp_user = User::new( - 2, - "Temporary User".to_string(), - "temp@example.com".to_string(), - "password".to_string(), - "Temp Corp".to_string(), - "Temp".to_string(), - ); - - // Start a transaction - db.begin_transaction().expect("Failed to begin transaction"); - - // Add the temporary user - db.set(&temp_user).expect("Failed to add temporary user to transaction"); - - // Perform a delete operation in the transaction - db.delete::(&company.id.to_string()).expect("Failed to delete company in transaction"); - - // Rollback the transaction - should discard all operations - db.rollback_transaction().expect("Failed to rollback transaction"); - assert!(!db.has_active_transaction()); - - // Verify the temporary user was not added - match db.get::(&temp_user.id.to_string()) { - Err(SledDBError::NotFound(_)) => (), // Expected outcome - Ok(_) => panic!("Temporary user should not exist after rollback"), - Err(e) => panic!("Unexpected error: {}", e), - } - - // Verify the company was not deleted - let company_still_exists = db.get::(&company.id.to_string()).is_ok(); - assert!(company_still_exists, "Company should still exist after transaction rollback"); - } - } - - #[test] - fn test_generic_db_operations() { - // Create a temporary directory for the test - let dir = tempdir().expect("Failed to create temp dir"); - let db = DB::new(dir.path()).expect("Failed to create DB"); - - // Test simple transaction functionality - assert!(!db.has_active_transaction()); - db.begin_transaction().expect("Failed to begin transaction"); - assert!(db.has_active_transaction()); - db.rollback_transaction().expect("Failed to rollback transaction"); - assert!(!db.has_active_transaction()); - - // Create a sample user - let user = User::new( - 1, - "Test User".to_string(), - "test@example.com".to_string(), - "password".to_string(), - "Test Corp".to_string(), - "Admin".to_string(), - ); - - // Insert the user - db.set(&user).expect("Failed to insert user"); - - // Get the user - let retrieved_user: User = db.get(&user.id.to_string()).expect("Failed to get user"); - assert_eq!(user.name, retrieved_user.name); - - // Create a sample company - let incorporation_date = Utc::now(); - let company = Company::new( - 1, - "Test Corp".to_string(), - "REG123".to_string(), - incorporation_date, - "12-31".to_string(), - "test@corp.com".to_string(), - "123-456-7890".to_string(), - "www.testcorp.com".to_string(), - "123 Test St".to_string(), - BusinessType::Global, - "Tech".to_string(), - "A test company".to_string(), - CompanyStatus::Active, - ); - - // Insert the company - db.set(&company).expect("Failed to insert company"); - - // Get the company - let retrieved_company: Company = db.get(&company.id.to_string()) - .expect("Failed to get company"); - assert_eq!(company.name, retrieved_company.name); - - // List all companies - let companies: Vec = db.list().expect("Failed to list companies"); - assert_eq!(companies.len(), 1); - assert_eq!(companies[0].name, company.name); - - // List all users - let users: Vec = db.list().expect("Failed to list users"); - assert_eq!(users.len(), 1); - assert_eq!(users[0].name, user.name); - - // Delete the company - db.delete::(&company.id.to_string()) - .expect("Failed to delete company"); - - // Try to get the deleted company (should fail) - match db.get::(&company.id.to_string()) { - Err(SledDBError::NotFound(_)) => (), - _ => panic!("Expected NotFound error"), - } - } -} diff --git a/herodb/src/zaz/mod.rs b/herodb/src/zaz/mod.rs index 0916b49..9557194 100644 --- a/herodb/src/zaz/mod.rs +++ b/herodb/src/zaz/mod.rs @@ -14,3 +14,6 @@ pub mod examples; // Expose the cmd module pub mod cmd; +// Include tests module when running tests +#[cfg(test)] +pub mod tests; diff --git a/herodb/src/zaz/tests/db_integration_test.rs b/herodb/src/zaz/tests/db_integration_test.rs index 7bc2e19..ef4c3e6 100644 --- a/herodb/src/zaz/tests/db_integration_test.rs +++ b/herodb/src/zaz/tests/db_integration_test.rs @@ -1,7 +1,8 @@ //! Integration tests for the zaz database module -use sled; -use bincode; +use crate::core::{DB, DBBuilder, SledDBResult, Storable, SledModel, SledDB}; +use crate::zaz::models::user::User; +use crate::zaz::models::company::{Company, BusinessType, CompanyStatus}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::fs; @@ -19,113 +20,6 @@ fn test_basic_database_operations() { } fn run_comprehensive_test() -> Result<(), Box> { - // User model - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - struct User { - id: u32, - name: String, - email: String, - password: String, - company: String, - role: String, - created_at: DateTime, - updated_at: DateTime, - } - - impl User { - fn new( - id: u32, - name: String, - email: String, - password: String, - company: String, - role: String, - ) -> Self { - let now = Utc::now(); - Self { - id, - name, - email, - password, - company, - role, - created_at: now, - updated_at: now, - } - } - } - - // Company model - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - enum BusinessType { - Local, - National, - Global, - } - - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - enum CompanyStatus { - Active, - Inactive, - Pending, - } - - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - struct Company { - id: u32, - name: String, - registration_number: String, - registration_date: DateTime, - fiscal_year_end: String, - email: String, - phone: String, - website: String, - address: String, - business_type: BusinessType, - industry: String, - description: String, - status: CompanyStatus, - created_at: DateTime, - updated_at: DateTime, - } - - impl Company { - fn new( - id: u32, - name: String, - registration_number: String, - registration_date: DateTime, - fiscal_year_end: String, - email: String, - phone: String, - website: String, - address: String, - business_type: BusinessType, - industry: String, - description: String, - status: CompanyStatus, - ) -> Self { - let now = Utc::now(); - Self { - id, - name, - registration_number, - registration_date, - fiscal_year_end, - email, - phone, - website, - address, - business_type, - industry, - description, - status, - created_at: now, - updated_at: now, - } - } - } - // Create a temporary directory for testing let temp_dir = tempdir()?; println!("Using temporary directory: {:?}", temp_dir.path()); @@ -147,44 +41,8 @@ fn run_comprehensive_test() -> Result<(), Box> { } fn test_user_operations(base_path: &Path) -> Result<(), Box> { - // User model (duplicate for scope) - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - struct User { - id: u32, - name: String, - email: String, - password: String, - company: String, - role: String, - created_at: DateTime, - updated_at: DateTime, - } - - impl User { - fn new( - id: u32, - name: String, - email: String, - password: String, - company: String, - role: String, - ) -> Self { - let now = Utc::now(); - Self { - id, - name, - email, - password, - company, - role, - created_at: now, - updated_at: now, - } - } - } - // Open the user database - let db = sled::open(base_path.join("users"))?; + let db = SledDB::::open(base_path.join("users"))?; println!("Opened user database at: {:?}", base_path.join("users")); // Create a test user @@ -198,21 +56,14 @@ fn test_user_operations(base_path: &Path) -> Result<(), Box Result<(), Box Result<(), Box> { - // Company model (duplicate for scope) - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - enum BusinessType { - Local, - National, - Global, - } - - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - enum CompanyStatus { - Active, - Inactive, - Pending, - } - - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - struct Company { - id: u32, - name: String, - registration_number: String, - registration_date: DateTime, - fiscal_year_end: String, - email: String, - phone: String, - website: String, - address: String, - business_type: BusinessType, - industry: String, - description: String, - status: CompanyStatus, - created_at: DateTime, - updated_at: DateTime, - } - - impl Company { - fn new( - id: u32, - name: String, - registration_number: String, - registration_date: DateTime, - fiscal_year_end: String, - email: String, - phone: String, - website: String, - address: String, - business_type: BusinessType, - industry: String, - description: String, - status: CompanyStatus, - ) -> Self { - let now = Utc::now(); - Self { - id, - name, - registration_number, - registration_date, - fiscal_year_end, - email, - phone, - website, - address, - business_type, - industry, - description, - status, - created_at: now, - updated_at: now, - } - } - } - // Open the company database - let db = sled::open(base_path.join("companies"))?; + let db = SledDB::::open(base_path.join("companies"))?; println!("Opened company database at: {:?}", base_path.join("companies")); // Create a test company @@ -346,43 +119,25 @@ fn test_company_operations(base_path: &Path) -> Result<(), Box Result<(), Box Result<(), Box> { - // User model (duplicate for scope) - #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] - struct User { - id: u32, - name: String, - email: String, - password: String, - company: String, - role: String, - created_at: DateTime, - updated_at: DateTime, - } + // Create a DB instance with User model registered + let mut db = DB::new(base_path.join("transaction"))?; + db.register::()?; - impl User { - fn new( - id: u32, - name: String, - email: String, - password: String, - company: String, - role: String, - ) -> Self { - let now = Utc::now(); - Self { - id, - name, - email, - password, - company, - role, - created_at: now, - updated_at: now, - } - } - } - - // Open the user database - let db = sled::open(base_path.join("tx_users"))?; - println!("Opened transaction test database at: {:?}", base_path.join("tx_users")); + println!("Created DB with User model registered at: {:?}", base_path.join("transaction")); // Add a user outside of transaction let user = User::new( @@ -440,28 +161,15 @@ fn test_transaction_simulation(base_path: &Path) -> Result<(), Box Result<(), Box Result<(), Box String { + self.id.to_string() + } + + fn db_prefix() -> &'static str { + "test_simple_user" + } } - // UPDATE: Update the user - let updated_user = User::new(1, "Updated User".to_string(), "updated@example.com".to_string()); - let updated_value = bincode::serialize(&updated_user).expect("Failed to serialize updated user"); - db.insert(user_key.as_bytes(), updated_value).expect("Failed to update user"); - db.flush().expect("Failed to flush database"); - println!("Updated user: {} ({})", updated_user.name, updated_user.email); + // Create a temporary directory for the test + let dir = tempdir().expect("Failed to create temp dir"); - // Verify update - let result = db.get(user_key.as_bytes()).expect("Failed to query database"); - assert!(result.is_some(), "Updated user should exist"); - if let Some(data) = result { - let retrieved_user: User = bincode::deserialize(&data).expect("Failed to deserialize user"); - println!("Retrieved updated user: {} ({})", retrieved_user.name, retrieved_user.email); - assert_eq!(updated_user, retrieved_user, "Retrieved user should match updated version"); - } + // Create a DB with the builder + let db = DBBuilder::new(dir.path()) + .register_model::() + .build() + .expect("Failed to build DB"); - // DELETE: Delete the user - db.remove(user_key.as_bytes()).expect("Failed to delete user"); - db.flush().expect("Failed to flush database"); - println!("Deleted user"); + // Create a test user + let user = User::new(1, "Simple Test User".to_string(), "simple@example.com".to_string()); - // Verify deletion - let result = db.get(user_key.as_bytes()).expect("Failed to query database"); - assert!(result.is_none(), "User should be deleted"); - println!("Verified user deletion"); + // Set the user + db.set(&user).expect("Failed to set user"); - // Clean up - drop(db); - temp_dir.close().expect("Failed to cleanup temporary directory"); + // Get the user + let retrieved: User = db.get(&user.id.to_string()).expect("Failed to get user"); - println!("Simple DB test completed successfully!"); + // Check that it matches + assert_eq!(user.name, retrieved.name); + assert_eq!(user.email, retrieved.email); + + println!("Simple DB test passed!"); } diff --git a/herodb/src/zaz/tests/mod.rs b/herodb/src/zaz/tests/mod.rs new file mode 100644 index 0000000..b8a7d02 --- /dev/null +++ b/herodb/src/zaz/tests/mod.rs @@ -0,0 +1,6 @@ +//! Tests for the Zaz module + +// Re-export the test modules +pub mod model_db_test; +pub mod db_integration_test; +pub mod transaction_test; \ No newline at end of file diff --git a/herodb/src/zaz/tests/model_db_test.rs b/herodb/src/zaz/tests/model_db_test.rs index 19e53e4..2ca13ba 100644 --- a/herodb/src/zaz/tests/model_db_test.rs +++ b/herodb/src/zaz/tests/model_db_test.rs @@ -2,7 +2,9 @@ use crate::core::{DB, DBBuilder, SledDBResult, Storable, SledModel}; use crate::zaz::factory::create_zaz_db; -use crate::zaz::models::*; +use crate::zaz::models::user::User; +use crate::zaz::models::company::{Company, BusinessType, CompanyStatus}; +use crate::zaz::models::product::{Product, ProductStatus, ProductType, Currency}; use chrono::Utc; use std::path::Path; use tempfile::tempdir; @@ -103,14 +105,13 @@ fn test_db_builder() { let product = Product::new( 1, "Unregistered Product".to_string(), - "PROD-123".to_string(), "A test product".to_string(), + Currency::new(100.0, "USD".to_string()), + ProductType::Product, "Test".to_string(), - ProductType::Standard, ProductStatus::Available, - Currency::USD, - 100.0, - vec![], + 10, // max_amount + 30, // validity_days ); // This should fail because Product was not registered