Draft: s3acl decorator
Current swift3 has a couple of ways for acl handling. To simplify test code, this introduces s3acl decorator which suggests which way the test method will check. In default, swift3 do the native acl testing. If needed, we can add the s3acl decorater and an argument like as follows: No decorator -> test only native acl @s3acl -> test both of native acl and s3acl @s3acl(s3acl_only=True) -> test only s3acl This is still a draft version and most of tests should be fixed. TODO: - keeping sysmeta for s3acl when the test override backend swift by register. Change-Id: I17a423b5c655a670a4304d47ff927df28ac0a37f
This commit is contained in:
parent
8e1e7152f9
commit
7fd58f9bfd
18
swift3/test/unit/exceptions.py
Normal file
18
swift3/test/unit/exceptions.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
class NotMethodException(Exception):
|
||||
pass
|
@ -21,6 +21,7 @@ from swift.common.swob import Request
|
||||
|
||||
from swift3.test.unit import Swift3TestCase
|
||||
from swift3.etree import Element, SubElement, fromstring, tostring
|
||||
from swift3.test.unit.test_s3_acl import s3acl
|
||||
|
||||
|
||||
class TestSwift3Bucket(Swift3TestCase):
|
||||
@ -211,6 +212,7 @@ class TestSwift3Bucket(Swift3TestCase):
|
||||
code = self._test_method_error('PUT', '/bucket', swob.HTTPServerError)
|
||||
self.assertEquals(code, 'InternalError')
|
||||
|
||||
@s3acl
|
||||
def test_bucket_PUT(self):
|
||||
req = Request.blank('/bucket',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
@ -219,6 +221,7 @@ class TestSwift3Bucket(Swift3TestCase):
|
||||
self.assertEquals(status.split()[0], '200')
|
||||
self.assertEquals(headers['Location'], '/bucket')
|
||||
|
||||
@s3acl
|
||||
def test_bucket_PUT_with_location(self):
|
||||
elem = Element('CreateBucketConfiguration')
|
||||
SubElement(elem, 'LocationConstraint').text = 'US'
|
||||
@ -242,6 +245,7 @@ class TestSwift3Bucket(Swift3TestCase):
|
||||
self.assertTrue('X-Container-Read' in headers)
|
||||
self.assertEquals(headers.get('X-Container-Read'), '.r:*,.rlistings')
|
||||
|
||||
@s3acl
|
||||
def test_bucket_PUT_with_location_error(self):
|
||||
elem = Element('CreateBucketConfiguration')
|
||||
SubElement(elem, 'LocationConstraint').text = 'XXX'
|
||||
@ -255,6 +259,7 @@ class TestSwift3Bucket(Swift3TestCase):
|
||||
self.assertEquals(self._get_error_code(body),
|
||||
'InvalidLocationConstraint')
|
||||
|
||||
@s3acl
|
||||
def test_bucket_PUT_with_location_invalid_xml(self):
|
||||
req = Request.blank('/bucket',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
@ -277,6 +282,7 @@ class TestSwift3Bucket(Swift3TestCase):
|
||||
swob.HTTPServerError)
|
||||
self.assertEquals(code, 'InternalError')
|
||||
|
||||
@s3acl
|
||||
def test_bucket_DELETE(self):
|
||||
req = Request.blank('/bucket',
|
||||
environ={'REQUEST_METHOD': 'DELETE'},
|
||||
|
@ -21,6 +21,7 @@ from swift.common import swob
|
||||
from swift.common.swob import Request
|
||||
|
||||
from swift3.test.unit import Swift3TestCase
|
||||
from swift3.test.unit.test_s3_acl import s3acl
|
||||
|
||||
|
||||
class TestSwift3Obj(Swift3TestCase):
|
||||
@ -119,9 +120,11 @@ class TestSwift3Obj(Swift3TestCase):
|
||||
swob.HTTPServiceUnavailable)
|
||||
self.assertEquals(code, 'InternalError')
|
||||
|
||||
@s3acl
|
||||
def test_object_GET(self):
|
||||
self._test_object_GETorHEAD('GET')
|
||||
|
||||
@s3acl
|
||||
def test_object_GET_Range(self):
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
@ -138,6 +141,7 @@ class TestSwift3Obj(Swift3TestCase):
|
||||
swob.HTTPRequestedRangeNotSatisfiable)
|
||||
self.assertEquals(code, 'InvalidRange')
|
||||
|
||||
@s3acl
|
||||
def test_object_GET_Response(self):
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': 'GET',
|
||||
@ -197,6 +201,7 @@ class TestSwift3Obj(Swift3TestCase):
|
||||
swob.HTTPServiceUnavailable)
|
||||
self.assertEquals(code, 'InternalError')
|
||||
|
||||
@s3acl
|
||||
def test_object_PUT(self):
|
||||
etag = self.response_headers['etag']
|
||||
content_md5 = etag.decode('hex').encode('base64').strip()
|
||||
@ -264,6 +269,7 @@ class TestSwift3Obj(Swift3TestCase):
|
||||
swob.HTTPServiceUnavailable)
|
||||
self.assertEquals(code, 'InternalError')
|
||||
|
||||
@s3acl
|
||||
def test_object_DELETE(self):
|
||||
req = Request.blank('/bucket/object',
|
||||
environ={'REQUEST_METHOD': 'DELETE'},
|
||||
|
@ -15,6 +15,10 @@
|
||||
|
||||
import unittest
|
||||
import simplejson as json
|
||||
import functools
|
||||
import sys
|
||||
import traceback
|
||||
from mock import patch, MagicMock
|
||||
|
||||
from swift.common import swob
|
||||
from swift.common.swob import Request
|
||||
@ -24,10 +28,50 @@ from swift3.subresource import ACL, ACLPrivate, User, encode_acl, \
|
||||
AuthenticatedUsers, AllUsers, Owner, Grant, PERMISSIONS
|
||||
from swift3.test.unit.test_middleware import Swift3TestCase
|
||||
from swift3.cfg import CONF
|
||||
from swift3.test.unit.exceptions import NotMethodException
|
||||
|
||||
XMLNS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
|
||||
|
||||
|
||||
def s3acl(func=None, s3acl_only=False):
|
||||
"""
|
||||
NOTE: s3acl decorator needs an instance of swift3 testing framework.
|
||||
(i.e. An instance for first argument is necessary)
|
||||
"""
|
||||
if func is None:
|
||||
return functools.partial(s3acl, s3acl_only=s3acl_only)
|
||||
|
||||
@functools.wraps(func)
|
||||
def s3acl_decorator(*args, **kwargs):
|
||||
if not args and not kwargs:
|
||||
raise NotMethodException('Use s3acl decorator for a method')
|
||||
|
||||
def call_func(failing_point=''):
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
except AssertionError:
|
||||
# Make traceback message to clarify the assertion
|
||||
exc_type, exc_instance, exc_traceback = sys.exc_info()
|
||||
formatted_traceback = ''.join(traceback.format_tb(
|
||||
exc_traceback))
|
||||
message = '\n%s\n%s:\n%s' % (formatted_traceback,
|
||||
exc_type.__name__,
|
||||
exc_instance.message)
|
||||
message += failing_point
|
||||
raise exc_type(message)
|
||||
|
||||
if not s3acl_only:
|
||||
call_func()
|
||||
|
||||
with patch('swift3.cfg.CONF.s3_acl', True):
|
||||
owner = Owner('test:tester', 'test:tester')
|
||||
instance = args[0]
|
||||
generate_s3acl_environ('test', instance.swift, owner)
|
||||
call_func(' (fail at s3_acl)')
|
||||
|
||||
return s3acl_decorator
|
||||
|
||||
|
||||
def _gen_test_headers(owner, grants=[], resource='container'):
|
||||
if not grants:
|
||||
grants = [Grant(User('test:tester'), 'FULL_CONTROL')]
|
||||
@ -607,5 +651,41 @@ class TestSwift3S3Acl(Swift3TestCase):
|
||||
self._test_object_copy('test:other', 'READ')
|
||||
self.assertEquals(status.split()[0], '403')
|
||||
|
||||
def test_s3acl_decorator(self):
|
||||
@s3acl
|
||||
def non_class_s3acl_error():
|
||||
raise
|
||||
|
||||
class FakeClass(object):
|
||||
def __init__(self):
|
||||
self.swift = MagicMock()
|
||||
|
||||
@s3acl
|
||||
def s3acl_error(self):
|
||||
raise
|
||||
|
||||
@s3acl
|
||||
def s3acl_assert_fail(self):
|
||||
assert False
|
||||
|
||||
@s3acl(s3acl_only=True)
|
||||
def s3acl_s3only_error(self):
|
||||
if CONF.s3_acl:
|
||||
raise
|
||||
|
||||
@s3acl(s3acl_only=True)
|
||||
def s3acl_s3only_no_error(self):
|
||||
if not CONF.s3_acl:
|
||||
raise
|
||||
|
||||
fake_class = FakeClass()
|
||||
|
||||
self.assertRaises(NotMethodException, non_class_s3acl_error)
|
||||
self.assertRaises(TypeError, fake_class.s3acl_error)
|
||||
self.assertRaises(AssertionError, fake_class.s3acl_assert_fail)
|
||||
self.assertRaises(TypeError, fake_class.s3acl_s3only_error)
|
||||
self.assertEquals(None, fake_class.s3acl_s3only_no_error())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user