Add new API endpoints for media retrieval by country and enhance configuration
Some checks failed
Test Suite / test (push) Has been cancelled
Some checks failed
Test Suite / test (push) Has been cancelled
- Introduced `/api/tmdb` and `/api/collection/missing-locations` endpoints to the backend for improved media management. - Added a new `get_media_by_country` function in the collection API to fetch media items based on country codes. - Updated configuration to allow overriding *arr base URLs via environment variables for better flexibility. - Enhanced frontend with a new `MissingLocations` component and integrated it into the routing structure. - Improved the `CollectionMap` component to handle country selection and display media items accordingly. - Added testing dependencies in `requirements.txt` and updated frontend configuration for testing support.
This commit is contained in:
153
backend/tests/test_database.py
Normal file
153
backend/tests/test_database.py
Normal file
@@ -0,0 +1,153 @@
|
||||
"""Tests for database operations"""
|
||||
import pytest
|
||||
import json
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_media_item_insert(test_db_pool):
|
||||
"""Test inserting a media item"""
|
||||
async with test_db_pool.connection() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_item
|
||||
(source_kind, source_item_id, title, year, media_type, arr_raw)
|
||||
VALUES ('radarr', 1, 'Test Movie', 2020, 'movie', %s::jsonb)
|
||||
RETURNING id, title
|
||||
""", (json.dumps({"test": "data"}),))
|
||||
|
||||
result = await cur.fetchone()
|
||||
assert result is not None
|
||||
assert result[1] == "Test Movie"
|
||||
|
||||
await conn.commit()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_media_country_association(test_db_pool):
|
||||
"""Test associating a country with a media item"""
|
||||
async with test_db_pool.connection() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
# Insert media item
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_item
|
||||
(source_kind, source_item_id, title, year, media_type, arr_raw)
|
||||
VALUES ('radarr', 1, 'Test Movie', 2020, 'movie', '{}'::jsonb)
|
||||
RETURNING id
|
||||
""")
|
||||
media_id = (await cur.fetchone())[0]
|
||||
|
||||
# Associate country
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_country (media_item_id, country_code)
|
||||
VALUES (%s, 'US')
|
||||
""", (media_id,))
|
||||
|
||||
# Verify association
|
||||
await cur.execute("""
|
||||
SELECT country_code FROM moviemap.media_country
|
||||
WHERE media_item_id = %s
|
||||
""", (media_id,))
|
||||
|
||||
result = await cur.fetchone()
|
||||
assert result is not None
|
||||
assert result[0] == "US"
|
||||
|
||||
await conn.commit()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_media_item_unique_constraint(test_db_pool):
|
||||
"""Test that source_kind + source_item_id is unique"""
|
||||
async with test_db_pool.connection() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
# Insert first item
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_item
|
||||
(source_kind, source_item_id, title, year, media_type, arr_raw)
|
||||
VALUES ('radarr', 1, 'Test Movie', 2020, 'movie', '{}'::jsonb)
|
||||
""")
|
||||
|
||||
# Try to insert duplicate
|
||||
with pytest.raises(Exception): # Should raise unique constraint violation
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_item
|
||||
(source_kind, source_item_id, title, year, media_type, arr_raw)
|
||||
VALUES ('radarr', 1, 'Another Movie', 2021, 'movie', '{}'::jsonb)
|
||||
""")
|
||||
|
||||
await conn.rollback()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_watched_item_insert(test_db_pool):
|
||||
"""Test inserting a watched item"""
|
||||
async with test_db_pool.connection() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.watched_item
|
||||
(media_type, title, year, country_code, notes)
|
||||
VALUES ('movie', 'Test Movie', 2020, 'US', 'Test notes')
|
||||
RETURNING id, title
|
||||
""")
|
||||
|
||||
result = await cur.fetchone()
|
||||
assert result is not None
|
||||
assert result[1] == "Test Movie"
|
||||
|
||||
await conn.commit()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_manual_pin_insert(test_db_pool):
|
||||
"""Test inserting a manual pin"""
|
||||
async with test_db_pool.connection() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.manual_pin (country_code, label)
|
||||
VALUES ('US', 'Test Pin')
|
||||
RETURNING id, country_code
|
||||
""")
|
||||
|
||||
result = await cur.fetchone()
|
||||
assert result is not None
|
||||
assert result[1] == "US"
|
||||
|
||||
await conn.commit()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cascade_delete(test_db_pool):
|
||||
"""Test that deleting a media item cascades to country associations"""
|
||||
async with test_db_pool.connection() as conn:
|
||||
async with conn.cursor() as cur:
|
||||
# Insert media item with country
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_item
|
||||
(source_kind, source_item_id, title, year, media_type, arr_raw)
|
||||
VALUES ('radarr', 1, 'Test Movie', 2020, 'movie', '{}'::jsonb)
|
||||
RETURNING id
|
||||
""")
|
||||
media_id = (await cur.fetchone())[0]
|
||||
|
||||
await cur.execute("""
|
||||
INSERT INTO moviemap.media_country (media_item_id, country_code)
|
||||
VALUES (%s, 'US')
|
||||
""", (media_id,))
|
||||
|
||||
# Delete media item
|
||||
await cur.execute("""
|
||||
DELETE FROM moviemap.media_item WHERE id = %s
|
||||
""", (media_id,))
|
||||
|
||||
# Verify country association is also deleted
|
||||
await cur.execute("""
|
||||
SELECT COUNT(*) FROM moviemap.media_country
|
||||
WHERE media_item_id = %s
|
||||
""", (media_id,))
|
||||
|
||||
count = (await cur.fetchone())[0]
|
||||
assert count == 0
|
||||
|
||||
await conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user