mixvideo-v2/cargos/tvai/tests/integration_tests.rs

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);
}