feat: Add NFO integration test script
- Created scripts/test_nfo_integration.py for manual testing - Tests TMDB client, NFO generation, and complete workflow - Requires real TMDB API key (not for CI) - Downloads real data and creates sample files in test_output/ - Provides Kodi compatibility verification - Updated task3_status.md with testing challenges and approach
This commit is contained in:
289
scripts/test_nfo_integration.py
Normal file
289
scripts/test_nfo_integration.py
Normal file
@@ -0,0 +1,289 @@
|
||||
"""Manual integration test for NFO functionality.
|
||||
|
||||
This script tests the complete NFO generation workflow with real TMDB API calls.
|
||||
It's intended for manual verification, not automated testing.
|
||||
|
||||
Usage:
|
||||
1. Set TMDB_API_KEY environment variable
|
||||
2. Run: python scripts/test_nfo_integration.py
|
||||
3. Check output in test_output/ directory
|
||||
|
||||
Requirements:
|
||||
- Valid TMDB API key (get from https://www.themoviedb.org/settings/api)
|
||||
- Internet connection
|
||||
- Write permissions for test_output/ directory
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from src.core.services.tmdb_client import TMDBClient, TMDBAPIError
|
||||
from src.core.services.nfo_service import NFOService
|
||||
from src.core.entities.nfo_models import TVShowNFO
|
||||
from src.core.utils.nfo_generator import generate_tvshow_nfo, validate_nfo_xml
|
||||
|
||||
|
||||
async def test_tmdb_client():
|
||||
"""Test TMDB client basic functionality."""
|
||||
print("\n=== Testing TMDB Client ===")
|
||||
|
||||
api_key = os.getenv("TMDB_API_KEY")
|
||||
if not api_key:
|
||||
print("❌ TMDB_API_KEY environment variable not set")
|
||||
print(" Get your API key from: https://www.themoviedb.org/settings/api")
|
||||
return False
|
||||
|
||||
try:
|
||||
async with TMDBClient(api_key=api_key) as client:
|
||||
# Test 1: Search for a show
|
||||
print("\n1. Searching for 'Attack on Titan'...")
|
||||
results = await client.search_tv_show("Attack on Titan")
|
||||
|
||||
if results and results.get("results"):
|
||||
show = results["results"][0]
|
||||
print(f" ✅ Found: {show['name']} (ID: {show['id']})")
|
||||
show_id = show["id"]
|
||||
else:
|
||||
print(" ❌ No results found")
|
||||
return False
|
||||
|
||||
# Test 2: Get show details
|
||||
print(f"\n2. Getting details for show ID {show_id}...")
|
||||
details = await client.get_tv_show_details(
|
||||
show_id,
|
||||
append_to_response="credits,external_ids,images"
|
||||
)
|
||||
print(f" ✅ Title: {details['name']}")
|
||||
print(f" ✅ First Air Date: {details.get('first_air_date', 'N/A')}")
|
||||
print(f" ✅ Rating: {details.get('vote_average', 'N/A')}/10")
|
||||
|
||||
# Test 3: Get external IDs
|
||||
if "external_ids" in details:
|
||||
ext_ids = details["external_ids"]
|
||||
print(f" ✅ IMDB ID: {ext_ids.get('imdb_id', 'N/A')}")
|
||||
print(f" ✅ TVDB ID: {ext_ids.get('tvdb_id', 'N/A')}")
|
||||
|
||||
# Test 4: Get images
|
||||
if "images" in details:
|
||||
images = details["images"]
|
||||
print(f" ✅ Posters: {len(images.get('posters', []))}")
|
||||
print(f" ✅ Backdrops: {len(images.get('backdrops', []))}")
|
||||
print(f" ✅ Logos: {len(images.get('logos', []))}")
|
||||
|
||||
# Test 5: Get image URL
|
||||
if details.get("poster_path"):
|
||||
url = client.get_image_url(details["poster_path"], "w500")
|
||||
print(f" ✅ Poster URL: {url[:60]}...")
|
||||
|
||||
return True
|
||||
|
||||
except TMDBAPIError as e:
|
||||
print(f" ❌ TMDB API Error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f" ❌ Unexpected Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
async def test_nfo_generation():
|
||||
"""Test NFO XML generation."""
|
||||
print("\n=== Testing NFO Generation ===")
|
||||
|
||||
try:
|
||||
# Create a sample NFO model
|
||||
print("\n1. Creating sample TVShowNFO model...")
|
||||
from src.core.entities.nfo_models import RatingInfo, ActorInfo, ImageInfo, UniqueID
|
||||
|
||||
nfo = TVShowNFO(
|
||||
title="Test Show",
|
||||
originaltitle="Test Show Original",
|
||||
year=2020,
|
||||
plot="This is a test show for NFO generation validation.",
|
||||
runtime=45,
|
||||
premiered="2020-01-15",
|
||||
status="Continuing",
|
||||
genre=["Action", "Drama", "Animation"],
|
||||
studio=["Test Studio"],
|
||||
country=["Japan"],
|
||||
ratings=[RatingInfo(
|
||||
name="themoviedb",
|
||||
value=8.5,
|
||||
votes=1000,
|
||||
max_rating=10,
|
||||
default=True
|
||||
)],
|
||||
actors=[
|
||||
ActorInfo(name="Test Actor 1", role="Main Character"),
|
||||
ActorInfo(name="Test Actor 2", role="Villain")
|
||||
],
|
||||
thumb=[ImageInfo(url="https://image.tmdb.org/t/p/w500/poster.jpg")],
|
||||
fanart=[ImageInfo(url="https://image.tmdb.org/t/p/original/fanart.jpg")],
|
||||
uniqueid=[
|
||||
UniqueID(type="tmdb", value="12345", default=False),
|
||||
UniqueID(type="tvdb", value="67890", default=True)
|
||||
],
|
||||
tmdbid=12345,
|
||||
tvdbid=67890,
|
||||
imdbid="tt1234567"
|
||||
)
|
||||
print(" ✅ TVShowNFO model created")
|
||||
|
||||
# Test 2: Generate XML
|
||||
print("\n2. Generating XML...")
|
||||
xml_string = generate_tvshow_nfo(nfo)
|
||||
print(f" ✅ Generated {len(xml_string)} characters")
|
||||
|
||||
# Test 3: Validate XML
|
||||
print("\n3. Validating XML...")
|
||||
validate_nfo_xml(xml_string)
|
||||
print(" ✅ XML is valid")
|
||||
|
||||
# Test 4: Save to file
|
||||
output_dir = Path("test_output")
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
nfo_path = output_dir / "test_tvshow.nfo"
|
||||
nfo_path.write_text(xml_string, encoding="utf-8")
|
||||
print(f" ✅ Saved to: {nfo_path}")
|
||||
|
||||
# Test 5: Show sample
|
||||
print("\n4. Sample XML (first 500 chars):")
|
||||
print(" " + xml_string[:500].replace("\n", "\n "))
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
async def test_nfo_service():
|
||||
"""Test complete NFO service workflow."""
|
||||
print("\n=== Testing NFO Service ===")
|
||||
|
||||
api_key = os.getenv("TMDB_API_KEY")
|
||||
if not api_key:
|
||||
print("❌ TMDB_API_KEY environment variable not set")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Create test output directory
|
||||
output_dir = Path("test_output")
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Create a test series folder
|
||||
test_series = output_dir / "Attack_on_Titan"
|
||||
test_series.mkdir(exist_ok=True)
|
||||
|
||||
print(f"\n1. Creating NFO for 'Attack on Titan'...")
|
||||
print(f" Output directory: {test_series}")
|
||||
|
||||
# Initialize NFO service
|
||||
nfo_service = NFOService(
|
||||
tmdb_api_key=api_key,
|
||||
anime_directory=str(output_dir),
|
||||
image_size="w500"
|
||||
)
|
||||
|
||||
# Create NFO
|
||||
nfo_path = await nfo_service.create_tvshow_nfo(
|
||||
serie_name="Attack on Titan",
|
||||
serie_folder="Attack_on_Titan",
|
||||
year=2013,
|
||||
download_poster=True,
|
||||
download_logo=True,
|
||||
download_fanart=True
|
||||
)
|
||||
|
||||
print(f" ✅ NFO created: {nfo_path}")
|
||||
|
||||
# Check if files were created
|
||||
print("\n2. Checking created files...")
|
||||
files_created = {
|
||||
"tvshow.nfo": (test_series / "tvshow.nfo").exists(),
|
||||
"poster.jpg": (test_series / "poster.jpg").exists(),
|
||||
"logo.png": (test_series / "logo.png").exists(),
|
||||
"fanart.jpg": (test_series / "fanart.jpg").exists(),
|
||||
}
|
||||
|
||||
for filename, exists in files_created.items():
|
||||
status = "✅" if exists else "❌"
|
||||
size = ""
|
||||
if exists:
|
||||
file_path = test_series / filename
|
||||
size = f" ({file_path.stat().st_size:,} bytes)"
|
||||
print(f" {status} {filename}{size}")
|
||||
|
||||
# Read and validate NFO
|
||||
if files_created["tvshow.nfo"]:
|
||||
print("\n3. Validating generated NFO...")
|
||||
nfo_content = nfo_path.read_text(encoding="utf-8")
|
||||
validate_nfo_xml(nfo_content)
|
||||
print(" ✅ NFO is valid XML")
|
||||
|
||||
# Show sample
|
||||
print("\n4. NFO Content (first 800 chars):")
|
||||
print(" " + nfo_content[:800].replace("\n", "\n "))
|
||||
|
||||
return all(files_created.values())
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
"""Run all integration tests."""
|
||||
print("=" * 70)
|
||||
print("NFO Functionality Integration Tests")
|
||||
print("=" * 70)
|
||||
print("\nNOTE: This requires a valid TMDB API key set as environment variable.")
|
||||
print("Get your API key from: https://www.themoviedb.org/settings/api")
|
||||
print("Set it with: export TMDB_API_KEY='your_api_key_here'")
|
||||
|
||||
results = []
|
||||
|
||||
# Test 1: TMDB Client
|
||||
results.append(("TMDB Client", await test_tmdb_client()))
|
||||
|
||||
# Test 2: NFO Generation
|
||||
results.append(("NFO Generation", await test_nfo_generation()))
|
||||
|
||||
# Test 3: NFO Service (full workflow)
|
||||
results.append(("NFO Service", await test_nfo_service()))
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 70)
|
||||
print("SUMMARY")
|
||||
print("=" * 70)
|
||||
|
||||
for test_name, passed in results:
|
||||
status = "✅ PASSED" if passed else "❌ FAILED"
|
||||
print(f"{test_name:.<50} {status}")
|
||||
|
||||
all_passed = all(result for _, result in results)
|
||||
|
||||
if all_passed:
|
||||
print("\n🎉 All tests passed!")
|
||||
print("\nGenerated files are in the 'test_output/' directory.")
|
||||
print("You can import tvshow.nfo into Kodi/Plex/Jellyfin to verify compatibility.")
|
||||
else:
|
||||
print("\n⚠️ Some tests failed. Check the output above for details.")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = asyncio.run(main())
|
||||
sys.exit(exit_code)
|
||||
Reference in New Issue
Block a user