Refactor: Replace CallbackManager with Events pattern

- Replace callback system with events library in SerieScanner
- Update SeriesApp to subscribe to loader and scanner events
- Refactor ScanService to use Events instead of CallbackManager
- Remove CallbackManager imports and callback classes
- Add safe event calling with error handling in SerieScanner
- Update AniworldLoader to use Events for download progress
- Remove progress_callback parameter from download methods
- Update all affected tests for Events pattern
- Fix test_series_app.py for new event subscription model
- Comment out obsolete callback tests in test_scan_service.py

All core tests passing. Events provide cleaner event-driven architecture.
This commit is contained in:
2025-12-30 21:04:45 +01:00
parent ff9dea0488
commit b1726968e5
8 changed files with 381 additions and 631 deletions

View File

@@ -1,29 +1,17 @@
"""Unit tests for ScanService.
This module contains comprehensive tests for the scan service,
including scan lifecycle, progress callbacks, event handling,
and key-based identification.
including scan lifecycle, progress events, and key-based identification.
"""
from datetime import datetime
from unittest.mock import AsyncMock, MagicMock
from unittest.mock import AsyncMock, MagicMock, Mock
import pytest
from src.core.interfaces.callbacks import (
CallbackManager,
CompletionContext,
ErrorContext,
OperationType,
ProgressContext,
ProgressPhase,
)
from src.server.services.scan_service import (
ScanProgress,
ScanService,
ScanServiceCompletionCallback,
ScanServiceError,
ScanServiceErrorCallback,
ScanServiceProgressCallback,
get_scan_service,
reset_scan_service,
)

View File

@@ -188,16 +188,17 @@ class TestSeriesAppDownload:
app.loader.download = Mock(side_effect=mock_download_cancelled)
# Perform download - should catch InterruptedError
result = await app.download(
"anime_folder",
season=1,
episode=1,
key="anime_key"
)
# Perform download - should re-raise InterruptedError
with pytest.raises(InterruptedError):
await app.download(
"anime_folder",
season=1,
episode=1,
key="anime_key"
)
# Verify cancellation was handled (returns False on error)
assert result is False
# Verify cancellation event was fired
assert app._events.download_status.called
@pytest.mark.asyncio
@patch('src.core.SeriesApp.Loaders')
@@ -264,10 +265,10 @@ class TestSeriesAppReScan:
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
async def test_rescan_with_callback(
async def test_rescan_with_events(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test rescan with progress callbacks."""
"""Test rescan with event progress notifications."""
test_dir = "/test/anime"
app = SeriesApp(test_dir)
@@ -278,19 +279,19 @@ class TestSeriesAppReScan:
app.serie_scanner.get_total_to_scan = Mock(return_value=3)
app.serie_scanner.reinit = Mock()
app.serie_scanner.keyDict = {}
def mock_scan(callback):
callback("folder1", 1)
callback("folder2", 2)
callback("folder3", 3)
app.serie_scanner.scan = Mock(side_effect=mock_scan)
app.serie_scanner.scan = Mock() # Scan no longer takes callback
app.serie_scanner.subscribe_on_progress = Mock()
app.serie_scanner.unsubscribe_on_progress = Mock()
# Perform rescan
await app.rescan()
# Verify rescan completed
# Verify scanner methods were called correctly
app.serie_scanner.reinit.assert_called_once()
app.serie_scanner.scan.assert_called_once()
# Verify event subscription/unsubscription happened
app.serie_scanner.subscribe_on_progress.assert_called_once()
app.serie_scanner.unsubscribe_on_progress.assert_called_once()
@pytest.mark.asyncio
@patch('src.core.SeriesApp.Loaders')