Merge "Make QuotaImageTagsProxy deep-copyable"

This commit is contained in:
Zuul 2019-01-09 13:17:20 +00:00 committed by Gerrit Code Review
commit fb2c2e7de1
2 changed files with 25 additions and 14 deletions

View File

@ -165,14 +165,15 @@ class QuotaImageTagsProxy(object):
return self.tags.__len__(*args, **kwargs) return self.tags.__len__(*args, **kwargs)
def __getattr__(self, name): def __getattr__(self, name):
# Use TypeError here, not AttributeError, as the latter is how we # Protect against deepcopy, which calls getattr. __getattr__
# know a tag is not present. TypeError says "this object is not # is only called when an attribute is not "normal", so when
# what it claims to be". # self.tags is called, this is not.
try: if name == 'tags':
tags = self.__getattribute__('tags') try:
except AttributeError: return self.__getattribute__('tags')
raise TypeError('QuotaImageTagsProxy has no tags.') except AttributeError:
return getattr(tags, name) return None
return getattr(self.tags, name)
class ImageMemberFactoryProxy(glance.domain.proxy.ImageMembershipFactory): class ImageMemberFactoryProxy(glance.domain.proxy.ImageMembershipFactory):

View File

@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import copy
import uuid import uuid
import mock import mock
@ -596,15 +597,24 @@ class TestQuotaImageTagsProxy(test_utils.BaseTestCase):
items.remove(item) items.remove(item)
self.assertEqual(0, len(items)) self.assertEqual(0, len(items))
def test_tags_attr_exception(self): def test_tags_attr_no_loop(self):
proxy = glance.quota.QuotaImageTagsProxy(None) proxy = glance.quota.QuotaImageTagsProxy(None)
self.assertRaises(AttributeError, lambda: proxy.foo) self.assertEqual(set([]), proxy.tags)
# Remove tags to cause the object to be broken. If tags def test_tags_deepcopy(self):
# is not there and we weren't raising TypeError, we'd proxy = glance.quota.QuotaImageTagsProxy(set(['a', 'b']))
# get an infinite loop when calling 'proxy.foo'. proxy_copy = copy.deepcopy(proxy)
self.assertEqual(set(['a', 'b']), proxy_copy.tags)
self.assertIn('a', proxy_copy)
# remove is a found via __getattr__
proxy_copy.remove('a')
self.assertNotIn('a', proxy_copy)
def test_tags_delete(self):
proxy = glance.quota.QuotaImageTagsProxy(set(['a', 'b']))
self.assertEqual(set(['a', 'b']), proxy.tags)
del proxy.tags del proxy.tags
self.assertRaises(TypeError, lambda: proxy.foo) self.assertIsNone(proxy.tags)
class TestImageMemberQuotas(test_utils.BaseTestCase): class TestImageMemberQuotas(test_utils.BaseTestCase):