Files
iptv-manager-service/tests/routers/test_channels.py
Stefano b8ac25e301
All checks were successful
AWS Deploy on Push / build (push) Successful in 7m39s
Introduced groups and added all related endpoints
2025-06-10 23:02:46 -05:00

1278 lines
44 KiB
Python

import uuid
from datetime import datetime, timezone
import pytest
from fastapi import status
from fastapi.testclient import TestClient
from sqlalchemy import String
from sqlalchemy.orm import Session
from app.auth.dependencies import get_current_user
from app.main import app
from app.utils.database import get_db
# Import mocks and fixtures
from tests.utils.auth_test_fixtures import (
admin_user_client,
db_session,
mock_get_current_user_admin,
mock_get_current_user_non_admin,
non_admin_user_client,
)
from tests.utils.db_mocks import (
MockBase,
MockChannelDB,
MockChannelURL,
MockGroup,
MockPriority,
create_mock_priorities_and_group,
engine_mock,
mock_get_db,
)
from tests.utils.db_mocks import session_mock as TestingSessionLocal
# Override dependencies for testing
app.dependency_overrides[get_db] = mock_get_db
client = TestClient(app)
# --- Test Cases For Channel Creation ---
def test_create_channel_success(db_session: Session, admin_user_client: TestClient):
# Create mock priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Test Group"
)
channel_data = {
"tvg_id": "channel1.tv",
"name": "Test Channel 1",
"group_id": str(group_id),
"tvg_name": "TestChannel1",
"tvg_logo": "logo.png",
"urls": [{"url": "http://stream1.com/test", "priority_id": 100}],
}
response = admin_user_client.post("/channels/", json=channel_data)
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert data["name"] == "Test Channel 1"
assert data["group_id"] == str(group_id)
assert data["tvg_id"] == "channel1.tv"
assert len(data["urls"]) == 1
assert data["urls"][0]["url"] == "http://stream1.com/test"
assert data["urls"][0]["priority_id"] == 100
# Verify in DB
db_channel = (
db_session.query(MockChannelDB)
.filter(MockChannelDB.name == "Test Channel 1")
.first()
)
assert db_channel is not None
assert db_channel.group_id == group_id
# Query URLs
db_urls = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.channel_id == db_channel.id)
.all()
)
assert len(db_urls) == 1
assert db_urls[0].url == "http://stream1.com/test"
def test_create_channel_duplicate(db_session: Session, admin_user_client: TestClient):
# Create mock priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Duplicate Group"
)
# Create initial channel
initial_channel_data = {
"tvg_id": "channel_dup.tv",
"name": "Duplicate Channel",
"group_id": str(group_id),
"tvg_name": "DuplicateChannelName",
"tvg_logo": "duplicate_logo.png",
"urls": [{"url": "http://stream_dup.com/test", "priority_id": 100}],
}
response1 = admin_user_client.post("/channels/", json=initial_channel_data)
assert response1.status_code == status.HTTP_201_CREATED
# Attempt to create the same channel again
response2 = admin_user_client.post("/channels/", json=initial_channel_data)
assert response2.status_code == status.HTTP_409_CONFLICT
assert "already exists" in response2.json()["detail"]
def test_create_channel_forbidden_for_non_admin(
db_session: Session, non_admin_user_client: TestClient
):
# Create mock priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Forbidden Group"
)
channel_data = {
"tvg_id": "channel_forbidden.tv",
"name": "Forbidden Channel",
"group_id": str(group_id),
"tvg_name": "ForbiddenChannelName",
"tvg_logo": "forbidden_logo.png",
"urls": [{"url": "http://stream_forbidden.com/test", "priority_id": 100}],
}
response = non_admin_user_client.post("/channels/", json=channel_data)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
def test_create_channel_group_not_found(
db_session: Session, admin_user_client: TestClient
):
"""Test creating channel with non-existent group returns 404"""
# No group created in DB
channel_data = {
"tvg_id": "no_group.tv",
"name": "No Group Channel",
"group_id": str(uuid.uuid4()), # Random non-existent group ID
"tvg_name": "NoGroupChannel",
"tvg_logo": "no_group_logo.png",
"urls": [{"url": "http://no_group.com/stream", "priority_id": 100}],
}
response = admin_user_client.post("/channels/", json=channel_data)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Group not found" in response.json()["detail"]
# --- Test Cases For Get Channel ---
def test_get_channel_success(db_session: Session, admin_user_client: TestClient):
# Create priority and group using utility function
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Get Group"
)
# Create a channel first
channel_data_create = {
"tvg_id": "get_me.tv",
"name": "Get Me Channel",
"group_id": str(group_id),
"tvg_name": "GetMeChannelName",
"tvg_logo": "get_me_logo.png",
"urls": [{"url": "http://get_me.com/stream", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=channel_data_create)
assert create_response.status_code == status.HTTP_201_CREATED
created_channel_id = create_response.json()["id"]
app.dependency_overrides[get_current_user] = (
mock_get_current_user_admin # Or a generic authenticated user
)
get_response = admin_user_client.get(f"/channels/{created_channel_id}")
assert get_response.status_code == status.HTTP_200_OK
data = get_response.json()
assert data["id"] == created_channel_id
assert data["name"] == "Get Me Channel"
assert data["group_id"] == str(group_id)
assert len(data["urls"]) == 1
app.dependency_overrides.pop(get_current_user, None)
def test_get_channel_not_found(db_session: Session, admin_user_client: TestClient):
app.dependency_overrides[get_current_user] = mock_get_current_user_admin
random_uuid = uuid.uuid4()
response = admin_user_client.get(f"/channels/{random_uuid}")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Channel not found" in response.json()["detail"]
app.dependency_overrides.pop(get_current_user, None)
# --- Test Cases For Update Channel ---
def test_update_channel_success(db_session: Session, admin_user_client: TestClient):
# Create priority and group using utility function
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Update Group"
)
initial_channel_data = {
"tvg_id": "update_me.tv",
"name": "Update Me Channel",
"group_id": str(group_id),
"tvg_name": "UpdateMeChannelName",
"tvg_logo": "update_me_logo.png",
"urls": [{"url": "http://update_me.com/stream", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=initial_channel_data)
assert create_response.status_code == status.HTTP_201_CREATED
created_channel_id = create_response.json()["id"]
update_data = {"name": "Updated Channel Name", "tvg_logo": "new_logo.png"}
response = admin_user_client.put(
f"/channels/{created_channel_id}", json=update_data
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["id"] == created_channel_id
assert data["name"] == "Updated Channel Name"
assert data["group_id"] == str(group_id)
assert data["tvg_logo"] == "new_logo.png"
# Verify in DB
db_channel = (
db_session.query(MockChannelDB)
.filter(MockChannelDB.id == created_channel_id)
.first()
)
assert db_channel is not None
assert db_channel.name == "Updated Channel Name"
assert db_channel.tvg_logo == "new_logo.png"
def test_update_channel_conflict(db_session: Session, admin_user_client: TestClient):
# Create priorities and groups using utility function
group1_id = create_mock_priorities_and_group(db_session, [(100, "High")], "Group A")
group2_id = create_mock_priorities_and_group(db_session, [], "Group B")
# Create channel 1
channel1_data = {
"tvg_id": "c1.tv",
"name": "Channel One",
"group_id": str(group1_id),
"tvg_name": "C1Name",
"tvg_logo": "c1logo.png",
"urls": [{"url": "http://c1.com", "priority_id": 100}],
}
admin_user_client.post("/channels/", json=channel1_data)
# Create channel 2
channel2_data = {
"tvg_id": "c2.tv",
"name": "Channel Two",
"group_id": str(group2_id),
"tvg_name": "C2Name",
"tvg_logo": "c2logo.png",
"urls": [{"url": "http://c2.com", "priority_id": 100}],
}
response_c2 = admin_user_client.post("/channels/", json=channel2_data)
channel2_id = response_c2.json()["id"]
# Attempt to update channel 2 to conflict with channel 1
update_conflict_data = {"name": "Channel One", "group_id": str(group1_id)}
response = admin_user_client.put(
f"/channels/{channel2_id}", json=update_conflict_data
)
assert response.status_code == status.HTTP_409_CONFLICT
assert "already exists" in response.json()["detail"]
def test_update_channel_not_found(db_session: Session, admin_user_client: TestClient):
random_uuid = uuid.uuid4()
update_data = {"name": "Non Existent Update"}
response = admin_user_client.put(f"/channels/{random_uuid}", json=update_data)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Channel not found" in response.json()["detail"]
def test_update_channel_group_not_found(
db_session: Session, admin_user_client: TestClient
):
"""Test updating channel with non-existent group returns 404"""
# Create priority and group using utility function
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Original Group"
)
initial_channel_data = {
"tvg_id": "original.tv",
"name": "Original Channel",
"group_id": str(group_id),
"tvg_name": "OriginalName",
"tvg_logo": "original_logo.png",
"urls": [{"url": "http://original.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=initial_channel_data)
created_channel_id = create_response.json()["id"]
# Attempt to update with non-existent group
update_data = {"group_id": str(uuid.uuid4())}
response = admin_user_client.put(
f"/channels/{created_channel_id}", json=update_data
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Group not found" in response.json()["detail"]
def test_update_channel_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
# Create priority and group using utility function
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Forbidden Update Group"
)
initial_channel_data = {
"tvg_id": "update_forbidden.tv",
"name": "Update Forbidden",
"group_id": str(group_id),
"tvg_name": "UFName",
"tvg_logo": "uflogo.png",
"urls": [{"url": "http://update_forbidden.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=initial_channel_data)
created_channel_id = create_response.json()["id"]
update_data = {"name": "Attempted Update"}
response = non_admin_user_client.put(
f"/channels/{created_channel_id}", json=update_data
)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
# --- Test Cases For Delete Channel ---
def test_delete_channel_success(db_session: Session, admin_user_client: TestClient):
# Create priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Delete Group"
)
initial_channel_data = {
"tvg_id": "delete_me.tv",
"name": "Delete Me Channel",
"group_id": str(group_id), # Use the ID of the created group
"tvg_name": "DMName",
"tvg_logo": "dmlogo.png",
"urls": [{"url": "http://delete_me.com/stream", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=initial_channel_data)
assert create_response.status_code == status.HTTP_201_CREATED
created_channel_id = create_response.json()["id"]
# Verify it exists before delete
db_channel_before_delete = (
db_session.query(MockChannelDB)
.filter(MockChannelDB.id == uuid.UUID(created_channel_id))
.first()
)
assert db_channel_before_delete is not None
delete_response = admin_user_client.delete(f"/channels/{created_channel_id}")
assert delete_response.status_code == status.HTTP_204_NO_CONTENT
# Verify it's gone from DB
db_channel_after_delete = (
db_session.query(MockChannelDB)
.filter(MockChannelDB.id == uuid.UUID(created_channel_id))
.first()
)
assert db_channel_after_delete is None
# Also verify associated URLs are deleted (due to CASCADE in mock model)
db_urls_after_delete = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.channel_id == uuid.UUID(created_channel_id))
.all()
)
assert len(db_urls_after_delete) == 0
def test_delete_channel_not_found(db_session: Session, admin_user_client: TestClient):
random_uuid = uuid.uuid4()
response = admin_user_client.delete(f"/channels/{random_uuid}")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Channel not found" in response.json()["detail"]
def test_delete_channel_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
# Create priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Forbidden Delete Group"
)
initial_channel_data = {
"tvg_id": "delete_forbidden.tv",
"name": "Delete Forbidden",
"group_id": str(group_id), # Use the ID of the created group
"tvg_name": "DFName",
"tvg_logo": "dflogo.png",
"urls": [{"url": "http://delete_forbidden.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=initial_channel_data)
created_channel_id = create_response.json()["id"]
response = non_admin_user_client.delete(f"/channels/{created_channel_id}")
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
# Ensure channel was not deleted
db_channel_not_deleted = (
db_session.query(MockChannelDB)
.filter(MockChannelDB.id == uuid.UUID(created_channel_id))
.first()
)
assert db_channel_not_deleted is not None
# --- Test Cases For List Channels ---
def test_list_channels_empty(db_session: Session, admin_user_client: TestClient):
response = admin_user_client.get("/channels/")
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
def test_get_channels_by_group_success(
db_session: Session, admin_user_client: TestClient
):
"""Test getting channels for an existing group"""
# Create priority and groups
group1_id = create_mock_priorities_and_group(db_session, [(100, "High")], "Group 1")
group2_id = create_mock_priorities_and_group(db_session, [], "Group 2")
# Create 2 channels in group1 and 1 in group2
channels_group1 = [
{
"tvg_id": f"g1c{i}.tv",
"name": f"Group1 Channel {i}",
"group_id": str(group1_id),
"tvg_name": f"G1C{i}",
"tvg_logo": f"g1c{i}_logo.png",
"urls": [{"url": f"http://g1c{i}.com", "priority_id": 100}],
}
for i in range(2)
]
channel_group2 = {
"tvg_id": "g2c1.tv",
"name": "Group2 Channel 1",
"group_id": str(group2_id),
"tvg_name": "G2C1",
"tvg_logo": "g2c1_logo.png",
"urls": [{"url": "http://g2c1.com", "priority_id": 100}],
}
# Create all channels
for channel_data in channels_group1 + [channel_group2]:
admin_user_client.post("/channels/", json=channel_data)
# Get channels for group1
response = admin_user_client.get(f"/channels/groups/{group1_id}/channels")
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert len(data) == 2
assert all(channel["group_id"] == str(group1_id) for channel in data)
def test_get_channels_by_group_not_found(
db_session: Session, admin_user_client: TestClient
):
"""Test getting channels for non-existent group returns 404"""
random_uuid = uuid.uuid4()
response = admin_user_client.get(f"/channels/groups/{random_uuid}/channels")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Group not found" in response.json()["detail"]
def test_update_channel_group_success(
db_session: Session, admin_user_client: TestClient
):
"""Test successfully updating a channel's group"""
# Create priority and group
group1_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Original Group"
)
channel_data = {
"tvg_id": "original.tv",
"name": "Original Channel",
"group_id": str(group1_id),
"tvg_name": "OriginalName",
"tvg_logo": "original_logo.png",
"urls": [{"url": "http://original.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=channel_data)
channel_id = create_response.json()["id"]
# Create target group
group2_id = create_mock_priorities_and_group(db_session, [], "Target Group")
# Update channel's group
response = admin_user_client.put(
f"/channels/{channel_id}/group?group_id={group2_id}"
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["id"] == channel_id
assert data["group_id"] == str(group2_id)
# Verify in DB
db_channel = (
db_session.query(MockChannelDB)
.filter(MockChannelDB.id == uuid.UUID(channel_id))
.first()
)
assert db_channel.group_id == group2_id
def test_update_channel_group_channel_not_found(
db_session: Session, admin_user_client: TestClient
):
"""Test updating non-existent channel's group returns 404"""
# Create priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Test Group"
)
# Attempt to update non-existent channel
random_uuid = uuid.uuid4()
response = admin_user_client.put(
f"/channels/{random_uuid}/group?group_id={group_id}"
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Channel not found" in response.json()["detail"]
def test_update_channel_group_group_not_found(
db_session: Session, admin_user_client: TestClient
):
"""Test updating channel to non-existent group returns 404"""
# Create priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Original Group"
)
# Create a channel in the original group
channel_data = {
"tvg_id": "original.tv",
"name": "Original Channel",
"group_id": str(group_id),
"tvg_name": "OriginalName",
"tvg_logo": "original_logo.png",
"urls": [{"url": "http://original.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=channel_data)
channel_id = create_response.json()["id"]
# Attempt to update with non-existent group
response = admin_user_client.put(
f"/channels/{channel_id}/group?group_id={uuid.uuid4()}"
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Group not found" in response.json()["detail"]
def test_update_channel_group_duplicate_name(
db_session: Session, admin_user_client: TestClient
):
"""Test updating channel to group with duplicate name returns 409"""
# Create priority and groups
group1_id = create_mock_priorities_and_group(db_session, [(100, "High")], "Group 1")
group2_id = create_mock_priorities_and_group(db_session, [], "Group 2")
# Create channel in each group with same name
channel_name = "Duplicate Channel"
channel1_data = {
"tvg_id": "c1.tv",
"name": channel_name,
"group_id": str(group1_id),
"tvg_name": "C1",
"tvg_logo": "c1.png",
"urls": [{"url": "http://c1.com", "priority_id": 100}],
}
channel2_data = {
"tvg_id": "c2.tv",
"name": channel_name,
"group_id": str(group2_id),
"tvg_name": "C2",
"tvg_logo": "c2.png",
"urls": [{"url": "http://c2.com", "priority_id": 100}],
}
admin_user_client.post("/channels/", json=channel1_data)
create2_response = admin_user_client.post("/channels/", json=channel2_data)
channel2_id = create2_response.json()["id"]
# Attempt to move channel2 to group1 (would create duplicate name)
response = admin_user_client.put(
f"/channels/{channel2_id}/group?group_id={group1_id}"
)
assert response.status_code == status.HTTP_409_CONFLICT
assert "already exists" in response.json()["detail"]
def test_update_channel_group_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
"""Test updating channel's group as non-admin returns 403"""
# Create priority and groups
group1_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Original Group"
)
group2_id = create_mock_priorities_and_group(db_session, [], "Target Group")
channel_data = {
"tvg_id": "protected.tv",
"name": "Protected Channel",
"group_id": str(group1_id),
"tvg_name": "Protected",
"tvg_logo": "protected.png",
"urls": [{"url": "http://protected.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=channel_data)
channel_id = create_response.json()["id"]
# Attempt to update group as non-admin
response = non_admin_user_client.put(
f"/channels/{channel_id}/group?group_id={group2_id}"
)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
def test_list_channels_with_data_and_pagination(
db_session: Session, admin_user_client: TestClient
):
# Create priority and group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "List Group"
)
# Create some channels
for i in range(5):
channel_data = {
"tvg_id": f"list_c{i}.tv",
"name": f"List Channel {i}",
"group_id": str(group_id),
"tvg_name": f"LCName{i}",
"tvg_logo": f"lclogo{i}.png",
"urls": [{"url": f"http://list_c{i}.com", "priority_id": 100}],
}
admin_user_client.post("/channels/", json=channel_data)
# Test default pagination (limit 100)
response_all = admin_user_client.get("/channels/")
assert response_all.status_code == status.HTTP_200_OK
data_all = response_all.json()
assert len(data_all) == 5
assert data_all[0]["name"] == "List Channel 0"
# Test limit
response_limit = admin_user_client.get("/channels/?limit=2")
assert response_limit.status_code == status.HTTP_200_OK
data_limit = response_limit.json()
assert len(data_limit) == 2
assert data_limit[0]["name"] == "List Channel 0"
assert data_limit[1]["name"] == "List Channel 1"
# Test skip and limit
response_skip_limit = admin_user_client.get("/channels/?skip=2&limit=2")
assert response_skip_limit.status_code == status.HTTP_200_OK
data_skip_limit = response_skip_limit.json()
assert len(data_skip_limit) == 2
assert data_skip_limit[0]["name"] == "List Channel 2"
assert data_skip_limit[1]["name"] == "List Channel 3"
# Test skip beyond data
response_skip_beyond = admin_user_client.get("/channels/?skip=10")
assert response_skip_beyond.status_code == status.HTTP_200_OK
assert response_skip_beyond.json() == []
def test_list_channels_forbidden_for_non_admin(
db_session: Session, non_admin_user_client: TestClient
):
response = non_admin_user_client.get("/channels/")
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
# --- Test Cases For Add Channel URL ---
def test_add_channel_url_success(db_session: Session, admin_user_client: TestClient):
# Setup priorities and create a group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High"), (200, "Medium")], "URL Group"
)
channel_data = {
"tvg_id": "channel_for_url.tv",
"name": "Channel For URL",
"group_id": str(group_id),
"tvg_name": "CFUName",
"tvg_logo": "cfulogo.png",
"urls": [{"url": "http://initial.com/stream", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=channel_data)
assert create_response.status_code == status.HTTP_201_CREATED
created_channel_id = create_response.json()["id"]
url_data = {"url": "http://new_stream.com/live", "priority_id": 200}
response = admin_user_client.post(
f"/channels/{created_channel_id}/urls", json=url_data
)
assert response.status_code == status.HTTP_201_CREATED
data = response.json()
assert data["url"] == "http://new_stream.com/live"
assert data["priority_id"] == 200
assert data["in_use"] is False # Default
# Verify in DB
db_url = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == uuid.UUID(data["id"]))
.first()
)
assert db_url is not None
assert db_url.url == "http://new_stream.com/live"
assert db_url.priority_id == 200
assert db_url.channel_id == uuid.UUID(created_channel_id)
# Check the channel now has two URLs
# Re-fetch channel to get updated URLs list
# Expire to ensure fresh data from DB if ChannelResponse is not dynamic
db_session.expire_all()
# Let's verify by querying the database directly
# for the count of URLs for the channel
url_count = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.channel_id == uuid.UUID(created_channel_id))
.count()
)
assert url_count == 2
# And also check the response from get_channel
channel_get_response = admin_user_client.get(f"/channels/{created_channel_id}")
assert channel_get_response.status_code == status.HTTP_200_OK
channel_details = channel_get_response.json()
assert len(channel_details["urls"]) == 2
def test_add_channel_url_channel_not_found(
db_session: Session, admin_user_client: TestClient
):
# Setup priority
create_mock_priorities_and_group(db_session, [(100, "High")], "My Group")
random_channel_uuid = uuid.uuid4()
url_data = {"url": "http://stream_no_channel.com", "priority_id": 100}
response = admin_user_client.post(
f"/channels/{random_channel_uuid}/urls", json=url_data
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Channel not found" in response.json()["detail"]
def test_add_channel_url_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
# Setup priority and create a channel with admin
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Forbidden Group"
)
channel_data = {
"tvg_id": "url_forbidden.tv",
"name": "URL Forbidden",
"group_id": str(group_id), # Use the ID of the created group
"tvg_name": "UFName2",
"tvg_logo": "uflogo2.png",
"urls": [{"url": "http://url_forbidden.com", "priority_id": 100}],
}
create_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_response.json()["id"]
url_data = {"url": "http://new_stream_forbidden.com", "priority_id": 100}
response = non_admin_user_client.post(
f"/channels/{created_channel_id}/urls", json=url_data
)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
# --- Test Cases For Update Channel URL ---
def test_update_channel_url_success(db_session: Session, admin_user_client: TestClient):
# Setup priorities and create a channel with a URL
group_id = create_mock_priorities_and_group(
db_session, [(100, "High"), (200, "Medium"), (300, "Low")], "URL Update Group"
)
channel_data = {
"tvg_id": "ch_update_url.tv",
"name": "Channel Update URL",
"group_id": str(group_id), # Use the ID of the created group
"tvg_name": "CUUName",
"tvg_logo": "cuulogo.png",
"urls": [{"url": "http://original_url.com/stream", "priority_id": 100}],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
# Get the ID of the initially created URL
initial_url_id = create_ch_response.json()["urls"][0]["id"]
update_url_data = {
"url": "http://updated_url.com/live",
"priority_id": 300,
"in_use": True,
}
response = admin_user_client.put(
f"/channels/{created_channel_id}/urls/{initial_url_id}", json=update_url_data
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["id"] == initial_url_id
assert data["url"] == "http://updated_url.com/live"
assert data["priority_id"] == 300
assert data["in_use"] is True
# Verify in DB
db_url = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == uuid.UUID(initial_url_id))
.first()
)
assert db_url is not None
assert db_url.url == "http://updated_url.com/live"
assert db_url.priority_id == 300
assert db_url.in_use is True
def test_update_channel_url_partial_success(
db_session: Session, admin_user_client: TestClient
):
# Setup priorities and create a channel with a URL
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Partial Update Group"
)
channel_data = {
"tvg_id": "ch_partial_update_url.tv",
"name": "Channel Partial Update URL",
"group_id": str(group_id),
"tvg_name": "CPUName",
"tvg_logo": "cpulogo.png",
"urls": [{"url": "http://partial_original.com/stream", "priority_id": 100}],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
initial_url_id = create_ch_response.json()["urls"][0]["id"]
# Update only 'in_use'
update_url_data = {"in_use": True}
response = admin_user_client.put(
f"/channels/{created_channel_id}/urls/{initial_url_id}", json=update_url_data
)
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert data["id"] == initial_url_id
assert data["url"] == "http://partial_original.com/stream"
assert data["priority_id"] == 100
assert data["in_use"] is True
# Verify in DB
db_url = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == uuid.UUID(initial_url_id))
.first()
)
assert db_url is not None
assert db_url.in_use is True
assert db_url.url == "http://partial_original.com/stream"
assert db_url.priority_id == 100
def test_update_channel_url_url_not_found(
db_session: Session, admin_user_client: TestClient
):
# Setup priority and create a group
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Not Found Group"
)
channel_data = {
"tvg_id": "ch_url_not_found.tv",
"name": "Channel URL Not Found",
"group_id": str(group_id),
"tvg_name": "CUNFName",
"tvg_logo": "cunflogo.png",
"urls": [],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
random_url_uuid = uuid.uuid4()
update_data = {"url": "http://does_not_matter.com"}
response = admin_user_client.put(
f"/channels/{created_channel_id}/urls/{random_url_uuid}", json=update_data
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "URL not found" in response.json()["detail"]
def test_update_channel_url_channel_id_mismatch_is_url_not_found(
db_session: Session, admin_user_client: TestClient
):
# This tests if a URL ID exists but is not associated
# with the given channel_id in the path
# Setup priority and create a group
group1_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "Ch1 Group"
)
# Create channel 1 with a URL
ch1_data = {
"tvg_id": "ch1_url_mismatch.tv",
"name": "CH1 URL Mismatch",
"group_id": str(group1_id),
"tvg_name": "C1UMName",
"tvg_logo": "c1umlogo.png",
"urls": [{"url": "http://ch1.url", "priority_id": 100}],
}
ch1_resp = admin_user_client.post("/channels/", json=ch1_data)
url_id_from_ch1 = ch1_resp.json()["urls"][0]["id"]
# Create another group
group2_id = create_mock_priorities_and_group(
db_session, [(200, "Medium")], "Ch2 Group"
)
# Create channel 2
ch2_data = {
"tvg_id": "ch2_url_mismatch.tv",
"name": "CH2 URL Mismatch",
"group_id": str(group2_id),
"tvg_name": "C2UMName",
"tvg_logo": "c2umlogo.png",
"urls": [],
} # priority_id not needed here
ch2_resp = admin_user_client.post("/channels/", json=ch2_data)
ch2_id = ch2_resp.json()["id"]
# Try to update URL from CH1 using CH2's ID in path
update_data = {"url": "http://mismatch_update.com"}
response = admin_user_client.put(
f"/channels/{ch2_id}/urls/{url_id_from_ch1}", json=update_data
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "URL not found" in response.json()["detail"]
def test_update_channel_url_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
# Setup priority, group and create channel with URL using admin
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Update Forbidden Group"
)
channel_data = {
"tvg_id": "ch_update_url_forbidden.tv",
"name": "Channel Update URL Forbidden",
"group_id": str(group_id),
"tvg_name": "CUFName",
"tvg_logo": "cuflgo.png",
"urls": [{"url": "http://original_forbidden.com/stream", "priority_id": 100}],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
initial_url_id = create_ch_response.json()["urls"][0]["id"]
update_url_data = {"url": "http://attempted_update_forbidden.com"}
response = non_admin_user_client.put(
f"/channels/{created_channel_id}/urls/{initial_url_id}", json=update_url_data
)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
# --- Test Cases For Delete Channel URL ---
def test_delete_channel_url_success(db_session: Session, admin_user_client: TestClient):
# Setup priority, group and create a channel with a URL
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Delete Group"
)
channel_data = {
"tvg_id": "ch_delete_url.tv",
"name": "Channel Delete URL",
"group_id": str(group_id),
"tvg_name": "CDUName",
"tvg_logo": "cdulogo.png",
"urls": [{"url": "http://delete_this_url.com/stream", "priority_id": 100}],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
url_to_delete_id = create_ch_response.json()["urls"][0]["id"]
# Verify URL exists before delete
db_url_before = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == url_to_delete_id)
.first()
)
assert db_url_before is not None
delete_response = admin_user_client.delete(
f"/channels/{created_channel_id}/urls/{url_to_delete_id}"
)
assert delete_response.status_code == status.HTTP_204_NO_CONTENT
# Verify URL is gone from DB
db_url_after = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == url_to_delete_id)
.first()
)
assert db_url_after is None
# Verify channel still exists and has no URLs
channel_response = admin_user_client.get(f"/channels/{created_channel_id}")
assert channel_response.status_code == status.HTTP_200_OK
assert len(channel_response.json()["urls"]) == 0
def test_delete_channel_url_url_not_found(
db_session: Session, admin_user_client: TestClient
):
# Setup priority, group and create a channel with a URL
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Del Not Found Group"
)
channel_data = {
"tvg_id": "ch_del_url_not_found.tv",
"name": "Channel Del URL Not Found",
"group_id": str(group_id),
"tvg_name": "CDUNFName",
"tvg_logo": "cdunflogo.png",
"urls": [],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
random_url_uuid = uuid.uuid4()
response = admin_user_client.delete(
f"/channels/{created_channel_id}/urls/{random_url_uuid}"
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "URL not found" in response.json()["detail"]
def test_delete_channel_url_channel_id_mismatch_is_url_not_found(
db_session: Session, admin_user_client: TestClient
):
# Setup priority, group 1 and create a channel 1 with a URL
group1_id = create_mock_priorities_and_group(db_session, [(100, "High")], "G1Del")
# Create channel 1 with a URL
ch1_data = {
"name": "CH1 Del URL Mismatch",
"tvg_id": "ch1_del_url_mismatch.tv",
"tvg_name": "CH1 Del URL Mismatch",
"tvg_logo": "ch1delogo.png",
"group_id": str(group1_id),
"urls": [{"url": "http://ch1del.url", "priority_id": 100}],
}
ch1_resp = admin_user_client.post("/channels/", json=ch1_data)
print(ch1_resp.json())
url_id_from_ch1 = ch1_resp.json()["urls"][0]["id"]
# Setup group 2 and create a channel 2
group2_id = create_mock_priorities_and_group(db_session, [], "G2Del")
# Create channel 2
ch2_data = {
"tvg_id": "ch2_del_url_mismatch.tv",
"name": "CH2 Del URL Mismatch",
"tvg_name": "CH2 Del URL Mismatch",
"tvg_logo": "ch2delogo.png",
"group_id": str(group2_id),
"urls": [],
}
ch2_resp = admin_user_client.post("/channels/", json=ch2_data)
ch2_id = ch2_resp.json()["id"]
# Try to delete URL from CH1 using CH2's ID in path
response = admin_user_client.delete(f"/channels/{ch2_id}/urls/{url_id_from_ch1}")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "URL not found" in response.json()["detail"]
# Ensure the original URL on CH1 was not deleted
db_url_ch1 = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == url_id_from_ch1)
.first()
)
assert db_url_ch1 is not None
def test_delete_channel_url_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
# Setup priority, group and create a channel with a URL
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Del Forbidden Group"
)
channel_data = {
"tvg_id": "ch_del_url_forbidden.tv",
"name": "Channel Del URL Forbidden",
"group_id": str(group_id),
"tvg_name": "CDUFName",
"tvg_logo": "cduflogo.png",
"urls": [
{"url": "http://original_del_forbidden.com/stream", "priority_id": 100}
],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
initial_url_id = create_ch_response.json()["urls"][0]["id"]
response = non_admin_user_client.delete(
f"/channels/{created_channel_id}/urls/{initial_url_id}"
)
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
# Ensure URL was not deleted
db_url_not_deleted = (
db_session.query(MockChannelURL)
.filter(MockChannelURL.id == initial_url_id)
.first()
)
assert db_url_not_deleted is not None
# --- Test Cases For List Channel URLs ---
def test_list_channel_urls_success(db_session: Session, admin_user_client: TestClient):
# Setup priorities, group and create a channel with a URL
group_id = create_mock_priorities_and_group(
db_session, [(100, "High"), (200, "Medium")], "URL List Group"
)
channel_data = {
"tvg_id": "ch_list_urls.tv",
"name": "Channel List URLs",
"group_id": str(group_id),
"tvg_name": "CLUName",
"tvg_logo": "clulogo.png",
"urls": [
{"url": "http://list_url1.com/stream", "priority_id": 100},
{"url": "http://list_url2.com/live", "priority_id": 200},
],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
# URLs are added during channel creation,
# let's get their IDs for assertion if needed
# For now, we'll just check the count and content based on what was provided.
response = admin_user_client.get(f"/channels/{created_channel_id}/urls")
assert response.status_code == status.HTTP_200_OK
data = response.json()
assert len(data) == 2
# Check if the URLs returned match what we expect
# (order might not be guaranteed by default)
returned_urls_set = {(item["url"], item["priority_id"]) for item in data}
expected_urls_set = {
("http://list_url1.com/stream", 100),
("http://list_url2.com/live", 200),
}
assert returned_urls_set == expected_urls_set
def test_list_channel_urls_empty(db_session: Session, admin_user_client: TestClient):
# Create a channel with no URLs initially
# No need to set up MockPriority if no URLs with priority_id are being created.
# Setup group
group_id = create_mock_priorities_and_group(db_session, [], "URL List Empty Group")
channel_data = {
"tvg_id": "ch_list_empty_urls.tv",
"name": "Channel List Empty URLs",
"group_id": str(group_id),
"tvg_name": "CLEUName",
"tvg_logo": "cleulogo.png",
"urls": [],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
response = admin_user_client.get(f"/channels/{created_channel_id}/urls")
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
def test_list_channel_urls_channel_not_found(
db_session: Session, admin_user_client: TestClient
):
random_channel_uuid = uuid.uuid4()
response = admin_user_client.get(f"/channels/{random_channel_uuid}/urls")
assert response.status_code == status.HTTP_404_NOT_FOUND
assert "Channel not found" in response.json()["detail"]
def test_list_channel_urls_forbidden_for_non_admin(
db_session: Session,
non_admin_user_client: TestClient,
admin_user_client: TestClient,
):
# Setup priority, group and create a channel admin
group_id = create_mock_priorities_and_group(
db_session, [(100, "High")], "URL Del Forbidden Group"
)
channel_data = {
"tvg_id": "ch_list_url_forbidden.tv",
"name": "Channel List URL Forbidden",
"group_id": str(group_id),
"tvg_name": "CLUFName",
"tvg_logo": "cluflogo.png",
"urls": [{"url": "http://list_url_forbidden.com", "priority_id": 100}],
}
create_ch_response = admin_user_client.post("/channels/", json=channel_data)
created_channel_id = create_ch_response.json()["id"]
response = non_admin_user_client.get(f"/channels/{created_channel_id}/urls")
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]
assert response.status_code == status.HTTP_403_FORBIDDEN
assert "required roles" in response.json()["detail"]