mirror of
https://github.com/readur/readur.git
synced 2025-12-17 20:35:17 -06:00
317 lines
11 KiB
Rust
317 lines
11 KiB
Rust
/*!
|
|
* Simple Source Scheduler Unit Tests
|
|
*
|
|
* Basic tests for the source scheduler functionality without complex mocking
|
|
*/
|
|
|
|
use std::sync::Arc;
|
|
use uuid::Uuid;
|
|
use chrono::Utc;
|
|
use serde_json::json;
|
|
|
|
use readur::{
|
|
AppState,
|
|
config::Config,
|
|
db::Database,
|
|
models::{Source, SourceType, SourceStatus, WebDAVSourceConfig, LocalFolderSourceConfig, S3SourceConfig},
|
|
scheduling::source_scheduler::SourceScheduler,
|
|
test_helpers::create_test_config_with_db,
|
|
};
|
|
|
|
/// Create a test app state
|
|
async fn create_test_app_state() -> Arc<AppState> {
|
|
let database_url = std::env::var("TEST_DATABASE_URL")
|
|
.or_else(|_| std::env::var("DATABASE_URL"))
|
|
.unwrap_or_else(|_| "postgresql://readur:readur@localhost:5432/readur".to_string());
|
|
|
|
let mut config = create_test_config_with_db(&database_url);
|
|
config.server_address = "127.0.0.1:8080".to_string();
|
|
config.jwt_secret = "test_secret".to_string();
|
|
|
|
let db = Database::new(&config.database_url).await.unwrap();
|
|
|
|
// Create file service
|
|
let storage_config = readur::storage::StorageConfig::Local { upload_path: config.upload_path.clone() };
|
|
let storage_backend = readur::storage::factory::create_storage_backend(storage_config).await.unwrap();
|
|
let file_service = std::sync::Arc::new(readur::services::file_service::FileService::with_storage(config.upload_path.clone(), storage_backend));
|
|
|
|
let queue_service = Arc::new(readur::ocr::queue::OcrQueueService::new(db.clone(), db.pool.clone(), 2, file_service.clone(), 100, 100));
|
|
Arc::new(AppState {
|
|
db: db.clone(),
|
|
config,
|
|
file_service,
|
|
webdav_scheduler: None,
|
|
source_scheduler: None,
|
|
queue_service,
|
|
oidc_client: None,
|
|
sync_progress_tracker: std::sync::Arc::new(readur::services::sync_progress_tracker::SyncProgressTracker::new()),
|
|
user_watch_service: None,
|
|
webdav_metrics_collector: None,
|
|
})
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_source_scheduler_creation() {
|
|
let state = create_test_app_state().await;
|
|
let _scheduler = SourceScheduler::new(state.clone());
|
|
|
|
// Test that scheduler is created successfully
|
|
assert!(true); // If we get here, creation succeeded
|
|
}
|
|
|
|
#[test]
|
|
fn test_webdav_config_parsing() {
|
|
let config_json = json!({
|
|
"server_url": "https://cloud.example.com",
|
|
"username": "testuser",
|
|
"password": "testpass",
|
|
"watch_folders": ["/Documents"],
|
|
"file_extensions": [".pdf", ".txt"],
|
|
"auto_sync": true,
|
|
"sync_interval_minutes": 60,
|
|
"server_type": "nextcloud"
|
|
});
|
|
|
|
let config: Result<WebDAVSourceConfig, _> = serde_json::from_value(config_json);
|
|
assert!(config.is_ok(), "WebDAV config should parse successfully");
|
|
|
|
let webdav_config = config.unwrap();
|
|
assert_eq!(webdav_config.server_url, "https://cloud.example.com");
|
|
assert_eq!(webdav_config.username, "testuser");
|
|
assert!(webdav_config.auto_sync);
|
|
assert_eq!(webdav_config.sync_interval_minutes, 60);
|
|
assert_eq!(webdav_config.server_type, Some("nextcloud".to_string()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_local_folder_config_parsing() {
|
|
let config_json = json!({
|
|
"watch_folders": ["/home/user/documents"],
|
|
"file_extensions": [".pdf", ".txt", ".jpg"],
|
|
"auto_sync": true,
|
|
"sync_interval_minutes": 30,
|
|
"recursive": true,
|
|
"follow_symlinks": false
|
|
});
|
|
|
|
let config: Result<LocalFolderSourceConfig, _> = serde_json::from_value(config_json);
|
|
assert!(config.is_ok(), "Local Folder config should parse successfully");
|
|
|
|
let local_config = config.unwrap();
|
|
assert_eq!(local_config.watch_folders.len(), 1);
|
|
assert_eq!(local_config.watch_folders[0], "/home/user/documents");
|
|
assert!(local_config.recursive);
|
|
assert!(!local_config.follow_symlinks);
|
|
assert_eq!(local_config.sync_interval_minutes, 30);
|
|
}
|
|
|
|
#[test]
|
|
fn test_s3_config_parsing() {
|
|
let config_json = json!({
|
|
"bucket_name": "test-documents",
|
|
"region": "us-east-1",
|
|
"access_key_id": "AKIATEST",
|
|
"secret_access_key": "secrettest",
|
|
"endpoint_url": null,
|
|
"prefix": "documents/",
|
|
"watch_folders": ["documents/"],
|
|
"file_extensions": [".pdf", ".docx"],
|
|
"auto_sync": true,
|
|
"sync_interval_minutes": 120
|
|
});
|
|
|
|
let config: Result<S3SourceConfig, _> = serde_json::from_value(config_json);
|
|
assert!(config.is_ok(), "S3 config should parse successfully");
|
|
|
|
let s3_config = config.unwrap();
|
|
assert_eq!(s3_config.bucket_name, "test-documents");
|
|
assert_eq!(s3_config.region, "us-east-1");
|
|
assert_eq!(s3_config.prefix, Some("documents/".to_string()));
|
|
assert_eq!(s3_config.sync_interval_minutes, 120);
|
|
}
|
|
|
|
#[test]
|
|
fn test_source_type_enum() {
|
|
assert_eq!(SourceType::WebDAV.to_string(), "webdav");
|
|
assert_eq!(SourceType::LocalFolder.to_string(), "local_folder");
|
|
assert_eq!(SourceType::S3.to_string(), "s3");
|
|
}
|
|
|
|
#[test]
|
|
fn test_source_status_enum() {
|
|
assert_eq!(SourceStatus::Idle.to_string(), "idle");
|
|
assert_eq!(SourceStatus::Syncing.to_string(), "syncing");
|
|
assert_eq!(SourceStatus::Error.to_string(), "error");
|
|
}
|
|
|
|
#[test]
|
|
fn test_interrupted_sync_detection() {
|
|
let user_id = Uuid::new_v4();
|
|
|
|
let interrupted_source = Source {
|
|
id: Uuid::new_v4(),
|
|
user_id,
|
|
name: "Test Source".to_string(),
|
|
source_type: SourceType::WebDAV,
|
|
enabled: true,
|
|
config: json!({
|
|
"server_url": "https://cloud.example.com",
|
|
"username": "test",
|
|
"password": "test",
|
|
"watch_folders": ["/test"],
|
|
"file_extensions": [".pdf"],
|
|
"auto_sync": true,
|
|
"sync_interval_minutes": 60,
|
|
"server_type": "nextcloud"
|
|
}),
|
|
status: SourceStatus::Syncing, // This indicates interruption
|
|
last_sync_at: None,
|
|
last_error: None,
|
|
last_error_at: None,
|
|
total_files_synced: 0,
|
|
total_files_pending: 0,
|
|
total_size_bytes: 0,
|
|
created_at: Utc::now(),
|
|
updated_at: Utc::now(),
|
|
validation_status: None,
|
|
last_validation_at: None,
|
|
validation_score: None,
|
|
validation_issues: None,
|
|
};
|
|
|
|
// Test that interrupted sync is detected
|
|
assert_eq!(interrupted_source.status, SourceStatus::Syncing);
|
|
|
|
let completed_source = Source {
|
|
id: Uuid::new_v4(),
|
|
user_id,
|
|
name: "Completed Source".to_string(),
|
|
source_type: SourceType::WebDAV,
|
|
enabled: true,
|
|
config: json!({
|
|
"server_url": "https://cloud.example.com",
|
|
"username": "test",
|
|
"password": "test",
|
|
"watch_folders": ["/test"],
|
|
"file_extensions": [".pdf"],
|
|
"auto_sync": true,
|
|
"sync_interval_minutes": 60,
|
|
"server_type": "nextcloud"
|
|
}),
|
|
status: SourceStatus::Idle, // Completed normally
|
|
last_sync_at: Some(Utc::now()),
|
|
last_error: None,
|
|
last_error_at: None,
|
|
total_files_synced: 10,
|
|
total_files_pending: 0,
|
|
total_size_bytes: 1024,
|
|
created_at: Utc::now(),
|
|
updated_at: Utc::now(),
|
|
validation_status: None,
|
|
last_validation_at: None,
|
|
validation_score: None,
|
|
validation_issues: None,
|
|
};
|
|
|
|
assert_eq!(completed_source.status, SourceStatus::Idle);
|
|
}
|
|
|
|
#[test]
|
|
fn test_auto_sync_configuration() {
|
|
// Test WebDAV auto sync enabled
|
|
let webdav_config = WebDAVSourceConfig {
|
|
server_url: "https://test.com".to_string(),
|
|
username: "test".to_string(),
|
|
password: "test".to_string(),
|
|
watch_folders: vec!["/test".to_string()],
|
|
file_extensions: vec![".pdf".to_string()],
|
|
auto_sync: true,
|
|
sync_interval_minutes: 60,
|
|
server_type: Some("nextcloud".to_string()),
|
|
};
|
|
|
|
assert!(webdav_config.auto_sync);
|
|
assert_eq!(webdav_config.sync_interval_minutes, 60);
|
|
|
|
// Test auto sync disabled
|
|
let webdav_disabled = WebDAVSourceConfig {
|
|
server_url: "https://test.com".to_string(),
|
|
username: "test".to_string(),
|
|
password: "test".to_string(),
|
|
watch_folders: vec!["/test".to_string()],
|
|
file_extensions: vec![".pdf".to_string()],
|
|
auto_sync: false,
|
|
sync_interval_minutes: 60,
|
|
server_type: Some("nextcloud".to_string()),
|
|
};
|
|
|
|
assert!(!webdav_disabled.auto_sync);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sync_interval_validation() {
|
|
let valid_intervals = vec![1, 15, 30, 60, 120, 240];
|
|
let invalid_intervals = vec![0, -1, -30];
|
|
|
|
for interval in valid_intervals {
|
|
assert!(interval > 0, "Valid interval should be positive: {}", interval);
|
|
}
|
|
|
|
for interval in invalid_intervals {
|
|
assert!(interval <= 0, "Invalid interval should be non-positive: {}", interval);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_file_extension_validation() {
|
|
let valid_extensions = vec![".pdf", ".txt", ".jpg", ".png", ".docx"];
|
|
let invalid_extensions = vec!["pdf", "txt", "", "no-dot"];
|
|
|
|
for ext in valid_extensions {
|
|
assert!(ext.starts_with('.'), "Valid extension should start with dot: {}", ext);
|
|
assert!(!ext.is_empty(), "Valid extension should not be empty");
|
|
}
|
|
|
|
for ext in invalid_extensions {
|
|
if !ext.is_empty() {
|
|
assert!(!ext.starts_with('.') || ext.len() == 1, "Invalid extension: {}", ext);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_trigger_sync_basic() {
|
|
let state = create_test_app_state().await;
|
|
let scheduler = SourceScheduler::new(state.clone());
|
|
|
|
// Test triggering sync with non-existent source
|
|
let non_existent_id = Uuid::new_v4();
|
|
let result = scheduler.trigger_sync(non_existent_id).await;
|
|
|
|
// Should return error for non-existent source
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_source_configuration_sizes() {
|
|
// Test that configurations don't grow too large
|
|
let webdav_config = WebDAVSourceConfig {
|
|
server_url: "https://very-long-server-url-that-might-be-too-long.example.com".to_string(),
|
|
username: "test".to_string(),
|
|
password: "test".to_string(),
|
|
watch_folders: vec!["/folder1".to_string(), "/folder2".to_string()],
|
|
file_extensions: vec![".pdf".to_string(), ".txt".to_string(), ".jpg".to_string()],
|
|
auto_sync: true,
|
|
sync_interval_minutes: 60,
|
|
server_type: Some("nextcloud".to_string()),
|
|
};
|
|
|
|
let serialized = serde_json::to_string(&webdav_config).unwrap();
|
|
assert!(serialized.len() < 1024, "Config should not be too large");
|
|
|
|
// Test that required fields are present
|
|
assert!(!webdav_config.server_url.is_empty());
|
|
assert!(!webdav_config.username.is_empty());
|
|
assert!(!webdav_config.watch_folders.is_empty());
|
|
assert!(!webdav_config.file_extensions.is_empty());
|
|
} |