Files
mixvideo-v2/cargos/tvai/tests/integration_tests.rs
imeepos bdac328e19 feat: 完成 tvai 库测试和文档 (阶段六) - 项目完成
集成测试套件
- 创建完整的集成测试 (integration_tests.rs)
- 测试库初始化和配置管理
- 测试 GPU 检测和优化功能
- 测试性能监控和基准测试
- 测试错误处理和用户友好消息
- 测试配置文件持久化
- 测试模型和参数验证
- 测试临时文件管理
- 所有测试通过

 性能基准测试
- 创建完整的基准测试套件 (performance_benchmarks.rs)
- GPU 检测性能: ~193ms
- 设置保存/加载: ~1.56ms
- 预设查找: ~29ns (超快)
- 临时文件管理: ~96μs
- 参数验证: ~3.6ns (极快)
- 错误消息生成: ~266ns
- 模型操作: ~1.9ns (极快)
- 系统检测: 24μs - 30ms

 完整 API 文档
- 创建详细的 API 文档 (docs/API.md)
- 核心组件使用指南
- 所有方法和参数说明
- 代码示例和最佳实践
- 错误处理指南
- 性能优化建议

 用户指南
- 创建完整的用户指南 (docs/USER_GUIDE.md)
- 快速入门教程
- 常见用例和场景
- 配置管理指南
- 模型选择指南
- 性能优化技巧
- 故障排除指南

 更新项目文档
- 更新主 README.md
- 标记项目为 100% 完成
- 添加文档链接和使用指南
- 添加性能和测试信息
- 添加开发设置说明
- 添加变更日志

 测试结果总结
-  单元测试: 6/6 通过
-  集成测试: 10/10 通过
-  文档测试: 1/1 通过
-  基准测试: 13/13 完成
-  所有示例运行成功

 最终项目统计
- **总代码行数**: 4,127行
- **模块文件**: 25个
- **示例文件**: 6个
- **测试文件**: 2个 (单元 + 集成)
- **基准测试**: 1个 (13项基准)
- **文档文件**: 3个 (API + 用户指南 + README)

 功能完整性 (100%)
-  视频处理 (超分辨率 + 插值)
-  图片处理 (超分辨率 + 批量)
-  格式转换 (视频  图片序列)
-  便捷接口 (一键处理函数)
-  配置管理 (全局设置 + 预设)
-  性能优化 (GPU检测 + 监控)
-  错误处理 (用户友好消息)
-  文档和测试 (完整覆盖)

 项目状态: 完成 (COMPLETE)
所有六个开发阶段已完成,tvai 库已准备好用于生产环境!
2025-08-11 16:20:27 +08:00

309 lines
11 KiB
Rust

