test: format test suite

This commit is contained in:
huanghuoguoguo
2026-06-16 11:13:05 +08:00
parent 1ae5aacc00
commit ff0c5a6f0a
92 changed files with 1658 additions and 1713 deletions
@@ -21,8 +21,8 @@ from langbot.pkg.storage.providers.localstorage import LocalStorageProvider
@pytest.fixture
def storage_provider(tmp_path):
"""Create a LocalStorageProvider with a temporary storage path."""
storage_path = str(tmp_path / "storage")
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
storage_path = str(tmp_path / 'storage')
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
mock_app = Mock()
provider = LocalStorageProvider(mock_app)
yield provider, storage_path
@@ -35,15 +35,15 @@ class TestPathTraversalPrevention:
async def test_absolute_path_save_rejected(self, storage_provider, tmp_path):
"""Saving with an absolute path key must be blocked."""
provider, storage_path = storage_provider
target_file = str(tmp_path / "pwned.txt")
target_file = str(tmp_path / 'pwned.txt')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
with pytest.raises((ValueError, PermissionError)):
await provider.save(target_file, b"malicious content")
await provider.save(target_file, b'malicious content')
# The file must NOT exist outside the storage directory
assert not os.path.exists(target_file), (
f"Path traversal succeeded: file was written outside storage to {target_file}"
f'Path traversal succeeded: file was written outside storage to {target_file}'
)
@pytest.mark.asyncio
@@ -52,32 +52,28 @@ class TestPathTraversalPrevention:
provider, storage_path = storage_provider
# Create a file outside the storage directory
target_file = str(tmp_path / "secret.txt")
with open(target_file, "wb") as f:
f.write(b"secret data")
target_file = str(tmp_path / 'secret.txt')
with open(target_file, 'wb') as f:
f.write(b'secret data')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
with pytest.raises((ValueError, PermissionError, FileNotFoundError)):
data = await provider.load(target_file)
assert data != b"secret data", (
"Path traversal succeeded: read file outside storage"
)
assert data != b'secret data', 'Path traversal succeeded: read file outside storage'
@pytest.mark.asyncio
async def test_absolute_path_exists_rejected(self, storage_provider, tmp_path):
"""Exists check with an absolute path key must be blocked or return False."""
provider, storage_path = storage_provider
target_file = str(tmp_path / "check_me.txt")
with open(target_file, "wb") as f:
f.write(b"data")
target_file = str(tmp_path / 'check_me.txt')
with open(target_file, 'wb') as f:
f.write(b'data')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
try:
result = await provider.exists(target_file)
assert result is False, (
"Path traversal succeeded: exists() returned True for file outside storage"
)
assert result is False, 'Path traversal succeeded: exists() returned True for file outside storage'
except (ValueError, PermissionError):
pass # Expected
@@ -86,28 +82,26 @@ class TestPathTraversalPrevention:
"""Deleting with an absolute path key must be blocked."""
provider, storage_path = storage_provider
target_file = str(tmp_path / "do_not_delete.txt")
with open(target_file, "wb") as f:
f.write(b"important data")
target_file = str(tmp_path / 'do_not_delete.txt')
with open(target_file, 'wb') as f:
f.write(b'important data')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
with pytest.raises((ValueError, PermissionError, FileNotFoundError)):
await provider.delete(target_file)
assert os.path.exists(target_file), (
"Path traversal succeeded: file outside storage was deleted"
)
assert os.path.exists(target_file), 'Path traversal succeeded: file outside storage was deleted'
@pytest.mark.asyncio
async def test_absolute_path_size_rejected(self, storage_provider, tmp_path):
"""Size check with an absolute path key must be blocked."""
provider, storage_path = storage_provider
target_file = str(tmp_path / "measure_me.txt")
with open(target_file, "wb") as f:
f.write(b"some data")
target_file = str(tmp_path / 'measure_me.txt')
with open(target_file, 'wb') as f:
f.write(b'some data')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
with pytest.raises((ValueError, PermissionError, FileNotFoundError)):
await provider.size(target_file)
@@ -116,41 +110,39 @@ class TestPathTraversalPrevention:
"""Relative path traversal with '..' must be blocked."""
provider, storage_path = storage_provider
target_file = str(tmp_path / "above_storage.txt")
with open(target_file, "wb") as f:
f.write(b"above storage secret")
target_file = str(tmp_path / 'above_storage.txt')
with open(target_file, 'wb') as f:
f.write(b'above storage secret')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
relative_key = os.path.join("..", "above_storage.txt")
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
relative_key = os.path.join('..', 'above_storage.txt')
with pytest.raises((ValueError, PermissionError, FileNotFoundError)):
data = await provider.load(relative_key)
assert data != b"above storage secret"
assert data != b'above storage secret'
@pytest.mark.asyncio
async def test_delete_dir_recursive_traversal_rejected(self, storage_provider, tmp_path):
"""delete_dir_recursive with traversal path must be blocked."""
provider, storage_path = storage_provider
outside_dir = tmp_path / "outside_dir"
outside_dir = tmp_path / 'outside_dir'
outside_dir.mkdir()
(outside_dir / "file.txt").write_text("important")
(outside_dir / 'file.txt').write_text('important')
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
with pytest.raises((ValueError, PermissionError)):
await provider.delete_dir_recursive(str(outside_dir))
assert outside_dir.exists(), (
"Path traversal succeeded: directory outside storage was deleted"
)
assert outside_dir.exists(), 'Path traversal succeeded: directory outside storage was deleted'
@pytest.mark.asyncio
async def test_legitimate_key_works(self, storage_provider):
"""Normal keys without traversal must still work."""
provider, storage_path = storage_provider
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
key = "test_image_abc123.png"
content = b"PNG image data"
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
key = 'test_image_abc123.png'
content = b'PNG image data'
await provider.save(key, content)
assert await provider.exists(key) is True
@@ -166,9 +158,9 @@ class TestPathTraversalPrevention:
"""Keys with legitimate subdirectories must still work."""
provider, storage_path = storage_provider
with patch("langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH", storage_path):
key = "bot_log_images/img_001.png"
content = b"PNG image data"
with patch('langbot.pkg.storage.providers.localstorage.LOCAL_STORAGE_PATH', storage_path):
key = 'bot_log_images/img_001.png'
content = b'PNG image data'
await provider.save(key, content)
assert await provider.exists(key) is True
@@ -181,33 +173,33 @@ class TestPathTraversalPrevention:
"""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):
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")
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):
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")
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")
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"])
if __name__ == '__main__':
pytest.main([__file__, '-v'])
+4 -1
View File
@@ -8,6 +8,7 @@ Tests cover:
Uses moto library to mock AWS S3 service.
"""
from __future__ import annotations
import pytest
@@ -44,8 +45,10 @@ def mock_app_with_s3_config():
def s3_mock():
"""Set up moto S3 mock context."""
from moto import mock_aws
with mock_aws():
import boto3
# Create bucket for tests that need pre-existing bucket
s3 = boto3.client('s3', region_name='us-east-1')
yield s3
@@ -325,4 +328,4 @@ class TestS3StorageProviderErrorHandling:
await provider.initialize()
with pytest.raises(Exception):
await provider.size('nonexistent.txt')
await provider.size('nonexistent.txt')
@@ -31,7 +31,7 @@ class TestStorageMgr:
storage_mgr = StorageMgr(mock_app)
with patch.object(LocalStorageProvider, "initialize", new_callable=AsyncMock):
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()
@@ -41,12 +41,12 @@ class TestStorageMgr:
"""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.instance_config.data = {'storage': {'use': 'local'}}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(LocalStorageProvider, "initialize", new_callable=AsyncMock):
with patch.object(LocalStorageProvider, 'initialize', new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, LocalStorageProvider)
@@ -55,14 +55,12 @@ class TestStorageMgr:
"""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.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):
with patch.object(S3StorageProvider, 'initialize', new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, S3StorageProvider)
@@ -71,12 +69,12 @@ class TestStorageMgr:
"""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.instance_config.data = {'storage': {'use': 'invalid_type'}}
mock_app.logger = Mock()
storage_mgr = StorageMgr(mock_app)
with patch.object(LocalStorageProvider, "initialize", new_callable=AsyncMock):
with patch.object(LocalStorageProvider, 'initialize', new_callable=AsyncMock):
await storage_mgr.initialize()
assert isinstance(storage_mgr.storage_provider, LocalStorageProvider)
@@ -90,9 +88,7 @@ class TestStorageMgr:
storage_mgr = StorageMgr(mock_app)
with patch.object(
LocalStorageProvider, "initialize", new_callable=AsyncMock
) as mock_init:
with patch.object(LocalStorageProvider, 'initialize', new_callable=AsyncMock) as mock_init:
await storage_mgr.initialize()
mock_init.assert_called_once()
@@ -105,8 +101,8 @@ class TestStorageProviderBase:
mock_app = Mock()
# Use LocalStorageProvider as concrete implementation
with patch("os.path.exists", return_value=True):
with patch("os.makedirs"):
with patch('os.path.exists', return_value=True):
with patch('os.makedirs'):
provider = LocalStorageProvider(mock_app)
assert provider.ap == mock_app
@@ -115,12 +111,12 @@ class TestStorageProviderBase:
"""Provider base initialize should be callable and do nothing."""
mock_app = Mock()
with patch("os.path.exists", return_value=True):
with patch("os.makedirs"):
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"])
if __name__ == '__main__':
pytest.main([__file__, '-v'])