Files
wehub-resource-sync b7f52be4c9
CI / Run CI (push) Has been cancelled
CI / check-backend (push) Has been cancelled
CI / check-frontend (push) Has been cancelled
CI / tests (push) Has been cancelled
CI / e2e-tests (push) Has been cancelled
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:48:47 +08:00

338 lines
12 KiB
Python

from unittest.mock import MagicMock, patch
import pytest
from chainlit.data.storage_clients.base import storage_expiry_time
from chainlit.data.storage_clients.gcs import GCSStorageClient
@pytest.fixture
def mock_gcs_client():
"""Create a mock Google Cloud Storage client."""
# First mock the service_account
with patch(
"chainlit.data.storage_clients.gcs.service_account"
) as mock_service_account:
mock_credentials = MagicMock()
mock_service_account.Credentials.from_service_account_info.return_value = (
mock_credentials
)
# Then mock the storage client
with patch("chainlit.data.storage_clients.gcs.storage") as mock_storage:
mock_client = MagicMock()
mock_storage.Client.return_value = mock_client
mock_bucket = MagicMock()
mock_client.bucket.return_value = mock_bucket
mock_blob = MagicMock()
mock_bucket.blob.return_value = mock_blob
yield {
"storage": mock_storage,
"client": mock_client,
"bucket": mock_bucket,
"blob": mock_blob,
"service_account": mock_service_account,
"credentials": mock_credentials,
}
class TestGCSStorageClient:
def test_init(self, mock_gcs_client):
"""Test initialization of GCS client."""
# Remove client assignment, directly call the constructor
GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Verify service account credentials were created correctly
mock_gcs_client[
"service_account"
].Credentials.from_service_account_info.assert_called_once_with(
{
"type": "service_account",
"project_id": "test-project",
"private_key": "test-key",
"client_email": "test@example.com",
"token_uri": "https://oauth2.googleapis.com/token",
}
)
# Verify storage client was initialized with credentials
mock_gcs_client["storage"].Client.assert_called_once_with(
project="test-project", credentials=mock_gcs_client["credentials"]
)
# Verify bucket was retrieved
mock_gcs_client["client"].bucket.assert_called_once_with("test-bucket")
def test_sync_get_read_url(self, mock_gcs_client):
"""Test generating a signed URL."""
# Set up the mock to return a URL
mock_gcs_client[
"blob"
].generate_signed_url.return_value = "https://signed-url.example.com"
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset mocks to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Test the method
url = client.sync_get_read_url("test/path/file.txt")
# Verify correct methods were called
mock_gcs_client["bucket"].blob.assert_called_once_with("test/path/file.txt")
mock_gcs_client["blob"].generate_signed_url.assert_called_once_with(
version="v4", expiration=storage_expiry_time, method="GET"
)
assert url == "https://signed-url.example.com"
@pytest.mark.asyncio
async def test_get_read_url(self, mock_gcs_client):
"""Test the async wrapper for getting a read URL."""
# Set up the mock to return a URL
mock_gcs_client[
"blob"
].generate_signed_url.return_value = "https://signed-url.example.com"
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset mocks to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Test the async method
url = await client.get_read_url("test/path/file.txt")
# Verify correct methods were called
mock_gcs_client["bucket"].blob.assert_called_once_with("test/path/file.txt")
mock_gcs_client["blob"].generate_signed_url.assert_called_once_with(
version="v4", expiration=storage_expiry_time, method="GET"
)
assert url == "https://signed-url.example.com"
def test_sync_upload_file(self, mock_gcs_client):
"""Test uploading a file to GCS."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Mock the bucket name property
mock_gcs_client["bucket"].name = "test-bucket"
# Test with binary data
binary_data = b"test content"
object_key = "test/path/file.txt"
# Remove the unused result assignment
client.sync_upload_file(
object_key=object_key, data=binary_data, mime="text/plain", overwrite=True
)
# Check that the blob was called with the correct object key (using assert_any_call instead of assert_called_once_with)
mock_gcs_client["bucket"].blob.assert_any_call(object_key)
mock_gcs_client["blob"].upload_from_string.assert_called_once_with(
binary_data, content_type="text/plain"
)
def test_sync_upload_file_string_data(self, mock_gcs_client):
"""Test uploading string data to GCS."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
mock_gcs_client["bucket"].name = "test-bucket"
# Test with string data that should be encoded
string_data = "test content"
object_key = "test/path/file.txt"
# Remove the unused result assignment
client.sync_upload_file(
object_key=object_key, data=string_data, mime="text/plain", overwrite=True
)
# Check that the correct methods were called
mock_gcs_client["bucket"].blob.assert_any_call(object_key)
mock_gcs_client["blob"].upload_from_string.assert_called_once_with(
b"test content", content_type="text/plain"
)
def test_sync_upload_file_no_overwrite(self, mock_gcs_client):
"""Test upload with overwrite=False and existing file."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Configure blob to indicate file exists
mock_gcs_client["blob"].exists.return_value = True
with pytest.raises(
Exception,
match=r"Failed to upload file to GCS: File test/path/existing\.txt already exists and overwrite is False",
):
client.sync_upload_file(
object_key="test/path/existing.txt",
data=b"test content",
overwrite=False,
)
mock_gcs_client["blob"].exists.assert_called_once()
mock_gcs_client["blob"].upload_from_string.assert_not_called()
def test_sync_upload_file_error(self, mock_gcs_client):
"""Test error handling during upload."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Configure upload to throw an exception
mock_gcs_client["blob"].upload_from_string.side_effect = ValueError(
"Upload failed"
)
with pytest.raises(
Exception, match="Failed to upload file to GCS: Upload failed"
):
client.sync_upload_file(
object_key="test/path/file.txt", data=b"test content"
)
@pytest.mark.asyncio
async def test_upload_file(self, mock_gcs_client):
"""Test the async wrapper for uploading a file."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
mock_gcs_client["bucket"].name = "test-bucket"
# Test with binary data
binary_data = b"test content"
object_key = "test/path/file.txt"
# Remove the unused result assignment
await client.upload_file(
object_key=object_key, data=binary_data, mime="text/plain", overwrite=True
)
# Check that the correct methods were called
mock_gcs_client["bucket"].blob.assert_any_call(object_key)
mock_gcs_client["blob"].upload_from_string.assert_called_once_with(
binary_data, content_type="text/plain"
)
def test_sync_delete_file(self, mock_gcs_client):
"""Test deleting a file from GCS."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Test successful delete
result = client.sync_delete_file("test/path/file.txt")
mock_gcs_client["bucket"].blob.assert_called_once_with("test/path/file.txt")
mock_gcs_client["blob"].delete.assert_called_once()
assert result is True
def test_sync_delete_file_error(self, mock_gcs_client):
"""Test error handling during file deletion."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Configure delete to throw an exception
mock_gcs_client["blob"].delete.side_effect = ValueError("Delete failed")
# The method should catch the exception and return False
result = client.sync_delete_file("test/path/file.txt")
mock_gcs_client["bucket"].blob.assert_called_once_with("test/path/file.txt")
mock_gcs_client["blob"].delete.assert_called_once()
assert result is False
@pytest.mark.asyncio
async def test_delete_file(self, mock_gcs_client):
"""Test the async wrapper for deleting a file."""
client = GCSStorageClient(
bucket_name="test-bucket",
project_id="test-project",
client_email="test@example.com",
private_key="test-key",
)
# Reset the mock to ensure clean state
mock_gcs_client["bucket"].reset_mock()
mock_gcs_client["blob"].reset_mock()
# Test successful delete
result = await client.delete_file("test/path/file.txt")
mock_gcs_client["bucket"].blob.assert_called_once_with("test/path/file.txt")
mock_gcs_client["blob"].delete.assert_called_once()
assert result is True