test: complete Phase 3 of backend testing improvement plan

Centralize test fixtures:
- Add mock_downloader fixture for configurable downloader mocking
- Add mock_websocket_manager fixture for WebSocket broadcast recording
- Add reset_singletons autouse fixture for test isolation
- Consolidate singleton cleanup in conftest.py

Split large test files:
- test_download_manager.py (1422 lines) → 3 focused files:
  - test_download_manager_basic.py: 12 core functionality tests
  - test_download_manager_error.py: 15 error handling tests
  - test_download_manager_concurrent.py: 6 advanced scenario tests

- test_cache_paths.py (530 lines) → 3 focused files:
  - test_cache_paths_resolution.py: 11 path resolution tests
  - test_cache_paths_validation.py: 9 legacy validation tests
  - test_cache_paths_migration.py: 9 migration scenario tests

Update documentation:
- Mark all Phase 3 checklist items as complete
- Add Phase 3 completion summary with test results

All 894 tests passing.
This commit is contained in:
Will Miao
2026-02-11 11:10:31 +08:00
parent e335a527d4
commit 8e30008b29
10 changed files with 2264 additions and 1956 deletions

View File

@@ -269,3 +269,75 @@ def mock_scanner(mock_cache: MockCache, mock_hash_index: MockHashIndex) -> MockS
def mock_service(mock_scanner: MockScanner) -> MockModelService:
return MockModelService(scanner=mock_scanner)
@pytest.fixture
def mock_downloader():
"""Provide a configurable mock downloader."""
class MockDownloader:
def __init__(self):
self.download_calls = []
self.should_fail = False
self.return_value = (True, "success")
async def download_file(self, url, target_path, **kwargs):
self.download_calls.append({"url": url, "target_path": target_path, "kwargs": kwargs})
if self.should_fail:
return False, "Download failed"
return self.return_value
return MockDownloader()
@pytest.fixture
def mock_websocket_manager():
"""Provide a recording WebSocket manager."""
class RecordingWebSocketManager:
def __init__(self):
self.payloads = []
self.broadcast_count = 0
async def broadcast(self, payload):
self.payloads.append(payload)
self.broadcast_count += 1
def get_payloads_by_type(self, msg_type: str):
"""Get all payloads of a specific message type."""
return [p for p in self.payloads if p.get("type") == msg_type]
return RecordingWebSocketManager()
@pytest.fixture(autouse=True)
def reset_singletons():
"""Reset all singletons before each test to ensure isolation."""
# Import here to avoid circular imports
from py.services.download_manager import DownloadManager
from py.services.service_registry import ServiceRegistry
from py.services.model_scanner import ModelScanner
from py.services.settings_manager import get_settings_manager
# Reset DownloadManager singleton
DownloadManager._instance = None
# Reset ServiceRegistry
ServiceRegistry._services = {}
ServiceRegistry._initialized = False
# Reset ModelScanner instances
if hasattr(ModelScanner, '_instances'):
ModelScanner._instances.clear()
# Reset SettingsManager
settings_manager = get_settings_manager()
if hasattr(settings_manager, '_reset'):
settings_manager._reset()
yield
# Cleanup after test
DownloadManager._instance = None
ServiceRegistry._services = {}
ServiceRegistry._initialized = False
if hasattr(ModelScanner, '_instances'):
ModelScanner._instances.clear()