Implemented bulk upload by passing a json structure. Added delete all channels, groups and priorities
All checks were successful
AWS Deploy on Push / build (push) Successful in 2m17s
All checks were successful
AWS Deploy on Push / build (push) Successful in 2m17s
This commit is contained in:
@@ -53,6 +53,15 @@ def test_sqliteuuid_process_result_value_valid_string():
|
||||
assert result == test_uuid
|
||||
|
||||
|
||||
def test_sqliteuuid_process_result_value_uuid_object():
|
||||
"""Test SQLiteUUID.process_result_value: UUID object returns itself."""
|
||||
uuid_type = SQLiteUUID()
|
||||
test_uuid = uuid.uuid4()
|
||||
result = uuid_type.process_result_value(test_uuid, None)
|
||||
assert isinstance(result, uuid.UUID)
|
||||
assert result is test_uuid # Ensure it's the same object, not a new one
|
||||
|
||||
|
||||
def test_sqliteuuid_compare_values_none():
|
||||
"""Test SQLiteUUID.compare_values handles None values"""
|
||||
uuid_type = SQLiteUUID()
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from unittest.mock import patch
|
||||
|
||||
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
|
||||
@@ -338,7 +336,69 @@ def test_update_channel_forbidden_for_non_admin(
|
||||
assert "required roles" in response.json()["detail"]
|
||||
|
||||
|
||||
# --- Test Cases For Delete Channel ---
|
||||
# --- Test Cases For Delete Channels ---
|
||||
|
||||
|
||||
def test_delete_all_channels_success(db_session, admin_user_client):
|
||||
"""Test reset channels endpoint"""
|
||||
# Create test data
|
||||
create_mock_priorities_and_group(db_session, [(100, "High")], "Test Group")
|
||||
channel_data = [
|
||||
{
|
||||
"name": "Channel 1",
|
||||
"group-title": "Group A",
|
||||
"tvg-id": "channel1.tv",
|
||||
"tvg-name": "Channel One",
|
||||
"tvg-logo": "logo1.png",
|
||||
"urls": ["http://stream1.com", "http://backup1.com"],
|
||||
}
|
||||
]
|
||||
admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
|
||||
# Verify data exists
|
||||
assert db_session.query(MockChannelDB).count() == 1
|
||||
assert db_session.query(MockChannelURL).count() == 2
|
||||
|
||||
# Reset channels
|
||||
response = admin_user_client.delete("/channels")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["deleted"] == 1
|
||||
|
||||
# Verify data is gone
|
||||
assert db_session.query(MockChannelDB).count() == 0
|
||||
assert db_session.query(MockChannelURL).count() == 0
|
||||
|
||||
|
||||
def test_delete_all_channels_forbidden_for_non_admin(db_session, non_admin_user_client):
|
||||
"""Test delete all channels requires admin role"""
|
||||
response = non_admin_user_client.delete("/channels")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
def test_delete_all_channels_error_handling(db_session, admin_user_client):
|
||||
"""Test error handling when deleting channels fails"""
|
||||
# Create some test data
|
||||
group_id = create_mock_priorities_and_group(
|
||||
db_session, [(100, "High")], "Error Group"
|
||||
)
|
||||
channel = MockChannelDB(
|
||||
name="Error Channel",
|
||||
group_id=group_id,
|
||||
tvg_id="error.tv",
|
||||
urls=[MockChannelURL(url="http://error.com/stream", priority_id=100)],
|
||||
)
|
||||
db_session.add(channel)
|
||||
db_session.commit()
|
||||
|
||||
# To test the error handling of the endpoint, we need to simulate a failure
|
||||
# during the database operation. We patch the 'commit' method of the session
|
||||
# class to raise an exception. This patch will be active during the API call.
|
||||
with patch.object(
|
||||
type(db_session), "commit", side_effect=Exception("Mock database commit error")
|
||||
):
|
||||
response = admin_user_client.delete("/channels/")
|
||||
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
assert "Failed to delete channels" in response.json()["detail"]
|
||||
|
||||
|
||||
def test_delete_channel_success(db_session: Session, admin_user_client: TestClient):
|
||||
@@ -1275,3 +1335,254 @@ def test_list_channel_urls_forbidden_for_non_admin(
|
||||
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
assert "required roles" in response.json()["detail"]
|
||||
|
||||
|
||||
# --- Test Cases For Bulk Upload Channels ---
|
||||
|
||||
|
||||
def test_bulk_upload_channels_success(
|
||||
db_session: Session, admin_user_client: TestClient
|
||||
):
|
||||
"""Test successful bulk upload of channels"""
|
||||
# Create priorities
|
||||
priorities = [(100, "High"), (200, "Medium"), (300, "Low")]
|
||||
for id, desc in priorities:
|
||||
db_session.add(MockPriority(id=id, description=desc))
|
||||
db_session.commit()
|
||||
|
||||
# Test data matching channels.json format
|
||||
channels = [
|
||||
{
|
||||
"name": "Channel 1",
|
||||
"group-title": "Group A",
|
||||
"tvg-id": "channel1.tv",
|
||||
"tvg-name": "Channel One",
|
||||
"tvg-logo": "logo1.png",
|
||||
"urls": ["http://stream1.com", "http://backup1.com"],
|
||||
},
|
||||
{
|
||||
"name": "Channel 2",
|
||||
"group-title": "Group B",
|
||||
"tvg-id": "channel2.tv",
|
||||
"tvg-name": "Channel Two",
|
||||
"tvg-logo": "logo2.png",
|
||||
"urls": ["http://stream2.com"],
|
||||
},
|
||||
]
|
||||
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=channels)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 2
|
||||
|
||||
# Verify groups created
|
||||
groups = db_session.query(MockGroup).all()
|
||||
assert len(groups) == 2
|
||||
assert {g.name for g in groups} == {"Group A", "Group B"}
|
||||
|
||||
# Verify channels and URLs
|
||||
channel1 = db_session.query(MockChannelDB).filter_by(name="Channel 1").first()
|
||||
assert channel1 is not None
|
||||
assert len(channel1.urls) == 2
|
||||
assert channel1.urls[0].url == "http://stream1.com"
|
||||
assert channel1.urls[0].priority_id == 100
|
||||
assert channel1.urls[1].url == "http://backup1.com"
|
||||
assert channel1.urls[1].priority_id == 200
|
||||
|
||||
channel2 = db_session.query(MockChannelDB).filter_by(name="Channel 2").first()
|
||||
assert channel2 is not None
|
||||
assert len(channel2.urls) == 1
|
||||
assert channel2.urls[0].url == "http://stream2.com"
|
||||
assert channel2.urls[0].priority_id == 100
|
||||
|
||||
|
||||
def test_bulk_upload_empty(db_session, admin_user_client):
|
||||
"""Test bulk upload with empty list"""
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=[])
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 0
|
||||
|
||||
|
||||
def test_bulk_upload_forbidden_for_non_admin(db_session, non_admin_user_client):
|
||||
"""Test bulk upload requires admin role"""
|
||||
response = non_admin_user_client.post("/channels/bulk-upload", json=[{}])
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
def test_bulk_upload_skip_missing_group_name(db_session, admin_user_client):
|
||||
"""Test bulk upload skips channels with missing group name"""
|
||||
channel_data = [{"name": "No Group Channel", "urls": ["http://no-group.com"]}]
|
||||
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 0
|
||||
assert db_session.query(MockChannelDB).count() == 0
|
||||
|
||||
|
||||
def test_bulk_upload_single_url_conversion(db_session, admin_user_client):
|
||||
"""Test bulk upload converts single URL string to list"""
|
||||
# Create priorities
|
||||
priorities = [(100, "High"), (200, "Medium"), (300, "Low")]
|
||||
for id, desc in priorities:
|
||||
db_session.add(MockPriority(id=id, description=desc))
|
||||
db_session.commit()
|
||||
|
||||
channel_data = [
|
||||
{
|
||||
"name": "Single URL Channel",
|
||||
"group-title": "Test Group",
|
||||
"urls": ["http://single-url.com"],
|
||||
}
|
||||
]
|
||||
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 1
|
||||
|
||||
channel = db_session.query(MockChannelDB).first()
|
||||
assert channel is not None
|
||||
urls = db_session.query(MockChannelURL).filter_by(channel_id=channel.id).all()
|
||||
assert len(urls) == 1
|
||||
assert urls[0].url == "http://single-url.com"
|
||||
|
||||
|
||||
def test_bulk_upload_update_existing_channel(db_session, admin_user_client):
|
||||
"""Test bulk upload updates existing channel and recreates URLs"""
|
||||
# First create a group and channel
|
||||
group_id = create_mock_priorities_and_group(
|
||||
db_session, [(100, "High")], "Existing Group"
|
||||
)
|
||||
channel = MockChannelDB(
|
||||
name="Existing Channel",
|
||||
group_id=group_id,
|
||||
tvg_id="existing.tv",
|
||||
tvg_name="Existing",
|
||||
tvg_logo="existing.png",
|
||||
)
|
||||
db_session.add(channel)
|
||||
db_session.commit()
|
||||
db_session.refresh(channel)
|
||||
|
||||
# Add some URLs
|
||||
db_url1 = MockChannelURL(
|
||||
channel_id=channel.id, url="http://old1.com", priority_id=100, in_use=False
|
||||
)
|
||||
db_url2 = MockChannelURL(
|
||||
channel_id=channel.id, url="http://old2.com", priority_id=200, in_use=False
|
||||
)
|
||||
db_session.add_all([db_url1, db_url2])
|
||||
db_session.commit()
|
||||
|
||||
# Bulk upload with same group and channel name but different URLs
|
||||
channel_data = [
|
||||
{
|
||||
"name": "Existing Channel",
|
||||
"group-title": "Existing Group",
|
||||
"tvg-id": "updated.tv",
|
||||
"tvg-name": "Updated",
|
||||
"tvg-logo": "updated.png",
|
||||
"urls": ["http://new1.com", "http://new2.com"],
|
||||
}
|
||||
]
|
||||
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 1
|
||||
|
||||
# Verify channel was updated
|
||||
print(
|
||||
"Channel after update:",
|
||||
db_session.query(MockChannelDB).filter().first().id,
|
||||
channel.tvg_id,
|
||||
)
|
||||
updated_channel = db_session.query(MockChannelDB).filter_by(id=channel.id).first()
|
||||
assert updated_channel.tvg_id == "updated.tv"
|
||||
assert updated_channel.tvg_name == "Updated"
|
||||
assert updated_channel.tvg_logo == "updated.png"
|
||||
|
||||
# Verify old URLs were deleted and new ones created
|
||||
urls = db_session.query(MockChannelURL).filter_by(channel_id=channel.id).all()
|
||||
assert len(urls) == 2
|
||||
assert {url.url for url in urls} == {"http://new1.com", "http://new2.com"}
|
||||
|
||||
|
||||
def test_bulk_upload_error_handling(db_session, admin_user_client):
|
||||
"""Test error handling in bulk upload continues processing"""
|
||||
# Create a group first
|
||||
create_mock_priorities_and_group(db_session, [(100, "High")], "Error Group")
|
||||
|
||||
channel_data = [
|
||||
{
|
||||
"name": "Good Channel",
|
||||
"group-title": "Error Group",
|
||||
"urls": ["http://good.com"],
|
||||
},
|
||||
{
|
||||
"name": "Bad Channel",
|
||||
"group-title": "Error Group",
|
||||
"urls": None, # This will cause an error
|
||||
},
|
||||
{
|
||||
"name": "Another Good Channel",
|
||||
"group-title": "Error Group",
|
||||
"urls": ["http://another-good.com"],
|
||||
},
|
||||
]
|
||||
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 2 # Only 2 successful
|
||||
|
||||
# Verify the good channels were processed
|
||||
channels = db_session.query(MockChannelDB).all()
|
||||
assert len(channels) == 2
|
||||
assert {c.name for c in channels} == {"Good Channel", "Another Good Channel"}
|
||||
|
||||
|
||||
def test_bulk_upload_channels_no_priorities(
|
||||
db_session: Session, admin_user_client: TestClient
|
||||
):
|
||||
"""Test bulk upload when no priorities are defined in the database.
|
||||
The channel should be processed, but its URLs should be skipped.
|
||||
"""
|
||||
# Ensure no priorities exist in the database
|
||||
db_session.query(MockPriority).delete()
|
||||
db_session.commit()
|
||||
|
||||
# Create a group for the channel
|
||||
group = MockGroup(name="No Priority Group")
|
||||
db_session.add(group)
|
||||
db_session.commit()
|
||||
db_session.refresh(group)
|
||||
|
||||
channel_data = [
|
||||
{
|
||||
"name": "Channel With No Priority URL",
|
||||
"group-title": "No Priority Group",
|
||||
"tvg-id": "nopriority.tv",
|
||||
"tvg-name": "NoPriorityChannel",
|
||||
"tvg-logo": "nopriority.png",
|
||||
"urls": ["http://nopriority.com/stream"],
|
||||
}
|
||||
]
|
||||
|
||||
# Call the bulk upload endpoint
|
||||
response = admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
|
||||
# Assert the response indicates 1 processed channel
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["processed"] == 1
|
||||
|
||||
# Verify the channel was added to the database
|
||||
db_channel = (
|
||||
db_session.query(MockChannelDB)
|
||||
.filter_by(name="Channel With No Priority URL")
|
||||
.first()
|
||||
)
|
||||
assert db_channel is not None
|
||||
assert db_channel.group_id == group.id
|
||||
|
||||
# Verify no URLs were added for this channel
|
||||
assert (
|
||||
db_session.query(MockChannelURL).filter_by(channel_id=db_channel.id).count()
|
||||
== 0
|
||||
)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
from fastapi import status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.auth.dependencies import get_current_user
|
||||
from app.routers.groups import router as groups_router
|
||||
from app.utils.database import get_db
|
||||
|
||||
# Import mocks and fixtures
|
||||
@@ -15,7 +13,11 @@ from tests.utils.auth_test_fixtures import (
|
||||
db_session,
|
||||
non_admin_user_client,
|
||||
)
|
||||
from tests.utils.db_mocks import MockChannelDB, MockGroup, SQLiteUUID
|
||||
from tests.utils.db_mocks import (
|
||||
MockChannelDB,
|
||||
MockGroup,
|
||||
create_mock_priorities_and_group,
|
||||
)
|
||||
|
||||
# --- Test Cases For Group Creation ---
|
||||
|
||||
@@ -188,6 +190,43 @@ def test_update_group_forbidden_for_non_admin(
|
||||
# --- Test Cases For Delete Group ---
|
||||
|
||||
|
||||
def test_delete_all_groups_success(db_session, admin_user_client):
|
||||
"""Test reset groups endpoint"""
|
||||
# Create test data
|
||||
group1_id = create_mock_priorities_and_group(db_session, [], "Group A")
|
||||
group2_id = create_mock_priorities_and_group(db_session, [], "Group B")
|
||||
|
||||
# Add channel to group2
|
||||
channel_data = [
|
||||
{
|
||||
"group-title": "Group A",
|
||||
"tvg_id": "channel1.tv",
|
||||
"name": "Channel One",
|
||||
"url": ["http://test.com", "http://example.com"],
|
||||
}
|
||||
]
|
||||
admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
|
||||
# Reset groups
|
||||
response = admin_user_client.delete("/groups")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["deleted"] == 1 # Only group2 should be deleted
|
||||
assert response.json()["skipped"] == 1 # group1 has channels
|
||||
|
||||
# Verify group2 deleted, group1 remains
|
||||
assert (
|
||||
db_session.query(MockGroup).filter(MockGroup.id == group1_id).first()
|
||||
is not None
|
||||
)
|
||||
assert db_session.query(MockGroup).filter(MockGroup.id == group2_id).first() is None
|
||||
|
||||
|
||||
def test_delete_all_groups_forbidden_for_non_admin(db_session, non_admin_user_client):
|
||||
"""Test reset groups requires admin role"""
|
||||
response = non_admin_user_client.delete("/groups")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
def test_delete_group_success(db_session: Session, admin_user_client):
|
||||
# Create group
|
||||
group_id = uuid.uuid4()
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
from fastapi import status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.db import ChannelURL, Priority
|
||||
from app.routers.priorities import router as priorities_router
|
||||
|
||||
# Import fixtures and mocks
|
||||
@@ -14,7 +12,13 @@ from tests.utils.auth_test_fixtures import (
|
||||
db_session,
|
||||
non_admin_user_client,
|
||||
)
|
||||
from tests.utils.db_mocks import MockChannelDB, MockChannelURL, MockGroup, MockPriority
|
||||
from tests.utils.db_mocks import (
|
||||
MockChannelDB,
|
||||
MockChannelURL,
|
||||
MockGroup,
|
||||
MockPriority,
|
||||
create_mock_priorities_and_group,
|
||||
)
|
||||
|
||||
# --- Test Cases For Priority Creation ---
|
||||
|
||||
@@ -127,6 +131,44 @@ def test_get_priority_forbidden_for_non_admin(
|
||||
# --- Test Cases For Delete Priority ---
|
||||
|
||||
|
||||
def test_delete_all_priorities_success(db_session, admin_user_client):
|
||||
"""Test reset priorities endpoint"""
|
||||
# Create test data
|
||||
priorities = [(100, "High"), (200, "Medium"), (300, "Low")]
|
||||
for id, desc in priorities:
|
||||
db_session.add(MockPriority(id=id, description=desc))
|
||||
db_session.commit()
|
||||
|
||||
# Create channel using priority 100
|
||||
create_mock_priorities_and_group(db_session, [], "Test Group")
|
||||
channel_data = [
|
||||
{
|
||||
"group-title": "Test Group",
|
||||
"tvg_id": "test.tv",
|
||||
"name": "Test Channel",
|
||||
"urls": ["http://test.com"],
|
||||
}
|
||||
]
|
||||
admin_user_client.post("/channels/bulk-upload", json=channel_data)
|
||||
|
||||
# Delete all priorities
|
||||
response = admin_user_client.delete("/priorities")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["deleted"] == 2 # Medium and Low priorities
|
||||
assert response.json()["skipped"] == 1 # High priority is in use
|
||||
|
||||
# Verify only priority 100 remains
|
||||
priorities = db_session.query(MockPriority).all()
|
||||
assert len(priorities) == 1
|
||||
assert priorities[0].id == 100
|
||||
|
||||
|
||||
def test_reset_priorities_forbidden_for_non_admin(db_session, non_admin_user_client):
|
||||
"""Test reset priorities requires admin role"""
|
||||
response = non_admin_user_client.delete("/priorities")
|
||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
|
||||
def test_delete_priority_success(db_session: Session, admin_user_client):
|
||||
# Create a test priority
|
||||
priority = MockPriority(id=100, description="To Delete")
|
||||
|
||||
@@ -60,6 +60,9 @@ class MockChannelDB(MockBase):
|
||||
onupdate=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
group = relationship("MockGroup", back_populates="channels")
|
||||
urls = relationship(
|
||||
"MockChannelURL", back_populates="channel", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class MockChannelURL(MockBase):
|
||||
@@ -77,6 +80,7 @@ class MockChannelURL(MockBase):
|
||||
default=lambda: datetime.now(timezone.utc),
|
||||
onupdate=lambda: datetime.now(timezone.utc),
|
||||
)
|
||||
channel = relationship("MockChannelDB", back_populates="urls")
|
||||
|
||||
|
||||
def create_mock_priorities_and_group(db_session, priorities, group_name):
|
||||
|
||||
Reference in New Issue
Block a user