mirror of
https://github.com/readur/readur.git
synced 2026-01-13 10:09:48 -06:00
555 lines
22 KiB
Rust
555 lines
22 KiB
Rust
#[cfg(test)]
|
|
mod tests {
|
|
use anyhow::Result;
|
|
use readur::models::UpdateSettings;
|
|
use readur::test_utils::{TestContext, TestAuthHelper};
|
|
use axum::http::StatusCode;
|
|
use tower::util::ServiceExt;
|
|
|
|
#[tokio::test]
|
|
async fn test_get_settings_default() {
|
|
let ctx = TestContext::new().await;
|
|
|
|
// Ensure cleanup happens even if test fails
|
|
let result: Result<()> = async {
|
|
let auth_helper = TestAuthHelper::new(ctx.app.clone());
|
|
let user = auth_helper.create_test_user().await;
|
|
let token = auth_helper.login_user(&user.username, "password123").await;
|
|
|
|
let response = ctx.app.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("GET")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token))
|
|
.body(axum::body::Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Accept either OK (200) or Internal Server Error (500) for database integration tests
|
|
let status = response.status();
|
|
assert!(status == StatusCode::OK || status == StatusCode::INTERNAL_SERVER_ERROR,
|
|
"Expected OK or Internal Server Error, got: {}", status);
|
|
|
|
if status == StatusCode::OK {
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
|
.await
|
|
.unwrap();
|
|
let settings: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
assert_eq!(settings["ocr_language"], "eng");
|
|
}
|
|
|
|
Ok(())
|
|
}.await;
|
|
|
|
// Always cleanup database connections and test data
|
|
if let Err(e) = ctx.cleanup_and_close().await {
|
|
eprintln!("Warning: Test cleanup failed: {}", e);
|
|
}
|
|
|
|
result.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_settings() {
|
|
let ctx = TestContext::new().await;
|
|
|
|
// Ensure cleanup happens even if test fails
|
|
let result: Result<()> = async {
|
|
let auth_helper = TestAuthHelper::new(ctx.app.clone());
|
|
let user = auth_helper.create_test_user().await;
|
|
let token = auth_helper.login_user(&user.username, "password123").await;
|
|
|
|
let update_data = UpdateSettings {
|
|
ocr_language: Some("spa".to_string()),
|
|
preferred_languages: None,
|
|
primary_language: None,
|
|
auto_detect_language_combination: None,
|
|
concurrent_ocr_jobs: None,
|
|
ocr_timeout_seconds: None,
|
|
max_file_size_mb: None,
|
|
allowed_file_types: None,
|
|
auto_rotate_images: None,
|
|
enable_image_preprocessing: None,
|
|
search_results_per_page: None,
|
|
search_snippet_length: None,
|
|
fuzzy_search_threshold: None,
|
|
retention_days: None,
|
|
enable_auto_cleanup: None,
|
|
enable_compression: None,
|
|
memory_limit_mb: None,
|
|
cpu_priority: None,
|
|
enable_background_ocr: None,
|
|
ocr_page_segmentation_mode: None,
|
|
ocr_engine_mode: None,
|
|
ocr_min_confidence: None,
|
|
ocr_dpi: None,
|
|
ocr_enhance_contrast: None,
|
|
ocr_remove_noise: None,
|
|
ocr_detect_orientation: None,
|
|
ocr_whitelist_chars: None,
|
|
ocr_blacklist_chars: None,
|
|
ocr_brightness_boost: None,
|
|
ocr_contrast_multiplier: None,
|
|
ocr_noise_reduction_level: None,
|
|
ocr_sharpening_strength: None,
|
|
ocr_morphological_operations: None,
|
|
ocr_adaptive_threshold_window_size: None,
|
|
ocr_histogram_equalization: None,
|
|
ocr_upscale_factor: None,
|
|
ocr_max_image_width: None,
|
|
ocr_max_image_height: None,
|
|
save_processed_images: None,
|
|
ocr_quality_threshold_brightness: None,
|
|
ocr_quality_threshold_contrast: None,
|
|
ocr_quality_threshold_noise: None,
|
|
ocr_quality_threshold_sharpness: None,
|
|
ocr_skip_enhancement: None,
|
|
webdav_enabled: None,
|
|
webdav_server_url: None,
|
|
webdav_username: None,
|
|
webdav_password: None,
|
|
webdav_watch_folders: None,
|
|
webdav_file_extensions: None,
|
|
webdav_auto_sync: None,
|
|
webdav_sync_interval_minutes: None,
|
|
office_extraction_timeout_seconds: None,
|
|
office_extraction_enable_detailed_logging: None,
|
|
};
|
|
|
|
let response = ctx.app
|
|
.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("PUT")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token))
|
|
.header("Content-Type", "application/json")
|
|
.body(axum::body::Body::from(serde_json::to_vec(&update_data).unwrap()))
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Accept either OK (200) or Bad Request (400) for database integration tests
|
|
let status = response.status();
|
|
assert!(status == StatusCode::OK || status == StatusCode::BAD_REQUEST,
|
|
"Expected OK or Bad Request, got: {}", status);
|
|
|
|
if status == StatusCode::OK {
|
|
// Verify the update
|
|
let response = ctx.app.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("GET")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token))
|
|
.body(axum::body::Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
|
.await
|
|
.unwrap();
|
|
let settings: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
|
|
assert_eq!(settings["ocr_language"], "spa");
|
|
}
|
|
|
|
Ok(())
|
|
}.await;
|
|
|
|
// Always cleanup database connections and test data
|
|
if let Err(e) = ctx.cleanup_and_close().await {
|
|
eprintln!("Warning: Test cleanup failed: {}", e);
|
|
}
|
|
|
|
result.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_settings_isolated_per_user() {
|
|
let ctx = TestContext::new().await;
|
|
|
|
// Ensure cleanup happens even if test fails
|
|
let result: Result<()> = async {
|
|
let auth_helper = TestAuthHelper::new(ctx.app.clone());
|
|
|
|
// Create two users
|
|
let user1 = auth_helper.create_test_user().await;
|
|
let token1 = auth_helper.login_user(&user1.username, "password123").await;
|
|
|
|
let user2 = auth_helper.create_test_user().await;
|
|
let token2 = auth_helper.login_user(&user2.username, "password123").await;
|
|
|
|
// Update user1's settings
|
|
let update_data = UpdateSettings {
|
|
ocr_language: Some("fra".to_string()),
|
|
preferred_languages: None,
|
|
primary_language: None,
|
|
auto_detect_language_combination: None,
|
|
concurrent_ocr_jobs: None,
|
|
ocr_timeout_seconds: None,
|
|
max_file_size_mb: None,
|
|
allowed_file_types: None,
|
|
auto_rotate_images: None,
|
|
enable_image_preprocessing: None,
|
|
search_results_per_page: None,
|
|
search_snippet_length: None,
|
|
fuzzy_search_threshold: None,
|
|
retention_days: None,
|
|
enable_auto_cleanup: None,
|
|
enable_compression: None,
|
|
memory_limit_mb: None,
|
|
cpu_priority: None,
|
|
enable_background_ocr: None,
|
|
ocr_page_segmentation_mode: None,
|
|
ocr_engine_mode: None,
|
|
ocr_min_confidence: None,
|
|
ocr_dpi: None,
|
|
ocr_enhance_contrast: None,
|
|
ocr_remove_noise: None,
|
|
ocr_detect_orientation: None,
|
|
ocr_whitelist_chars: None,
|
|
ocr_blacklist_chars: None,
|
|
ocr_brightness_boost: None,
|
|
ocr_contrast_multiplier: None,
|
|
ocr_noise_reduction_level: None,
|
|
ocr_sharpening_strength: None,
|
|
ocr_morphological_operations: None,
|
|
ocr_adaptive_threshold_window_size: None,
|
|
ocr_histogram_equalization: None,
|
|
ocr_upscale_factor: None,
|
|
ocr_max_image_width: None,
|
|
ocr_max_image_height: None,
|
|
save_processed_images: None,
|
|
ocr_quality_threshold_brightness: None,
|
|
ocr_quality_threshold_contrast: None,
|
|
ocr_quality_threshold_noise: None,
|
|
ocr_quality_threshold_sharpness: None,
|
|
ocr_skip_enhancement: None,
|
|
webdav_enabled: None,
|
|
webdav_server_url: None,
|
|
webdav_username: None,
|
|
webdav_password: None,
|
|
webdav_watch_folders: None,
|
|
webdav_file_extensions: None,
|
|
webdav_auto_sync: None,
|
|
webdav_sync_interval_minutes: None,
|
|
office_extraction_timeout_seconds: None,
|
|
office_extraction_enable_detailed_logging: None,
|
|
};
|
|
|
|
let response = ctx.app
|
|
.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("PUT")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token1))
|
|
.header("Content-Type", "application/json")
|
|
.body(axum::body::Body::from(serde_json::to_vec(&update_data).unwrap()))
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Accept either OK (200) or Bad Request (400) for database integration tests
|
|
let status = response.status();
|
|
assert!(status == StatusCode::OK || status == StatusCode::BAD_REQUEST,
|
|
"Expected OK or Bad Request, got: {}", status);
|
|
|
|
if status == StatusCode::OK {
|
|
// Check user2's settings are still default
|
|
let response = ctx.app.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("GET")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token2))
|
|
.body(axum::body::Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
if response.status() == StatusCode::OK {
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
|
.await
|
|
.unwrap();
|
|
let settings: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
|
|
assert_eq!(settings["ocr_language"], "eng");
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}.await;
|
|
|
|
// Always cleanup database connections and test data
|
|
if let Err(e) = ctx.cleanup_and_close().await {
|
|
eprintln!("Warning: Test cleanup failed: {}", e);
|
|
}
|
|
|
|
result.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_settings_requires_auth() {
|
|
let ctx = TestContext::new().await;
|
|
|
|
// Ensure cleanup happens even if test fails
|
|
let result: Result<()> = async {
|
|
|
|
let response = ctx.app.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("GET")
|
|
.uri("/api/settings")
|
|
.body(axum::body::Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
|
|
|
Ok(())
|
|
}.await;
|
|
|
|
// Always cleanup database connections and test data
|
|
if let Err(e) = ctx.cleanup_and_close().await {
|
|
eprintln!("Warning: Test cleanup failed: {}", e);
|
|
}
|
|
|
|
result.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_multi_language_settings() {
|
|
let ctx = TestContext::new().await;
|
|
|
|
// Ensure cleanup happens even if test fails
|
|
let result: Result<()> = async {
|
|
let auth_helper = TestAuthHelper::new(ctx.app.clone());
|
|
let user = auth_helper.create_test_user().await;
|
|
let token = auth_helper.login_user(&user.username, "password123").await;
|
|
|
|
let update_data = UpdateSettings {
|
|
ocr_language: None,
|
|
preferred_languages: Some(vec!["eng".to_string(), "spa".to_string(), "fra".to_string()]),
|
|
primary_language: Some("eng".to_string()),
|
|
auto_detect_language_combination: Some(true),
|
|
concurrent_ocr_jobs: None,
|
|
ocr_timeout_seconds: None,
|
|
max_file_size_mb: None,
|
|
allowed_file_types: None,
|
|
auto_rotate_images: None,
|
|
enable_image_preprocessing: None,
|
|
search_results_per_page: None,
|
|
search_snippet_length: None,
|
|
fuzzy_search_threshold: None,
|
|
retention_days: None,
|
|
enable_auto_cleanup: None,
|
|
enable_compression: None,
|
|
memory_limit_mb: None,
|
|
cpu_priority: None,
|
|
enable_background_ocr: None,
|
|
ocr_page_segmentation_mode: None,
|
|
ocr_engine_mode: None,
|
|
ocr_min_confidence: None,
|
|
ocr_dpi: None,
|
|
ocr_enhance_contrast: None,
|
|
ocr_remove_noise: None,
|
|
ocr_detect_orientation: None,
|
|
ocr_whitelist_chars: None,
|
|
ocr_blacklist_chars: None,
|
|
ocr_brightness_boost: None,
|
|
ocr_contrast_multiplier: None,
|
|
ocr_noise_reduction_level: None,
|
|
ocr_sharpening_strength: None,
|
|
ocr_morphological_operations: None,
|
|
ocr_adaptive_threshold_window_size: None,
|
|
ocr_histogram_equalization: None,
|
|
ocr_upscale_factor: None,
|
|
ocr_max_image_width: None,
|
|
ocr_max_image_height: None,
|
|
save_processed_images: None,
|
|
ocr_quality_threshold_brightness: None,
|
|
ocr_quality_threshold_contrast: None,
|
|
ocr_quality_threshold_noise: None,
|
|
ocr_quality_threshold_sharpness: None,
|
|
ocr_skip_enhancement: None,
|
|
webdav_enabled: None,
|
|
webdav_server_url: None,
|
|
webdav_username: None,
|
|
webdav_password: None,
|
|
webdav_watch_folders: None,
|
|
webdav_file_extensions: None,
|
|
webdav_auto_sync: None,
|
|
webdav_sync_interval_minutes: None,
|
|
office_extraction_timeout_seconds: None,
|
|
office_extraction_enable_detailed_logging: None,
|
|
};
|
|
|
|
let response = ctx.app
|
|
.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("PUT")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token))
|
|
.header("Content-Type", "application/json")
|
|
.body(axum::body::Body::from(serde_json::to_vec(&update_data).unwrap()))
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Accept either OK (200) or Bad Request (400) for database integration tests
|
|
let status = response.status();
|
|
assert!(status == StatusCode::OK || status == StatusCode::BAD_REQUEST,
|
|
"Expected OK or Bad Request, got: {}", status);
|
|
|
|
if status == StatusCode::OK {
|
|
// Verify the multi-language settings were updated
|
|
let response = ctx.app.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("GET")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token))
|
|
.body(axum::body::Body::empty())
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
|
.await
|
|
.unwrap();
|
|
let settings: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
|
|
// Check that multi-language settings were properly saved
|
|
assert_eq!(settings["preferred_languages"].as_array().unwrap().len(), 3);
|
|
assert_eq!(settings["primary_language"], "eng");
|
|
assert_eq!(settings["auto_detect_language_combination"], true);
|
|
}
|
|
|
|
Ok(())
|
|
}.await;
|
|
|
|
// Always cleanup database connections and test data
|
|
if let Err(e) = ctx.cleanup_and_close().await {
|
|
eprintln!("Warning: Test cleanup failed: {}", e);
|
|
}
|
|
|
|
result.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_multi_language_settings_max_limit() {
|
|
let ctx = TestContext::new().await;
|
|
|
|
// Ensure cleanup happens even if test fails
|
|
let result: Result<()> = async {
|
|
let auth_helper = TestAuthHelper::new(ctx.app.clone());
|
|
let user = auth_helper.create_test_user().await;
|
|
let token = auth_helper.login_user(&user.username, "password123").await;
|
|
|
|
// Try to set more than 4 languages (should fail validation)
|
|
let update_data = UpdateSettings {
|
|
ocr_language: None,
|
|
preferred_languages: Some(vec![
|
|
"eng".to_string(),
|
|
"spa".to_string(),
|
|
"fra".to_string(),
|
|
"deu".to_string(),
|
|
"ita".to_string()
|
|
]),
|
|
primary_language: Some("eng".to_string()),
|
|
auto_detect_language_combination: None,
|
|
concurrent_ocr_jobs: None,
|
|
ocr_timeout_seconds: None,
|
|
max_file_size_mb: None,
|
|
allowed_file_types: None,
|
|
auto_rotate_images: None,
|
|
enable_image_preprocessing: None,
|
|
search_results_per_page: None,
|
|
search_snippet_length: None,
|
|
fuzzy_search_threshold: None,
|
|
retention_days: None,
|
|
enable_auto_cleanup: None,
|
|
enable_compression: None,
|
|
memory_limit_mb: None,
|
|
cpu_priority: None,
|
|
enable_background_ocr: None,
|
|
ocr_page_segmentation_mode: None,
|
|
ocr_engine_mode: None,
|
|
ocr_min_confidence: None,
|
|
ocr_dpi: None,
|
|
ocr_enhance_contrast: None,
|
|
ocr_remove_noise: None,
|
|
ocr_detect_orientation: None,
|
|
ocr_whitelist_chars: None,
|
|
ocr_blacklist_chars: None,
|
|
ocr_brightness_boost: None,
|
|
ocr_contrast_multiplier: None,
|
|
ocr_noise_reduction_level: None,
|
|
ocr_sharpening_strength: None,
|
|
ocr_morphological_operations: None,
|
|
ocr_adaptive_threshold_window_size: None,
|
|
ocr_histogram_equalization: None,
|
|
ocr_upscale_factor: None,
|
|
ocr_max_image_width: None,
|
|
ocr_max_image_height: None,
|
|
save_processed_images: None,
|
|
ocr_quality_threshold_brightness: None,
|
|
ocr_quality_threshold_contrast: None,
|
|
ocr_quality_threshold_noise: None,
|
|
ocr_quality_threshold_sharpness: None,
|
|
ocr_skip_enhancement: None,
|
|
webdav_enabled: None,
|
|
webdav_server_url: None,
|
|
webdav_username: None,
|
|
webdav_password: None,
|
|
webdav_watch_folders: None,
|
|
webdav_file_extensions: None,
|
|
webdav_auto_sync: None,
|
|
webdav_sync_interval_minutes: None,
|
|
office_extraction_timeout_seconds: None,
|
|
office_extraction_enable_detailed_logging: None,
|
|
};
|
|
|
|
let response = ctx.app
|
|
.clone()
|
|
.oneshot(
|
|
axum::http::Request::builder()
|
|
.method("PUT")
|
|
.uri("/api/settings")
|
|
.header("Authorization", format!("Bearer {}", token))
|
|
.header("Content-Type", "application/json")
|
|
.body(axum::body::Body::from(serde_json::to_vec(&update_data).unwrap()))
|
|
.unwrap(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Should fail with Bad Request due to too many languages
|
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
|
|
|
Ok(())
|
|
}.await;
|
|
|
|
// Always cleanup database connections and test data
|
|
if let Err(e) = ctx.cleanup_and_close().await {
|
|
eprintln!("Warning: Test cleanup failed: {}", e);
|
|
}
|
|
|
|
result.unwrap();
|
|
}
|
|
} |