- Implement core Rust backend with FFmpeg integration - Add TheTVDB API client with token caching - Implement directory scanner with progress callbacks - Create file manager with rename and move operations - Add audit logging functionality - Implement file mapping for TV episode renaming - Build Node.js native addon via NAPI - Include comprehensive unit and integration tests - Update gitignore to exclude build artifacts and temp files Resolves #TBD
298 lines
9.4 KiB
Rust
298 lines
9.4 KiB
Rust
// Integration tests for MovieMapper
|
|
// Tests module interactions and integration between components
|
|
|
|
use movie_mapper::model::file::MediaFile;
|
|
use movie_mapper::service::audit_logger::{AuditAction, AuditLogger};
|
|
use movie_mapper::service::file_mapper::FileMapper;
|
|
use movie_mapper::service::file_metadata::MetadataExtractor;
|
|
use movie_mapper::service::file_scanner::FileScanner;
|
|
use movie_mapper::service::tag_manager::TagManager;
|
|
use std::fs::{self, File};
|
|
use std::io::Write;
|
|
use tempfile::tempdir;
|
|
|
|
/// Integration test for scanning directory and extracting metadata
|
|
#[tokio::test]
|
|
async fn test_scan_and_extract_metadata() {
|
|
let temp_dir = tempdir().unwrap();
|
|
|
|
// Create a test media file
|
|
let media_file = temp_dir.path().join("test_video.mp4");
|
|
let mut file = File::create(&media_file).unwrap();
|
|
// Write some dummy data (not a real video, but enough for testing)
|
|
file.write_all(b"dummy data").unwrap();
|
|
|
|
// Scan directory
|
|
let scanner = FileScanner::new();
|
|
let files = scanner.scan_directory(temp_dir.path(), None).await.unwrap();
|
|
|
|
assert_eq!(files.len(), 1);
|
|
assert_eq!(files[0].name, "test_video.mp4");
|
|
|
|
// Extract metadata
|
|
let extractor = MetadataExtractor::new();
|
|
let metadata_file = extractor.extract_metadata(&media_file).unwrap();
|
|
|
|
assert_eq!(metadata_file.name, "test_video.mp4");
|
|
// Duration and quality should be default values since it's not a real video
|
|
assert_eq!(metadata_file.duration, "00:00");
|
|
assert_eq!(metadata_file.quality, "unknown");
|
|
}
|
|
|
|
/// Integration test for file tagging and movement
|
|
#[tokio::test]
|
|
async fn test_tag_and_move_files() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let extra_folder = temp_dir.path().join("extras");
|
|
|
|
// Create test files
|
|
let file1 = temp_dir.path().join("video1.mp4");
|
|
let file2 = temp_dir.path().join("video2.mkv");
|
|
|
|
File::create(&file1).unwrap();
|
|
File::create(&file2).unwrap();
|
|
|
|
// Tag files
|
|
let mut tag_manager = TagManager::new();
|
|
tag_manager.add_tag(&file1, "extra").unwrap();
|
|
tag_manager.add_tag(&file2, "extra").unwrap();
|
|
|
|
// Move tagged files
|
|
fs::create_dir_all(&extra_folder).unwrap();
|
|
let moved_count = tag_manager
|
|
.move_tagged_files("extra", &extra_folder)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(moved_count, 2);
|
|
assert!(!file1.exists());
|
|
assert!(!file2.exists());
|
|
assert!(extra_folder.join("video1.mp4").exists());
|
|
assert!(extra_folder.join("video2.mkv").exists());
|
|
}
|
|
|
|
/// Integration test for audit logging
|
|
#[tokio::test]
|
|
async fn test_audit_logging_integration() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let logger = AuditLogger::new(temp_dir.path().to_str().unwrap());
|
|
|
|
// Test directory selection logging
|
|
let action = AuditAction::DirectorySelected {
|
|
path: temp_dir.path().to_string_lossy().to_string(),
|
|
};
|
|
|
|
logger.log_event(action).unwrap();
|
|
|
|
// Verify .audit file was created
|
|
let audit_path = temp_dir.path().join(".audit");
|
|
assert!(audit_path.exists());
|
|
|
|
// Test file rename logging
|
|
let file1 = temp_dir.path().join("original.mp4");
|
|
File::create(&file1).unwrap();
|
|
|
|
let file2 = temp_dir.path().join("renamed.mp4");
|
|
fs::rename(&file1, &file2).unwrap();
|
|
|
|
let rename_action = AuditAction::RenameFile {
|
|
old_path: file1.to_string_lossy().to_string(),
|
|
new_path: file2.to_string_lossy().to_string(),
|
|
old_name: "original.mp4".to_string(),
|
|
new_name: "renamed.mp4".to_string(),
|
|
};
|
|
|
|
logger.log_event(rename_action).unwrap();
|
|
|
|
// Verify audit log contains both entries
|
|
let content = fs::read_to_string(&audit_path).unwrap();
|
|
assert!(content.contains("directory_selected"));
|
|
assert!(content.contains("rename_file"));
|
|
}
|
|
|
|
/// Integration test for complete file workflow
|
|
#[tokio::test]
|
|
async fn test_complete_file_workflow() {
|
|
let temp_dir = tempdir().unwrap();
|
|
|
|
// Step 1: Scan directory
|
|
let scanner = FileScanner::new();
|
|
let mut file = File::create(temp_dir.path().join("movie.mp4")).unwrap();
|
|
file.write_all(b"test").unwrap();
|
|
|
|
let files = scanner.scan_directory(temp_dir.path(), None).await.unwrap();
|
|
assert_eq!(files.len(), 1);
|
|
|
|
// Step 2: Extract metadata
|
|
let extractor = MetadataExtractor::new();
|
|
let metadata = extractor.extract_metadata(&files[0].path).unwrap();
|
|
assert_eq!(metadata.name, "movie.mp4");
|
|
|
|
// Step 3: Tag file
|
|
let mut tag_manager = TagManager::new();
|
|
tag_manager.add_tag(&metadata.path, "extra").unwrap();
|
|
assert!(tag_manager.has_tag(&metadata.path, "extra"));
|
|
|
|
// Step 4: Log audit event
|
|
let logger = AuditLogger::new(temp_dir.path().to_str().unwrap());
|
|
let action = AuditAction::TagFile {
|
|
file_path: metadata.path.to_string_lossy().to_string(),
|
|
tag: "extra".to_string(),
|
|
};
|
|
logger.log_event(action).unwrap();
|
|
|
|
// Verify .audit file exists
|
|
let audit_path = temp_dir.path().join(".audit");
|
|
assert!(audit_path.exists());
|
|
}
|
|
|
|
/// Integration test for file mapping
|
|
#[tokio::test]
|
|
async fn test_file_mapping() {
|
|
let temp_dir = tempdir().unwrap();
|
|
|
|
// Create test files
|
|
let file1 = temp_dir.path().join("video1.mp4");
|
|
let file2 = temp_dir.path().join("video2.mkv");
|
|
File::create(&file1).unwrap();
|
|
File::create(&file2).unwrap();
|
|
|
|
// Create MediaFile objects
|
|
let files = vec![MediaFile::from_path(file1), MediaFile::from_path(file2)];
|
|
|
|
// Map files
|
|
let mapper = FileMapper::new();
|
|
let result = mapper
|
|
.map_files(&files, "Test Show", 1, None)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(result.success, 2);
|
|
assert_eq!(result.errors, 0);
|
|
}
|
|
|
|
/// Integration test for error handling in scanning
|
|
#[tokio::test]
|
|
async fn test_scan_error_handling() {
|
|
let scanner = FileScanner::new();
|
|
|
|
// Test with non-existent directory
|
|
let result = scanner
|
|
.scan_directory(std::path::Path::new("/nonexistent/path/xyz"), None)
|
|
.await;
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
/// Integration test for TVDB API integration (requires API key)
|
|
#[tokio::test]
|
|
async fn test_tvdb_api_integration() {
|
|
let api_key = match std::env::var("TVDB_API_KEY") {
|
|
Ok(key) => key,
|
|
Err(_) => {
|
|
// Skip test if no API key
|
|
return;
|
|
}
|
|
};
|
|
|
|
let mut tvdb = movie_mapper::service::tvdb_api::TVDBClient::new(&api_key).unwrap();
|
|
|
|
// Test authentication
|
|
let auth_result = tvdb.authenticate().await;
|
|
assert!(
|
|
auth_result.is_ok(),
|
|
"Authentication should succeed with valid API key"
|
|
);
|
|
|
|
// Test search functionality
|
|
let shows = tvdb.search("Breaking Bad").await;
|
|
assert!(shows.is_ok(), "Search should succeed");
|
|
let shows = shows.unwrap();
|
|
assert!(!shows.is_empty(), "Should find at least one show");
|
|
|
|
// Test get show details
|
|
if !shows.is_empty() {
|
|
let details = tvdb.get_show_details(shows[0].id).await;
|
|
assert!(details.is_ok(), "Get show details should succeed");
|
|
let details = details.unwrap();
|
|
assert_eq!(details.id, shows[0].id);
|
|
}
|
|
}
|
|
|
|
/// Integration test for progress callback during scanning
|
|
#[tokio::test]
|
|
async fn test_scan_with_progress_callback() {
|
|
let temp_dir = tempdir().unwrap();
|
|
|
|
// Create multiple test files
|
|
for i in 0..5 {
|
|
let file_path = temp_dir.path().join(format!("video{}.mp4", i));
|
|
File::create(&file_path).unwrap();
|
|
}
|
|
|
|
let scanner = FileScanner::new();
|
|
let mut progress_events = Vec::new();
|
|
|
|
let _ = scanner
|
|
.scan_directory(
|
|
temp_dir.path(),
|
|
Some(&mut |current, total, filename| {
|
|
progress_events.push((current, total, filename.to_string()));
|
|
}),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(!progress_events.is_empty());
|
|
assert_eq!(progress_events.last().unwrap().0, 5); // Final count should be 5
|
|
}
|
|
|
|
/// Integration test for TagManager persistence
|
|
#[tokio::test]
|
|
async fn test_tag_manager_persistence() {
|
|
let temp_dir = tempdir().unwrap();
|
|
let tags_file = temp_dir.path().join("tags.json");
|
|
|
|
let mut tag_manager = TagManager::new();
|
|
let file_path = temp_dir.path().join("video.mp4");
|
|
|
|
// Add tags
|
|
tag_manager.add_tag(&file_path, "extra").unwrap();
|
|
tag_manager.add_tag(&file_path, "commentary").unwrap();
|
|
|
|
// Save to file
|
|
tag_manager.save_tags_to_file(&tags_file).unwrap();
|
|
assert!(tags_file.exists());
|
|
|
|
// Load tags into new manager
|
|
let mut new_manager = TagManager::new();
|
|
new_manager.load_tags_from_file(&tags_file).unwrap();
|
|
|
|
// Verify tags were loaded
|
|
assert!(new_manager.has_tag(&file_path, "extra"));
|
|
assert!(new_manager.has_tag(&file_path, "commentary"));
|
|
assert_eq!(new_manager.get_tags(&file_path).len(), 2);
|
|
}
|
|
|
|
/// Integration test for FileMapper filename generation
|
|
#[test]
|
|
fn test_file_mapper_filename_generation() {
|
|
let mapper = FileMapper::new();
|
|
|
|
// Test basic filename generation
|
|
let filename = mapper.generate_jellyfin_filename("Show Name", 1, 1, 1, "1080p", ".mp4");
|
|
assert_eq!(filename, "Show Name S01E01 - 1080p.mp4");
|
|
|
|
// Test with no quality
|
|
let filename = mapper.generate_jellyfin_filename("Show Name", 1, 1, 1, "", ".mp4");
|
|
assert_eq!(filename, "Show Name S01E01.mp4");
|
|
|
|
// Test with unknown quality
|
|
let filename = mapper.generate_jellyfin_filename("Show Name", 1, 1, 1, "unknown", ".mp4");
|
|
assert_eq!(filename, "Show Name S01E01.mp4");
|
|
|
|
// Test with episode range
|
|
let filename = mapper.generate_jellyfin_filename("Show Name", 2, 1, 3, "720p", ".mkv");
|
|
assert_eq!(filename, "Show Name S02E01-03 - 720p.mkv");
|
|
}
|