Skip to content

Commit 96a33a7

Browse files
committed
chore(tests): add more code coverage
1 parent 2cc43cf commit 96a33a7

File tree

8 files changed

+1004
-29
lines changed

8 files changed

+1004
-29
lines changed

Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ tests_only:
2525

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

2931
sleep:
3032
sleep 2

storage3/__init__.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,24 @@
33
from typing import Literal, Union, overload
44

55
from storage3._async import AsyncStorageClient
6+
from storage3._async.bucket import AsyncStorageBucketAPI
7+
from storage3._async.file_api import AsyncBucket
68
from storage3._sync import SyncStorageClient
9+
from storage3._sync.bucket import SyncStorageBucketAPI
10+
from storage3._sync.file_api import SyncBucket
711
from storage3.constants import DEFAULT_TIMEOUT
812
from storage3.version import __version__
913

10-
__all__ = ["create_client", "__version__"]
14+
__all__ = [
15+
"create_client",
16+
"__version__",
17+
"AsyncStorageClient",
18+
"AsyncBucket",
19+
"AsyncStorageBucketAPI",
20+
"SyncStorageClient",
21+
"SyncBucket",
22+
"SyncStorageBucketAPI",
23+
]
1124

1225

1326
@overload

tests/_async/test_bucket.py

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import pytest
2+
from httpx import HTTPStatusError, Response
3+
from unittest.mock import AsyncMock, Mock, patch
4+
5+
from storage3.exceptions import StorageApiError
6+
from storage3.types import CreateOrUpdateBucketOptions
7+
from storage3 import AsyncBucket, AsyncStorageBucketAPI
8+
9+
@pytest.fixture
10+
def mock_client():
11+
return AsyncMock()
12+
13+
@pytest.fixture
14+
def storage_api(mock_client):
15+
return AsyncStorageBucketAPI(mock_client)
16+
17+
@pytest.fixture
18+
def mock_response():
19+
response = Mock(spec=Response)
20+
response.raise_for_status = Mock()
21+
return response
22+
23+
async def test_list_buckets(storage_api, mock_client, mock_response):
24+
# Mock response data
25+
mock_response.json.return_value = [
26+
{"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/*"]},
27+
{"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/*"]}
28+
]
29+
mock_client.request.return_value = mock_response
30+
31+
buckets = await storage_api.list_buckets()
32+
33+
assert len(buckets) == 2
34+
assert all(isinstance(bucket, AsyncBucket) for bucket in buckets)
35+
assert buckets[0].id == "bucket1"
36+
assert buckets[1].id == "bucket2"
37+
38+
mock_client.request.assert_called_once_with("GET", "/bucket", json=None)
39+
40+
async def test_get_bucket(storage_api, mock_client, mock_response):
41+
bucket_id = "test-bucket"
42+
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/*"]}
43+
mock_client.request.return_value = mock_response
44+
45+
bucket = await storage_api.get_bucket(bucket_id)
46+
47+
assert isinstance(bucket, AsyncBucket)
48+
assert bucket.id == bucket_id
49+
assert bucket.name == "Test Bucket"
50+
assert bucket.public is True
51+
assert bucket.owner == "test-owner"
52+
53+
mock_client.request.assert_called_once_with("GET", f"/bucket/{bucket_id}", json=None)
54+
55+
async def test_create_bucket(storage_api, mock_client, mock_response):
56+
bucket_id = "new-bucket"
57+
bucket_name = "New Bucket"
58+
options = CreateOrUpdateBucketOptions(
59+
public=True,
60+
file_size_limit=1000000,
61+
allowed_mime_types=["image/*"]
62+
)
63+
64+
mock_response.json.return_value = {"message": "Bucket created successfully"}
65+
mock_client.request.return_value = mock_response
66+
67+
result = await storage_api.create_bucket(bucket_id, bucket_name, options)
68+
69+
assert result == {"message": "Bucket created successfully"}
70+
mock_client.request.assert_called_once_with(
71+
"POST",
72+
"/bucket",
73+
json={
74+
"id": bucket_id,
75+
"name": bucket_name,
76+
"public": True,
77+
"file_size_limit": 1000000,
78+
"allowed_mime_types": ["image/*"]
79+
}
80+
)
81+
82+
async def test_create_bucket_minimal(storage_api, mock_client, mock_response):
83+
bucket_id = "minimal-bucket"
84+
mock_response.json.return_value = {"message": "Bucket created successfully"}
85+
mock_client.request.return_value = mock_response
86+
87+
result = await storage_api.create_bucket(bucket_id)
88+
89+
assert result == {"message": "Bucket created successfully"}
90+
mock_client.request.assert_called_once_with(
91+
"POST",
92+
"/bucket",
93+
json={"id": bucket_id, "name": bucket_id}
94+
)
95+
96+
async def test_update_bucket(storage_api, mock_client, mock_response):
97+
bucket_id = "update-bucket"
98+
options = CreateOrUpdateBucketOptions(
99+
public=False,
100+
file_size_limit=2000000
101+
)
102+
103+
mock_response.json.return_value = {"message": "Bucket updated successfully"}
104+
mock_client.request.return_value = mock_response
105+
106+
result = await storage_api.update_bucket(bucket_id, options)
107+
108+
assert result == {"message": "Bucket updated successfully"}
109+
mock_client.request.assert_called_once_with(
110+
"PUT",
111+
f"/bucket/{bucket_id}",
112+
json={
113+
"id": bucket_id,
114+
"name": bucket_id,
115+
"public": False,
116+
"file_size_limit": 2000000
117+
}
118+
)
119+
120+
async def test_empty_bucket(storage_api, mock_client, mock_response):
121+
bucket_id = "empty-bucket"
122+
mock_response.json.return_value = {"message": "Bucket emptied successfully"}
123+
mock_client.request.return_value = mock_response
124+
125+
result = await storage_api.empty_bucket(bucket_id)
126+
127+
assert result == {"message": "Bucket emptied successfully"}
128+
mock_client.request.assert_called_once_with(
129+
"POST",
130+
f"/bucket/{bucket_id}/empty",
131+
json={}
132+
)
133+
134+
async def test_delete_bucket(storage_api, mock_client, mock_response):
135+
bucket_id = "delete-bucket"
136+
mock_response.json.return_value = {"message": "Bucket deleted successfully"}
137+
mock_client.request.return_value = mock_response
138+
139+
result = await storage_api.delete_bucket(bucket_id)
140+
141+
assert result == {"message": "Bucket deleted successfully"}
142+
mock_client.request.assert_called_once_with(
143+
"DELETE",
144+
f"/bucket/{bucket_id}",
145+
json={}
146+
)
147+
148+
async def test_request_error_handling(storage_api, mock_client):
149+
error_response = Mock(spec=Response)
150+
error_response.json.return_value = {
151+
"message": "Test error message",
152+
"error": "Test error",
153+
"statusCode": 400
154+
}
155+
156+
exc = HTTPStatusError(
157+
"HTTP Error",
158+
request=Mock(),
159+
response=error_response
160+
)
161+
mock_client.request.side_effect = exc
162+
163+
with pytest.raises(StorageApiError) as exc_info:
164+
await storage_api._request("GET", "/test")
165+
166+
assert exc_info.value.message == "Test error message"
167+
168+
@pytest.mark.parametrize("method,url,json_data", [
169+
("GET", "/test", None),
170+
("POST", "/test", {"key": "value"}),
171+
("PUT", "/test", {"id": "123"}),
172+
("DELETE", "/test", {})
173+
])
174+
async def test_request_methods(storage_api, mock_client, mock_response, method, url, json_data):
175+
mock_client.request.return_value = mock_response
176+
await storage_api._request(method, url, json_data)
177+
mock_client.request.assert_called_once_with(method, url, json=json_data)

0 commit comments

Comments
 (0)