Rebase to Swift 2.2.1 release
NOTE: The previous rebase was to Swift 2.1.0 and this rebase is to Swift 2.2.1 (first release in kilo series). There was a Swift 2.2.0 (last release in juno series) release in between. Change-Id: Ibce2e299935e165db89a91a6fe8c4c5c027db098 Signed-off-by: Prashanth Pai <ppai@redhat.com>
This commit is contained in:
parent
486668b880
commit
aa1bfb3e67
@ -1,3 +1,7 @@
|
|||||||
|
# The order of packages is significant, because pip processes them in the order
|
||||||
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
|
# process, which may cause wedges in the gate later.
|
||||||
|
|
||||||
dnspython>=1.9.4
|
dnspython>=1.9.4
|
||||||
eventlet>=0.9.15
|
eventlet>=0.9.15
|
||||||
greenlet>=0.3.1
|
greenlet>=0.3.1
|
||||||
|
@ -43,6 +43,6 @@ class PkgInfo(object):
|
|||||||
|
|
||||||
|
|
||||||
# Change the Package version here
|
# Change the Package version here
|
||||||
_pkginfo = PkgInfo('2.1.0', '0', 'swiftonfile', False)
|
_pkginfo = PkgInfo('2.2.1', '0', 'swiftonfile', False)
|
||||||
__version__ = _pkginfo.pretty_version
|
__version__ = _pkginfo.pretty_version
|
||||||
__canonical_version__ = _pkginfo.canonical_version
|
__canonical_version__ = _pkginfo.canonical_version
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
# The order of packages is significant, because pip processes them in the order
|
||||||
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
|
# process, which may cause wedges in the gate later.
|
||||||
|
|
||||||
# Hacking already pins down pep8, pyflakes and flake8
|
# Hacking already pins down pep8, pyflakes and flake8
|
||||||
hacking>=0.8.0,<0.9
|
hacking>=0.8.0,<0.9
|
||||||
coverage
|
coverage
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import pickle
|
import pickle
|
||||||
@ -30,6 +31,7 @@ from contextlib import closing
|
|||||||
from gzip import GzipFile
|
from gzip import GzipFile
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
|
from swift.common.middleware.memcache import MemcacheMiddleware
|
||||||
|
|
||||||
from test import get_config
|
from test import get_config
|
||||||
from test.functional.swift_test_client import Account, Connection, \
|
from test.functional.swift_test_client import Account, Connection, \
|
||||||
@ -40,15 +42,12 @@ from test.functional.swift_test_client import Account, Connection, \
|
|||||||
from test.unit import debug_logger, FakeMemcache
|
from test.unit import debug_logger, FakeMemcache
|
||||||
|
|
||||||
from swift.common import constraints, utils, ring, storage_policy
|
from swift.common import constraints, utils, ring, storage_policy
|
||||||
from swift.common.wsgi import monkey_patch_mimetools
|
from swift.common.ring import Ring
|
||||||
from swift.common.middleware import catch_errors, gatekeeper, healthcheck, \
|
from swift.common.wsgi import monkey_patch_mimetools, loadapp
|
||||||
proxy_logging, container_sync, bulk, tempurl, slo, dlo, ratelimit, \
|
|
||||||
tempauth, container_quotas, account_quotas
|
|
||||||
from swift.common.utils import config_true_value
|
from swift.common.utils import config_true_value
|
||||||
from swift.proxy import server as proxy_server
|
|
||||||
from swift.account import server as account_server
|
from swift.account import server as account_server
|
||||||
from swift.container import server as container_server
|
from swift.container import server as container_server
|
||||||
from swift.obj import server as object_server
|
from swift.obj import server as object_server, mem_server as mem_object_server
|
||||||
import swift.proxy.controllers.obj
|
import swift.proxy.controllers.obj
|
||||||
|
|
||||||
# In order to get the proper blocking behavior of sockets without using
|
# In order to get the proper blocking behavior of sockets without using
|
||||||
@ -83,10 +82,13 @@ normalized_urls = None
|
|||||||
# If no config was read, we will fall back to old school env vars
|
# If no config was read, we will fall back to old school env vars
|
||||||
swift_test_auth_version = None
|
swift_test_auth_version = None
|
||||||
swift_test_auth = os.environ.get('SWIFT_TEST_AUTH')
|
swift_test_auth = os.environ.get('SWIFT_TEST_AUTH')
|
||||||
swift_test_user = [os.environ.get('SWIFT_TEST_USER'), None, None]
|
swift_test_user = [os.environ.get('SWIFT_TEST_USER'), None, None, '']
|
||||||
swift_test_key = [os.environ.get('SWIFT_TEST_KEY'), None, None]
|
swift_test_key = [os.environ.get('SWIFT_TEST_KEY'), None, None, '']
|
||||||
swift_test_tenant = ['', '', '']
|
swift_test_tenant = ['', '', '', '']
|
||||||
swift_test_perm = ['', '', '']
|
swift_test_perm = ['', '', '', '']
|
||||||
|
swift_test_domain = ['', '', '', '']
|
||||||
|
swift_test_user_id = ['', '', '', '']
|
||||||
|
swift_test_tenant_id = ['', '', '', '']
|
||||||
|
|
||||||
skip, skip2, skip3 = False, False, False
|
skip, skip2, skip3 = False, False, False
|
||||||
|
|
||||||
@ -100,25 +102,16 @@ in_process = False
|
|||||||
_testdir = _test_servers = _test_sockets = _test_coros = None
|
_testdir = _test_servers = _test_sockets = _test_coros = None
|
||||||
|
|
||||||
|
|
||||||
class FakeMemcacheMiddleware(object):
|
class FakeMemcacheMiddleware(MemcacheMiddleware):
|
||||||
"""
|
"""
|
||||||
Caching middleware that fakes out caching in swift.
|
Caching middleware that fakes out caching in swift if memcached
|
||||||
|
does not appear to be running.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, app, conf):
|
def __init__(self, app, conf):
|
||||||
self.app = app
|
super(FakeMemcacheMiddleware, self).__init__(app, conf)
|
||||||
self.memcache = FakeMemcache()
|
self.memcache = FakeMemcache()
|
||||||
|
|
||||||
def __call__(self, env, start_response):
|
|
||||||
env['swift.cache'] = self.memcache
|
|
||||||
return self.app(env, start_response)
|
|
||||||
|
|
||||||
|
|
||||||
def fake_memcache_filter_factory(conf):
|
|
||||||
def filter_app(app):
|
|
||||||
return FakeMemcacheMiddleware(app, conf)
|
|
||||||
return filter_app
|
|
||||||
|
|
||||||
|
|
||||||
# swift.conf contents for in-process functional test runs
|
# swift.conf contents for in-process functional test runs
|
||||||
functests_swift_conf = '''
|
functests_swift_conf = '''
|
||||||
@ -133,6 +126,16 @@ max_file_size = %d
|
|||||||
|
|
||||||
def in_process_setup(the_object_server=object_server):
|
def in_process_setup(the_object_server=object_server):
|
||||||
print >>sys.stderr, 'IN-PROCESS SERVERS IN USE FOR FUNCTIONAL TESTS'
|
print >>sys.stderr, 'IN-PROCESS SERVERS IN USE FOR FUNCTIONAL TESTS'
|
||||||
|
print >>sys.stderr, 'Using object_server: %s' % the_object_server.__name__
|
||||||
|
_dir = os.path.normpath(os.path.join(os.path.abspath(__file__),
|
||||||
|
os.pardir, os.pardir, os.pardir))
|
||||||
|
proxy_conf = os.path.join(_dir, 'etc', 'proxy-server.conf-sample')
|
||||||
|
if os.path.exists(proxy_conf):
|
||||||
|
print >>sys.stderr, 'Using proxy-server config from %s' % proxy_conf
|
||||||
|
|
||||||
|
else:
|
||||||
|
print >>sys.stderr, 'Failed to find conf file %s' % proxy_conf
|
||||||
|
return
|
||||||
|
|
||||||
monkey_patch_mimetools()
|
monkey_patch_mimetools()
|
||||||
|
|
||||||
@ -159,7 +162,9 @@ def in_process_setup(the_object_server=object_server):
|
|||||||
if constraints.SWIFT_CONSTRAINTS_LOADED:
|
if constraints.SWIFT_CONSTRAINTS_LOADED:
|
||||||
# Use the swift constraints that are loaded for the test framework
|
# Use the swift constraints that are loaded for the test framework
|
||||||
# configuration
|
# configuration
|
||||||
config.update(constraints.EFFECTIVE_CONSTRAINTS)
|
_c = dict((k, str(v))
|
||||||
|
for k, v in constraints.EFFECTIVE_CONSTRAINTS.items())
|
||||||
|
config.update(_c)
|
||||||
else:
|
else:
|
||||||
# In-process swift constraints were not loaded, somethings wrong
|
# In-process swift constraints were not loaded, somethings wrong
|
||||||
raise SkipTest
|
raise SkipTest
|
||||||
@ -180,12 +185,9 @@ def in_process_setup(the_object_server=object_server):
|
|||||||
'devices': _testdir,
|
'devices': _testdir,
|
||||||
'swift_dir': _testdir,
|
'swift_dir': _testdir,
|
||||||
'mount_check': 'false',
|
'mount_check': 'false',
|
||||||
'client_timeout': 4,
|
'client_timeout': '4',
|
||||||
'allow_account_management': 'true',
|
'allow_account_management': 'true',
|
||||||
'account_autocreate': 'true',
|
'account_autocreate': 'true',
|
||||||
'allowed_headers':
|
|
||||||
'content-disposition, content-encoding, x-delete-at,'
|
|
||||||
' x-object-manifest, x-static-large-object',
|
|
||||||
'allow_versions': 'True',
|
'allow_versions': 'True',
|
||||||
# Below are values used by the functional test framework, as well as
|
# Below are values used by the functional test framework, as well as
|
||||||
# by the various in-process swift servers
|
# by the various in-process swift servers
|
||||||
@ -257,7 +259,6 @@ def in_process_setup(the_object_server=object_server):
|
|||||||
# Default to only 4 seconds for in-process functional test runs
|
# Default to only 4 seconds for in-process functional test runs
|
||||||
eventlet.wsgi.WRITE_TIMEOUT = 4
|
eventlet.wsgi.WRITE_TIMEOUT = 4
|
||||||
|
|
||||||
prosrv = proxy_server.Application(config, logger=debug_logger('proxy'))
|
|
||||||
acc1srv = account_server.AccountController(
|
acc1srv = account_server.AccountController(
|
||||||
config, logger=debug_logger('acct1'))
|
config, logger=debug_logger('acct1'))
|
||||||
acc2srv = account_server.AccountController(
|
acc2srv = account_server.AccountController(
|
||||||
@ -270,35 +271,16 @@ def in_process_setup(the_object_server=object_server):
|
|||||||
config, logger=debug_logger('obj1'))
|
config, logger=debug_logger('obj1'))
|
||||||
obj2srv = the_object_server.ObjectController(
|
obj2srv = the_object_server.ObjectController(
|
||||||
config, logger=debug_logger('obj2'))
|
config, logger=debug_logger('obj2'))
|
||||||
global _test_servers
|
|
||||||
_test_servers = \
|
|
||||||
(prosrv, acc1srv, acc2srv, con1srv, con2srv, obj1srv, obj2srv)
|
|
||||||
|
|
||||||
pipeline = [
|
logger = debug_logger('proxy')
|
||||||
catch_errors.filter_factory,
|
|
||||||
gatekeeper.filter_factory,
|
def get_logger(name, *args, **kwargs):
|
||||||
healthcheck.filter_factory,
|
return logger
|
||||||
proxy_logging.filter_factory,
|
|
||||||
fake_memcache_filter_factory,
|
with mock.patch('swift.common.utils.get_logger', get_logger):
|
||||||
container_sync.filter_factory,
|
with mock.patch('swift.common.middleware.memcache.MemcacheMiddleware',
|
||||||
bulk.filter_factory,
|
FakeMemcacheMiddleware):
|
||||||
tempurl.filter_factory,
|
app = loadapp(proxy_conf, global_conf=config)
|
||||||
slo.filter_factory,
|
|
||||||
dlo.filter_factory,
|
|
||||||
ratelimit.filter_factory,
|
|
||||||
tempauth.filter_factory,
|
|
||||||
container_quotas.filter_factory,
|
|
||||||
account_quotas.filter_factory,
|
|
||||||
proxy_logging.filter_factory,
|
|
||||||
]
|
|
||||||
app = prosrv
|
|
||||||
import mock
|
|
||||||
for filter_factory in reversed(pipeline):
|
|
||||||
app_filter = filter_factory(config)
|
|
||||||
with mock.patch('swift.common.utils') as mock_utils:
|
|
||||||
mock_utils.get_logger.return_value = None
|
|
||||||
app = app_filter(app)
|
|
||||||
app.logger = prosrv.logger
|
|
||||||
|
|
||||||
nl = utils.NullLogger()
|
nl = utils.NullLogger()
|
||||||
prospa = eventlet.spawn(eventlet.wsgi.server, prolis, app, nl)
|
prospa = eventlet.spawn(eventlet.wsgi.server, prolis, app, nl)
|
||||||
@ -315,7 +297,8 @@ def in_process_setup(the_object_server=object_server):
|
|||||||
# Create accounts "test" and "test2"
|
# Create accounts "test" and "test2"
|
||||||
def create_account(act):
|
def create_account(act):
|
||||||
ts = utils.normalize_timestamp(time())
|
ts = utils.normalize_timestamp(time())
|
||||||
partition, nodes = prosrv.account_ring.get_nodes(act)
|
account_ring = Ring(_testdir, ring_name='account')
|
||||||
|
partition, nodes = account_ring.get_nodes(act)
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
# Note: we are just using the http_connect method in the object
|
# Note: we are just using the http_connect method in the object
|
||||||
# controller here to talk to the account server nodes.
|
# controller here to talk to the account server nodes.
|
||||||
@ -348,7 +331,13 @@ def get_cluster_info():
|
|||||||
# test.conf data
|
# test.conf data
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
eff_constraints.update(cluster_info.get('swift', {}))
|
try:
|
||||||
|
eff_constraints.update(cluster_info['swift'])
|
||||||
|
except KeyError:
|
||||||
|
# Most likely the swift cluster has "expose_info = false" set
|
||||||
|
# in its proxy-server.conf file, so we'll just do the best we
|
||||||
|
# can.
|
||||||
|
print >>sys.stderr, "** Swift Cluster not exposing /info **"
|
||||||
|
|
||||||
# Finally, we'll allow any constraint present in the swift-constraints
|
# Finally, we'll allow any constraint present in the swift-constraints
|
||||||
# section of test.conf to override everything. Note that only those
|
# section of test.conf to override everything. Note that only those
|
||||||
@ -402,7 +391,10 @@ def setup_package():
|
|||||||
config.update(get_config('func_test'))
|
config.update(get_config('func_test'))
|
||||||
|
|
||||||
if in_process:
|
if in_process:
|
||||||
in_process_setup()
|
in_mem_obj_env = os.environ.get('SWIFT_TEST_IN_MEMORY_OBJ')
|
||||||
|
in_mem_obj = utils.config_true_value(in_mem_obj_env)
|
||||||
|
in_process_setup(the_object_server=(
|
||||||
|
mem_object_server if in_mem_obj else object_server))
|
||||||
|
|
||||||
global web_front_end
|
global web_front_end
|
||||||
web_front_end = config.get('web_front_end', 'integral')
|
web_front_end = config.get('web_front_end', 'integral')
|
||||||
@ -422,6 +414,7 @@ def setup_package():
|
|||||||
global swift_test_key
|
global swift_test_key
|
||||||
global swift_test_tenant
|
global swift_test_tenant
|
||||||
global swift_test_perm
|
global swift_test_perm
|
||||||
|
global swift_test_domain
|
||||||
|
|
||||||
if config:
|
if config:
|
||||||
swift_test_auth_version = str(config.get('auth_version', '1'))
|
swift_test_auth_version = str(config.get('auth_version', '1'))
|
||||||
@ -478,8 +471,13 @@ def setup_package():
|
|||||||
swift_test_user[2] = config['username3']
|
swift_test_user[2] = config['username3']
|
||||||
swift_test_tenant[2] = config['account']
|
swift_test_tenant[2] = config['account']
|
||||||
swift_test_key[2] = config['password3']
|
swift_test_key[2] = config['password3']
|
||||||
|
if 'username4' in config:
|
||||||
|
swift_test_user[3] = config['username4']
|
||||||
|
swift_test_tenant[3] = config['account4']
|
||||||
|
swift_test_key[3] = config['password4']
|
||||||
|
swift_test_domain[3] = config['domain4']
|
||||||
|
|
||||||
for _ in range(3):
|
for _ in range(4):
|
||||||
swift_test_perm[_] = swift_test_tenant[_] + ':' \
|
swift_test_perm[_] = swift_test_tenant[_] + ':' \
|
||||||
+ swift_test_user[_]
|
+ swift_test_user[_]
|
||||||
|
|
||||||
@ -501,6 +499,15 @@ def setup_package():
|
|||||||
print >>sys.stderr, \
|
print >>sys.stderr, \
|
||||||
'SKIPPING THIRD ACCOUNT FUNCTIONAL TESTS DUE TO NO CONFIG FOR THEM'
|
'SKIPPING THIRD ACCOUNT FUNCTIONAL TESTS DUE TO NO CONFIG FOR THEM'
|
||||||
|
|
||||||
|
global skip_if_not_v3
|
||||||
|
skip_if_not_v3 = (swift_test_auth_version != '3'
|
||||||
|
or not all([not skip,
|
||||||
|
swift_test_user[3],
|
||||||
|
swift_test_key[3]]))
|
||||||
|
if not skip and skip_if_not_v3:
|
||||||
|
print >>sys.stderr, \
|
||||||
|
'SKIPPING FUNCTIONAL TESTS SPECIFIC TO AUTH VERSION 3'
|
||||||
|
|
||||||
get_cluster_info()
|
get_cluster_info()
|
||||||
|
|
||||||
|
|
||||||
@ -539,10 +546,10 @@ class InternalServerError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
url = [None, None, None]
|
url = [None, None, None, None]
|
||||||
token = [None, None, None]
|
token = [None, None, None, None]
|
||||||
parsed = [None, None, None]
|
parsed = [None, None, None, None]
|
||||||
conn = [None, None, None]
|
conn = [None, None, None, None]
|
||||||
|
|
||||||
|
|
||||||
def connection(url):
|
def connection(url):
|
||||||
@ -569,7 +576,8 @@ def retry(func, *args, **kwargs):
|
|||||||
|
|
||||||
# access our own account by default
|
# access our own account by default
|
||||||
url_account = kwargs.pop('url_account', use_account + 1) - 1
|
url_account = kwargs.pop('url_account', use_account + 1) - 1
|
||||||
|
os_options = {'user_domain_name': swift_test_domain[use_account],
|
||||||
|
'project_domain_name': swift_test_domain[use_account]}
|
||||||
while attempts <= retries:
|
while attempts <= retries:
|
||||||
attempts += 1
|
attempts += 1
|
||||||
try:
|
try:
|
||||||
@ -580,7 +588,7 @@ def retry(func, *args, **kwargs):
|
|||||||
snet=False,
|
snet=False,
|
||||||
tenant_name=swift_test_tenant[use_account],
|
tenant_name=swift_test_tenant[use_account],
|
||||||
auth_version=swift_test_auth_version,
|
auth_version=swift_test_auth_version,
|
||||||
os_options={})
|
os_options=os_options)
|
||||||
parsed[use_account] = conn[use_account] = None
|
parsed[use_account] = conn[use_account] = None
|
||||||
if not parsed[use_account] or not conn[use_account]:
|
if not parsed[use_account] or not conn[use_account]:
|
||||||
parsed[use_account], conn[use_account] = \
|
parsed[use_account], conn[use_account] = \
|
||||||
|
@ -174,8 +174,10 @@ class Connection(object):
|
|||||||
# unicode and this would cause troubles when doing
|
# unicode and this would cause troubles when doing
|
||||||
# no_safe_quote query.
|
# no_safe_quote query.
|
||||||
self.storage_url = str('/%s/%s' % (x[3], x[4]))
|
self.storage_url = str('/%s/%s' % (x[3], x[4]))
|
||||||
|
self.account_name = str(x[4])
|
||||||
|
self.auth_user = auth_user
|
||||||
self.storage_token = storage_token
|
self.storage_token = storage_token
|
||||||
|
self.user_acl = '%s:%s' % (self.account, self.username)
|
||||||
|
|
||||||
self.http_connect()
|
self.http_connect()
|
||||||
return self.storage_url, self.storage_token
|
return self.storage_url, self.storage_token
|
||||||
@ -664,6 +666,32 @@ class File(Base):
|
|||||||
return self.conn.make_request('COPY', self.path, hdrs=headers,
|
return self.conn.make_request('COPY', self.path, hdrs=headers,
|
||||||
parms=parms) == 201
|
parms=parms) == 201
|
||||||
|
|
||||||
|
def copy_account(self, dest_account, dest_cont, dest_file,
|
||||||
|
hdrs=None, parms=None, cfg=None):
|
||||||
|
if hdrs is None:
|
||||||
|
hdrs = {}
|
||||||
|
if parms is None:
|
||||||
|
parms = {}
|
||||||
|
if cfg is None:
|
||||||
|
cfg = {}
|
||||||
|
if 'destination' in cfg:
|
||||||
|
headers = {'Destination': cfg['destination']}
|
||||||
|
elif cfg.get('no_destination'):
|
||||||
|
headers = {}
|
||||||
|
else:
|
||||||
|
headers = {'Destination-Account': dest_account,
|
||||||
|
'Destination': '%s/%s' % (dest_cont, dest_file)}
|
||||||
|
headers.update(hdrs)
|
||||||
|
|
||||||
|
if 'Destination-Account' in headers:
|
||||||
|
headers['Destination-Account'] = \
|
||||||
|
urllib.quote(headers['Destination-Account'])
|
||||||
|
if 'Destination' in headers:
|
||||||
|
headers['Destination'] = urllib.quote(headers['Destination'])
|
||||||
|
|
||||||
|
return self.conn.make_request('COPY', self.path, hdrs=headers,
|
||||||
|
parms=parms) == 201
|
||||||
|
|
||||||
def delete(self, hdrs=None, parms=None):
|
def delete(self, hdrs=None, parms=None):
|
||||||
if hdrs is None:
|
if hdrs is None:
|
||||||
hdrs = {}
|
hdrs = {}
|
||||||
|
@ -777,6 +777,21 @@ class TestAccount(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
|
|
||||||
|
def test_bad_metadata2(self):
|
||||||
|
if tf.skip:
|
||||||
|
raise SkipTest
|
||||||
|
|
||||||
|
def post(url, token, parsed, conn, extra_headers):
|
||||||
|
headers = {'X-Auth-Token': token}
|
||||||
|
headers.update(extra_headers)
|
||||||
|
conn.request('POST', parsed.path, '', headers)
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
# TODO: Find the test that adds these and remove them.
|
||||||
|
headers = {'x-remove-account-meta-temp-url-key': 'remove',
|
||||||
|
'x-remove-account-meta-temp-url-key-2': 'remove'}
|
||||||
|
resp = retry(post, headers)
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
for x in xrange(self.max_meta_count):
|
for x in xrange(self.max_meta_count):
|
||||||
headers['X-Account-Meta-%d' % x] = 'v'
|
headers['X-Account-Meta-%d' % x] = 'v'
|
||||||
@ -790,6 +805,16 @@ class TestAccount(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
|
|
||||||
|
def test_bad_metadata3(self):
|
||||||
|
if tf.skip:
|
||||||
|
raise SkipTest
|
||||||
|
|
||||||
|
def post(url, token, parsed, conn, extra_headers):
|
||||||
|
headers = {'X-Auth-Token': token}
|
||||||
|
headers.update(extra_headers)
|
||||||
|
conn.request('POST', parsed.path, '', headers)
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
header_value = 'k' * self.max_meta_value_length
|
header_value = 'k' * self.max_meta_value_length
|
||||||
size = 0
|
size = 0
|
||||||
@ -812,5 +837,33 @@ class TestAccount(unittest.TestCase):
|
|||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAccountInNonDefaultDomain(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
if tf.skip or tf.skip2 or tf.skip_if_not_v3:
|
||||||
|
raise SkipTest('AUTH VERSION 3 SPECIFIC TEST')
|
||||||
|
|
||||||
|
def test_project_domain_id_header(self):
|
||||||
|
# make sure account exists (assumes account auto create)
|
||||||
|
def post(url, token, parsed, conn):
|
||||||
|
conn.request('POST', parsed.path, '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(post, use_account=4)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
# account in non-default domain should have a project domain id
|
||||||
|
def head(url, token, parsed, conn):
|
||||||
|
conn.request('HEAD', parsed.path, '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(head, use_account=4)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
self.assertTrue('X-Account-Project-Domain-Id' in resp.headers)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -404,6 +404,16 @@ class TestContainer(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
|
|
||||||
|
def test_POST_bad_metadata2(self):
|
||||||
|
if tf.skip:
|
||||||
|
raise SkipTest
|
||||||
|
|
||||||
|
def post(url, token, parsed, conn, extra_headers):
|
||||||
|
headers = {'X-Auth-Token': token}
|
||||||
|
headers.update(extra_headers)
|
||||||
|
conn.request('POST', parsed.path + '/' + self.name, '', headers)
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
for x in xrange(self.max_meta_count):
|
for x in xrange(self.max_meta_count):
|
||||||
headers['X-Container-Meta-%d' % x] = 'v'
|
headers['X-Container-Meta-%d' % x] = 'v'
|
||||||
@ -417,6 +427,16 @@ class TestContainer(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
|
|
||||||
|
def test_POST_bad_metadata3(self):
|
||||||
|
if tf.skip:
|
||||||
|
raise SkipTest
|
||||||
|
|
||||||
|
def post(url, token, parsed, conn, extra_headers):
|
||||||
|
headers = {'X-Auth-Token': token}
|
||||||
|
headers.update(extra_headers)
|
||||||
|
conn.request('POST', parsed.path + '/' + self.name, '', headers)
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
header_value = 'k' * self.max_meta_value_length
|
header_value = 'k' * self.max_meta_value_length
|
||||||
size = 0
|
size = 0
|
||||||
@ -1419,7 +1439,7 @@ class TestContainer(unittest.TestCase):
|
|||||||
self.assertEquals(headers.get('x-storage-policy'),
|
self.assertEquals(headers.get('x-storage-policy'),
|
||||||
policy['name'])
|
policy['name'])
|
||||||
|
|
||||||
# and test recreate with-out specifiying Storage Policy
|
# and test recreate with-out specifying Storage Policy
|
||||||
resp = retry(put)
|
resp = retry(put)
|
||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 202)
|
self.assertEqual(resp.status, 202)
|
||||||
@ -1514,5 +1534,179 @@ class TestContainer(unittest.TestCase):
|
|||||||
policy['name'])
|
policy['name'])
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTestContainerACLs(unittest.TestCase):
|
||||||
|
# subclasses can change the account in which container
|
||||||
|
# is created/deleted by setUp/tearDown
|
||||||
|
account = 1
|
||||||
|
|
||||||
|
def _get_account(self, url, token, parsed, conn):
|
||||||
|
return parsed.path
|
||||||
|
|
||||||
|
def _get_tenant_id(self, url, token, parsed, conn):
|
||||||
|
account = parsed.path
|
||||||
|
return account.replace('/v1/AUTH_', '', 1)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
if tf.skip or tf.skip2 or tf.skip_if_not_v3:
|
||||||
|
raise SkipTest('AUTH VERSION 3 SPECIFIC TEST')
|
||||||
|
self.name = uuid4().hex
|
||||||
|
|
||||||
|
def put(url, token, parsed, conn):
|
||||||
|
conn.request('PUT', parsed.path + '/' + self.name, '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(put, use_account=self.account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 201)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
if tf.skip or tf.skip2 or tf.skip_if_not_v3:
|
||||||
|
raise SkipTest
|
||||||
|
|
||||||
|
def get(url, token, parsed, conn):
|
||||||
|
conn.request('GET', parsed.path + '/' + self.name + '?format=json',
|
||||||
|
'', {'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
def delete(url, token, parsed, conn, obj):
|
||||||
|
conn.request('DELETE',
|
||||||
|
'/'.join([parsed.path, self.name, obj['name']]), '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
resp = retry(get, use_account=self.account)
|
||||||
|
body = resp.read()
|
||||||
|
self.assert_(resp.status // 100 == 2, resp.status)
|
||||||
|
objs = json.loads(body)
|
||||||
|
if not objs:
|
||||||
|
break
|
||||||
|
for obj in objs:
|
||||||
|
resp = retry(delete, obj, use_account=self.account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
def delete(url, token, parsed, conn):
|
||||||
|
conn.request('DELETE', parsed.path + '/' + self.name, '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(delete, use_account=self.account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
def _assert_cross_account_acl_granted(self, granted, grantee_account, acl):
|
||||||
|
'''
|
||||||
|
Check whether a given container ACL is granted when a user specified
|
||||||
|
by account_b attempts to access a container.
|
||||||
|
'''
|
||||||
|
# Obtain the first account's string
|
||||||
|
first_account = retry(self._get_account, use_account=self.account)
|
||||||
|
|
||||||
|
# Ensure we can't access the container with the grantee account
|
||||||
|
def get2(url, token, parsed, conn):
|
||||||
|
conn.request('GET', first_account + '/' + self.name, '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(get2, use_account=grantee_account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 403)
|
||||||
|
|
||||||
|
def put2(url, token, parsed, conn):
|
||||||
|
conn.request('PUT', first_account + '/' + self.name + '/object',
|
||||||
|
'test object', {'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(put2, use_account=grantee_account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 403)
|
||||||
|
|
||||||
|
# Post ACL to the container
|
||||||
|
def post(url, token, parsed, conn):
|
||||||
|
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||||
|
{'X-Auth-Token': token,
|
||||||
|
'X-Container-Read': acl,
|
||||||
|
'X-Container-Write': acl})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(post, use_account=self.account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
# Check access to container from grantee account with ACL in place
|
||||||
|
resp = retry(get2, use_account=grantee_account)
|
||||||
|
resp.read()
|
||||||
|
expected = 204 if granted else 403
|
||||||
|
self.assertEqual(resp.status, expected)
|
||||||
|
|
||||||
|
resp = retry(put2, use_account=grantee_account)
|
||||||
|
resp.read()
|
||||||
|
expected = 201 if granted else 403
|
||||||
|
self.assertEqual(resp.status, expected)
|
||||||
|
|
||||||
|
# Make the container private again
|
||||||
|
def post(url, token, parsed, conn):
|
||||||
|
conn.request('POST', parsed.path + '/' + self.name, '',
|
||||||
|
{'X-Auth-Token': token, 'X-Container-Read': '',
|
||||||
|
'X-Container-Write': ''})
|
||||||
|
return check_response(conn)
|
||||||
|
|
||||||
|
resp = retry(post, use_account=self.account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
# Ensure we can't access the container with the grantee account again
|
||||||
|
resp = retry(get2, use_account=grantee_account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 403)
|
||||||
|
|
||||||
|
resp = retry(put2, use_account=grantee_account)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 403)
|
||||||
|
|
||||||
|
|
||||||
|
class TestContainerACLsAccount1(BaseTestContainerACLs):
|
||||||
|
def test_cross_account_acl_names_with_user_in_non_default_domain(self):
|
||||||
|
# names in acls are disallowed when grantee is in a non-default domain
|
||||||
|
acl = '%s:%s' % (tf.swift_test_tenant[3], tf.swift_test_user[3])
|
||||||
|
self._assert_cross_account_acl_granted(False, 4, acl)
|
||||||
|
|
||||||
|
def test_cross_account_acl_ids_with_user_in_non_default_domain(self):
|
||||||
|
# ids are allowed in acls when grantee is in a non-default domain
|
||||||
|
tenant_id = retry(self._get_tenant_id, use_account=4)
|
||||||
|
acl = '%s:%s' % (tenant_id, '*')
|
||||||
|
self._assert_cross_account_acl_granted(True, 4, acl)
|
||||||
|
|
||||||
|
def test_cross_account_acl_names_in_default_domain(self):
|
||||||
|
# names are allowed in acls when grantee and project are in
|
||||||
|
# the default domain
|
||||||
|
acl = '%s:%s' % (tf.swift_test_tenant[1], tf.swift_test_user[1])
|
||||||
|
self._assert_cross_account_acl_granted(True, 2, acl)
|
||||||
|
|
||||||
|
def test_cross_account_acl_ids_in_default_domain(self):
|
||||||
|
# ids are allowed in acls when grantee and project are in
|
||||||
|
# the default domain
|
||||||
|
tenant_id = retry(self._get_tenant_id, use_account=2)
|
||||||
|
acl = '%s:%s' % (tenant_id, '*')
|
||||||
|
self._assert_cross_account_acl_granted(True, 2, acl)
|
||||||
|
|
||||||
|
|
||||||
|
class TestContainerACLsAccount4(BaseTestContainerACLs):
|
||||||
|
account = 4
|
||||||
|
|
||||||
|
def test_cross_account_acl_names_with_project_in_non_default_domain(self):
|
||||||
|
# names in acls are disallowed when project is in a non-default domain
|
||||||
|
acl = '%s:%s' % (tf.swift_test_tenant[0], tf.swift_test_user[0])
|
||||||
|
self._assert_cross_account_acl_granted(False, 1, acl)
|
||||||
|
|
||||||
|
def test_cross_account_acl_ids_with_project_in_non_default_domain(self):
|
||||||
|
# ids are allowed in acls when project is in a non-default domain
|
||||||
|
tenant_id = retry(self._get_tenant_id, use_account=1)
|
||||||
|
acl = '%s:%s' % (tenant_id, '*')
|
||||||
|
self._assert_cross_account_acl_granted(True, 1, acl)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -35,6 +35,7 @@ class TestObject(unittest.TestCase):
|
|||||||
|
|
||||||
self.containers = []
|
self.containers = []
|
||||||
self._create_container(self.container)
|
self._create_container(self.container)
|
||||||
|
self._create_container(self.container, use_account=2)
|
||||||
|
|
||||||
self.obj = uuid4().hex
|
self.obj = uuid4().hex
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ class TestObject(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 201)
|
self.assertEqual(resp.status, 201)
|
||||||
|
|
||||||
def _create_container(self, name=None, headers=None):
|
def _create_container(self, name=None, headers=None, use_account=1):
|
||||||
if not name:
|
if not name:
|
||||||
name = uuid4().hex
|
name = uuid4().hex
|
||||||
self.containers.append(name)
|
self.containers.append(name)
|
||||||
@ -58,7 +59,7 @@ class TestObject(unittest.TestCase):
|
|||||||
conn.request('PUT', parsed.path + '/' + name, '',
|
conn.request('PUT', parsed.path + '/' + name, '',
|
||||||
new_headers)
|
new_headers)
|
||||||
return check_response(conn)
|
return check_response(conn)
|
||||||
resp = retry(put, name)
|
resp = retry(put, name, use_account=use_account)
|
||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 201)
|
self.assertEqual(resp.status, 201)
|
||||||
return name
|
return name
|
||||||
@ -133,6 +134,45 @@ class TestObject(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEquals(resp.status, 400)
|
self.assertEquals(resp.status, 400)
|
||||||
|
|
||||||
|
def test_non_integer_x_delete_after(self):
|
||||||
|
def put(url, token, parsed, conn):
|
||||||
|
conn.request('PUT', '%s/%s/%s' % (parsed.path, self.container,
|
||||||
|
'non_integer_x_delete_after'),
|
||||||
|
'', {'X-Auth-Token': token,
|
||||||
|
'Content-Length': '0',
|
||||||
|
'X-Delete-After': '*'})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(put)
|
||||||
|
body = resp.read()
|
||||||
|
self.assertEquals(resp.status, 400)
|
||||||
|
self.assertEqual(body, 'Non-integer X-Delete-After')
|
||||||
|
|
||||||
|
def test_non_integer_x_delete_at(self):
|
||||||
|
def put(url, token, parsed, conn):
|
||||||
|
conn.request('PUT', '%s/%s/%s' % (parsed.path, self.container,
|
||||||
|
'non_integer_x_delete_at'),
|
||||||
|
'', {'X-Auth-Token': token,
|
||||||
|
'Content-Length': '0',
|
||||||
|
'X-Delete-At': '*'})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(put)
|
||||||
|
body = resp.read()
|
||||||
|
self.assertEquals(resp.status, 400)
|
||||||
|
self.assertEqual(body, 'Non-integer X-Delete-At')
|
||||||
|
|
||||||
|
def test_x_delete_at_in_the_past(self):
|
||||||
|
def put(url, token, parsed, conn):
|
||||||
|
conn.request('PUT', '%s/%s/%s' % (parsed.path, self.container,
|
||||||
|
'x_delete_at_in_the_past'),
|
||||||
|
'', {'X-Auth-Token': token,
|
||||||
|
'Content-Length': '0',
|
||||||
|
'X-Delete-At': '0'})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(put)
|
||||||
|
body = resp.read()
|
||||||
|
self.assertEquals(resp.status, 400)
|
||||||
|
self.assertEqual(body, 'X-Delete-At in past')
|
||||||
|
|
||||||
def test_copy_object(self):
|
def test_copy_object(self):
|
||||||
if tf.skip:
|
if tf.skip:
|
||||||
raise SkipTest
|
raise SkipTest
|
||||||
@ -207,6 +247,116 @@ class TestObject(unittest.TestCase):
|
|||||||
resp.read()
|
resp.read()
|
||||||
self.assertEqual(resp.status, 204)
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
def test_copy_between_accounts(self):
|
||||||
|
if tf.skip:
|
||||||
|
raise SkipTest
|
||||||
|
|
||||||
|
source = '%s/%s' % (self.container, self.obj)
|
||||||
|
dest = '%s/%s' % (self.container, 'test_copy')
|
||||||
|
|
||||||
|
# get contents of source
|
||||||
|
def get_source(url, token, parsed, conn):
|
||||||
|
conn.request('GET',
|
||||||
|
'%s/%s' % (parsed.path, source),
|
||||||
|
'', {'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(get_source)
|
||||||
|
source_contents = resp.read()
|
||||||
|
self.assertEqual(resp.status, 200)
|
||||||
|
self.assertEqual(source_contents, 'test')
|
||||||
|
|
||||||
|
acct = tf.parsed[0].path.split('/', 2)[2]
|
||||||
|
|
||||||
|
# copy source to dest with X-Copy-From-Account
|
||||||
|
def put(url, token, parsed, conn):
|
||||||
|
conn.request('PUT', '%s/%s' % (parsed.path, dest), '',
|
||||||
|
{'X-Auth-Token': token,
|
||||||
|
'Content-Length': '0',
|
||||||
|
'X-Copy-From-Account': acct,
|
||||||
|
'X-Copy-From': source})
|
||||||
|
return check_response(conn)
|
||||||
|
# try to put, will not succeed
|
||||||
|
# user does not have permissions to read from source
|
||||||
|
resp = retry(put, use_account=2)
|
||||||
|
self.assertEqual(resp.status, 403)
|
||||||
|
|
||||||
|
# add acl to allow reading from source
|
||||||
|
def post(url, token, parsed, conn):
|
||||||
|
conn.request('POST', '%s/%s' % (parsed.path, self.container), '',
|
||||||
|
{'X-Auth-Token': token,
|
||||||
|
'X-Container-Read': tf.swift_test_perm[1]})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(post)
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
# retry previous put, now should succeed
|
||||||
|
resp = retry(put, use_account=2)
|
||||||
|
self.assertEqual(resp.status, 201)
|
||||||
|
|
||||||
|
# contents of dest should be the same as source
|
||||||
|
def get_dest(url, token, parsed, conn):
|
||||||
|
conn.request('GET',
|
||||||
|
'%s/%s' % (parsed.path, dest),
|
||||||
|
'', {'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(get_dest, use_account=2)
|
||||||
|
dest_contents = resp.read()
|
||||||
|
self.assertEqual(resp.status, 200)
|
||||||
|
self.assertEqual(dest_contents, source_contents)
|
||||||
|
|
||||||
|
# delete the copy
|
||||||
|
def delete(url, token, parsed, conn):
|
||||||
|
conn.request('DELETE', '%s/%s' % (parsed.path, dest), '',
|
||||||
|
{'X-Auth-Token': token})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(delete, use_account=2)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
# verify dest does not exist
|
||||||
|
resp = retry(get_dest, use_account=2)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 404)
|
||||||
|
|
||||||
|
acct_dest = tf.parsed[1].path.split('/', 2)[2]
|
||||||
|
|
||||||
|
# copy source to dest with COPY
|
||||||
|
def copy(url, token, parsed, conn):
|
||||||
|
conn.request('COPY', '%s/%s' % (parsed.path, source), '',
|
||||||
|
{'X-Auth-Token': token,
|
||||||
|
'Destination-Account': acct_dest,
|
||||||
|
'Destination': dest})
|
||||||
|
return check_response(conn)
|
||||||
|
# try to copy, will not succeed
|
||||||
|
# user does not have permissions to write to destination
|
||||||
|
resp = retry(copy)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 403)
|
||||||
|
|
||||||
|
# add acl to allow write to destination
|
||||||
|
def post(url, token, parsed, conn):
|
||||||
|
conn.request('POST', '%s/%s' % (parsed.path, self.container), '',
|
||||||
|
{'X-Auth-Token': token,
|
||||||
|
'X-Container-Write': tf.swift_test_perm[0]})
|
||||||
|
return check_response(conn)
|
||||||
|
resp = retry(post, use_account=2)
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
|
# now copy will succeed
|
||||||
|
resp = retry(copy)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 201)
|
||||||
|
|
||||||
|
# contents of dest should be the same as source
|
||||||
|
resp = retry(get_dest, use_account=2)
|
||||||
|
dest_contents = resp.read()
|
||||||
|
self.assertEqual(resp.status, 200)
|
||||||
|
self.assertEqual(dest_contents, source_contents)
|
||||||
|
|
||||||
|
# delete the copy
|
||||||
|
resp = retry(delete, use_account=2)
|
||||||
|
resp.read()
|
||||||
|
self.assertEqual(resp.status, 204)
|
||||||
|
|
||||||
def test_public_object(self):
|
def test_public_object(self):
|
||||||
if tf.skip:
|
if tf.skip:
|
||||||
raise SkipTest
|
raise SkipTest
|
||||||
|
@ -25,6 +25,7 @@ import time
|
|||||||
import unittest
|
import unittest
|
||||||
import urllib
|
import urllib
|
||||||
import uuid
|
import uuid
|
||||||
|
from copy import deepcopy
|
||||||
import eventlet
|
import eventlet
|
||||||
from nose import SkipTest
|
from nose import SkipTest
|
||||||
|
|
||||||
@ -269,6 +270,8 @@ class TestAccount(Base):
|
|||||||
containers)
|
containers)
|
||||||
|
|
||||||
def testQuotedWWWAuthenticateHeader(self):
|
def testQuotedWWWAuthenticateHeader(self):
|
||||||
|
# check that the www-authenticate header value with the swift realm
|
||||||
|
# is correctly quoted.
|
||||||
conn = Connection(tf.config)
|
conn = Connection(tf.config)
|
||||||
conn.authenticate()
|
conn.authenticate()
|
||||||
inserted_html = '<b>Hello World'
|
inserted_html = '<b>Hello World'
|
||||||
@ -277,9 +280,16 @@ class TestAccount(Base):
|
|||||||
quoted_hax = urllib.quote(hax)
|
quoted_hax = urllib.quote(hax)
|
||||||
conn.connection.request('GET', '/v1/' + quoted_hax, None, {})
|
conn.connection.request('GET', '/v1/' + quoted_hax, None, {})
|
||||||
resp = conn.connection.getresponse()
|
resp = conn.connection.getresponse()
|
||||||
resp_headers = resp.getheaders()
|
resp_headers = dict(resp.getheaders())
|
||||||
expected = ('www-authenticate', 'Swift realm="%s"' % quoted_hax)
|
self.assertTrue('www-authenticate' in resp_headers,
|
||||||
self.assert_(expected in resp_headers)
|
'www-authenticate not found in %s' % resp_headers)
|
||||||
|
actual = resp_headers['www-authenticate']
|
||||||
|
expected = 'Swift realm="%s"' % quoted_hax
|
||||||
|
# other middleware e.g. auth_token may also set www-authenticate
|
||||||
|
# headers in which case actual values will be a comma separated list.
|
||||||
|
# check that expected value is among the actual values
|
||||||
|
self.assertTrue(expected in actual,
|
||||||
|
'%s not found in %s' % (expected, actual))
|
||||||
|
|
||||||
|
|
||||||
class TestAccountUTF8(Base2, TestAccount):
|
class TestAccountUTF8(Base2, TestAccount):
|
||||||
@ -794,9 +804,22 @@ class TestFileEnv(object):
|
|||||||
def setUp(cls):
|
def setUp(cls):
|
||||||
cls.conn = Connection(tf.config)
|
cls.conn = Connection(tf.config)
|
||||||
cls.conn.authenticate()
|
cls.conn.authenticate()
|
||||||
|
cls.account = Account(cls.conn, tf.config.get('account',
|
||||||
|
tf.config['username']))
|
||||||
|
# creating another account and connection
|
||||||
|
# for account to account copy tests
|
||||||
|
config2 = deepcopy(tf.config)
|
||||||
|
config2['account'] = tf.config['account2']
|
||||||
|
config2['username'] = tf.config['username2']
|
||||||
|
config2['password'] = tf.config['password2']
|
||||||
|
cls.conn2 = Connection(config2)
|
||||||
|
cls.conn2.authenticate()
|
||||||
|
|
||||||
cls.account = Account(cls.conn, tf.config.get('account',
|
cls.account = Account(cls.conn, tf.config.get('account',
|
||||||
tf.config['username']))
|
tf.config['username']))
|
||||||
cls.account.delete_containers()
|
cls.account.delete_containers()
|
||||||
|
cls.account2 = cls.conn2.get_account()
|
||||||
|
cls.account2.delete_containers()
|
||||||
|
|
||||||
cls.container = cls.account.container(Utils.create_name())
|
cls.container = cls.account.container(Utils.create_name())
|
||||||
if not cls.container.create():
|
if not cls.container.create():
|
||||||
@ -850,6 +873,62 @@ class TestFile(Base):
|
|||||||
self.assert_(file_item.initialize())
|
self.assert_(file_item.initialize())
|
||||||
self.assert_(metadata == file_item.metadata)
|
self.assert_(metadata == file_item.metadata)
|
||||||
|
|
||||||
|
def testCopyAccount(self):
|
||||||
|
# makes sure to test encoded characters
|
||||||
|
source_filename = 'dealde%2Fl04 011e%204c8df/flash.png'
|
||||||
|
file_item = self.env.container.file(source_filename)
|
||||||
|
|
||||||
|
metadata = {Utils.create_ascii_name(): Utils.create_name()}
|
||||||
|
|
||||||
|
data = file_item.write_random()
|
||||||
|
file_item.sync_metadata(metadata)
|
||||||
|
|
||||||
|
dest_cont = self.env.account.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create())
|
||||||
|
|
||||||
|
acct = self.env.conn.account_name
|
||||||
|
# copy both from within and across containers
|
||||||
|
for cont in (self.env.container, dest_cont):
|
||||||
|
# copy both with and without initial slash
|
||||||
|
for prefix in ('', '/'):
|
||||||
|
dest_filename = Utils.create_name()
|
||||||
|
|
||||||
|
file_item = self.env.container.file(source_filename)
|
||||||
|
file_item.copy_account(acct,
|
||||||
|
'%s%s' % (prefix, cont),
|
||||||
|
dest_filename)
|
||||||
|
|
||||||
|
self.assert_(dest_filename in cont.files())
|
||||||
|
|
||||||
|
file_item = cont.file(dest_filename)
|
||||||
|
|
||||||
|
self.assert_(data == file_item.read())
|
||||||
|
self.assert_(file_item.initialize())
|
||||||
|
self.assert_(metadata == file_item.metadata)
|
||||||
|
|
||||||
|
dest_cont = self.env.account2.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create(hdrs={
|
||||||
|
'X-Container-Write': self.env.conn.user_acl
|
||||||
|
}))
|
||||||
|
|
||||||
|
acct = self.env.conn2.account_name
|
||||||
|
# copy both with and without initial slash
|
||||||
|
for prefix in ('', '/'):
|
||||||
|
dest_filename = Utils.create_name()
|
||||||
|
|
||||||
|
file_item = self.env.container.file(source_filename)
|
||||||
|
file_item.copy_account(acct,
|
||||||
|
'%s%s' % (prefix, dest_cont),
|
||||||
|
dest_filename)
|
||||||
|
|
||||||
|
self.assert_(dest_filename in dest_cont.files())
|
||||||
|
|
||||||
|
file_item = dest_cont.file(dest_filename)
|
||||||
|
|
||||||
|
self.assert_(data == file_item.read())
|
||||||
|
self.assert_(file_item.initialize())
|
||||||
|
self.assert_(metadata == file_item.metadata)
|
||||||
|
|
||||||
def testCopy404s(self):
|
def testCopy404s(self):
|
||||||
source_filename = Utils.create_name()
|
source_filename = Utils.create_name()
|
||||||
file_item = self.env.container.file(source_filename)
|
file_item = self.env.container.file(source_filename)
|
||||||
@ -888,6 +967,77 @@ class TestFile(Base):
|
|||||||
'%s%s' % (prefix, Utils.create_name()),
|
'%s%s' % (prefix, Utils.create_name()),
|
||||||
Utils.create_name()))
|
Utils.create_name()))
|
||||||
|
|
||||||
|
def testCopyAccount404s(self):
|
||||||
|
acct = self.env.conn.account_name
|
||||||
|
acct2 = self.env.conn2.account_name
|
||||||
|
source_filename = Utils.create_name()
|
||||||
|
file_item = self.env.container.file(source_filename)
|
||||||
|
file_item.write_random()
|
||||||
|
|
||||||
|
dest_cont = self.env.account.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create(hdrs={
|
||||||
|
'X-Container-Read': self.env.conn2.user_acl
|
||||||
|
}))
|
||||||
|
dest_cont2 = self.env.account2.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont2.create(hdrs={
|
||||||
|
'X-Container-Write': self.env.conn.user_acl,
|
||||||
|
'X-Container-Read': self.env.conn.user_acl
|
||||||
|
}))
|
||||||
|
|
||||||
|
for acct, cont in ((acct, dest_cont), (acct2, dest_cont2)):
|
||||||
|
for prefix in ('', '/'):
|
||||||
|
# invalid source container
|
||||||
|
source_cont = self.env.account.container(Utils.create_name())
|
||||||
|
file_item = source_cont.file(source_filename)
|
||||||
|
self.assert_(not file_item.copy_account(
|
||||||
|
acct,
|
||||||
|
'%s%s' % (prefix, self.env.container),
|
||||||
|
Utils.create_name()))
|
||||||
|
if acct == acct2:
|
||||||
|
# there is no such source container
|
||||||
|
# and foreign user can have no permission to read it
|
||||||
|
self.assert_status(403)
|
||||||
|
else:
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
|
self.assert_(not file_item.copy_account(
|
||||||
|
acct,
|
||||||
|
'%s%s' % (prefix, cont),
|
||||||
|
Utils.create_name()))
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
|
# invalid source object
|
||||||
|
file_item = self.env.container.file(Utils.create_name())
|
||||||
|
self.assert_(not file_item.copy_account(
|
||||||
|
acct,
|
||||||
|
'%s%s' % (prefix, self.env.container),
|
||||||
|
Utils.create_name()))
|
||||||
|
if acct == acct2:
|
||||||
|
# there is no such object
|
||||||
|
# and foreign user can have no permission to read it
|
||||||
|
self.assert_status(403)
|
||||||
|
else:
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
|
self.assert_(not file_item.copy_account(
|
||||||
|
acct,
|
||||||
|
'%s%s' % (prefix, cont),
|
||||||
|
Utils.create_name()))
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
|
# invalid destination container
|
||||||
|
file_item = self.env.container.file(source_filename)
|
||||||
|
self.assert_(not file_item.copy_account(
|
||||||
|
acct,
|
||||||
|
'%s%s' % (prefix, Utils.create_name()),
|
||||||
|
Utils.create_name()))
|
||||||
|
if acct == acct2:
|
||||||
|
# there is no such destination container
|
||||||
|
# and foreign user can have no permission to write there
|
||||||
|
self.assert_status(403)
|
||||||
|
else:
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
def testCopyNoDestinationHeader(self):
|
def testCopyNoDestinationHeader(self):
|
||||||
source_filename = Utils.create_name()
|
source_filename = Utils.create_name()
|
||||||
file_item = self.env.container.file(source_filename)
|
file_item = self.env.container.file(source_filename)
|
||||||
@ -942,6 +1092,49 @@ class TestFile(Base):
|
|||||||
self.assert_(file_item.initialize())
|
self.assert_(file_item.initialize())
|
||||||
self.assert_(metadata == file_item.metadata)
|
self.assert_(metadata == file_item.metadata)
|
||||||
|
|
||||||
|
def testCopyFromAccountHeader(self):
|
||||||
|
acct = self.env.conn.account_name
|
||||||
|
src_cont = self.env.account.container(Utils.create_name())
|
||||||
|
self.assert_(src_cont.create(hdrs={
|
||||||
|
'X-Container-Read': self.env.conn2.user_acl
|
||||||
|
}))
|
||||||
|
source_filename = Utils.create_name()
|
||||||
|
file_item = src_cont.file(source_filename)
|
||||||
|
|
||||||
|
metadata = {}
|
||||||
|
for i in range(1):
|
||||||
|
metadata[Utils.create_ascii_name()] = Utils.create_name()
|
||||||
|
file_item.metadata = metadata
|
||||||
|
|
||||||
|
data = file_item.write_random()
|
||||||
|
|
||||||
|
dest_cont = self.env.account.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create())
|
||||||
|
dest_cont2 = self.env.account2.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont2.create(hdrs={
|
||||||
|
'X-Container-Write': self.env.conn.user_acl
|
||||||
|
}))
|
||||||
|
|
||||||
|
for cont in (src_cont, dest_cont, dest_cont2):
|
||||||
|
# copy both with and without initial slash
|
||||||
|
for prefix in ('', '/'):
|
||||||
|
dest_filename = Utils.create_name()
|
||||||
|
|
||||||
|
file_item = cont.file(dest_filename)
|
||||||
|
file_item.write(hdrs={'X-Copy-From-Account': acct,
|
||||||
|
'X-Copy-From': '%s%s/%s' % (
|
||||||
|
prefix,
|
||||||
|
src_cont.name,
|
||||||
|
source_filename)})
|
||||||
|
|
||||||
|
self.assert_(dest_filename in cont.files())
|
||||||
|
|
||||||
|
file_item = cont.file(dest_filename)
|
||||||
|
|
||||||
|
self.assert_(data == file_item.read())
|
||||||
|
self.assert_(file_item.initialize())
|
||||||
|
self.assert_(metadata == file_item.metadata)
|
||||||
|
|
||||||
def testCopyFromHeader404s(self):
|
def testCopyFromHeader404s(self):
|
||||||
source_filename = Utils.create_name()
|
source_filename = Utils.create_name()
|
||||||
file_item = self.env.container.file(source_filename)
|
file_item = self.env.container.file(source_filename)
|
||||||
@ -973,6 +1166,52 @@ class TestFile(Base):
|
|||||||
self.env.container.name, source_filename)})
|
self.env.container.name, source_filename)})
|
||||||
self.assert_status(404)
|
self.assert_status(404)
|
||||||
|
|
||||||
|
def testCopyFromAccountHeader404s(self):
|
||||||
|
acct = self.env.conn2.account_name
|
||||||
|
src_cont = self.env.account2.container(Utils.create_name())
|
||||||
|
self.assert_(src_cont.create(hdrs={
|
||||||
|
'X-Container-Read': self.env.conn.user_acl
|
||||||
|
}))
|
||||||
|
source_filename = Utils.create_name()
|
||||||
|
file_item = src_cont.file(source_filename)
|
||||||
|
file_item.write_random()
|
||||||
|
dest_cont = self.env.account.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create())
|
||||||
|
|
||||||
|
for prefix in ('', '/'):
|
||||||
|
# invalid source container
|
||||||
|
file_item = dest_cont.file(Utils.create_name())
|
||||||
|
self.assertRaises(ResponseError, file_item.write,
|
||||||
|
hdrs={'X-Copy-From-Account': acct,
|
||||||
|
'X-Copy-From': '%s%s/%s' %
|
||||||
|
(prefix,
|
||||||
|
Utils.create_name(),
|
||||||
|
source_filename)})
|
||||||
|
# looks like cached responses leak "not found"
|
||||||
|
# to un-authorized users, not going to fix it now, but...
|
||||||
|
self.assert_status([403, 404])
|
||||||
|
|
||||||
|
# invalid source object
|
||||||
|
file_item = self.env.container.file(Utils.create_name())
|
||||||
|
self.assertRaises(ResponseError, file_item.write,
|
||||||
|
hdrs={'X-Copy-From-Account': acct,
|
||||||
|
'X-Copy-From': '%s%s/%s' %
|
||||||
|
(prefix,
|
||||||
|
src_cont,
|
||||||
|
Utils.create_name())})
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
|
# invalid destination container
|
||||||
|
dest_cont = self.env.account.container(Utils.create_name())
|
||||||
|
file_item = dest_cont.file(Utils.create_name())
|
||||||
|
self.assertRaises(ResponseError, file_item.write,
|
||||||
|
hdrs={'X-Copy-From-Account': acct,
|
||||||
|
'X-Copy-From': '%s%s/%s' %
|
||||||
|
(prefix,
|
||||||
|
src_cont,
|
||||||
|
source_filename)})
|
||||||
|
self.assert_status(404)
|
||||||
|
|
||||||
def testNameLimit(self):
|
def testNameLimit(self):
|
||||||
|
|
||||||
raise SkipTest('SOF constraints middleware enforces constraints.')
|
raise SkipTest('SOF constraints middleware enforces constraints.')
|
||||||
@ -1196,6 +1435,16 @@ class TestFile(Base):
|
|||||||
cfg={'no_content_length': True})
|
cfg={'no_content_length': True})
|
||||||
self.assert_status(400)
|
self.assert_status(400)
|
||||||
|
|
||||||
|
# no content-length
|
||||||
|
self.assertRaises(ResponseError, file_item.write_random, file_length,
|
||||||
|
cfg={'no_content_length': True})
|
||||||
|
self.assert_status(411)
|
||||||
|
|
||||||
|
self.assertRaises(ResponseError, file_item.write_random, file_length,
|
||||||
|
hdrs={'transfer-encoding': 'gzip,chunked'},
|
||||||
|
cfg={'no_content_length': True})
|
||||||
|
self.assert_status(501)
|
||||||
|
|
||||||
# bad request types
|
# bad request types
|
||||||
#for req in ('LICK', 'GETorHEAD_base', 'container_info',
|
#for req in ('LICK', 'GETorHEAD_base', 'container_info',
|
||||||
# 'best_response'):
|
# 'best_response'):
|
||||||
@ -1598,6 +1847,30 @@ class TestDlo(Base):
|
|||||||
file_contents,
|
file_contents,
|
||||||
"aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff")
|
"aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff")
|
||||||
|
|
||||||
|
def test_copy_account(self):
|
||||||
|
# dlo use same account and same container only
|
||||||
|
acct = self.env.conn.account_name
|
||||||
|
# Adding a new segment, copying the manifest, and then deleting the
|
||||||
|
# segment proves that the new object is really the concatenated
|
||||||
|
# segments and not just a manifest.
|
||||||
|
f_segment = self.env.container.file("%s/seg_lowerf" %
|
||||||
|
(self.env.segment_prefix))
|
||||||
|
f_segment.write('ffffffffff')
|
||||||
|
try:
|
||||||
|
man1_item = self.env.container.file('man1')
|
||||||
|
man1_item.copy_account(acct,
|
||||||
|
self.env.container.name,
|
||||||
|
"copied-man1")
|
||||||
|
finally:
|
||||||
|
# try not to leave this around for other tests to stumble over
|
||||||
|
f_segment.delete()
|
||||||
|
|
||||||
|
file_item = self.env.container.file('copied-man1')
|
||||||
|
file_contents = file_item.read()
|
||||||
|
self.assertEqual(
|
||||||
|
file_contents,
|
||||||
|
"aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff")
|
||||||
|
|
||||||
def test_copy_manifest(self):
|
def test_copy_manifest(self):
|
||||||
# Copying the manifest should result in another manifest
|
# Copying the manifest should result in another manifest
|
||||||
try:
|
try:
|
||||||
@ -1794,6 +2067,14 @@ class TestSloEnv(object):
|
|||||||
def setUp(cls):
|
def setUp(cls):
|
||||||
cls.conn = Connection(tf.config)
|
cls.conn = Connection(tf.config)
|
||||||
cls.conn.authenticate()
|
cls.conn.authenticate()
|
||||||
|
config2 = deepcopy(tf.config)
|
||||||
|
config2['account'] = tf.config['account2']
|
||||||
|
config2['username'] = tf.config['username2']
|
||||||
|
config2['password'] = tf.config['password2']
|
||||||
|
cls.conn2 = Connection(config2)
|
||||||
|
cls.conn2.authenticate()
|
||||||
|
cls.account2 = cls.conn2.get_account()
|
||||||
|
cls.account2.delete_containers()
|
||||||
|
|
||||||
if cls.slo_enabled is None:
|
if cls.slo_enabled is None:
|
||||||
cls.slo_enabled = 'slo' in cluster_info
|
cls.slo_enabled = 'slo' in cluster_info
|
||||||
@ -1976,6 +2257,29 @@ class TestSlo(Base):
|
|||||||
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
||||||
self.assertEqual(4 * 1024 * 1024 + 1, len(copied_contents))
|
self.assertEqual(4 * 1024 * 1024 + 1, len(copied_contents))
|
||||||
|
|
||||||
|
def test_slo_copy_account(self):
|
||||||
|
acct = self.env.conn.account_name
|
||||||
|
# same account copy
|
||||||
|
file_item = self.env.container.file("manifest-abcde")
|
||||||
|
file_item.copy_account(acct, self.env.container.name, "copied-abcde")
|
||||||
|
|
||||||
|
copied = self.env.container.file("copied-abcde")
|
||||||
|
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
||||||
|
self.assertEqual(4 * 1024 * 1024 + 1, len(copied_contents))
|
||||||
|
|
||||||
|
# copy to different account
|
||||||
|
acct = self.env.conn2.account_name
|
||||||
|
dest_cont = self.env.account2.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create(hdrs={
|
||||||
|
'X-Container-Write': self.env.conn.user_acl
|
||||||
|
}))
|
||||||
|
file_item = self.env.container.file("manifest-abcde")
|
||||||
|
file_item.copy_account(acct, dest_cont, "copied-abcde")
|
||||||
|
|
||||||
|
copied = dest_cont.file("copied-abcde")
|
||||||
|
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
||||||
|
self.assertEqual(4 * 1024 * 1024 + 1, len(copied_contents))
|
||||||
|
|
||||||
def test_slo_copy_the_manifest(self):
|
def test_slo_copy_the_manifest(self):
|
||||||
file_item = self.env.container.file("manifest-abcde")
|
file_item = self.env.container.file("manifest-abcde")
|
||||||
file_item.copy(self.env.container.name, "copied-abcde-manifest-only",
|
file_item.copy(self.env.container.name, "copied-abcde-manifest-only",
|
||||||
@ -1988,6 +2292,40 @@ class TestSlo(Base):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
self.fail("COPY didn't copy the manifest (invalid json on GET)")
|
self.fail("COPY didn't copy the manifest (invalid json on GET)")
|
||||||
|
|
||||||
|
def test_slo_copy_the_manifest_account(self):
|
||||||
|
acct = self.env.conn.account_name
|
||||||
|
# same account
|
||||||
|
file_item = self.env.container.file("manifest-abcde")
|
||||||
|
file_item.copy_account(acct,
|
||||||
|
self.env.container.name,
|
||||||
|
"copied-abcde-manifest-only",
|
||||||
|
parms={'multipart-manifest': 'get'})
|
||||||
|
|
||||||
|
copied = self.env.container.file("copied-abcde-manifest-only")
|
||||||
|
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
||||||
|
try:
|
||||||
|
json.loads(copied_contents)
|
||||||
|
except ValueError:
|
||||||
|
self.fail("COPY didn't copy the manifest (invalid json on GET)")
|
||||||
|
|
||||||
|
# different account
|
||||||
|
acct = self.env.conn2.account_name
|
||||||
|
dest_cont = self.env.account2.container(Utils.create_name())
|
||||||
|
self.assert_(dest_cont.create(hdrs={
|
||||||
|
'X-Container-Write': self.env.conn.user_acl
|
||||||
|
}))
|
||||||
|
file_item.copy_account(acct,
|
||||||
|
dest_cont,
|
||||||
|
"copied-abcde-manifest-only",
|
||||||
|
parms={'multipart-manifest': 'get'})
|
||||||
|
|
||||||
|
copied = dest_cont.file("copied-abcde-manifest-only")
|
||||||
|
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
||||||
|
try:
|
||||||
|
json.loads(copied_contents)
|
||||||
|
except ValueError:
|
||||||
|
self.fail("COPY didn't copy the manifest (invalid json on GET)")
|
||||||
|
|
||||||
def test_slo_get_the_manifest(self):
|
def test_slo_get_the_manifest(self):
|
||||||
manifest = self.env.container.file("manifest-abcde")
|
manifest = self.env.container.file("manifest-abcde")
|
||||||
got_body = manifest.read(parms={'multipart-manifest': 'get'})
|
got_body = manifest.read(parms={'multipart-manifest': 'get'})
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
# Copyright (c) 2013 Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
""" Tests for swiftonfile.swift.obj.server subclass """
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from nose import SkipTest
|
|
||||||
|
|
||||||
import swiftonfile.swift.obj.server as server
|
|
||||||
|
|
||||||
|
|
||||||
class TestObjServer(unittest.TestCase):
|
|
||||||
"""
|
|
||||||
Tests for object server subclass.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_constructor(self):
|
|
||||||
raise SkipTest
|
|
2
tox.ini
2
tox.ini
@ -21,7 +21,7 @@ deps =
|
|||||||
# Note: pip supports installing from git repos.
|
# Note: pip supports installing from git repos.
|
||||||
# https://pip.pypa.io/en/latest/reference/pip_install.html#git
|
# https://pip.pypa.io/en/latest/reference/pip_install.html#git
|
||||||
# Example: git+https://github.com/openstack/swift.git@2.0.0
|
# Example: git+https://github.com/openstack/swift.git@2.0.0
|
||||||
https://launchpad.net/swift/juno/2.1.0/+download/swift-2.1.0.tar.gz
|
https://launchpad.net/swift/kilo/2.2.1/+download/swift-2.2.1.tar.gz
|
||||||
-r{toxinidir}/test-requirements.txt
|
-r{toxinidir}/test-requirements.txt
|
||||||
changedir = {toxinidir}/test/unit
|
changedir = {toxinidir}/test/unit
|
||||||
commands = nosetests -v {posargs}
|
commands = nosetests -v {posargs}
|
||||||
|
Loading…
Reference in New Issue
Block a user