MovieMapper/Rust/tests/integration/tvdb_api_tests.rs
Jarian Cottingham 323df5de2e feat: Add Rust implementation for performance-critical components
- 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
2026-02-28 09:52:08 -06:00

244 lines
9.1 KiB
Rust

//! Integration tests for TVDB API client
//!
//! These tests make real API calls to TheTVDB and require a valid API key.
//! Set the TVDB_API_KEY environment variable before running these tests.
use movie_mapper::service::tvdb_api::TVDBClient;
use movie_mapper::utils::TVDBError;
/// Get API key from environment or return a default test value
fn get_api_key() -> String {
std::env::var("TVDB_API_KEY").unwrap_or_else(|_| {
panic!("TVDB_API_KEY environment variable must be set for integration tests")
})
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_authenticate_success() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
// This should succeed with a valid API key
let result = client.authenticate().await;
assert!(result.is_ok(), "Authentication should succeed");
assert!(client.token.is_some(), "Token should be set after authentication");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_search_finding_broken_bad() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
// Authenticate first
client.authenticate().await.expect("Authentication failed");
// Search for a well-known show
let shows = client.search("Breaking Bad").await.expect("Search failed");
assert!(!shows.is_empty(), "Should find at least one show");
// Verify the first result looks reasonable
let first_show = &shows[0];
assert_eq!(first_show.series_name, "Breaking Bad", "First result should be Breaking Bad");
assert!(first_show.id > 0, "Show should have a valid ID");
assert!(!first_show.overview.is_empty(), "Show should have an overview");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_search_no_results() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
client.authenticate().await.expect("Authentication failed");
// Search for something that shouldn't exist
let shows = client.search("NonExistentShow12345XYZ").await.expect("Search should not fail");
// Should return empty array, not error
assert!(shows.is_empty(), "Should not find any shows for non-existent query");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_search_partial_match() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
client.authenticate().await.expect("Authentication failed");
// Search with partial name
let shows = client.search("Breaking").await.expect("Search should not fail");
// Should find Breaking Bad and possibly other shows with "Breaking" in name
assert!(!shows.is_empty(), "Should find shows with 'Breaking' in name");
// Verify Breaking Bad is in results
let breaking_in_results = shows.iter().any(|s| s.series_name.contains("Breaking"));
assert!(breaking_in_results, "Should find shows containing 'Breaking'");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_get_show_details() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
client.authenticate().await.expect("Authentication failed");
// First search to get a show ID
let shows = client.search("Breaking Bad").await.expect("Search failed");
let show_id = shows[0].id;
// Get detailed information
let details = client.get_show_details(show_id).await.expect("Get show details failed");
assert_eq!(details.id, show_id, "Details should match show ID");
assert_eq!(details.name, "Breaking Bad", "Show name should match");
assert!(!details.overview.is_empty(), "Should have an overview");
assert!(!details.seasons.is_empty(), "Should have at least one season");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_get_season_episodes() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
client.authenticate().await.expect("Authentication failed");
// First search to get a show ID
let shows = client.search("Breaking Bad").await.expect("Search failed");
let show_id = shows[0].id;
// Get episodes for season 1
let episodes = client.get_season_episodes(show_id, 1).await.expect("Get episodes failed");
assert!(!episodes.is_empty(), "Should have at least one episode in season 1");
// Verify episode structure
let first_episode = &episodes[0];
assert_eq!(first_episode.season_number, 1, "Episode should be from season 1");
assert!(first_episode.number > 0, "Episode should have valid number");
assert!(!first_episode.name.is_empty(), "Episode should have a name");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_token_caching() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
// First authentication
client.authenticate().await.expect("First auth failed");
let first_token = client.token.clone().expect("Should have token");
// Call search again - should use cached token
let shows = client.search("Breaking Bad").await.expect("Search failed");
// Verify we got results
assert!(!shows.is_empty(), "Should find shows");
// Token should still be the same (cached)
let second_token = client.token.clone().expect("Should still have token");
assert_eq!(first_token, second_token, "Token should be cached");
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_multiple_searches() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
client.authenticate().await.expect("Authentication failed");
// Perform multiple searches
let search_terms = vec!["Breaking Bad", "Better Call Saul", "The Wire"];
for term in search_terms {
let shows = client.search(term).await.expect(&format!("Search for {} failed", term));
println!("Search for '{}': Found {} results", term, shows.len());
}
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_full_workflow() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
// 1. Authenticate
client.authenticate().await.expect("Authentication failed");
// 2. Search for a show
let shows = client.search("Breaking Bad").await.expect("Search failed");
assert!(!shows.is_empty(), "Should find shows");
let show_id = shows[0].id;
// 3. Get show details
let details = client.get_show_details(show_id).await.expect("Get details failed");
println!("Show: {} ({})", details.name, details.status);
println!("Seasons: {}", details.seasons.len());
// 4. Get episodes for first season
if !details.seasons.is_empty() {
let season_number = details.seasons[0].number;
let episodes = client.get_season_episodes(show_id, season_number)
.await
.expect("Get episodes failed");
println!("Season {} has {} episodes", season_number, episodes.len());
// 5. Verify episode structure
for episode in &episodes {
println!(" - E{:02}: {}", episode.number, episode.name);
}
}
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_error_handling_invalid_key() {
// Test with an invalid key to verify error handling
let mut client = TVDBClient::new("invalid-api-key-12345").expect("Failed to create client");
let result = client.authenticate().await;
// Should fail with authentication error
assert!(result.is_err(), "Authentication should fail with invalid key");
// The error should be related to authentication
let err = result.unwrap_err();
println!("Expected error: {}", err);
}
#[tokio::test]
#[ignore = "Integration test - requires real API calls"]
async fn test_tvdb_rate_limit_simulation() {
let api_key = get_api_key();
let mut client = TVDBClient::new(&api_key).expect("Failed to create client");
client.authenticate().await.expect("Authentication failed");
// Make many rapid requests to potentially hit rate limit
// This test may take some time and should be run with patience
for i in 0..5 {
let shows = client.search("Breaking Bad").await;
match shows {
Ok(_) => {
println!("Request {}: Success", i + 1);
}
Err(e) => {
println!("Request {}: Error - {}", i + 1, e);
// If we hit rate limit, that's actually expected behavior
break;
}
}
// Small delay between requests
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
}
}