Readur/src/tests/ignored_files_tests.rs

317 lines
12 KiB
Rust

#[cfg(test)]
mod tests {
use crate::db::ignored_files::{
create_ignored_file, list_ignored_files, get_ignored_file_by_id, delete_ignored_file,
is_file_ignored, count_ignored_files, bulk_delete_ignored_files,
create_ignored_file_from_document
};
use crate::models::{CreateIgnoredFile, IgnoredFilesQuery, User, UserRole, Document, AuthProvider};
use uuid::Uuid;
use chrono::Utc;
use sqlx::PgPool;
use std::env;
async fn create_test_db_pool() -> PgPool {
let database_url = env::var("TEST_DATABASE_URL")
.or_else(|_| env::var("DATABASE_URL"))
.unwrap_or_else(|_| {
// Skip tests if no database URL is available
println!("Skipping database tests: TEST_DATABASE_URL or DATABASE_URL not set");
std::process::exit(0);
});
PgPool::connect(&database_url)
.await
.expect("Failed to connect to test database")
}
async fn create_test_user(pool: &PgPool) -> User {
let user_id = Uuid::new_v4();
let user = User {
id: user_id,
username: format!("testuser_{}", user_id),
email: format!("test_{}@example.com", user_id),
password_hash: Some("hashed_password".to_string()),
role: UserRole::User,
created_at: Utc::now(),
updated_at: Utc::now(),
oidc_subject: None,
oidc_issuer: None,
oidc_email: None,
auth_provider: AuthProvider::Local,
};
sqlx::query("INSERT INTO users (id, username, email, password_hash, role, created_at, updated_at, oidc_subject, oidc_issuer, oidc_email, auth_provider) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)")
.bind(user.id)
.bind(&user.username)
.bind(&user.email)
.bind(&user.password_hash)
.bind(user.role.to_string())
.bind(user.created_at)
.bind(user.updated_at)
.bind(&user.oidc_subject)
.bind(&user.oidc_issuer)
.bind(&user.oidc_email)
.bind(user.auth_provider.to_string())
.execute(pool)
.await
.expect("Failed to insert test user");
user
}
async fn create_test_document(pool: &PgPool, user_id: Uuid) -> Document {
let document_id = Uuid::new_v4();
let document = Document {
id: document_id,
filename: "test_document.pdf".to_string(),
original_filename: "test_document.pdf".to_string(),
file_path: "/uploads/test_document.pdf".to_string(),
file_size: 1024000,
mime_type: "application/pdf".to_string(),
content: Some("Test document content".to_string()),
ocr_text: Some("This is extracted OCR text from the test document.".to_string()),
ocr_confidence: Some(95.5),
ocr_word_count: Some(150),
ocr_processing_time_ms: Some(1200),
ocr_status: Some("completed".to_string()),
ocr_error: None,
ocr_completed_at: Some(Utc::now()),
tags: vec!["test".to_string(), "document".to_string()],
created_at: Utc::now(),
updated_at: Utc::now(),
user_id,
file_hash: Some("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef".to_string()),
};
sqlx::query("INSERT INTO documents (id, filename, original_filename, file_path, file_size, mime_type, content, ocr_text, ocr_confidence, ocr_word_count, ocr_processing_time_ms, ocr_status, ocr_error, ocr_completed_at, tags, created_at, updated_at, user_id, file_hash) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)")
.bind(document.id)
.bind(&document.filename)
.bind(&document.original_filename)
.bind(&document.file_path)
.bind(document.file_size as i64)
.bind(&document.mime_type)
.bind(&document.content)
.bind(&document.ocr_text)
.bind(document.ocr_confidence)
.bind(document.ocr_word_count.map(|x| x as i32))
.bind(document.ocr_processing_time_ms.map(|x| x as i32))
.bind(&document.ocr_status)
.bind(&document.ocr_error)
.bind(document.ocr_completed_at)
.bind(&document.tags)
.bind(document.created_at)
.bind(document.updated_at)
.bind(document.user_id)
.bind(&document.file_hash)
.execute(pool)
.await
.expect("Failed to insert test document");
document
}
#[tokio::test]
async fn test_create_ignored_file() {
let pool = create_test_db_pool().await;
let user = create_test_user(&pool).await;
let ignored_file = CreateIgnoredFile {
file_hash: "abc123".to_string(),
filename: "test.pdf".to_string(),
original_filename: "original_test.pdf".to_string(),
file_path: "/path/to/test.pdf".to_string(),
file_size: 1024,
mime_type: "application/pdf".to_string(),
source_type: Some("webdav".to_string()),
source_path: Some("/webdav/test.pdf".to_string()),
source_identifier: Some("webdav-server-1".to_string()),
ignored_by: user.id,
reason: Some("deleted by user".to_string()),
};
let result = create_ignored_file(&pool, ignored_file).await;
assert!(result.is_ok());
let created = result.unwrap();
assert_eq!(created.file_hash, "abc123");
assert_eq!(created.filename, "test.pdf");
assert_eq!(created.ignored_by, user.id);
assert_eq!(created.source_type, Some("webdav".to_string()));
}
#[tokio::test]
async fn test_list_ignored_files() {
let pool = create_test_db_pool().await;
let user = create_test_user(&pool).await;
// Create multiple ignored files
for i in 0..3 {
let ignored_file = CreateIgnoredFile {
file_hash: format!("hash{}", i),
filename: format!("test{}.pdf", i),
original_filename: format!("original_test{}.pdf", i),
file_path: format!("/path/to/test{}.pdf", i),
file_size: 1024 * (i + 1) as i64,
mime_type: "application/pdf".to_string(),
source_type: Some("webdav".to_string()),
source_path: Some(format!("/webdav/test{}.pdf", i)),
source_identifier: Some("webdav-server-1".to_string()),
ignored_by: user.id,
reason: Some("deleted by user".to_string()),
};
create_ignored_file(&pool, ignored_file).await.unwrap();
}
let query = IgnoredFilesQuery {
limit: Some(10),
offset: Some(0),
source_type: None,
source_identifier: None,
ignored_by: None,
filename: None,
};
let result = list_ignored_files(&pool, user.id, &query).await;
assert!(result.is_ok());
let ignored_files = result.unwrap();
assert_eq!(ignored_files.len(), 3);
assert!(ignored_files.iter().all(|f| f.ignored_by == user.id));
}
#[tokio::test]
async fn test_get_ignored_file_by_id() {
let pool = create_test_db_pool().await;
let user = create_test_user(&pool).await;
let ignored_file = CreateIgnoredFile {
file_hash: "test_hash".to_string(),
filename: "test.pdf".to_string(),
original_filename: "original_test.pdf".to_string(),
file_path: "/path/to/test.pdf".to_string(),
file_size: 1024,
mime_type: "application/pdf".to_string(),
source_type: Some("webdav".to_string()),
source_path: Some("/webdav/test.pdf".to_string()),
source_identifier: Some("webdav-server-1".to_string()),
ignored_by: user.id,
reason: Some("deleted by user".to_string()),
};
let created = create_ignored_file(&pool, ignored_file).await.unwrap();
let result = get_ignored_file_by_id(&pool, created.id, user.id).await;
assert!(result.is_ok());
let fetched = result.unwrap();
assert!(fetched.is_some());
let fetched = fetched.unwrap();
assert_eq!(fetched.id, created.id);
assert_eq!(fetched.file_hash, "test_hash");
assert_eq!(fetched.filename, "test.pdf");
}
#[tokio::test]
async fn test_delete_ignored_file() {
let pool = create_test_db_pool().await;
let user = create_test_user(&pool).await;
let ignored_file = CreateIgnoredFile {
file_hash: "test_hash".to_string(),
filename: "test.pdf".to_string(),
original_filename: "original_test.pdf".to_string(),
file_path: "/path/to/test.pdf".to_string(),
file_size: 1024,
mime_type: "application/pdf".to_string(),
source_type: Some("webdav".to_string()),
source_path: Some("/webdav/test.pdf".to_string()),
source_identifier: Some("webdav-server-1".to_string()),
ignored_by: user.id,
reason: Some("deleted by user".to_string()),
};
let created = create_ignored_file(&pool, ignored_file).await.unwrap();
let result = delete_ignored_file(&pool, created.id, user.id).await;
assert!(result.is_ok());
assert!(result.unwrap());
// Verify it's deleted
let fetched = get_ignored_file_by_id(&pool, created.id, user.id).await;
assert!(fetched.is_ok());
assert!(fetched.unwrap().is_none());
}
#[tokio::test]
async fn test_is_file_ignored() {
let pool = create_test_db_pool().await;
let user = create_test_user(&pool).await;
let ignored_file = CreateIgnoredFile {
file_hash: "test_hash".to_string(),
filename: "test.pdf".to_string(),
original_filename: "original_test.pdf".to_string(),
file_path: "/path/to/test.pdf".to_string(),
file_size: 1024,
mime_type: "application/pdf".to_string(),
source_type: Some("webdav".to_string()),
source_path: Some("/webdav/test.pdf".to_string()),
source_identifier: Some("webdav-server-1".to_string()),
ignored_by: user.id,
reason: Some("deleted by user".to_string()),
};
create_ignored_file(&pool, ignored_file).await.unwrap();
// Test with exact match
let result = is_file_ignored(
&pool,
"test_hash",
Some("webdav"),
Some("/webdav/test.pdf")
).await;
assert!(result.is_ok());
assert!(result.unwrap());
// Test with just hash
let result = is_file_ignored(&pool, "test_hash", None, None).await;
assert!(result.is_ok());
assert!(result.unwrap());
// Test with non-existing hash
let result = is_file_ignored(&pool, "non_existing", None, None).await;
assert!(result.is_ok());
assert!(!result.unwrap());
}
#[tokio::test]
async fn test_create_ignored_file_from_document() {
let pool = create_test_db_pool().await;
let user = create_test_user(&pool).await;
let document = create_test_document(&pool, user.id).await;
let result = create_ignored_file_from_document(
&pool,
document.id,
user.id,
Some("deleted by user".to_string()),
Some("webdav".to_string()),
Some("/webdav/test.pdf".to_string()),
Some("webdav-server-1".to_string()),
).await;
assert!(result.is_ok());
let ignored_file = result.unwrap();
assert!(ignored_file.is_some());
let ignored_file = ignored_file.unwrap();
assert_eq!(ignored_file.filename, document.filename);
assert_eq!(ignored_file.file_size, document.file_size);
assert_eq!(ignored_file.mime_type, document.mime_type);
assert_eq!(ignored_file.ignored_by, user.id);
assert_eq!(ignored_file.source_type, Some("webdav".to_string()));
assert_eq!(ignored_file.reason, Some("deleted by user".to_string()));
}
}