Files
qiming/qiming-mcp-proxy/document-parser/tests/image_processing_integration_tests.rs
2026-06-01 13:03:20 +08:00

313 lines
9.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use document_parser::services::image_processor::{
ImageProcessor, ImageProcessorConfig, ImageUploadResult,
};
use std::path::Path;
use tempfile::TempDir;
#[tokio::test]
async fn test_image_processing_pipeline() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 创建测试图片文件
let test_images = create_test_images(&temp_dir).await;
// 测试批量处理
let result = processor.batch_upload_images(test_images.clone()).await;
assert!(result.is_ok());
let batch_result = result.unwrap();
assert_eq!(batch_result.len(), test_images.len());
// 检查结果
for upload_result in &batch_result {
// 由于没有OSS服务预期会失败但不会panic
assert!(!upload_result.success);
assert!(upload_result.error_message.is_some());
}
}
#[tokio::test]
async fn test_image_extraction_from_directory() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 创建测试目录结构
let test_dir = temp_dir.path().join("images");
tokio::fs::create_dir_all(&test_dir).await.unwrap();
// 创建测试图片
create_test_image(&test_dir.join("test1.jpg")).await;
create_test_image(&test_dir.join("test2.png")).await;
// 测试提取(注意:当前实现不支持递归子目录)
let result = processor
.extract_images_from_directory(test_dir.to_str().unwrap())
.await;
assert!(result.is_ok());
let image_paths = result.unwrap();
assert_eq!(image_paths.len(), 2);
}
#[tokio::test]
async fn test_error_handling_and_recovery() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 测试不存在的文件
let non_existent_files = vec![
"/non/existent/file1.jpg".to_string(),
"/non/existent/file2.png".to_string(),
];
let result = processor.batch_upload_images(non_existent_files).await;
assert!(result.is_ok());
let batch_result = result.unwrap();
assert_eq!(batch_result.len(), 2);
// 所有结果都应该失败
for upload_result in &batch_result {
assert!(!upload_result.success);
assert!(upload_result.error_message.is_some());
}
}
#[tokio::test]
async fn test_performance_with_large_batch() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 创建大量测试图片
let mut test_images = Vec::new();
for i in 0..50 {
let image_path = temp_dir.path().join(format!("test_{i}.jpg"));
create_test_image(&image_path).await;
test_images.push(image_path.to_string_lossy().to_string());
}
let start_time = std::time::Instant::now();
let result = processor.batch_upload_images(test_images.clone()).await;
let processing_time = start_time.elapsed();
assert!(result.is_ok());
let batch_result = result.unwrap();
assert_eq!(batch_result.len(), test_images.len());
// 性能检查处理50个图片应该在合理时间内完成
assert!(
processing_time.as_secs() < 30,
"Processing took too long: {processing_time:?}"
);
println!(
"Processed {} images in {:?}",
test_images.len(),
processing_time
);
}
#[tokio::test]
async fn test_concurrent_processing() {
let temp_dir = TempDir::new().unwrap();
// 创建多个处理器实例
let config1 = ImageProcessorConfig::default();
let config2 = ImageProcessorConfig::default();
let processor1 = ImageProcessor::new(config1, None);
let processor2 = ImageProcessor::new(config2, None);
// 创建测试图片
let test_images1 = create_test_images(&temp_dir).await;
let test_images2 = create_test_images(&temp_dir).await;
// 并发处理
let (result1, result2): (
anyhow::Result<Vec<ImageUploadResult>>,
anyhow::Result<Vec<ImageUploadResult>>,
) = tokio::join!(
processor1.batch_upload_images(test_images1.clone()),
processor2.batch_upload_images(test_images2.clone())
);
assert!(result1.is_ok());
assert!(result2.is_ok());
let batch_result1 = result1.unwrap();
let batch_result2 = result2.unwrap();
assert_eq!(batch_result1.len(), test_images1.len());
assert_eq!(batch_result2.len(), test_images2.len());
}
#[tokio::test]
async fn test_markdown_image_replacement() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 创建测试图片
let image_path = temp_dir.path().join("test.jpg");
create_test_image(&image_path).await;
// 创建包含图片的Markdown内容
let markdown_content = format!(
"# Test Document\n\n![Test Image]({})\n\nSome text here.",
image_path.to_string_lossy()
);
// 测试替换由于没有OSS服务图片路径不会被替换
let result = processor.replace_markdown_images(&markdown_content).await;
assert!(result.is_ok());
let processed_content = result.unwrap();
// 由于没有OSS服务内容应该保持不变
assert_eq!(processed_content, markdown_content);
}
#[tokio::test]
async fn test_image_validation() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 创建有效的图片文件
let valid_image = temp_dir.path().join("valid.jpg");
create_test_image(&valid_image).await;
// 创建无效的文件(非图片格式)
let invalid_file = temp_dir.path().join("invalid.txt");
tokio::fs::write(&invalid_file, "not an image")
.await
.unwrap();
// 测试验证
let valid_result = processor
.validate_image_file(valid_image.to_str().unwrap())
.await;
assert!(valid_result.is_ok());
assert!(valid_result.unwrap());
let invalid_result = processor
.validate_image_file(invalid_file.to_str().unwrap())
.await;
assert!(invalid_result.is_ok());
assert!(!invalid_result.unwrap());
// 测试不存在的文件
let nonexistent_result = processor.validate_image_file("/nonexistent/file.jpg").await;
assert!(nonexistent_result.is_ok());
assert!(!nonexistent_result.unwrap());
}
#[tokio::test]
async fn test_extract_image_paths_from_markdown() {
let markdown_content = r#"
# Test Document
![Image 1](images/test1.jpg)
![Image 2](./local/test2.png)
![External Image](https://example.com/image.jpg)
![Another Image](../parent/test3.gif)
Some text here.
"#;
let paths = ImageProcessor::extract_image_paths(markdown_content);
// 应该提取到3个本地图片路径排除外部URL
assert_eq!(paths.len(), 3);
assert!(paths.contains(&"images/test1.jpg".to_string()));
assert!(paths.contains(&"./local/test2.png".to_string()));
assert!(paths.contains(&"../parent/test3.gif".to_string()));
}
#[tokio::test]
async fn test_cache_functionality() {
let temp_dir = TempDir::new().unwrap();
let config = ImageProcessorConfig::default();
let processor = ImageProcessor::new(config, None);
// 初始缓存应该为空
let (total, successful) = processor.get_cache_stats().await;
assert_eq!(total, 0);
assert_eq!(successful, 0);
// 尝试上传一些图片由于没有OSS服务会失败且不会被缓存
let test_images = create_test_images(&temp_dir).await;
let result = processor.batch_upload_images(test_images).await;
// 验证上传结果
assert!(result.is_ok());
let upload_results = result.unwrap();
assert!(!upload_results.is_empty());
// 由于没有OSS服务所有上传都应该失败
for upload_result in &upload_results {
assert!(!upload_result.success);
assert!(upload_result.error_message.is_some());
}
// 检查缓存统计(失败的上传不会被缓存)
let (total_after, successful_after) = processor.get_cache_stats().await;
assert_eq!(total_after, 0); // 失败的上传不会被缓存
assert_eq!(successful_after, 0);
// 清空缓存(即使为空也应该正常工作)
processor.clear_cache().await;
let (total_cleared, successful_cleared) = processor.get_cache_stats().await;
assert_eq!(total_cleared, 0);
assert_eq!(successful_cleared, 0);
}
// 辅助函数
async fn create_test_images(temp_dir: &TempDir) -> Vec<String> {
let mut images = Vec::new();
for (i, ext) in ["jpg", "png", "gif"].iter().enumerate() {
let image_path = temp_dir.path().join(format!("test_{i}.{ext}"));
create_test_image(&image_path).await;
images.push(image_path.to_string_lossy().to_string());
}
images
}
async fn create_test_image(path: &Path) {
// 创建模拟图片文件(简单的二进制数据)
let mut content = Vec::new();
// 根据扩展名添加相应的文件头
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
match ext.to_lowercase().as_str() {
"jpg" | "jpeg" => {
content.extend_from_slice(&[0xFF, 0xD8, 0xFF, 0xE0]); // JPEG header
}
"png" => {
content.extend_from_slice(&[0x89, 0x50, 0x4E, 0x47]); // PNG header
}
"gif" => {
content.extend_from_slice(&[0x47, 0x49, 0x46, 0x38]); // GIF header
}
_ => {
content.extend_from_slice(&[0xFF, 0xD8, 0xFF, 0xE0]); // Default to JPEG
}
}
}
// 添加一些随机数据
for i in 0..1024 {
content.push((i % 256) as u8);
}
tokio::fs::write(path, &content).await.unwrap();
}