Files
sdb2-backend/tests/services/test_dashboard.py
JSC d3d7edb287
Some checks failed
Backend CI / lint (push) Has been cancelled
Backend CI / test (push) Has been cancelled
feat: Add tests for dashboard service including statistics and date filters
2025-08-12 23:34:02 +02:00

277 lines
9.3 KiB
Python

"""Tests for dashboard service."""
from datetime import UTC, datetime, timedelta
from unittest.mock import AsyncMock, Mock, patch
import pytest
from app.services.dashboard import DashboardService
@pytest.fixture
def mock_sound_repository():
"""Mock sound repository."""
return Mock()
@pytest.fixture
def dashboard_service(mock_sound_repository):
"""Dashboard service with mocked dependencies."""
return DashboardService(sound_repository=mock_sound_repository)
class TestDashboardService:
"""Test dashboard service."""
@pytest.mark.asyncio
async def test_init(self, mock_sound_repository):
"""Test dashboard service initialization."""
service = DashboardService(sound_repository=mock_sound_repository)
assert service.sound_repository == mock_sound_repository
@pytest.mark.asyncio
async def test_get_soundboard_statistics_success(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting soundboard statistics successfully."""
# Mock repository response
mock_stats = {
"count": 25,
"total_plays": 150,
"total_duration": 75000,
"total_size": 1024000,
}
mock_sound_repository.get_soundboard_statistics = AsyncMock(return_value=mock_stats)
result = await dashboard_service.get_soundboard_statistics()
assert result == {
"sound_count": 25,
"total_play_count": 150,
"total_duration": 75000,
"total_size": 1024000,
}
mock_sound_repository.get_soundboard_statistics.assert_called_once()
@pytest.mark.asyncio
async def test_get_soundboard_statistics_exception(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting soundboard statistics with exception."""
mock_sound_repository.get_soundboard_statistics = AsyncMock(
side_effect=Exception("Database error")
)
with pytest.raises(Exception, match="Database error"):
await dashboard_service.get_soundboard_statistics()
mock_sound_repository.get_soundboard_statistics.assert_called_once()
@pytest.mark.asyncio
async def test_get_track_statistics_success(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting track statistics successfully."""
# Mock repository response
mock_stats = {
"count": 15,
"total_plays": 80,
"total_duration": 45000,
"total_size": 512000,
}
mock_sound_repository.get_track_statistics = AsyncMock(return_value=mock_stats)
result = await dashboard_service.get_track_statistics()
assert result == {
"track_count": 15,
"total_play_count": 80,
"total_duration": 45000,
"total_size": 512000,
}
mock_sound_repository.get_track_statistics.assert_called_once()
@pytest.mark.asyncio
async def test_get_track_statistics_exception(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting track statistics with exception."""
mock_sound_repository.get_track_statistics = AsyncMock(
side_effect=Exception("Database error")
)
with pytest.raises(Exception, match="Database error"):
await dashboard_service.get_track_statistics()
mock_sound_repository.get_track_statistics.assert_called_once()
@pytest.mark.asyncio
async def test_get_top_sounds_success_all_time(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting top sounds for all time successfully."""
# Mock repository response
mock_sounds = [
{
"id": 1,
"name": "Sound 1",
"type": "SDB",
"play_count": 100,
"duration": 5000,
"created_at": datetime(2023, 1, 1, 12, 0, 0, tzinfo=UTC),
},
{
"id": 2,
"name": "Sound 2",
"type": "SDB",
"play_count": 50,
"duration": 3000,
"created_at": None,
},
]
mock_sound_repository.get_top_sounds = AsyncMock(return_value=mock_sounds)
result = await dashboard_service.get_top_sounds("SDB", "all_time", 10)
assert len(result) == 2
assert result[0] == {
"id": 1,
"name": "Sound 1",
"type": "SDB",
"play_count": 100,
"duration": 5000,
"created_at": "2023-01-01T12:00:00+00:00",
}
assert result[1] == {
"id": 2,
"name": "Sound 2",
"type": "SDB",
"play_count": 50,
"duration": 3000,
"created_at": None,
}
mock_sound_repository.get_top_sounds.assert_called_once_with(
sound_type="SDB",
date_filter=None,
limit=10,
)
@pytest.mark.asyncio
async def test_get_top_sounds_success_with_period(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting top sounds with specific period."""
mock_sounds = []
mock_sound_repository.get_top_sounds = AsyncMock(return_value=mock_sounds)
with patch.object(dashboard_service, "_get_date_filter") as mock_date_filter:
mock_date_filter.return_value = datetime(2023, 1, 1, tzinfo=UTC)
result = await dashboard_service.get_top_sounds("EXT", "1_week", 5)
assert result == []
mock_date_filter.assert_called_once_with("1_week")
mock_sound_repository.get_top_sounds.assert_called_once_with(
sound_type="EXT",
date_filter=datetime(2023, 1, 1, tzinfo=UTC),
limit=5,
)
@pytest.mark.asyncio
async def test_get_top_sounds_exception(
self,
dashboard_service,
mock_sound_repository,
):
"""Test getting top sounds with exception."""
mock_sound_repository.get_top_sounds = AsyncMock(
side_effect=Exception("Database error")
)
with pytest.raises(Exception, match="Database error"):
await dashboard_service.get_top_sounds("SDB", "all_time", 10)
mock_sound_repository.get_top_sounds.assert_called_once()
def test_get_date_filter_today(self, dashboard_service):
"""Test date filter for today."""
with patch("app.services.dashboard.datetime") as mock_datetime:
mock_now = datetime(2023, 6, 15, 14, 30, 45, 123456, tzinfo=UTC)
mock_datetime.now.return_value = mock_now
mock_datetime.UTC = UTC
result = dashboard_service._get_date_filter("today")
expected = datetime(2023, 6, 15, 0, 0, 0, 0, tzinfo=UTC)
assert result == expected
def test_get_date_filter_1_day(self, dashboard_service):
"""Test date filter for 1 day."""
with patch("app.services.dashboard.datetime") as mock_datetime:
mock_now = datetime(2023, 6, 15, 14, 30, 45, tzinfo=UTC)
mock_datetime.now.return_value = mock_now
mock_datetime.UTC = UTC
result = dashboard_service._get_date_filter("1_day")
expected = datetime(2023, 6, 14, 14, 30, 45, tzinfo=UTC)
assert result == expected
def test_get_date_filter_1_week(self, dashboard_service):
"""Test date filter for 1 week."""
with patch("app.services.dashboard.datetime") as mock_datetime:
mock_now = datetime(2023, 6, 15, 14, 30, 45, tzinfo=UTC)
mock_datetime.now.return_value = mock_now
mock_datetime.UTC = UTC
result = dashboard_service._get_date_filter("1_week")
expected = datetime(2023, 6, 8, 14, 30, 45, tzinfo=UTC)
assert result == expected
def test_get_date_filter_1_month(self, dashboard_service):
"""Test date filter for 1 month."""
with patch("app.services.dashboard.datetime") as mock_datetime:
mock_now = datetime(2023, 6, 15, 14, 30, 45, tzinfo=UTC)
mock_datetime.now.return_value = mock_now
mock_datetime.UTC = UTC
result = dashboard_service._get_date_filter("1_month")
expected = datetime(2023, 5, 16, 14, 30, 45, tzinfo=UTC)
assert result == expected
def test_get_date_filter_1_year(self, dashboard_service):
"""Test date filter for 1 year."""
with patch("app.services.dashboard.datetime") as mock_datetime:
mock_now = datetime(2023, 6, 15, 14, 30, 45, tzinfo=UTC)
mock_datetime.now.return_value = mock_now
mock_datetime.UTC = UTC
result = dashboard_service._get_date_filter("1_year")
expected = datetime(2022, 6, 15, 14, 30, 45, tzinfo=UTC)
assert result == expected
def test_get_date_filter_all_time(self, dashboard_service):
"""Test date filter for all time."""
result = dashboard_service._get_date_filter("all_time")
assert result is None
def test_get_date_filter_unknown_period(self, dashboard_service):
"""Test date filter for unknown period."""
result = dashboard_service._get_date_filter("unknown_period")
assert result is None