Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.

Commit ee8401e

Browse files
committed
refactor: use 'Client._put_resource' in 'Blob.set_iam_policy'
Toward #38.
1 parent f1a7979 commit ee8401e

File tree

2 files changed

+77
-60
lines changed

2 files changed

+77
-60
lines changed

google/cloud/storage/blob.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2898,16 +2898,16 @@ def set_iam_policy(
28982898
if self.user_project is not None:
28992899
query_params["userProject"] = self.user_project
29002900

2901+
path = "{}/iam".format(self.path)
29012902
resource = policy.to_api_repr()
29022903
resource["resourceId"] = self.path
2903-
info = client._connection.api_request(
2904-
method="PUT",
2905-
path="%s/iam" % (self.path,),
2904+
info = client._put_resource(
2905+
path,
2906+
resource,
29062907
query_params=query_params,
2907-
data=resource,
2908-
_target_object=None,
29092908
timeout=timeout,
29102909
retry=retry,
2910+
_target_object=None,
29112911
)
29122912
return Policy.from_api_repr(info)
29132913

tests/unit/test_blob.py

Lines changed: 72 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from six.moves import http_client
2828

2929
from google.cloud.storage.retry import DEFAULT_RETRY
30+
from google.cloud.storage.retry import DEFAULT_RETRY_IF_ETAG_IN_JSON
3031
from google.cloud.storage.retry import DEFAULT_RETRY_IF_GENERATION_SPECIFIED
3132

3233

@@ -3269,84 +3270,100 @@ def test_set_iam_policy(self):
32693270
from google.cloud.storage.iam import STORAGE_VIEWER_ROLE
32703271
from google.api_core.iam import Policy
32713272

3272-
BLOB_NAME = "blob-name"
3273-
PATH = "/b/name/o/%s" % (BLOB_NAME,)
3274-
ETAG = "DEADBEEF"
3275-
VERSION = 1
3276-
OWNER1 = "user:phred@example.com"
3277-
OWNER2 = "group:cloud-logs@google.com"
3278-
EDITOR1 = "domain:google.com"
3279-
EDITOR2 = "user:phred@example.com"
3280-
VIEWER1 = "serviceAccount:1234-abcdef@service.example.com"
3281-
VIEWER2 = "user:phred@example.com"
3282-
BINDINGS = [
3283-
{"role": STORAGE_OWNER_ROLE, "members": [OWNER1, OWNER2]},
3284-
{"role": STORAGE_EDITOR_ROLE, "members": [EDITOR1, EDITOR2]},
3285-
{"role": STORAGE_VIEWER_ROLE, "members": [VIEWER1, VIEWER2]},
3273+
blob_name = "blob-name"
3274+
path = "/b/name/o/%s" % (blob_name,)
3275+
etag = "DEADBEEF"
3276+
version = 1
3277+
owner1 = "user:phred@example.com"
3278+
owner2 = "group:cloud-logs@google.com"
3279+
editor1 = "domain:google.com"
3280+
editor2 = "user:phred@example.com"
3281+
viewer1 = "serviceAccount:1234-abcdef@service.example.com"
3282+
viewer2 = "user:phred@example.com"
3283+
bindings = [
3284+
{"role": STORAGE_OWNER_ROLE, "members": [owner1, owner2]},
3285+
{"role": STORAGE_EDITOR_ROLE, "members": [editor1, editor2]},
3286+
{"role": STORAGE_VIEWER_ROLE, "members": [viewer1, viewer2]},
32863287
]
3287-
RETURNED = {"etag": ETAG, "version": VERSION, "bindings": BINDINGS}
3288-
after = ({"status": http_client.OK}, RETURNED)
3288+
api_response = {"etag": etag, "version": version, "bindings": bindings}
32893289
policy = Policy()
3290-
for binding in BINDINGS:
3290+
for binding in bindings:
32913291
policy[binding["role"]] = binding["members"]
32923292

3293-
connection = _Connection(after)
3294-
client = _Client(connection)
3293+
client = mock.Mock(spec=["_put_resource"])
3294+
client._put_resource.return_value = api_response
32953295
bucket = _Bucket(client=client)
3296-
blob = self._make_one(BLOB_NAME, bucket=bucket)
3296+
blob = self._make_one(blob_name, bucket=bucket)
32973297

3298-
returned = blob.set_iam_policy(policy, timeout=42)
3298+
returned = blob.set_iam_policy(policy)
32993299

3300-
self.assertEqual(returned.etag, ETAG)
3301-
self.assertEqual(returned.version, VERSION)
3300+
self.assertEqual(returned.etag, etag)
3301+
self.assertEqual(returned.version, version)
33023302
self.assertEqual(dict(returned), dict(policy))
33033303

3304-
kw = connection._requested
3305-
self.assertEqual(len(kw), 1)
3306-
self.assertEqual(kw[0]["method"], "PUT")
3307-
self.assertEqual(kw[0]["path"], "%s/iam" % (PATH,))
3308-
self.assertEqual(kw[0]["query_params"], {})
3309-
self.assertEqual(kw[0]["timeout"], 42)
3310-
sent = kw[0]["data"]
3311-
self.assertEqual(sent["resourceId"], PATH)
3312-
self.assertEqual(len(sent["bindings"]), len(BINDINGS))
3304+
expected_path = "%s/iam" % (path,)
3305+
expected_data = {
3306+
"resourceId": path,
3307+
"bindings": mock.ANY,
3308+
}
3309+
expected_query_params = {}
3310+
client._put_resource.assert_called_once_with(
3311+
expected_path,
3312+
expected_data,
3313+
query_params=expected_query_params,
3314+
timeout=self._get_default_timeout(),
3315+
retry=DEFAULT_RETRY_IF_ETAG_IN_JSON,
3316+
_target_object=None,
3317+
)
3318+
3319+
sent_bindings = client._put_resource.call_args.args[1]["bindings"]
33133320
key = operator.itemgetter("role")
33143321
for found, expected in zip(
3315-
sorted(sent["bindings"], key=key), sorted(BINDINGS, key=key)
3322+
sorted(sent_bindings, key=key), sorted(bindings, key=key)
33163323
):
33173324
self.assertEqual(found["role"], expected["role"])
33183325
self.assertEqual(sorted(found["members"]), sorted(expected["members"]))
33193326

3320-
def test_set_iam_policy_w_user_project(self):
3327+
def test_set_iam_policy_w_user_project_w_explicit_client_w_timeout_retry(self):
33213328
from google.api_core.iam import Policy
33223329

3323-
BLOB_NAME = "blob-name"
3324-
USER_PROJECT = "user-project-123"
3325-
PATH = "/b/name/o/%s" % (BLOB_NAME,)
3326-
ETAG = "DEADBEEF"
3327-
VERSION = 1
3328-
BINDINGS = []
3329-
RETURNED = {"etag": ETAG, "version": VERSION, "bindings": BINDINGS}
3330-
after = ({"status": http_client.OK}, RETURNED)
3330+
blob_name = "blob-name"
3331+
user_project = "user-project-123"
3332+
path = "/b/name/o/%s" % (blob_name,)
3333+
etag = "DEADBEEF"
3334+
version = 1
3335+
bindings = []
33313336
policy = Policy()
33323337

3333-
connection = _Connection(after)
3334-
client = _Client(connection)
3335-
bucket = _Bucket(client=client, user_project=USER_PROJECT)
3336-
blob = self._make_one(BLOB_NAME, bucket=bucket)
3338+
api_response = {"etag": etag, "version": version, "bindings": bindings}
3339+
client = mock.Mock(spec=["_put_resource"])
3340+
client._put_resource.return_value = api_response
3341+
bucket = _Bucket(client=None, user_project=user_project)
3342+
blob = self._make_one(blob_name, bucket=bucket)
3343+
timeout = 42
3344+
retry = mock.Mock(spec=[])
33373345

3338-
returned = blob.set_iam_policy(policy)
3346+
returned = blob.set_iam_policy(
3347+
policy, client=client, timeout=timeout, retry=retry,
3348+
)
33393349

3340-
self.assertEqual(returned.etag, ETAG)
3341-
self.assertEqual(returned.version, VERSION)
3350+
self.assertEqual(returned.etag, etag)
3351+
self.assertEqual(returned.version, version)
33423352
self.assertEqual(dict(returned), dict(policy))
33433353

3344-
kw = connection._requested
3345-
self.assertEqual(len(kw), 1)
3346-
self.assertEqual(kw[0]["method"], "PUT")
3347-
self.assertEqual(kw[0]["path"], "%s/iam" % (PATH,))
3348-
self.assertEqual(kw[0]["query_params"], {"userProject": USER_PROJECT})
3349-
self.assertEqual(kw[0]["data"], {"resourceId": PATH})
3354+
expected_path = "%s/iam" % (path,)
3355+
expected_data = { # bindings omitted
3356+
"resourceId": path,
3357+
}
3358+
expected_query_params = {"userProject": user_project}
3359+
client._put_resource.assert_called_once_with(
3360+
expected_path,
3361+
expected_data,
3362+
query_params=expected_query_params,
3363+
timeout=timeout,
3364+
retry=retry,
3365+
_target_object=None,
3366+
)
33503367

33513368
def test_test_iam_permissions_defaults(self):
33523369
from google.cloud.storage.iam import STORAGE_OBJECTS_LIST

0 commit comments

Comments
 (0)