feat(test): Phase 1.5 coverage expansion - COV-001 to COV-013

Coverage baseline raised from 13.65% to 26% (+12.35%)
Gate raised from 12% to 18%

Tasks completed:
- COV-001: Command system unit tests (100% coverage)
- COV-002: API service unit tests batch 1 (user/apikey/model/provider)
- COV-003: Provider model manager unit tests
- COV-004: Pipeline remaining stage tests (aggregator/cntfilter/longtext/msgtrun)
- COV-005: Storage and utils coverage pass
- COV-006: Gate ratchet 12%→15%
- COV-007: Gate ratchet 15%→18%
- COV-008: API service batch 2 (bot/pipeline/webhook/space/maintenance/mcp)
- COV-009: Blocked - API controller circular import issue documented
- COV-010: Plugin runtime unit tests (+0.08%)
- COV-011: RAG and vector unit tests (+0.68%)
- COV-012: Core boot and migration unit tests
- COV-013: Provider requester logic unit tests (+0.62%)

Key additions:
- tests/utils/import_isolation.py: sys.modules isolation for circular imports
- Provider requester mock tests: proved HTTP-dependent code can be tested locally
- Vector filter utilities: 100% coverage on pure functions
- API services: fake persistence pattern for unit testing

Blocked issue COV-009 documented in langbot-test-plan/1.5/issues/

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
huanghuoguoguo
2026-05-09 18:40:40 +08:00
parent 9e1ff7f85c
commit 70ec75f9a2
52 changed files with 15990 additions and 6 deletions
@@ -176,6 +176,38 @@ class TestPathTraversalPrevention:
assert loaded == content
await provider.delete(key)
@pytest.mark.asyncio
async def test_delete_dir_recursive_non_existing_dir(self, storage_provider):
"""delete_dir_recursive should handle non-existing directories gracefully."""
provider, storage_path = storage_provider
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
# Try to delete a non-existing directory - should not raise
await provider.delete_dir_recursive("nonexistent_dir")
@pytest.mark.asyncio
async def test_delete_dir_recursive_with_files(self, storage_provider):
"""delete_dir_recursive should delete directory with files inside."""
provider, storage_path = storage_provider
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
# Create a directory with files
key1 = "test_dir/file1.txt"
key2 = "test_dir/file2.txt"
await provider.save(key1, b"content1")
await provider.save(key2, b"content2")
# Verify files exist
assert await provider.exists(key1)
assert await provider.exists(key2)
# Delete directory recursively
await provider.delete_dir_recursive("test_dir")
# Verify files no longer exist
assert not await provider.exists(key1)
assert not await provider.exists(key2)
if __name__ == "__main__":
pytest.main([__file__, "-v"])
@@ -0,0 +1,126 @@
"""
Tests for langbot.pkg.storage.mgr module.
Tests storage manager initialization and provider selection.
"""
import pytest
from unittest.mock import Mock, AsyncMock, patch
from langbot.pkg.storage.mgr import StorageMgr
from langbot.pkg.storage.providers.localstorage import LocalStorageProvider
from langbot.pkg.storage.providers.s3storage import S3StorageProvider
class TestStorageMgr:
"""Test StorageMgr class."""
def test_init_stores_app_reference(self):
"""StorageMgr should store the application reference."""
mock_app = Mock()
storage_mgr = StorageMgr(mock_app)
assert storage_mgr.ap == mock_app
@pytest.mark.asyncio
async def test_initialize_default_local(self):
"""Should use local storage by default."""
mock_app = Mock()
mock_app.instance_config = Mock()
mock_app.instance_config.data = {}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(LocalStorageProvider, "initialize", new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, LocalStorageProvider)
mock_app.logger.info.assert_called()
@pytest.mark.asyncio
async def test_initialize_with_explicit_local(self):
"""Should use local storage when explicitly configured."""
mock_app = Mock()
mock_app.instance_config = Mock()
mock_app.instance_config.data = {"storage": {"use": "local"}}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(LocalStorageProvider, "initialize", new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, LocalStorageProvider)
@pytest.mark.asyncio
async def test_initialize_with_s3(self):
"""Should use S3 storage when configured."""
mock_app = Mock()
mock_app.instance_config = Mock()
mock_app.instance_config.data = {
"storage": {"use": "s3", "s3": {"endpoint_url": "https://s3.amazonaws.com"}}
}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(S3StorageProvider, "initialize", new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, S3StorageProvider)
@pytest.mark.asyncio
async def test_initialize_invalid_type_defaults_to_local(self):
"""Should default to local storage for invalid storage type."""
mock_app = Mock()
mock_app.instance_config = Mock()
mock_app.instance_config.data = {"storage": {"use": "invalid_type"}}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(LocalStorageProvider, "initialize", new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, LocalStorageProvider)
@pytest.mark.asyncio
async def test_initialize_calls_provider_initialize(self):
"""Should call the provider's initialize method."""
mock_app = Mock()
mock_app.instance_config = Mock()
mock_app.instance_config.data = {}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(
LocalStorageProvider, "initialize", new_callable=AsyncMock
) as mock_init:
await storage_mgr.initialize()
mock_init.assert_called_once()
class TestStorageProviderBase:
"""Test StorageProvider base class methods."""
def test_provider_stores_app_reference(self):
"""Provider should store app reference."""
mock_app = Mock()
# Use LocalStorageProvider as concrete implementation
with patch("os.path.exists", return_value=True):
with patch("os.makedirs"):
provider = LocalStorageProvider(mock_app)
assert provider.ap == mock_app
@pytest.mark.asyncio
async def test_provider_base_initialize(self):
"""Provider base initialize should be callable and do nothing."""
mock_app = Mock()
with patch("os.path.exists", return_value=True):
with patch("os.makedirs"):
provider = LocalStorageProvider(mock_app)
# Initialize should not raise
await provider.initialize()
if __name__ == "__main__":
pytest.main([__file__, "-v"])