//! Integration tests for the tvai library
use tempfile::TempDir;
use tvai::*;
/// Test basic library initialization and configuration
#[tokio::test]
async fn test_library_initialization() {
// Test global settings
let settings_manager = global_settings();
let settings = settings_manager.get_settings();
assert!(settings.max_concurrent_jobs > 0);
assert!(settings.default_quality_preset.len() > 0);
// Test preset management
let presets = global_presets();
let preset_manager = presets.lock().unwrap();
let video_presets = preset_manager.list_video_presets();
let image_presets = preset_manager.list_image_presets();
assert!(!video_presets.is_empty(), "Should have video presets");
assert!(!image_presets.is_empty(), "Should have image presets");
// Test specific presets exist
assert!(preset_manager.get_video_preset("general_2x").is_some());
assert!(preset_manager.get_image_preset("photo_2x").is_some());
}
/// Test GPU detection and optimization
#[tokio::test]
async fn test_gpu_detection() {
let gpu_info = GpuManager::detect_detailed_gpu_info();
// Basic GPU info should be available
assert!(gpu_info.devices.len() > 0, "Should detect at least one GPU device");
// Test GPU suitability check
let suitable = GpuManager::is_gpu_suitable_for_ai();
println!("GPU suitable for AI: {}", suitable);
// Test GPU benchmark
let benchmark_result = GpuManager::benchmark_gpu_performance().await;
assert!(benchmark_result.is_ok(), "GPU benchmark should complete");
let benchmark = benchmark_result.unwrap();
assert!(benchmark.processing_time.as_millis() > 0);
assert!(benchmark.compute_score > 0);
}
/// Test performance monitoring
#[tokio::test]
async fn test_performance_monitoring() {
let settings = optimize_for_system();
let mut monitor = PerformanceMonitor::new(settings);
// Test operation monitoring
let metrics = {
let _permit = monitor.acquire_slot().await.expect("Should acquire slot");
let operation_monitor = monitor.start_operation("test_operation", 50.0);
// Simulate some work
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
operation_monitor.finish(100.0)
};
// Record metrics after permit is dropped
monitor.record_metrics(metrics.clone());
assert_eq!(metrics.operation_type, "test_operation");
assert_eq!(metrics.input_size_mb, 50.0);
assert_eq!(metrics.output_size_mb, 100.0);
assert!(metrics.processing_time.as_millis() >= 10);
// Test performance summary
let summary = monitor.get_summary();
assert_eq!(summary.total_operations, 1);
}
/// Test error handling and user-friendly messages
#[test]
fn test_error_handling() {
let errors = vec![
TvaiError::TopazNotFound("/invalid/path".to_string()),
TvaiError::FfmpegError("Test error".to_string()),
TvaiError::InvalidParameter("Test parameter".to_string()),
TvaiError::GpuError("Test GPU error".to_string()),
TvaiError::UnsupportedFormat("WEBM".to_string()),
TvaiError::InsufficientResources("Test resources".to_string()),
TvaiError::PermissionDenied("Test permission".to_string()),
];
for error in errors {
// Test user-friendly messages
let friendly_msg = error.user_friendly_message();
assert!(!friendly_msg.is_empty(), "Should have user-friendly message");
// Some errors have suggestions, others just return the basic message
if matches!(error,
TvaiError::TopazNotFound(_) |
TvaiError::FfmpegError(_) |
TvaiError::InvalidParameter(_) |
TvaiError::GpuError(_) |
TvaiError::UnsupportedFormat(_) |
TvaiError::InsufficientResources(_) |
TvaiError::PermissionDenied(_)
) {
assert!(friendly_msg.contains("Suggestions:") || friendly_msg.contains("Suggestion:"),
"Should contain suggestions for error: {}", error);
}
// Test error categorization
let category = error.category();
assert!(!category.is_empty(), "Should have error category");
// Test recoverability
let recoverable = error.is_recoverable();
println!("Error {} is recoverable: {}", category, recoverable);
}
}
/// Test configuration management
#[tokio::test]
async fn test_configuration_management() {
let temp_dir = TempDir::new().expect("Should create temp dir");
let config_path = temp_dir.path().join("test_config.toml");
// Create settings manager with custom config file
let settings_manager = SettingsManager::with_config_file(&config_path);
// Update some settings
settings_manager.set_default_use_gpu(false).expect("Should update GPU setting");
settings_manager.set_max_concurrent_jobs(3).expect("Should update concurrent jobs");
// Save settings
settings_manager.save_to_file().expect("Should save settings");
// Verify file was created
assert!(config_path.exists(), "Config file should be created");
// Load settings in new manager
let new_manager = SettingsManager::with_config_file(&config_path);
let loaded_settings = new_manager.get_settings();
assert_eq!(loaded_settings.default_use_gpu, false);
assert_eq!(loaded_settings.max_concurrent_jobs, 3);
}
/// Test model and parameter validation
#[test]
fn test_model_validation() {
// Test upscale models
let models = [
UpscaleModel::Iris3,
UpscaleModel::Nyx3,
UpscaleModel::Thf4,
UpscaleModel::Ghq5,
];
for model in models {
let model_str = model.as_str();
assert!(!model_str.is_empty(), "Model should have string representation");
let description = model.description();
assert!(!description.is_empty(), "Model should have description");
// Test forced scale (if any)
if let Some(scale) = model.forces_scale() {
assert!(scale > 0.0, "Forced scale should be positive");
}
}
// Test interpolation models
let interp_models = [
InterpolationModel::Apo8,
InterpolationModel::Chr2,
InterpolationModel::Apf1,
InterpolationModel::Chf3,
];
for model in interp_models {
let model_str = model.as_str();
assert!(!model_str.is_empty(), "Interpolation model should have string representation");
let description = model.description();
assert!(!description.is_empty(), "Interpolation model should have description");
}
}
/// Test image format handling
#[test]
fn test_image_formats() {
let formats = [
ImageFormat::Png,
ImageFormat::Jpg,
ImageFormat::Tiff,
ImageFormat::Bmp,
];
for format in formats {
let extension = format.extension();
assert!(!extension.is_empty(), "Format should have extension");
let ffmpeg_format = format.ffmpeg_format();
assert!(!ffmpeg_format.is_empty(), "Format should have FFmpeg format");
}
}
/// Test parameter presets
#[test]
fn test_parameter_presets() {
// Test video upscale presets
let video_presets = [
VideoUpscaleParams::for_old_video(),
VideoUpscaleParams::for_game_content(),
VideoUpscaleParams::for_animation(),
VideoUpscaleParams::for_portrait(),
];
for preset in video_presets {
assert!(preset.scale_factor > 0.0, "Scale factor should be positive");
assert!(preset.scale_factor <= 4.0, "Scale factor should be reasonable");
assert!(preset.compression >= -1.0 && preset.compression <= 1.0, "Compression should be in valid range");
assert!(preset.blend >= 0.0 && preset.blend <= 1.0, "Blend should be in valid range");
}
// Test image upscale presets
let image_presets = [
ImageUpscaleParams::for_photo(),
ImageUpscaleParams::for_artwork(),
ImageUpscaleParams::for_screenshot(),
ImageUpscaleParams::for_portrait(),
];
for preset in image_presets {
assert!(preset.scale_factor > 0.0, "Scale factor should be positive");
assert!(preset.scale_factor <= 4.0, "Scale factor should be reasonable");
assert!(preset.compression >= -1.0 && preset.compression <= 1.0, "Compression should be in valid range");
assert!(preset.blend >= 0.0 && preset.blend <= 1.0, "Blend should be in valid range");
}
// Test interpolation presets
let slow_motion = InterpolationParams::for_slow_motion(30, 2.0);
assert_eq!(slow_motion.input_fps, 30);
assert_eq!(slow_motion.multiplier, 2.0);
let animation = InterpolationParams::for_animation(24, 2.0);
assert_eq!(animation.input_fps, 24);
assert_eq!(animation.multiplier, 2.0);
}
/// Test utility functions
#[tokio::test]
async fn test_utility_functions() {
// Test Topaz detection
let topaz_path = detect_topaz_installation();
if let Some(path) = topaz_path {
assert!(path.exists(), "Detected Topaz path should exist");
println!("Detected Topaz at: {}", path.display());
} else {
println!("Topaz Video AI not detected (this is expected in CI)");
}
// Test FFmpeg detection
let ffmpeg_info = detect_ffmpeg();
println!("System FFmpeg available: {}", ffmpeg_info.system_available);
println!("Topaz FFmpeg available: {}", ffmpeg_info.topaz_available);
// Test GPU detection
let gpu_info = detect_gpu_support();
assert!(gpu_info.available, "Should detect GPU availability");
println!("GPU available: {}", gpu_info.available);
println!("CUDA available: {}", gpu_info.cuda_available);
}
/// Test temporary file management
#[tokio::test]
async fn test_temp_file_management() {
let temp_dir = TempDir::new().expect("Should create temp dir");
let mut temp_manager = TempFileManager::new(Some(temp_dir.path())).expect("Should create temp manager");
// Test temp path creation
let temp_path1 = temp_manager.create_temp_path("test_op", "file1.txt");
let temp_path2 = temp_manager.create_unique_temp_path("file2.txt");
assert_eq!(temp_manager.file_count(), 2);
assert!(temp_manager.is_tracked(&temp_path1));
assert!(temp_manager.is_tracked(&temp_path2));
// Create actual files
std::fs::write(&temp_path1, "test content 1").expect("Should write file");
std::fs::write(&temp_path2, "test content 2").expect("Should write file");
assert!(temp_path1.exists());
assert!(temp_path2.exists());
// Test cleanup
temp_manager.cleanup_operation("test_op").expect("Should cleanup operation");
assert!(!temp_path1.exists(), "File should be cleaned up");
assert!(temp_path2.exists(), "Other file should remain");
// Test cleanup all
temp_manager.cleanup_all().expect("Should cleanup all");
assert!(!temp_path2.exists(), "All files should be cleaned up");
assert_eq!(temp_manager.file_count(), 0);
}