Skip to content

Commit 4644b9a

Browse files
authored
tests: add retry conformance test cases (#580)
* add s4 never idempotent methods to json schema * add project based method test cases * add hmacKey.update method test case * add ACL methods test cases * add instruction cases and update test names * fix typo
1 parent 695694c commit 4644b9a

File tree

2 files changed

+246
-15
lines changed

2 files changed

+246
-15
lines changed

packages/google-cloud-storage/tests/conformance/retry_strategy_test_data.json

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
"cases": [
77
{
88
"instructions": ["return-503", "return-503"]
9+
},
10+
{
11+
"instructions": ["return-reset-connection", "return-reset-connection"]
12+
},
13+
{
14+
"instructions": ["return-reset-connection", "return-503"]
915
}
1016
],
1117
"methods": [
@@ -41,6 +47,12 @@
4147
"cases": [
4248
{
4349
"instructions": ["return-503", "return-503"]
50+
},
51+
{
52+
"instructions": ["return-reset-connection", "return-reset-connection"]
53+
},
54+
{
55+
"instructions": ["return-reset-connection", "return-503"]
4456
}
4557
],
4658
"methods": [
@@ -65,6 +77,9 @@
6577
"cases": [
6678
{
6779
"instructions": ["return-503"]
80+
},
81+
{
82+
"instructions": ["return-reset-connection"]
6883
}
6984
],
7085
"methods": [
@@ -85,13 +100,31 @@
85100
},
86101
{
87102
"id": 4,
88-
"description": "non idempotent",
103+
"description": "non_idempotent",
89104
"cases": [
90105
{
91-
"instructions": []
106+
"instructions": ["return-503"]
107+
},
108+
{
109+
"instructions": ["return-reset-connection"]
92110
}
93111
],
94-
"methods": [],
112+
"methods": [
113+
{"name": "storage.bucket_acl.delete", "resources": ["BUCKET"]},
114+
{"name": "storage.bucket_acl.insert", "resources": ["BUCKET"]},
115+
{"name": "storage.bucket_acl.patch", "resources": ["BUCKET"]},
116+
{"name": "storage.bucket_acl.update", "resources": ["BUCKET"]},
117+
{"name": "storage.default_object_acl.delete", "resources": ["BUCKET"]},
118+
{"name": "storage.default_object_acl.insert", "resources": ["BUCKET"]},
119+
{"name": "storage.default_object_acl.patch", "resources": ["BUCKET"]},
120+
{"name": "storage.default_object_acl.update", "resources": ["BUCKET"]},
121+
{"name": "storage.hmacKey.create", "resources": []},
122+
{"name": "storage.notifications.insert", "resources": ["BUCKET"]},
123+
{"name": "storage.object_acl.delete", "resources": ["BUCKET", "OBJECT"]},
124+
{"name": "storage.object_acl.insert", "resources": ["BUCKET", "OBJECT"]},
125+
{"name": "storage.object_acl.patch", "resources": ["BUCKET", "OBJECT"]},
126+
{"name": "storage.object_acl.update", "resources": ["BUCKET", "OBJECT"]}
127+
],
95128
"preconditionProvided": false,
96129
"expectSuccess": false
97130
}

packages/google-cloud-storage/tests/conformance/test_conformance.py

Lines changed: 210 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
from google.cloud import storage
2626
from google.auth.credentials import AnonymousCredentials
27+
from google.cloud.storage.hmac_key import HMACKeyMetadata
2728

2829
from . import _read_local_json
2930

@@ -42,6 +43,9 @@
4243

4344
_STRING_CONTENT = "hello world"
4445
_BYTE_CONTENT = b"12345678"
46+
_BUCKET_ACL_PATCH_MSG = "BucketACL patch operations call storage.buckets.patch, but are never idempotent; Preconditions are irrelevant."
47+
_DEFAULT_OBJECT_ACL_PATCH_MSG = "DefaultObjectACL patch operations call storage.buckets.patch, but are never idempotent; Preconditions are irrelevant."
48+
_OBJECT_ACL_PATCH_MSG = "ObjectACL patch operations call storage.objects.patch, but are never idempotent; Preconditions are irrelevant."
4549

4650

4751
########################################################################################################################################
@@ -171,6 +175,10 @@ def bucket_lock_retention_policy(client, _preconditions, **resources):
171175
bucket.lock_retention_policy()
172176

173177

178+
def client_get_service_account_email(client, _preconditions, **_):
179+
client.get_service_account_email()
180+
181+
174182
def notification_create(client, _preconditions, **resources):
175183
bucket = client.get_bucket(resources.get("bucket").name)
176184
notification = bucket.notification()
@@ -217,8 +225,44 @@ def client_list_hmac_keys(client, _preconditions, **_):
217225
pass
218226

219227

220-
def client_get_service_account_email(client, _preconditions, **_):
221-
client.get_service_account_email()
228+
def client_get_hmac_key_metadata(client, _preconditions, **resources):
229+
access_id = resources.get("hmac_key").access_id
230+
client.get_hmac_key_metadata(access_id=access_id)
231+
232+
233+
def hmac_key_exists(client, _preconditions, **resources):
234+
access_id = resources.get("hmac_key").access_id
235+
hmac_key = HMACKeyMetadata(client, access_id=access_id)
236+
hmac_key.exists()
237+
238+
239+
def hmac_key_reload(client, _preconditions, **resources):
240+
access_id = resources.get("hmac_key").access_id
241+
hmac_key = HMACKeyMetadata(client, access_id=access_id)
242+
hmac_key.reload()
243+
244+
245+
def hmac_key_delete(client, _preconditions, **resources):
246+
access_id = resources.get("hmac_key").access_id
247+
hmac_key = HMACKeyMetadata(client, access_id=access_id)
248+
hmac_key.state = "INACTIVE"
249+
hmac_key.update()
250+
hmac_key.delete()
251+
252+
253+
def client_create_hmac_key(client, _preconditions, **_):
254+
client.create_hmac_key(service_account_email=_CONF_TEST_SERVICE_ACCOUNT_EMAIL)
255+
256+
257+
def hmac_key_update(client, _preconditions, **resources):
258+
access_id = resources.get("hmac_key").access_id
259+
etag = resources.get("hmac_key").etag
260+
hmac_key = HMACKeyMetadata(client, access_id=access_id)
261+
if _preconditions:
262+
pytest.skip("Etag is not yet supported")
263+
hmac_key.etag = etag
264+
hmac_key.state = "INACTIVE"
265+
hmac_key.update()
222266

223267

224268
def bucket_patch(client, _preconditions, **resources):
@@ -423,6 +467,131 @@ def blob_create_resumable_upload_session(client, _preconditions, **resources):
423467
blob.create_resumable_upload_session()
424468

425469

470+
def blob_make_private(client, _preconditions, **resources):
471+
if _preconditions:
472+
pytest.skip(_OBJECT_ACL_PATCH_MSG)
473+
bucket = resources.get("bucket")
474+
object = resources.get("object")
475+
blob = client.bucket(bucket.name).blob(object.name)
476+
blob.make_private()
477+
478+
479+
def blob_make_public(client, _preconditions, **resources):
480+
if _preconditions:
481+
pytest.skip(_OBJECT_ACL_PATCH_MSG)
482+
bucket = resources.get("bucket")
483+
object = resources.get("object")
484+
blob = client.bucket(bucket.name).blob(object.name)
485+
blob.make_public()
486+
487+
488+
def bucket_make_private(client, _preconditions, **resources):
489+
if _preconditions:
490+
pytest.skip(_BUCKET_ACL_PATCH_MSG)
491+
bucket = client.bucket(resources.get("bucket").name)
492+
bucket.make_private()
493+
494+
495+
def bucket_make_public(client, _preconditions, **resources):
496+
if _preconditions:
497+
pytest.skip(_BUCKET_ACL_PATCH_MSG)
498+
bucket = client.bucket(resources.get("bucket").name)
499+
bucket.make_public()
500+
501+
502+
def bucket_acl_reload(client, _preconditions, **resources):
503+
bucket = client.bucket(resources.get("bucket").name)
504+
bucket.acl.reload()
505+
506+
507+
def bucket_acl_save(client, _preconditions, **resources):
508+
if _preconditions:
509+
pytest.skip(_BUCKET_ACL_PATCH_MSG)
510+
bucket = client.bucket(resources.get("bucket").name)
511+
bucket.acl.reload()
512+
bucket.acl.user(_CONF_TEST_SERVICE_ACCOUNT_EMAIL).grant_owner()
513+
bucket.acl.save()
514+
515+
516+
def bucket_acl_save_predefined(client, _preconditions, **resources):
517+
if _preconditions:
518+
pytest.skip(_BUCKET_ACL_PATCH_MSG)
519+
bucket = client.bucket(resources.get("bucket").name)
520+
bucket.acl.save_predefined("bucketOwnerFullControl")
521+
522+
523+
def bucket_acl_clear(client, _preconditions, **resources):
524+
if _preconditions:
525+
pytest.skip(_BUCKET_ACL_PATCH_MSG)
526+
bucket = client.bucket(resources.get("bucket").name)
527+
bucket.acl.clear()
528+
529+
530+
def default_object_acl_reload(client, _preconditions, **resources):
531+
bucket = client.bucket(resources.get("bucket").name)
532+
print(bucket.default_object_acl)
533+
bucket.default_object_acl.reload()
534+
535+
536+
def default_object_acl_save(client, _preconditions, **resources):
537+
if _preconditions:
538+
pytest.skip(_DEFAULT_OBJECT_ACL_PATCH_MSG)
539+
bucket = client.bucket(resources.get("bucket").name)
540+
bucket.default_object_acl.reload()
541+
bucket.default_object_acl.user(_CONF_TEST_SERVICE_ACCOUNT_EMAIL).grant_owner()
542+
bucket.default_object_acl.save()
543+
544+
545+
def default_object_acl_save_predefined(client, _preconditions, **resources):
546+
if _preconditions:
547+
pytest.skip(_DEFAULT_OBJECT_ACL_PATCH_MSG)
548+
bucket = client.bucket(resources.get("bucket").name)
549+
bucket.default_object_acl.save_predefined("bucketOwnerFullControl")
550+
551+
552+
def default_object_acl_clear(client, _preconditions, **resources):
553+
if _preconditions:
554+
pytest.skip(_DEFAULT_OBJECT_ACL_PATCH_MSG)
555+
bucket = client.bucket(resources.get("bucket").name)
556+
bucket.default_object_acl.clear()
557+
558+
559+
def object_acl_reload(client, _preconditions, **resources):
560+
bucket = resources.get("bucket")
561+
object = resources.get("object")
562+
blob = client.bucket(bucket.name).blob(object.name)
563+
blob.acl.reload()
564+
565+
566+
def object_acl_save(client, _preconditions, **resources):
567+
if _preconditions:
568+
pytest.skip(_OBJECT_ACL_PATCH_MSG)
569+
bucket = resources.get("bucket")
570+
object = resources.get("object")
571+
blob = client.bucket(bucket.name).blob(object.name)
572+
blob.acl.reload()
573+
blob.acl.user(_CONF_TEST_SERVICE_ACCOUNT_EMAIL).grant_owner()
574+
blob.acl.save()
575+
576+
577+
def object_acl_save_predefined(client, _preconditions, **resources):
578+
if _preconditions:
579+
pytest.skip(_OBJECT_ACL_PATCH_MSG)
580+
bucket = resources.get("bucket")
581+
object = resources.get("object")
582+
blob = client.bucket(bucket.name).blob(object.name)
583+
blob.acl.save_predefined("bucketOwnerFullControl")
584+
585+
586+
def object_acl_clear(client, _preconditions, **resources):
587+
if _preconditions:
588+
pytest.skip(_OBJECT_ACL_PATCH_MSG)
589+
bucket = resources.get("bucket")
590+
object = resources.get("object")
591+
blob = client.bucket(bucket.name).blob(object.name)
592+
blob.acl.clear()
593+
594+
426595
########################################################################################################################################
427596
### Method Invocation Mapping ##########################################################################################################
428597
########################################################################################################################################
@@ -434,7 +603,8 @@ def blob_create_resumable_upload_session(client, _preconditions, **resources):
434603
# read or just a metadata get).
435604

436605
method_mapping = {
437-
"storage.buckets.delete": [bucket_delete], # S1 start
606+
"storage.bucket_acl.list": [bucket_acl_reload], # S1 start
607+
"storage.buckets.delete": [bucket_delete],
438608
"storage.buckets.get": [
439609
client_get_bucket,
440610
bucket_reload,
@@ -446,13 +616,22 @@ def blob_create_resumable_upload_session(client, _preconditions, **resources):
446616
"storage.buckets.list": [client_list_buckets],
447617
"storage.buckets.lockRetentionPolicy": [bucket_lock_retention_policy],
448618
"storage.buckets.testIamPermissions": [bucket_test_iam_permissions],
619+
"storage.default_object_acl.list": [default_object_acl_reload],
620+
"storage.hmacKey.delete": [hmac_key_delete],
621+
"storage.hmacKey.get": [
622+
client_get_hmac_key_metadata,
623+
hmac_key_exists,
624+
hmac_key_reload,
625+
],
626+
"storage.hmacKey.list": [client_list_hmac_keys],
449627
"storage.notifications.delete": [notification_delete],
450628
"storage.notifications.get": [
451629
bucket_get_notification,
452630
notification_exists,
453631
notification_reload,
454632
],
455633
"storage.notifications.list": [bucket_list_notifications],
634+
"storage.object_acl.list": [object_acl_reload],
456635
"storage.objects.get": [
457636
bucket_get_blob,
458637
blob_exists,
@@ -462,14 +641,22 @@ def blob_create_resumable_upload_session(client, _preconditions, **resources):
462641
blob_download_as_text,
463642
blobreader_read,
464643
],
465-
"storage.objects.list": [
466-
client_list_blobs,
467-
bucket_list_blobs,
468-
bucket_delete,
469-
], # S1 end
470-
"storage.buckets.patch": [bucket_patch], # S2/S3 start
644+
"storage.objects.list": [client_list_blobs, bucket_list_blobs, bucket_delete],
645+
"storage.serviceaccount.get": [client_get_service_account_email], # S1 end
646+
"storage.buckets.patch": [
647+
bucket_patch,
648+
bucket_make_public,
649+
bucket_make_private,
650+
bucket_acl_save,
651+
bucket_acl_save_predefined,
652+
bucket_acl_clear,
653+
default_object_acl_save,
654+
default_object_acl_save_predefined,
655+
default_object_acl_clear,
656+
], # S2/S3 start
471657
"storage.buckets.setIamPolicy": [bucket_set_iam_policy],
472658
"storage.buckets.update": [bucket_update],
659+
"storage.hmacKey.update": [hmac_key_update],
473660
"storage.objects.compose": [blob_compose],
474661
"storage.objects.copy": [bucket_copy_blob, bucket_rename_blob],
475662
"storage.objects.delete": [
@@ -485,9 +672,18 @@ def blob_create_resumable_upload_session(client, _preconditions, **resources):
485672
blobwriter_write,
486673
blob_create_resumable_upload_session,
487674
],
488-
"storage.objects.patch": [blob_patch],
675+
"storage.objects.patch": [
676+
blob_patch,
677+
object_acl_save,
678+
object_acl_save_predefined,
679+
object_acl_clear,
680+
blob_make_private,
681+
blob_make_public,
682+
],
489683
"storage.objects.rewrite": [blob_rewrite, blob_update_storage_class],
490684
"storage.objects.update": [blob_update], # S2/S3 end
685+
"storage.hmacKey.create": [client_create_hmac_key], # S4 start
686+
"storage.notifications.insert": [notification_create],
491687
}
492688

493689

@@ -715,15 +911,17 @@ def run_test_case(
715911
id = scenario["id"]
716912
methods = scenario["methods"]
717913
cases = scenario["cases"]
718-
for c in cases:
914+
for i, c in enumerate(cases):
719915
for m in methods:
720916
method_name = m["name"]
721917
if method_name not in method_mapping:
722918
logging.info("No tests for operation {}".format(method_name))
723919
continue
724920

725921
for lib_func in method_mapping[method_name]:
726-
test_name = "test-S{}-{}-{}".format(id, method_name, lib_func.__name__)
922+
test_name = "test-S{}-{}-{}-{}".format(
923+
id, method_name, lib_func.__name__, i
924+
)
727925
globals()[test_name] = functools.partial(
728926
run_test_case, id, m, c, lib_func, host
729927
)

0 commit comments

Comments
 (0)