From 23c9d68c0b52496d2a7ef37db2b4f02250e7186a Mon Sep 17 00:00:00 2001 From: perf3ct Date: Tue, 29 Jul 2025 02:28:39 +0000 Subject: [PATCH] feat(tests): mom, take a picture, the tests pass --- src/test_utils.rs | 8 ++- .../integration_smart_sync_error_handling.rs | 58 +++++++++++++++---- tests/integration_smart_sync_first_time.rs | 24 +++++--- tests/integration_smart_sync_no_changes.rs | 26 ++++++--- tests/integration_smart_sync_targeted_scan.rs | 35 ++++++++--- 5 files changed, 114 insertions(+), 37 deletions(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index f1ee608..605596a 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -241,7 +241,13 @@ impl TestContext { let mut retries = 0; const MAX_RETRIES: u32 = 15; let db = loop { - match crate::db::Database::new_with_pool_config(&database_url, 5, 1).await { + // Use larger pool for error handling tests that need more concurrent connections + let (max_connections, min_connections) = if std::env::var("TEST_REQUIRES_LARGER_POOL").is_ok() { + (15, 3) // Larger pool for error handling tests + } else { + (5, 1) // Standard small pool for regular tests + }; + match crate::db::Database::new_with_pool_config(&database_url, max_connections, min_connections).await { Ok(test_db) => { // Run migrations let migrations = sqlx::migrate!("./migrations"); diff --git a/tests/integration_smart_sync_error_handling.rs b/tests/integration_smart_sync_error_handling.rs index 15b92aa..f7812d8 100644 --- a/tests/integration_smart_sync_error_handling.rs +++ b/tests/integration_smart_sync_error_handling.rs @@ -1,14 +1,24 @@ -use std::sync::Arc; use readur::{ - AppState, models::{CreateWebDAVDirectory, User, AuthProvider}, services::webdav::{SmartSyncService, SmartSyncStrategy, SmartSyncDecision, WebDAVService, WebDAVConfig}, test_utils::{TestContext, TestAuthHelper}, }; -/// Helper function to create test database and user -async fn create_test_setup() -> (Arc, User) { - let test_context = TestContext::new().await; +/// Helper function to create test database and user with enhanced pool configuration +async fn create_test_setup() -> (TestContext, User) { + // Set environment variable to use larger database pool for error handling tests + std::env::set_var("TEST_REQUIRES_LARGER_POOL", "1"); + + // Create TestContext with larger connection pool for error handling tests + let config_builder = readur::test_utils::TestConfigBuilder::default() + .with_concurrent_ocr_jobs(2); // Reduce concurrent jobs to prevent pool exhaustion + let test_context = TestContext::with_config(config_builder).await; + + // Wait for pool to be ready before proceeding + if let Err(e) = test_context.wait_for_pool_health(10).await { + eprintln!("Warning: Pool health check failed: {}", e); + } + let auth_helper = TestAuthHelper::new(test_context.app().clone()); let test_user = auth_helper.create_test_user().await; @@ -27,7 +37,7 @@ async fn create_test_setup() -> (Arc, User) { auth_provider: AuthProvider::Local, }; - (test_context.state().clone(), user) + (test_context, user) } /// Helper function to create WebDAV service for testing @@ -50,7 +60,8 @@ async fn test_webdav_error_fallback() { // Integration Test: WebDAV server error scenarios should fall back to traditional sync // Expected: When WebDAV service fails, should gracefully handle errors - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); let smart_sync_service = SmartSyncService::new(state.clone()); // Create some existing directories to test database robustness @@ -117,6 +128,11 @@ async fn test_webdav_error_fallback() { assert_eq!(root_dir.directory_etag, "existing-root"); println!("✅ WebDAV error fallback test completed - database remains intact"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -124,7 +140,8 @@ async fn test_database_error_handling() { // Integration Test: Database errors should be handled gracefully // This tests the system's resilience to database connectivity issues - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); let smart_sync_service = SmartSyncService::new(state.clone()); // Test with invalid user ID (simulates database query errors) @@ -163,6 +180,11 @@ async fn test_database_error_handling() { assert_eq!(saved_dirs.len(), 1, "Normal database operations should work after error handling"); println!("✅ Database error handling test completed"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -170,7 +192,8 @@ async fn test_concurrent_smart_sync_operations() { // Integration Test: Concurrent smart sync operations should not interfere with each other // This tests race conditions and database locking - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Create initial directories let initial_dirs = vec![ @@ -195,8 +218,8 @@ async fn test_concurrent_smart_sync_operations() { .expect("Failed to create initial directory"); } - // Run multiple concurrent operations - let num_concurrent = 5; + // Run multiple concurrent operations (reduced from 5 to 3 to prevent pool exhaustion) + let num_concurrent = 3; let mut handles = Vec::new(); for i in 0..num_concurrent { @@ -261,6 +284,11 @@ async fn test_concurrent_smart_sync_operations() { println!(" {} initial directories preserved", initial_dirs.len()); println!(" {} concurrent operations executed", num_concurrent); println!(" {} operations successful", success_count); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -268,7 +296,8 @@ async fn test_malformed_data_recovery() { // Integration Test: System should handle and recover from malformed data gracefully // This tests robustness against data corruption scenarios - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Create a directory with normal data first let normal_dir = CreateWebDAVDirectory { @@ -348,4 +377,9 @@ async fn test_malformed_data_recovery() { println!(" {} edge cases handled successfully", successful_edge_cases); println!(" {} edge cases failed as expected", failed_edge_cases); println!(" Database remains functional after edge case testing"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } \ No newline at end of file diff --git a/tests/integration_smart_sync_first_time.rs b/tests/integration_smart_sync_first_time.rs index 5a99277..89ff12f 100644 --- a/tests/integration_smart_sync_first_time.rs +++ b/tests/integration_smart_sync_first_time.rs @@ -1,13 +1,11 @@ -use std::sync::Arc; use readur::{ - AppState, models::{CreateWebDAVDirectory, User, AuthProvider}, services::webdav::{SmartSyncService, SmartSyncStrategy, SmartSyncDecision, WebDAVService, WebDAVConfig}, test_utils::{TestContext, TestAuthHelper}, }; -/// Helper function to create test database and user -async fn create_test_setup() -> (Arc, User) { +/// Helper function to create test database and user with automatic cleanup +async fn create_test_setup() -> (TestContext, User) { let test_context = TestContext::new().await; let auth_helper = TestAuthHelper::new(test_context.app().clone()); let test_user = auth_helper.create_test_user().await; @@ -27,7 +25,7 @@ async fn create_test_setup() -> (Arc, User) { auth_provider: AuthProvider::Local, }; - (test_context.state().clone(), user) + (test_context, user) } /// Helper function to create WebDAV service for testing @@ -50,7 +48,8 @@ async fn test_first_time_sync_full_deep_scan() { // Integration Test: First-time sync with no existing directory ETags // Expected: Should perform full deep scan and save all discovered directory ETags - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); let smart_sync_service = SmartSyncService::new(state.clone()); // Verify no existing directories tracked @@ -74,6 +73,11 @@ async fn test_first_time_sync_full_deep_scan() { } println!("✅ First-time sync test completed successfully"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -81,7 +85,8 @@ async fn test_first_time_sync_saves_directory_etags() { // Integration Test: First-time sync should save discovered directory ETags to database // This test focuses on the database persistence aspect - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Manually create directories that would be discovered by WebDAV let discovered_directories = vec![ @@ -135,4 +140,9 @@ async fn test_first_time_sync_saves_directory_etags() { assert_eq!(archive_dir.total_size_bytes, 2048000); println!("✅ First-time sync directory ETag persistence test completed successfully"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } \ No newline at end of file diff --git a/tests/integration_smart_sync_no_changes.rs b/tests/integration_smart_sync_no_changes.rs index 4dfac93..3a36617 100644 --- a/tests/integration_smart_sync_no_changes.rs +++ b/tests/integration_smart_sync_no_changes.rs @@ -1,13 +1,11 @@ -use std::sync::Arc; use readur::{ - AppState, models::{CreateWebDAVDirectory, User, AuthProvider}, - services::webdav::{SmartSyncService, SmartSyncStrategy, SmartSyncDecision, WebDAVService, WebDAVConfig}, + services::webdav::{SmartSyncService, WebDAVService, WebDAVConfig}, test_utils::{TestContext, TestAuthHelper}, }; -/// Helper function to create test database and user -async fn create_test_setup() -> (Arc, User) { +/// Helper function to create test database and user with automatic cleanup +async fn create_test_setup() -> (TestContext, User) { let test_context = TestContext::new().await; let auth_helper = TestAuthHelper::new(test_context.app().clone()); let test_user = auth_helper.create_test_user().await; @@ -27,7 +25,7 @@ async fn create_test_setup() -> (Arc, User) { auth_provider: AuthProvider::Local, }; - (test_context.state().clone(), user) + (test_context, user) } /// Helper function to create WebDAV service for testing @@ -50,7 +48,8 @@ async fn test_smart_sync_no_changes_skip() { // Integration Test: Smart sync with no directory changes should skip sync entirely // Expected: Should return SkipSync when all directory ETags are unchanged - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); let smart_sync_service = SmartSyncService::new(state.clone()); // Pre-populate database with known directory ETags @@ -112,6 +111,11 @@ async fn test_smart_sync_no_changes_skip() { assert_eq!(archive_dir.file_count, 25); println!("✅ No changes sync test completed successfully - bulk fetch in {:?}", fetch_duration); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -119,7 +123,8 @@ async fn test_directory_etag_comparison_efficiency() { // Integration Test: Directory ETag comparison should be efficient for large numbers of directories // This tests the bulk fetching performance optimization - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Create a larger number of directories to test performance let num_directories = 100; @@ -169,4 +174,9 @@ async fn test_directory_etag_comparison_efficiency() { println!("✅ Directory ETag comparison efficiency test completed successfully"); println!(" Created {} directories in {:?}", num_directories, insert_duration); println!(" Fetched {} directories in {:?}", num_directories, fetch_duration); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } \ No newline at end of file diff --git a/tests/integration_smart_sync_targeted_scan.rs b/tests/integration_smart_sync_targeted_scan.rs index f1de4bd..b8e6cf4 100644 --- a/tests/integration_smart_sync_targeted_scan.rs +++ b/tests/integration_smart_sync_targeted_scan.rs @@ -1,13 +1,12 @@ -use std::sync::Arc; use readur::{ - AppState, models::{CreateWebDAVDirectory, User, AuthProvider}, - services::webdav::{SmartSyncService, SmartSyncStrategy, SmartSyncDecision, WebDAVService, WebDAVConfig}, + services::webdav::{WebDAVService, WebDAVConfig}, test_utils::{TestContext, TestAuthHelper}, }; +use std::collections::HashMap; -/// Helper function to create test database and user -async fn create_test_setup() -> (Arc, User) { +/// Helper function to create test database and user with automatic cleanup +async fn create_test_setup() -> (TestContext, User) { let test_context = TestContext::new().await; let auth_helper = TestAuthHelper::new(test_context.app().clone()); let test_user = auth_helper.create_test_user().await; @@ -27,7 +26,7 @@ async fn create_test_setup() -> (Arc, User) { auth_provider: AuthProvider::Local, }; - (test_context.state().clone(), user) + (test_context, user) } /// Helper function to create WebDAV service for testing @@ -50,7 +49,8 @@ async fn test_smart_sync_targeted_scan() { // Integration Test: Smart sync with single directory changed should use targeted scan // Expected: Should return RequiresSync(TargetedScan) when only a few directories have changed - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Create a scenario with many directories, where only one has changed let unchanged_directories = vec![ @@ -93,6 +93,11 @@ async fn test_smart_sync_targeted_scan() { assert!(should_use_targeted, "Should use targeted scan for small changes: {:.1}% change ratio", change_ratio * 100.0); println!("✅ Targeted scan strategy selection test passed - 10% change triggers targeted scan"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -100,7 +105,8 @@ async fn test_targeted_scan_vs_full_scan_thresholds() { // Integration Test: Test various scenarios for when to use targeted vs full scan // Expected: Strategy should be chosen based on change ratio and new directory count - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Create base directories for testing different scenarios let base_directories = 20; // Start with 20 directories @@ -150,6 +156,11 @@ async fn test_targeted_scan_vs_full_scan_thresholds() { println!(" Scenario 2 (40% changes, 2 new): Full scan"); println!(" Scenario 3 (5% changes, 7 new): Full scan"); println!(" Scenario 4 (30% changes, 5 new): Targeted scan"); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } #[tokio::test] @@ -157,7 +168,8 @@ async fn test_directory_change_detection_logic() { // Integration Test: Test the logic for detecting changed, new, and unchanged directories // This is the core of the targeted scan decision making - let (state, user) = create_test_setup().await; + let (test_context, user) = create_test_setup().await; + let state = test_context.state().clone(); // Set up known directories in database let known_dirs = vec![ @@ -256,4 +268,9 @@ async fn test_directory_change_detection_logic() { println!(" Deleted: {} directories", deleted_directories.len()); println!(" Change ratio: {:.1}%", change_ratio * 100.0); println!(" Strategy: {}", if should_use_targeted { "Targeted scan" } else { "Full scan" }); + + // Clean up test context + if let Err(e) = test_context.cleanup_and_close().await { + eprintln!("Warning: Test cleanup failed: {}", e); + } } \ No newline at end of file