From bc67e62de5a5645fb93f1e1db02dc9d2ba673b66 Mon Sep 17 00:00:00 2001 From: Chris Wilcox Date: Fri, 30 Nov 2018 10:20:53 -0800 Subject: [PATCH 1/4] move google.cloud.iam (core) to google.api.core.iam --- api_core/google/api_core/iam.py | 248 ++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 api_core/google/api_core/iam.py diff --git a/api_core/google/api_core/iam.py b/api_core/google/api_core/iam.py new file mode 100644 index 000000000000..c17bddcd9dfd --- /dev/null +++ b/api_core/google/api_core/iam.py @@ -0,0 +1,248 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Non-API-specific IAM policy definitions + +For allowed roles / permissions, see: +https://cloud.google.com/iam/docs/understanding-roles +""" + +import collections +try: + from collections import abc as collections_abc +except ImportError: # Python 2.7 + import collections as collections_abc +import warnings + +# Generic IAM roles + +OWNER_ROLE = "roles/owner" +"""Generic role implying all rights to an object.""" + +EDITOR_ROLE = "roles/editor" +"""Generic role implying rights to modify an object.""" + +VIEWER_ROLE = "roles/viewer" +"""Generic role implying rights to access an object.""" + +_ASSIGNMENT_DEPRECATED_MSG = """\ +Assigning to '{}' is deprecated. Replace with 'policy[{}] = members.""" + + +class Policy(collections_abc.MutableMapping): + """IAM Policy + + See + https://cloud.google.com/iam/reference/rest/v1/Policy + + :type etag: str + :param etag: ETag used to identify a unique of the policy + + :type version: int + :param version: unique version of the policy + """ + + _OWNER_ROLES = (OWNER_ROLE,) + """Roles mapped onto our ``owners`` attribute.""" + + _EDITOR_ROLES = (EDITOR_ROLE,) + """Roles mapped onto our ``editors`` attribute.""" + + _VIEWER_ROLES = (VIEWER_ROLE,) + """Roles mapped onto our ``viewers`` attribute.""" + + def __init__(self, etag=None, version=None): + self.etag = etag + self.version = version + self._bindings = collections.defaultdict(set) + + def __iter__(self): + return iter(self._bindings) + + def __len__(self): + return len(self._bindings) + + def __getitem__(self, key): + return self._bindings[key] + + def __setitem__(self, key, value): + self._bindings[key] = set(value) + + def __delitem__(self, key): + del self._bindings[key] + + @property + def owners(self): + """Legacy access to owner role.""" + result = set() + for role in self._OWNER_ROLES: + for member in self._bindings.get(role, ()): + result.add(member) + return frozenset(result) + + @owners.setter + def owners(self, value): + """Update owners.""" + warnings.warn( + _ASSIGNMENT_DEPRECATED_MSG.format("owners", OWNER_ROLE), DeprecationWarning + ) + self[OWNER_ROLE] = value + + @property + def editors(self): + """Legacy access to editor role.""" + result = set() + for role in self._EDITOR_ROLES: + for member in self._bindings.get(role, ()): + result.add(member) + return frozenset(result) + + @editors.setter + def editors(self, value): + """Update editors.""" + warnings.warn( + _ASSIGNMENT_DEPRECATED_MSG.format("editors", EDITOR_ROLE), + DeprecationWarning, + ) + self[EDITOR_ROLE] = value + + @property + def viewers(self): + """Legacy access to viewer role.""" + result = set() + for role in self._VIEWER_ROLES: + for member in self._bindings.get(role, ()): + result.add(member) + return frozenset(result) + + @viewers.setter + def viewers(self, value): + """Update viewers.""" + warnings.warn( + _ASSIGNMENT_DEPRECATED_MSG.format("viewers", VIEWER_ROLE), + DeprecationWarning, + ) + self[VIEWER_ROLE] = value + + @staticmethod + def user(email): + """Factory method for a user member. + + :type email: str + :param email: E-mail for this particular user. + + :rtype: str + :returns: A member string corresponding to the given user. + """ + return "user:%s" % (email,) + + @staticmethod + def service_account(email): + """Factory method for a service account member. + + :type email: str + :param email: E-mail for this particular service account. + + :rtype: str + :returns: A member string corresponding to the given service account. + """ + return "serviceAccount:%s" % (email,) + + @staticmethod + def group(email): + """Factory method for a group member. + + :type email: str + :param email: An id or e-mail for this particular group. + + :rtype: str + :returns: A member string corresponding to the given group. + """ + return "group:%s" % (email,) + + @staticmethod + def domain(domain): + """Factory method for a domain member. + + :type domain: str + :param domain: The domain for this member. + + :rtype: str + :returns: A member string corresponding to the given domain. + """ + return "domain:%s" % (domain,) + + @staticmethod + def all_users(): + """Factory method for a member representing all users. + + :rtype: str + :returns: A member string representing all users. + """ + return "allUsers" + + @staticmethod + def authenticated_users(): + """Factory method for a member representing all authenticated users. + + :rtype: str + :returns: A member string representing all authenticated users. + """ + return "allAuthenticatedUsers" + + @classmethod + def from_api_repr(cls, resource): + """Create a policy from the resource returned from the API. + + :type resource: dict + :param resource: resource returned from the ``getIamPolicy`` API. + + :rtype: :class:`Policy` + :returns: the parsed policy + """ + version = resource.get("version") + etag = resource.get("etag") + policy = cls(etag, version) + for binding in resource.get("bindings", ()): + role = binding["role"] + members = sorted(binding["members"]) + policy[role] = members + return policy + + def to_api_repr(self): + """Construct a Policy resource. + + :rtype: dict + :returns: a resource to be passed to the ``setIamPolicy`` API. + """ + resource = {} + + if self.etag is not None: + resource["etag"] = self.etag + + if self.version is not None: + resource["version"] = self.version + + if self._bindings: + bindings = resource["bindings"] = [] + for role, members in sorted(self._bindings.items()): + if members: + bindings.append({"role": role, "members": sorted(set(members))}) + + if not bindings: + del resource["bindings"] + + return resource + + +collections_abc.MutableMapping.register(Policy) From b6df196b54346136d73ce4b4413cd0ae5d66d3ff Mon Sep 17 00:00:00 2001 From: Chris Wilcox Date: Fri, 30 Nov 2018 10:40:31 -0800 Subject: [PATCH 2/4] move tests --- api_core/tests/unit/test_iam.py | 281 ++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 api_core/tests/unit/test_iam.py diff --git a/api_core/tests/unit/test_iam.py b/api_core/tests/unit/test_iam.py new file mode 100644 index 000000000000..39b7595cf8b0 --- /dev/null +++ b/api_core/tests/unit/test_iam.py @@ -0,0 +1,281 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + + +class TestPolicy(unittest.TestCase): + @staticmethod + def _get_target_class(): + from google.cloud.iam import Policy + + return Policy + + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) + + def test_ctor_defaults(self): + empty = frozenset() + policy = self._make_one() + self.assertIsNone(policy.etag) + self.assertIsNone(policy.version) + self.assertEqual(policy.owners, empty) + self.assertEqual(policy.editors, empty) + self.assertEqual(policy.viewers, empty) + self.assertEqual(len(policy), 0) + self.assertEqual(dict(policy), {}) + + def test_ctor_explicit(self): + VERSION = 17 + ETAG = "ETAG" + empty = frozenset() + policy = self._make_one(ETAG, VERSION) + self.assertEqual(policy.etag, ETAG) + self.assertEqual(policy.version, VERSION) + self.assertEqual(policy.owners, empty) + self.assertEqual(policy.editors, empty) + self.assertEqual(policy.viewers, empty) + self.assertEqual(len(policy), 0) + self.assertEqual(dict(policy), {}) + + def test___getitem___miss(self): + policy = self._make_one() + self.assertEqual(policy["nonesuch"], set()) + + def test___setitem__(self): + USER = "user:phred@example.com" + PRINCIPALS = set([USER]) + policy = self._make_one() + policy["rolename"] = [USER] + self.assertEqual(policy["rolename"], PRINCIPALS) + self.assertEqual(len(policy), 1) + self.assertEqual(dict(policy), {"rolename": PRINCIPALS}) + + def test___delitem___hit(self): + policy = self._make_one() + policy._bindings["rolename"] = ["phred@example.com"] + del policy["rolename"] + self.assertEqual(len(policy), 0) + self.assertEqual(dict(policy), {}) + + def test___delitem___miss(self): + policy = self._make_one() + with self.assertRaises(KeyError): + del policy["nonesuch"] + + def test_owners_getter(self): + from google.cloud.iam import OWNER_ROLE + + MEMBER = "user:phred@example.com" + expected = frozenset([MEMBER]) + policy = self._make_one() + policy[OWNER_ROLE] = [MEMBER] + self.assertEqual(policy.owners, expected) + + def test_owners_setter(self): + import warnings + from google.cloud.iam import OWNER_ROLE + + MEMBER = "user:phred@example.com" + expected = set([MEMBER]) + policy = self._make_one() + with warnings.catch_warnings(): + warnings.simplefilter("always") + policy.owners = [MEMBER] + self.assertEqual(policy[OWNER_ROLE], expected) + + def test_editors_getter(self): + from google.cloud.iam import EDITOR_ROLE + + MEMBER = "user:phred@example.com" + expected = frozenset([MEMBER]) + policy = self._make_one() + policy[EDITOR_ROLE] = [MEMBER] + self.assertEqual(policy.editors, expected) + + def test_editors_setter(self): + import warnings + from google.cloud.iam import EDITOR_ROLE + + MEMBER = "user:phred@example.com" + expected = set([MEMBER]) + policy = self._make_one() + with warnings.catch_warnings(): + warnings.simplefilter("always") + policy.editors = [MEMBER] + self.assertEqual(policy[EDITOR_ROLE], expected) + + def test_viewers_getter(self): + from google.cloud.iam import VIEWER_ROLE + + MEMBER = "user:phred@example.com" + expected = frozenset([MEMBER]) + policy = self._make_one() + policy[VIEWER_ROLE] = [MEMBER] + self.assertEqual(policy.viewers, expected) + + def test_viewers_setter(self): + import warnings + from google.cloud.iam import VIEWER_ROLE + + MEMBER = "user:phred@example.com" + expected = set([MEMBER]) + policy = self._make_one() + with warnings.catch_warnings(): + warnings.simplefilter("always") + policy.viewers = [MEMBER] + self.assertEqual(policy[VIEWER_ROLE], expected) + + def test_user(self): + EMAIL = "phred@example.com" + MEMBER = "user:%s" % (EMAIL,) + policy = self._make_one() + self.assertEqual(policy.user(EMAIL), MEMBER) + + def test_service_account(self): + EMAIL = "phred@example.com" + MEMBER = "serviceAccount:%s" % (EMAIL,) + policy = self._make_one() + self.assertEqual(policy.service_account(EMAIL), MEMBER) + + def test_group(self): + EMAIL = "phred@example.com" + MEMBER = "group:%s" % (EMAIL,) + policy = self._make_one() + self.assertEqual(policy.group(EMAIL), MEMBER) + + def test_domain(self): + DOMAIN = "example.com" + MEMBER = "domain:%s" % (DOMAIN,) + policy = self._make_one() + self.assertEqual(policy.domain(DOMAIN), MEMBER) + + def test_all_users(self): + policy = self._make_one() + self.assertEqual(policy.all_users(), "allUsers") + + def test_authenticated_users(self): + policy = self._make_one() + self.assertEqual(policy.authenticated_users(), "allAuthenticatedUsers") + + def test_from_api_repr_only_etag(self): + empty = frozenset() + RESOURCE = {"etag": "ACAB"} + klass = self._get_target_class() + policy = klass.from_api_repr(RESOURCE) + self.assertEqual(policy.etag, "ACAB") + self.assertIsNone(policy.version) + self.assertEqual(policy.owners, empty) + self.assertEqual(policy.editors, empty) + self.assertEqual(policy.viewers, empty) + self.assertEqual(dict(policy), {}) + + def test_from_api_repr_complete(self): + from google.cloud.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE + + OWNER1 = "group:cloud-logs@google.com" + OWNER2 = "user:phred@example.com" + EDITOR1 = "domain:google.com" + EDITOR2 = "user:phred@example.com" + VIEWER1 = "serviceAccount:1234-abcdef@service.example.com" + VIEWER2 = "user:phred@example.com" + RESOURCE = { + "etag": "DEADBEEF", + "version": 17, + "bindings": [ + {"role": OWNER_ROLE, "members": [OWNER1, OWNER2]}, + {"role": EDITOR_ROLE, "members": [EDITOR1, EDITOR2]}, + {"role": VIEWER_ROLE, "members": [VIEWER1, VIEWER2]}, + ], + } + klass = self._get_target_class() + policy = klass.from_api_repr(RESOURCE) + self.assertEqual(policy.etag, "DEADBEEF") + self.assertEqual(policy.version, 17) + self.assertEqual(policy.owners, frozenset([OWNER1, OWNER2])) + self.assertEqual(policy.editors, frozenset([EDITOR1, EDITOR2])) + self.assertEqual(policy.viewers, frozenset([VIEWER1, VIEWER2])) + self.assertEqual( + dict(policy), + { + OWNER_ROLE: set([OWNER1, OWNER2]), + EDITOR_ROLE: set([EDITOR1, EDITOR2]), + VIEWER_ROLE: set([VIEWER1, VIEWER2]), + }, + ) + + def test_from_api_repr_unknown_role(self): + USER = "user:phred@example.com" + GROUP = "group:cloud-logs@google.com" + RESOURCE = { + "etag": "DEADBEEF", + "version": 17, + "bindings": [{"role": "unknown", "members": [USER, GROUP]}], + } + klass = self._get_target_class() + policy = klass.from_api_repr(RESOURCE) + self.assertEqual(policy.etag, "DEADBEEF") + self.assertEqual(policy.version, 17) + self.assertEqual(dict(policy), {"unknown": set([GROUP, USER])}) + + def test_to_api_repr_defaults(self): + policy = self._make_one() + self.assertEqual(policy.to_api_repr(), {}) + + def test_to_api_repr_only_etag(self): + policy = self._make_one("DEADBEEF") + self.assertEqual(policy.to_api_repr(), {"etag": "DEADBEEF"}) + + def test_to_api_repr_binding_wo_members(self): + policy = self._make_one() + policy["empty"] = [] + self.assertEqual(policy.to_api_repr(), {}) + + def test_to_api_repr_binding_w_duplicates(self): + from google.cloud.iam import OWNER_ROLE + + OWNER = "group:cloud-logs@google.com" + policy = self._make_one() + policy.owners = [OWNER, OWNER] + self.assertEqual( + policy.to_api_repr(), + {"bindings": [{"role": OWNER_ROLE, "members": [OWNER]}]}, + ) + + def test_to_api_repr_full(self): + import operator + from google.cloud.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE + + OWNER1 = "group:cloud-logs@google.com" + OWNER2 = "user:phred@example.com" + EDITOR1 = "domain:google.com" + EDITOR2 = "user:phred@example.com" + VIEWER1 = "serviceAccount:1234-abcdef@service.example.com" + VIEWER2 = "user:phred@example.com" + BINDINGS = [ + {"role": OWNER_ROLE, "members": [OWNER1, OWNER2]}, + {"role": EDITOR_ROLE, "members": [EDITOR1, EDITOR2]}, + {"role": VIEWER_ROLE, "members": [VIEWER1, VIEWER2]}, + ] + policy = self._make_one("DEADBEEF", 17) + policy.owners = [OWNER1, OWNER2] + policy.editors = [EDITOR1, EDITOR2] + policy.viewers = [VIEWER1, VIEWER2] + resource = policy.to_api_repr() + self.assertEqual(resource["etag"], "DEADBEEF") + self.assertEqual(resource["version"], 17) + key = operator.itemgetter("role") + self.assertEqual( + sorted(resource["bindings"], key=key), sorted(BINDINGS, key=key) + ) From aad15cf4ad9a664fcaa6aaea20464221fdf1627f Mon Sep 17 00:00:00 2001 From: Chris Wilcox Date: Fri, 30 Nov 2018 11:19:25 -0800 Subject: [PATCH 3/4] alter imports in iam tests --- api_core/tests/unit/test_iam.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/api_core/tests/unit/test_iam.py b/api_core/tests/unit/test_iam.py index 39b7595cf8b0..f6f7b01fe6d7 100644 --- a/api_core/tests/unit/test_iam.py +++ b/api_core/tests/unit/test_iam.py @@ -18,7 +18,7 @@ class TestPolicy(unittest.TestCase): @staticmethod def _get_target_class(): - from google.cloud.iam import Policy + from google.api_core.iam import Policy return Policy @@ -75,7 +75,7 @@ def test___delitem___miss(self): del policy["nonesuch"] def test_owners_getter(self): - from google.cloud.iam import OWNER_ROLE + from google.api_core.iam import OWNER_ROLE MEMBER = "user:phred@example.com" expected = frozenset([MEMBER]) @@ -85,7 +85,7 @@ def test_owners_getter(self): def test_owners_setter(self): import warnings - from google.cloud.iam import OWNER_ROLE + from google.api_core.iam import OWNER_ROLE MEMBER = "user:phred@example.com" expected = set([MEMBER]) @@ -96,7 +96,7 @@ def test_owners_setter(self): self.assertEqual(policy[OWNER_ROLE], expected) def test_editors_getter(self): - from google.cloud.iam import EDITOR_ROLE + from google.api_core.iam import EDITOR_ROLE MEMBER = "user:phred@example.com" expected = frozenset([MEMBER]) @@ -106,7 +106,7 @@ def test_editors_getter(self): def test_editors_setter(self): import warnings - from google.cloud.iam import EDITOR_ROLE + from google.api_core.iam import EDITOR_ROLE MEMBER = "user:phred@example.com" expected = set([MEMBER]) @@ -117,7 +117,7 @@ def test_editors_setter(self): self.assertEqual(policy[EDITOR_ROLE], expected) def test_viewers_getter(self): - from google.cloud.iam import VIEWER_ROLE + from google.api_core.iam import VIEWER_ROLE MEMBER = "user:phred@example.com" expected = frozenset([MEMBER]) @@ -127,7 +127,7 @@ def test_viewers_getter(self): def test_viewers_setter(self): import warnings - from google.cloud.iam import VIEWER_ROLE + from google.api_core.iam import VIEWER_ROLE MEMBER = "user:phred@example.com" expected = set([MEMBER]) @@ -182,7 +182,7 @@ def test_from_api_repr_only_etag(self): self.assertEqual(dict(policy), {}) def test_from_api_repr_complete(self): - from google.cloud.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE + from google.api_core.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE OWNER1 = "group:cloud-logs@google.com" OWNER2 = "user:phred@example.com" @@ -243,7 +243,7 @@ def test_to_api_repr_binding_wo_members(self): self.assertEqual(policy.to_api_repr(), {}) def test_to_api_repr_binding_w_duplicates(self): - from google.cloud.iam import OWNER_ROLE + from google.api_core.iam import OWNER_ROLE OWNER = "group:cloud-logs@google.com" policy = self._make_one() @@ -255,7 +255,7 @@ def test_to_api_repr_binding_w_duplicates(self): def test_to_api_repr_full(self): import operator - from google.cloud.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE + from google.api_core.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE OWNER1 = "group:cloud-logs@google.com" OWNER2 = "user:phred@example.com" From 8b10276fcf6b867905ed295510da24b39e4e84ff Mon Sep 17 00:00:00 2001 From: Chris Wilcox Date: Fri, 30 Nov 2018 12:23:38 -0800 Subject: [PATCH 4/4] alter tests to use pytest assert style --- api_core/tests/unit/test_iam.py | 132 +++++++++++++++----------------- 1 file changed, 63 insertions(+), 69 deletions(-) diff --git a/api_core/tests/unit/test_iam.py b/api_core/tests/unit/test_iam.py index f6f7b01fe6d7..59f3b2c8a309 100644 --- a/api_core/tests/unit/test_iam.py +++ b/api_core/tests/unit/test_iam.py @@ -12,10 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest +import pytest -class TestPolicy(unittest.TestCase): +class TestPolicy: @staticmethod def _get_target_class(): from google.api_core.iam import Policy @@ -28,50 +28,50 @@ def _make_one(self, *args, **kw): def test_ctor_defaults(self): empty = frozenset() policy = self._make_one() - self.assertIsNone(policy.etag) - self.assertIsNone(policy.version) - self.assertEqual(policy.owners, empty) - self.assertEqual(policy.editors, empty) - self.assertEqual(policy.viewers, empty) - self.assertEqual(len(policy), 0) - self.assertEqual(dict(policy), {}) + assert policy.etag is None + assert policy.version is None + assert policy.owners == empty + assert policy.editors == empty + assert policy.viewers == empty + assert len(policy) == 0 + assert dict(policy) == {} def test_ctor_explicit(self): VERSION = 17 ETAG = "ETAG" empty = frozenset() policy = self._make_one(ETAG, VERSION) - self.assertEqual(policy.etag, ETAG) - self.assertEqual(policy.version, VERSION) - self.assertEqual(policy.owners, empty) - self.assertEqual(policy.editors, empty) - self.assertEqual(policy.viewers, empty) - self.assertEqual(len(policy), 0) - self.assertEqual(dict(policy), {}) + assert policy.etag == ETAG + assert policy.version == VERSION + assert policy.owners == empty + assert policy.editors == empty + assert policy.viewers == empty + assert len(policy) == 0 + assert dict(policy) == {} def test___getitem___miss(self): policy = self._make_one() - self.assertEqual(policy["nonesuch"], set()) + assert policy["nonesuch"] == set() def test___setitem__(self): USER = "user:phred@example.com" PRINCIPALS = set([USER]) policy = self._make_one() policy["rolename"] = [USER] - self.assertEqual(policy["rolename"], PRINCIPALS) - self.assertEqual(len(policy), 1) - self.assertEqual(dict(policy), {"rolename": PRINCIPALS}) + assert policy["rolename"] == PRINCIPALS + assert len(policy) == 1 + assert dict(policy) == {"rolename": PRINCIPALS} def test___delitem___hit(self): policy = self._make_one() policy._bindings["rolename"] = ["phred@example.com"] del policy["rolename"] - self.assertEqual(len(policy), 0) - self.assertEqual(dict(policy), {}) + assert len(policy) == 0 + assert dict(policy) == {} def test___delitem___miss(self): policy = self._make_one() - with self.assertRaises(KeyError): + with pytest.raises(KeyError): del policy["nonesuch"] def test_owners_getter(self): @@ -81,7 +81,7 @@ def test_owners_getter(self): expected = frozenset([MEMBER]) policy = self._make_one() policy[OWNER_ROLE] = [MEMBER] - self.assertEqual(policy.owners, expected) + assert policy.owners == expected def test_owners_setter(self): import warnings @@ -93,7 +93,7 @@ def test_owners_setter(self): with warnings.catch_warnings(): warnings.simplefilter("always") policy.owners = [MEMBER] - self.assertEqual(policy[OWNER_ROLE], expected) + assert policy[OWNER_ROLE] == expected def test_editors_getter(self): from google.api_core.iam import EDITOR_ROLE @@ -102,7 +102,7 @@ def test_editors_getter(self): expected = frozenset([MEMBER]) policy = self._make_one() policy[EDITOR_ROLE] = [MEMBER] - self.assertEqual(policy.editors, expected) + assert policy.editors == expected def test_editors_setter(self): import warnings @@ -114,7 +114,7 @@ def test_editors_setter(self): with warnings.catch_warnings(): warnings.simplefilter("always") policy.editors = [MEMBER] - self.assertEqual(policy[EDITOR_ROLE], expected) + assert policy[EDITOR_ROLE] == expected def test_viewers_getter(self): from google.api_core.iam import VIEWER_ROLE @@ -123,7 +123,7 @@ def test_viewers_getter(self): expected = frozenset([MEMBER]) policy = self._make_one() policy[VIEWER_ROLE] = [MEMBER] - self.assertEqual(policy.viewers, expected) + assert policy.viewers == expected def test_viewers_setter(self): import warnings @@ -135,51 +135,51 @@ def test_viewers_setter(self): with warnings.catch_warnings(): warnings.simplefilter("always") policy.viewers = [MEMBER] - self.assertEqual(policy[VIEWER_ROLE], expected) + assert policy[VIEWER_ROLE] == expected def test_user(self): EMAIL = "phred@example.com" MEMBER = "user:%s" % (EMAIL,) policy = self._make_one() - self.assertEqual(policy.user(EMAIL), MEMBER) + assert policy.user(EMAIL) == MEMBER def test_service_account(self): EMAIL = "phred@example.com" MEMBER = "serviceAccount:%s" % (EMAIL,) policy = self._make_one() - self.assertEqual(policy.service_account(EMAIL), MEMBER) + assert policy.service_account(EMAIL) == MEMBER def test_group(self): EMAIL = "phred@example.com" MEMBER = "group:%s" % (EMAIL,) policy = self._make_one() - self.assertEqual(policy.group(EMAIL), MEMBER) + assert policy.group(EMAIL) == MEMBER def test_domain(self): DOMAIN = "example.com" MEMBER = "domain:%s" % (DOMAIN,) policy = self._make_one() - self.assertEqual(policy.domain(DOMAIN), MEMBER) + assert policy.domain(DOMAIN) == MEMBER def test_all_users(self): policy = self._make_one() - self.assertEqual(policy.all_users(), "allUsers") + assert policy.all_users() == "allUsers" def test_authenticated_users(self): policy = self._make_one() - self.assertEqual(policy.authenticated_users(), "allAuthenticatedUsers") + assert policy.authenticated_users() == "allAuthenticatedUsers" def test_from_api_repr_only_etag(self): empty = frozenset() RESOURCE = {"etag": "ACAB"} klass = self._get_target_class() policy = klass.from_api_repr(RESOURCE) - self.assertEqual(policy.etag, "ACAB") - self.assertIsNone(policy.version) - self.assertEqual(policy.owners, empty) - self.assertEqual(policy.editors, empty) - self.assertEqual(policy.viewers, empty) - self.assertEqual(dict(policy), {}) + assert policy.etag == "ACAB" + assert policy.version is None + assert policy.owners == empty + assert policy.editors == empty + assert policy.viewers == empty + assert dict(policy) == {} def test_from_api_repr_complete(self): from google.api_core.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE @@ -201,19 +201,16 @@ def test_from_api_repr_complete(self): } klass = self._get_target_class() policy = klass.from_api_repr(RESOURCE) - self.assertEqual(policy.etag, "DEADBEEF") - self.assertEqual(policy.version, 17) - self.assertEqual(policy.owners, frozenset([OWNER1, OWNER2])) - self.assertEqual(policy.editors, frozenset([EDITOR1, EDITOR2])) - self.assertEqual(policy.viewers, frozenset([VIEWER1, VIEWER2])) - self.assertEqual( - dict(policy), - { - OWNER_ROLE: set([OWNER1, OWNER2]), - EDITOR_ROLE: set([EDITOR1, EDITOR2]), - VIEWER_ROLE: set([VIEWER1, VIEWER2]), - }, - ) + assert policy.etag == "DEADBEEF" + assert policy.version == 17 + assert policy.owners, frozenset([OWNER1 == OWNER2]) + assert policy.editors, frozenset([EDITOR1 == EDITOR2]) + assert policy.viewers, frozenset([VIEWER1 == VIEWER2]) + assert dict(policy) == { + OWNER_ROLE: set([OWNER1, OWNER2]), + EDITOR_ROLE: set([EDITOR1, EDITOR2]), + VIEWER_ROLE: set([VIEWER1, VIEWER2]), + } def test_from_api_repr_unknown_role(self): USER = "user:phred@example.com" @@ -225,22 +222,22 @@ def test_from_api_repr_unknown_role(self): } klass = self._get_target_class() policy = klass.from_api_repr(RESOURCE) - self.assertEqual(policy.etag, "DEADBEEF") - self.assertEqual(policy.version, 17) - self.assertEqual(dict(policy), {"unknown": set([GROUP, USER])}) + assert policy.etag == "DEADBEEF" + assert policy.version == 17 + assert dict(policy), {"unknown": set([GROUP == USER])} def test_to_api_repr_defaults(self): policy = self._make_one() - self.assertEqual(policy.to_api_repr(), {}) + assert policy.to_api_repr() == {} def test_to_api_repr_only_etag(self): policy = self._make_one("DEADBEEF") - self.assertEqual(policy.to_api_repr(), {"etag": "DEADBEEF"}) + assert policy.to_api_repr() == {"etag": "DEADBEEF"} def test_to_api_repr_binding_wo_members(self): policy = self._make_one() policy["empty"] = [] - self.assertEqual(policy.to_api_repr(), {}) + assert policy.to_api_repr() == {} def test_to_api_repr_binding_w_duplicates(self): from google.api_core.iam import OWNER_ROLE @@ -248,10 +245,9 @@ def test_to_api_repr_binding_w_duplicates(self): OWNER = "group:cloud-logs@google.com" policy = self._make_one() policy.owners = [OWNER, OWNER] - self.assertEqual( - policy.to_api_repr(), - {"bindings": [{"role": OWNER_ROLE, "members": [OWNER]}]}, - ) + assert policy.to_api_repr() == { + "bindings": [{"role": OWNER_ROLE, "members": [OWNER]}] + } def test_to_api_repr_full(self): import operator @@ -273,9 +269,7 @@ def test_to_api_repr_full(self): policy.editors = [EDITOR1, EDITOR2] policy.viewers = [VIEWER1, VIEWER2] resource = policy.to_api_repr() - self.assertEqual(resource["etag"], "DEADBEEF") - self.assertEqual(resource["version"], 17) + assert resource["etag"] == "DEADBEEF" + assert resource["version"] == 17 key = operator.itemgetter("role") - self.assertEqual( - sorted(resource["bindings"], key=key), sorted(BINDINGS, key=key) - ) + assert sorted(resource["bindings"], key=key) == sorted(BINDINGS, key=key)