Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(tests): add more test coverage #336

Merged
merged 3 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ tests_only:

build_sync:
poetry run unasync storage3 tests
sed -i '0,/SyncMock, /{s/SyncMock, //}' tests/_sync/test_bucket.py tests/_sync/test_client.py
sed -i 's/SyncMock/Mock/g' tests/_sync/test_bucket.py tests/_sync/test_client.py

sleep:
sleep 2
15 changes: 14 additions & 1 deletion storage3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@
from typing import Literal, Union, overload

from storage3._async import AsyncStorageClient
from storage3._async.bucket import AsyncStorageBucketAPI
from storage3._async.file_api import AsyncBucket
from storage3._sync import SyncStorageClient
from storage3._sync.bucket import SyncStorageBucketAPI
from storage3._sync.file_api import SyncBucket
from storage3.constants import DEFAULT_TIMEOUT
from storage3.version import __version__

__all__ = ["create_client", "__version__"]
__all__ = [
"create_client",
"__version__",
"AsyncStorageClient",
"AsyncBucket",
"AsyncStorageBucketAPI",
"SyncStorageClient",
"SyncBucket",
"SyncStorageBucketAPI",
]


@overload
Expand Down
209 changes: 209 additions & 0 deletions tests/_async/test_bucket.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
from unittest.mock import AsyncMock, Mock

import pytest
from httpx import HTTPStatusError, Response

from storage3 import AsyncBucket, AsyncStorageBucketAPI
from storage3.exceptions import StorageApiError
from storage3.types import CreateOrUpdateBucketOptions


@pytest.fixture
def mock_client():
return AsyncMock()


@pytest.fixture
def storage_api(mock_client):
return AsyncStorageBucketAPI(mock_client)


@pytest.fixture
def mock_response():
response = Mock(spec=Response)
response.raise_for_status = Mock()
return response


async def test_list_buckets(storage_api, mock_client, mock_response):
# Mock response data
mock_response.json.return_value = [
{
"id": "bucket1",
"name": "Bucket 1",
"public": True,
"owner": "test-owner",
"created_at": "2024-01-01",
"updated_at": "2024-01-01",
"file_size_limit": 1000000,
"allowed_mime_types": ["image/*"],
},
{
"id": "bucket2",
"name": "Bucket 2",
"public": True,
"owner": "test-owner",
"created_at": "2024-01-01",
"updated_at": "2024-01-01",
"file_size_limit": 1000000,
"allowed_mime_types": ["image/*"],
},
]
mock_client.request.return_value = mock_response

buckets = await storage_api.list_buckets()

assert len(buckets) == 2
assert all(isinstance(bucket, AsyncBucket) for bucket in buckets)
assert buckets[0].id == "bucket1"
assert buckets[1].id == "bucket2"

mock_client.request.assert_called_once_with("GET", "/bucket", json=None)


async def test_get_bucket(storage_api, mock_client, mock_response):
bucket_id = "test-bucket"
mock_response.json.return_value = {
"id": bucket_id,
"name": "Test Bucket",
"public": True,
"owner": "test-owner",
"created_at": "2024-01-01",
"updated_at": "2024-01-01",
"file_size_limit": 1000000,
"allowed_mime_types": ["image/*"],
}
mock_client.request.return_value = mock_response

bucket = await storage_api.get_bucket(bucket_id)

assert isinstance(bucket, AsyncBucket)
assert bucket.id == bucket_id
assert bucket.name == "Test Bucket"
assert bucket.public is True
assert bucket.owner == "test-owner"

mock_client.request.assert_called_once_with(
"GET", f"/bucket/{bucket_id}", json=None
)


async def test_create_bucket(storage_api, mock_client, mock_response):
bucket_id = "new-bucket"
bucket_name = "New Bucket"
options = CreateOrUpdateBucketOptions(
public=True, file_size_limit=1000000, allowed_mime_types=["image/*"]
)

mock_response.json.return_value = {"message": "Bucket created successfully"}
mock_client.request.return_value = mock_response

result = await storage_api.create_bucket(bucket_id, bucket_name, options)

assert result == {"message": "Bucket created successfully"}
mock_client.request.assert_called_once_with(
"POST",
"/bucket",
json={
"id": bucket_id,
"name": bucket_name,
"public": True,
"file_size_limit": 1000000,
"allowed_mime_types": ["image/*"],
},
)


async def test_create_bucket_minimal(storage_api, mock_client, mock_response):
bucket_id = "minimal-bucket"
mock_response.json.return_value = {"message": "Bucket created successfully"}
mock_client.request.return_value = mock_response

result = await storage_api.create_bucket(bucket_id)

assert result == {"message": "Bucket created successfully"}
mock_client.request.assert_called_once_with(
"POST", "/bucket", json={"id": bucket_id, "name": bucket_id}
)


async def test_update_bucket(storage_api, mock_client, mock_response):
bucket_id = "update-bucket"
options = CreateOrUpdateBucketOptions(public=False, file_size_limit=2000000)

mock_response.json.return_value = {"message": "Bucket updated successfully"}
mock_client.request.return_value = mock_response

result = await storage_api.update_bucket(bucket_id, options)

assert result == {"message": "Bucket updated successfully"}
mock_client.request.assert_called_once_with(
"PUT",
f"/bucket/{bucket_id}",
json={
"id": bucket_id,
"name": bucket_id,
"public": False,
"file_size_limit": 2000000,
},
)


async def test_empty_bucket(storage_api, mock_client, mock_response):
bucket_id = "empty-bucket"
mock_response.json.return_value = {"message": "Bucket emptied successfully"}
mock_client.request.return_value = mock_response

result = await storage_api.empty_bucket(bucket_id)

assert result == {"message": "Bucket emptied successfully"}
mock_client.request.assert_called_once_with(
"POST", f"/bucket/{bucket_id}/empty", json={}
)


async def test_delete_bucket(storage_api, mock_client, mock_response):
bucket_id = "delete-bucket"
mock_response.json.return_value = {"message": "Bucket deleted successfully"}
mock_client.request.return_value = mock_response

result = await storage_api.delete_bucket(bucket_id)

assert result == {"message": "Bucket deleted successfully"}
mock_client.request.assert_called_once_with(
"DELETE", f"/bucket/{bucket_id}", json={}
)


async def test_request_error_handling(storage_api, mock_client):
error_response = Mock(spec=Response)
error_response.json.return_value = {
"message": "Test error message",
"error": "Test error",
"statusCode": 400,
}

exc = HTTPStatusError("HTTP Error", request=Mock(), response=error_response)
mock_client.request.side_effect = exc

with pytest.raises(StorageApiError) as exc_info:
await storage_api._request("GET", "/test")

assert exc_info.value.message == "Test error message"


@pytest.mark.parametrize(
"method,url,json_data",
[
("GET", "/test", None),
("POST", "/test", {"key": "value"}),
("PUT", "/test", {"id": "123"}),
("DELETE", "/test", {}),
],
)
async def test_request_methods(
storage_api, mock_client, mock_response, method, url, json_data
):
mock_client.request.return_value = mock_response
await storage_api._request(method, url, json_data)
mock_client.request.assert_called_once_with(method, url, json=json_data)
Loading
Loading