mirror of
https://github.com/readur/readur.git
synced 2025-12-17 20:35:17 -06:00
338 lines
12 KiB
Rust
338 lines
12 KiB
Rust
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use tokio::time::timeout;
|
|
use uuid::Uuid;
|
|
|
|
use readur::{
|
|
services::webdav::{WebDAVService, WebDAVConfig, RetryConfig},
|
|
scheduling::webdav_scheduler::WebDAVScheduler,
|
|
models::*,
|
|
db::Database,
|
|
test_helpers::create_test_config_with_db,
|
|
AppState,
|
|
};
|
|
|
|
#[tokio::test]
|
|
async fn test_retry_config_default() {
|
|
let retry_config = RetryConfig::default();
|
|
|
|
assert_eq!(retry_config.max_retries, 3);
|
|
assert_eq!(retry_config.initial_delay_ms, 1000);
|
|
assert_eq!(retry_config.max_delay_ms, 10000);
|
|
assert_eq!(retry_config.backoff_multiplier, 2.0);
|
|
assert_eq!(retry_config.timeout_seconds, 30);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_webdav_service_with_custom_retry() {
|
|
let config = WebDAVConfig {
|
|
server_url: "https://cloud.example.com".to_string(),
|
|
username: "testuser".to_string(),
|
|
password: "testpass".to_string(),
|
|
watch_folders: vec!["/Documents".to_string()],
|
|
file_extensions: vec!["pdf".to_string()],
|
|
timeout_seconds: 30,
|
|
server_type: Some("nextcloud".to_string()),
|
|
};
|
|
|
|
let retry_config = RetryConfig {
|
|
max_retries: 5,
|
|
initial_delay_ms: 500,
|
|
max_delay_ms: 10000,
|
|
backoff_multiplier: 1.5,
|
|
timeout_seconds: 60,
|
|
rate_limit_backoff_ms: 5000,
|
|
};
|
|
|
|
let result = WebDAVService::new_with_retry(config, retry_config);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn test_webdav_config_builder() {
|
|
let config = WebDAVConfig {
|
|
server_url: "https://nextcloud.example.com".to_string(),
|
|
username: "admin".to_string(),
|
|
password: "secret123".to_string(),
|
|
watch_folders: vec!["/Documents".to_string(), "/Photos".to_string()],
|
|
file_extensions: vec!["pdf".to_string(), "png".to_string(), "jpg".to_string()],
|
|
timeout_seconds: 60,
|
|
server_type: Some("nextcloud".to_string()),
|
|
};
|
|
|
|
// Test Nextcloud URL construction
|
|
let service = WebDAVService::new(config.clone()).unwrap();
|
|
// Note: We can't directly test the private base_webdav_url field,
|
|
// but we can test that the service was created successfully
|
|
|
|
assert_eq!(config.watch_folders.len(), 2);
|
|
assert_eq!(config.file_extensions.len(), 3);
|
|
}
|
|
|
|
#[test]
|
|
fn test_notification_models() {
|
|
let notification_id = Uuid::new_v4();
|
|
let user_id = Uuid::new_v4();
|
|
|
|
let notification = Notification {
|
|
id: notification_id,
|
|
user_id,
|
|
notification_type: "success".to_string(),
|
|
title: "WebDAV Sync Complete".to_string(),
|
|
message: "Successfully processed 5 files".to_string(),
|
|
read: false,
|
|
action_url: Some("/documents".to_string()),
|
|
metadata: Some(serde_json::json!({
|
|
"sync_type": "webdav",
|
|
"files_processed": 5
|
|
})),
|
|
created_at: chrono::Utc::now(),
|
|
};
|
|
|
|
assert_eq!(notification.id, notification_id);
|
|
assert_eq!(notification.user_id, user_id);
|
|
assert_eq!(notification.notification_type, "success");
|
|
assert_eq!(notification.title, "WebDAV Sync Complete");
|
|
assert!(!notification.read);
|
|
assert_eq!(notification.action_url, Some("/documents".to_string()));
|
|
|
|
// Test metadata extraction
|
|
let metadata = notification.metadata.unwrap();
|
|
assert_eq!(metadata["sync_type"], "webdav");
|
|
assert_eq!(metadata["files_processed"], 5);
|
|
}
|
|
|
|
#[test]
|
|
fn test_create_notification_model() {
|
|
let create_notification = CreateNotification {
|
|
notification_type: "warning".to_string(),
|
|
title: "WebDAV Connection Issue".to_string(),
|
|
message: "Unable to connect to WebDAV server, retrying...".to_string(),
|
|
action_url: Some("/settings".to_string()),
|
|
metadata: Some(serde_json::json!({
|
|
"error_type": "connection_timeout",
|
|
"retry_count": 2
|
|
})),
|
|
};
|
|
|
|
assert_eq!(create_notification.notification_type, "warning");
|
|
assert_eq!(create_notification.title, "WebDAV Connection Issue");
|
|
assert_eq!(create_notification.action_url, Some("/settings".to_string()));
|
|
|
|
let metadata = create_notification.metadata.unwrap();
|
|
assert_eq!(metadata["error_type"], "connection_timeout");
|
|
assert_eq!(metadata["retry_count"], 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_notification_summary() {
|
|
let user_id = Uuid::new_v4();
|
|
|
|
let notification1 = Notification {
|
|
id: Uuid::new_v4(),
|
|
user_id,
|
|
notification_type: "success".to_string(),
|
|
title: "Sync Complete".to_string(),
|
|
message: "10 files processed".to_string(),
|
|
read: false,
|
|
action_url: None,
|
|
metadata: None,
|
|
created_at: chrono::Utc::now(),
|
|
};
|
|
|
|
let notification2 = Notification {
|
|
id: Uuid::new_v4(),
|
|
user_id,
|
|
notification_type: "error".to_string(),
|
|
title: "Sync Failed".to_string(),
|
|
message: "Connection timeout".to_string(),
|
|
read: true,
|
|
action_url: Some("/settings".to_string()),
|
|
metadata: None,
|
|
created_at: chrono::Utc::now(),
|
|
};
|
|
|
|
let summary = NotificationSummary {
|
|
unread_count: 1,
|
|
recent_notifications: vec![notification1, notification2],
|
|
};
|
|
|
|
assert_eq!(summary.unread_count, 1);
|
|
assert_eq!(summary.recent_notifications.len(), 2);
|
|
assert!(!summary.recent_notifications[0].read);
|
|
assert!(summary.recent_notifications[1].read);
|
|
}
|
|
|
|
#[test]
|
|
fn test_webdav_error_handling() {
|
|
// Test error classification for retry logic
|
|
let timeout_error = anyhow::anyhow!("Connection timeout occurred");
|
|
let network_error = anyhow::anyhow!("Network connection failed");
|
|
let auth_error = anyhow::anyhow!("401 Unauthorized");
|
|
|
|
// These would be tested by WebDAVService::is_retryable_error if it were public
|
|
// For now, we test that errors can be created and formatted
|
|
assert!(timeout_error.to_string().contains("timeout"));
|
|
assert!(network_error.to_string().contains("connection"));
|
|
assert!(auth_error.to_string().contains("401"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_webdav_file_filtering() {
|
|
let supported_extensions = vec!["pdf", "png", "jpg", "jpeg", "tiff", "bmp", "txt"];
|
|
|
|
// Test file extension extraction and filtering
|
|
let test_files = vec![
|
|
"document.pdf",
|
|
"image.PNG", // Test case insensitivity
|
|
"photo.jpg",
|
|
"spreadsheet.xlsx", // Should be filtered out
|
|
"text.txt",
|
|
"archive.zip", // Should be filtered out
|
|
"picture.jpeg",
|
|
];
|
|
|
|
let mut supported_count = 0;
|
|
for filename in test_files {
|
|
if let Some(extension) = std::path::Path::new(filename)
|
|
.extension()
|
|
.and_then(|ext| ext.to_str())
|
|
{
|
|
let ext_lower = extension.to_lowercase();
|
|
if supported_extensions.contains(&ext_lower.as_str()) {
|
|
supported_count += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert_eq!(supported_count, 5); // pdf, PNG, jpg, txt, jpeg
|
|
}
|
|
|
|
#[test]
|
|
fn test_priority_calculation() {
|
|
// Test OCR priority calculation based on file size
|
|
let test_cases = vec![
|
|
(500_000, 10), // 500KB -> highest priority
|
|
(2_000_000, 8), // 2MB -> high priority
|
|
(7_000_000, 6), // 7MB -> medium priority
|
|
(25_000_000, 4), // 25MB -> low priority
|
|
(100_000_000, 2), // 100MB -> lowest priority
|
|
];
|
|
|
|
for (file_size, expected_priority) in test_cases {
|
|
let priority = match file_size {
|
|
0..=1048576 => 10, // <= 1MB
|
|
..=5242880 => 8, // 1-5MB
|
|
..=10485760 => 6, // 5-10MB
|
|
..=52428800 => 4, // 10-50MB
|
|
_ => 2, // > 50MB
|
|
};
|
|
|
|
assert_eq!(priority, expected_priority,
|
|
"File size {} bytes should have priority {}", file_size, expected_priority);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_webdav_url_construction() {
|
|
// Test different server types and URL construction
|
|
let test_cases = vec![
|
|
("nextcloud", "https://cloud.example.com", "testuser", "https://cloud.example.com/remote.php/dav/files/testuser"),
|
|
("owncloud", "https://cloud.example.com/", "admin", "https://cloud.example.com/remote.php/dav/files/admin"),
|
|
("generic", "https://webdav.example.com", "user", "https://webdav.example.com/webdav"),
|
|
];
|
|
|
|
for (server_type, server_url, username, expected_base) in test_cases {
|
|
let config = WebDAVConfig {
|
|
server_url: server_url.to_string(),
|
|
username: username.to_string(),
|
|
password: "password".to_string(),
|
|
watch_folders: vec!["/Documents".to_string()],
|
|
file_extensions: vec!["pdf".to_string()],
|
|
timeout_seconds: 30,
|
|
server_type: Some(server_type.to_string()),
|
|
};
|
|
|
|
let service = WebDAVService::new(config);
|
|
assert!(service.is_ok(), "Failed to create WebDAV service for {} server type", server_type);
|
|
|
|
// Note: We can't directly test the URL construction since base_webdav_url is private,
|
|
// but we can verify the service was created successfully with the config
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_settings_webdav_integration() {
|
|
let mut settings = Settings::default();
|
|
|
|
// Test enabling WebDAV
|
|
settings.webdav_enabled = true;
|
|
settings.webdav_server_url = Some("https://nextcloud.example.com".to_string());
|
|
settings.webdav_username = Some("testuser".to_string());
|
|
settings.webdav_password = Some("testpass".to_string());
|
|
settings.webdav_auto_sync = true;
|
|
settings.webdav_sync_interval_minutes = 30;
|
|
settings.webdav_watch_folders = vec!["/Documents".to_string(), "/Photos".to_string()];
|
|
|
|
assert!(settings.webdav_enabled);
|
|
assert_eq!(settings.webdav_server_url, Some("https://nextcloud.example.com".to_string()));
|
|
assert_eq!(settings.webdav_username, Some("testuser".to_string()));
|
|
assert!(settings.webdav_auto_sync);
|
|
assert_eq!(settings.webdav_sync_interval_minutes, 30);
|
|
assert_eq!(settings.webdav_watch_folders.len(), 2);
|
|
|
|
// Test that we can build a WebDAVConfig from settings
|
|
if let (Some(server_url), Some(username)) = (&settings.webdav_server_url, &settings.webdav_username) {
|
|
let webdav_config = WebDAVConfig {
|
|
server_url: server_url.clone(),
|
|
username: username.clone(),
|
|
password: settings.webdav_password.clone().unwrap_or_default(),
|
|
watch_folders: settings.webdav_watch_folders.clone(),
|
|
file_extensions: settings.webdav_file_extensions.clone(),
|
|
timeout_seconds: 30,
|
|
server_type: Some("nextcloud".to_string()),
|
|
};
|
|
|
|
assert_eq!(webdav_config.server_url, "https://nextcloud.example.com");
|
|
assert_eq!(webdav_config.username, "testuser");
|
|
assert_eq!(webdav_config.watch_folders.len(), 2);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_backoff_calculation() {
|
|
let retry_config = RetryConfig::default();
|
|
let mut delay = retry_config.initial_delay_ms;
|
|
|
|
// Test exponential backoff calculation
|
|
let expected_delays = vec![1000, 2000, 4000]; // 1s, 2s, 4s with 2.0 multiplier
|
|
|
|
for expected in expected_delays {
|
|
assert_eq!(delay, expected);
|
|
delay = ((delay as f64 * retry_config.backoff_multiplier) as u64)
|
|
.min(retry_config.max_delay_ms);
|
|
}
|
|
|
|
// Test that delay doesn't exceed max
|
|
for _ in 0..10 {
|
|
delay = ((delay as f64 * retry_config.backoff_multiplier) as u64)
|
|
.min(retry_config.max_delay_ms);
|
|
assert!(delay <= retry_config.max_delay_ms);
|
|
}
|
|
}
|
|
|
|
// Mock test for WebDAV scheduler (without actual database)
|
|
#[test]
|
|
fn test_webdav_scheduler_creation() {
|
|
// Create mock state - in a real test environment you'd use test database
|
|
let mut config = create_test_config_with_db("postgres://test");
|
|
config.server_address = "127.0.0.1:3000".to_string();
|
|
|
|
// Note: This is a minimal test since we can't easily mock the database
|
|
// In a full integration test, you'd set up a test database
|
|
|
|
assert_eq!(config.server_address, "127.0.0.1:3000");
|
|
assert_eq!(config.upload_path, "/tmp/test_uploads");
|
|
|
|
// The scheduler would be tested with a real database in integration tests
|
|
} |