feat: add fixed-key metadata support in AAOW (#16817) · googleapis/google-cloud-python@28487f5 · GitHub
Skip to content

Commit 28487f5

Browse files
feat: add fixed-key metadata support in AAOW (#16817)
Add fixed-key metadata support in AAOW by updating `blob_to_proto` conversion logic. - Updated `_grpc_conversions.py` with simple and complex field mappings. - Added unit tests in `tests/unit/test__grpc_conversions.py`. - Updated system tests in `tests/system/test_zonal.py`. - Fixed regression in `tests/unit/asyncio/test_async_write_object_stream.py`. --- *PR created automatically by Jules for task [11384837182247010380](https://jules.google.com/task/11384837182247010380) started by @nidhiii-27* --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: nidhiii-27 <224584462+nidhiii-27@users.noreply.github.com>
1 parent 0500c76 commit 28487f5

4 files changed

Lines changed: 247 additions & 1 deletion

File tree

packages/google-cloud-storage/google/cloud/storage/_grpc_conversions.py

Lines changed: 49 additions & 0 deletions

packages/google-cloud-storage/tests/system/test_zonal.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# py standard imports
22
import asyncio
3+
import datetime
34
import gc
45
import os
56
import random
@@ -347,13 +348,23 @@ def test_write_from_blob(
347348
object_name = f"test_from_blob-{str(uuid.uuid4())[:4]}"
348349
content_type = "text/plain"
349350
metadata = {"environment": "system-test"}
351+
cache_control = "public, max-age=3600"
352+
content_disposition = "attachment; filename=test.txt"
353+
content_encoding = "identity"
354+
content_language = "en"
355+
custom_time = datetime.datetime(2025, 1, 1, 12, 0, 0, tzinfo=datetime.timezone.utc)
350356
test_data = b"system-test-data"
351357

352358
async def _run():
353359
# 1. Create a Blob instance
354360
blob = storage_client.bucket(_ZONAL_BUCKET).blob(object_name)
355361
blob.content_type = content_type
356362
blob.metadata = metadata
363+
blob.cache_control = cache_control
364+
blob.content_disposition = content_disposition
365+
blob.content_encoding = content_encoding
366+
blob.content_language = content_language
367+
blob.custom_time = custom_time
357368

358369
# 2. Use from_blob to create the writer
359370
writer = AsyncAppendableObjectWriter.from_blob(grpc_client, blob)
@@ -369,6 +380,11 @@ async def _run():
369380

370381
assert obj.content_type == content_type
371382
assert obj.metadata["environment"] == "system-test"
383+
assert obj.cache_control == cache_control
384+
assert obj.content_disposition == content_disposition
385+
assert obj.content_encoding == content_encoding
386+
assert obj.content_language == content_language
387+
assert int(obj.custom_time.timestamp()) == int(custom_time.timestamp())
372388

373389
blobs_to_delete.append(blob)
374390

packages/google-cloud-storage/tests/unit/asyncio/test_async_write_object_stream.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import datetime
1516
import unittest.mock as mock
1617
from unittest.mock import AsyncMock, MagicMock
1718

@@ -169,7 +170,33 @@ async def test_open_new_object_with_blob_sync_attrs(
169170
mock_blob.bucket = mock_bucket
170171
mock_blob.content_type = "text/plain"
171172
mock_blob.metadata = {"test-key": "test-value"}
172-
mock_blob.kms_key_name = None
173+
mock_blob.kms_key_name = "kms-key-name"
174+
mock_blob.cache_control = "cache-control"
175+
mock_blob.content_disposition = "content-disposition"
176+
mock_blob.content_encoding = "content-encoding"
177+
mock_blob.content_language = "content-language"
178+
mock_blob.temporary_hold = True
179+
mock_blob.event_based_hold = True
180+
181+
custom_time = datetime.datetime(
182+
2025, 1, 1, 12, 0, 0, tzinfo=datetime.timezone.utc
183+
)
184+
mock_blob.custom_time = custom_time
185+
186+
acl_mock = MagicMock()
187+
acl_mock.loaded = True
188+
acl_mock.__iter__.return_value = iter(
189+
[{"role": "READER", "entity": "allUsers"}]
190+
)
191+
mock_blob.acl = acl_mock
192+
193+
retain_until_time = datetime.datetime(
194+
2026, 1, 1, 12, 0, 0, tzinfo=datetime.timezone.utc
195+
)
196+
mock_blob.retention = {
197+
"mode": "Locked",
198+
"retain_until_time": retain_until_time,
199+
}
173200

174201
stream = _AsyncWriteObjectStream(mock_client, BUCKET, OBJECT, blob=mock_blob)
175202
await stream.open()
@@ -180,6 +207,24 @@ async def test_open_new_object_with_blob_sync_attrs(
180207

181208
assert resource.content_type == "text/plain"
182209
assert resource.metadata == {"test-key": "test-value"}
210+
assert resource.kms_key == "kms-key-name"
211+
assert resource.cache_control == "cache-control"
212+
assert resource.content_disposition == "content-disposition"
213+
assert resource.content_encoding == "content-encoding"
214+
assert resource.content_language == "content-language"
215+
assert resource.temporary_hold is True
216+
assert resource.event_based_hold is True
217+
218+
assert int(resource.custom_time.timestamp()) == int(custom_time.timestamp())
219+
220+
assert len(resource.acl) == 1
221+
assert resource.acl[0].role == "READER"
222+
assert resource.acl[0].entity == "allUsers"
223+
224+
assert resource.retention.mode == _storage_v2.Object.Retention.Mode.LOCKED
225+
assert int(resource.retention.retain_until_time.timestamp()) == int(
226+
retain_until_time.timestamp()
227+
)
183228

184229
@pytest.mark.asyncio
185230
async def test_open_already_open_raises(self, mock_client):
Lines changed: 136 additions & 0 deletions

0 commit comments

Comments
 (0)