Files
tempest/tempest/api/object_storage/test_object_services.py
Jordan Pittier 4408c4a5fe Swift object client: use urllib3 builtin support for chunked transfer
Urllib3 has native support for chunked encoding, so let's use this
instead of rolling our own. Less code to maintain, additional logging
and timing (thanks to our common RestClient). Yeah \O/.

Change-Id: I4a253a5cec0fc35009af25872239363625d417e3
2016-05-25 16:51:31 +02:00

1081 lines
46 KiB
Python

# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# 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 hashlib
import random
import re
import time
import zlib
import six
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
from tempest import config
from tempest import test
CONF = config.CONF
class ObjectTest(base.BaseObjectTest):
@classmethod
def resource_setup(cls):
super(ObjectTest, cls).resource_setup()
cls.container_name = data_utils.rand_name(name='TestContainer')
cls.container_client.create_container(cls.container_name)
cls.containers = [cls.container_name]
@classmethod
def resource_cleanup(cls):
cls.delete_containers(cls.containers)
super(ObjectTest, cls).resource_cleanup()
def _create_object(self, metadata=None):
# setup object
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
self.object_client.create_object(self.container_name,
object_name, data, metadata=metadata)
return object_name, data
def _upload_segments(self):
# create object
object_name = data_utils.rand_name(name='LObject')
data = data_utils.arbitrary_string()
segments = 10
data_segments = [data + str(i) for i in six.moves.xrange(segments)]
# uploading segments
for i in six.moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
return object_name, data_segments
def _copy_object_2d(self, src_object_name, metadata=None):
dst_object_name = data_utils.rand_name(name='TestObject')
resp, _ = self.object_client.copy_object_2d_way(self.container_name,
src_object_name,
dst_object_name,
metadata=metadata)
return dst_object_name, resp
def _check_copied_obj(self, dst_object_name, src_body,
in_meta=None, not_in_meta=None):
resp, dest_body = self.object_client.get_object(self.container_name,
dst_object_name)
self.assertEqual(src_body, dest_body)
if in_meta:
for meta_key in in_meta:
self.assertIn('x-object-meta-' + meta_key, resp)
if not_in_meta:
for meta_key in not_in_meta:
self.assertNotIn('x-object-meta-' + meta_key, resp)
@test.attr(type='smoke')
@test.idempotent_id('5b4ce26f-3545-46c9-a2ba-5754358a4c62')
def test_create_object(self):
# create object
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
# create another object
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
self.assertHeaders(resp, 'Object', 'PUT')
# check uploaded content
_, body = self.object_client.get_object(self.container_name,
object_name)
self.assertEqual(data, body)
@test.idempotent_id('5daebb1d-f0d5-4dc9-b541-69672eff00b0')
def test_create_object_with_content_disposition(self):
# create object with content_disposition
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata = {}
metadata['content-disposition'] = 'inline'
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata)
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=None)
self.assertIn('content-disposition', resp)
self.assertEqual(resp['content-disposition'], 'inline')
self.assertEqual(body, data)
@test.idempotent_id('605f8317-f945-4bee-ae91-013f1da8f0a0')
def test_create_object_with_content_encoding(self):
# create object with content_encoding
object_name = data_utils.rand_name(name='TestObject')
# put compressed string
data_before = 'x' * 2000
data = zlib.compress(data_before)
metadata = {}
metadata['content-encoding'] = 'deflate'
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata)
self.assertHeaders(resp, 'Object', 'PUT')
# download compressed object
metadata = {}
metadata['accept-encoding'] = 'deflate'
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=metadata)
self.assertEqual(body, data_before)
@test.idempotent_id('73820093-0503-40b1-a478-edf0e69c7d1f')
def test_create_object_with_etag(self):
# create object with etag
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
md5 = hashlib.md5(data).hexdigest()
metadata = {'Etag': md5}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata)
self.assertHeaders(resp, 'Object', 'PUT')
# check uploaded content
_, body = self.object_client.get_object(self.container_name,
object_name)
self.assertEqual(data, body)
@test.idempotent_id('84dafe57-9666-4f6d-84c8-0814d37923b8')
def test_create_object_with_expect_continue(self):
# create object with expect_continue
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
status, _ = self.object_client.create_object_continue(
self.container_name, object_name, data)
self.assertEqual(status, 201)
# check uploaded content
_, body = self.object_client.get_object(self.container_name,
object_name)
self.assertEqual(data, body)
@test.idempotent_id('4f84422a-e2f2-4403-b601-726a4220b54e')
def test_create_object_with_transfer_encoding(self):
# create object with transfer_encoding
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string(1024)
status, _, resp_headers = self.object_client.put_object_with_chunk(
container=self.container_name,
name=object_name,
contents=data_utils.chunkify(data, 512)
)
self.assertHeaders(resp_headers, 'Object', 'PUT')
# check uploaded content
_, body = self.object_client.get_object(self.container_name,
object_name)
self.assertEqual(data, body)
@test.idempotent_id('0f3d62a6-47e3-4554-b0e5-1a5dc372d501')
def test_create_object_with_x_fresh_metadata(self):
# create object with x_fresh_metadata
object_name_base = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata_1 = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name_base,
data,
metadata=metadata_1)
object_name = data_utils.rand_name(name='TestObject')
metadata_2 = {'X-Copy-From': '%s/%s' % (self.container_name,
object_name_base),
'X-Fresh-Metadata': 'true'}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
'',
metadata=metadata_2)
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
object_name)
self.assertNotIn('x-object-meta-test-meta', resp)
self.assertEqual(data, body)
@test.idempotent_id('1c7ed3e4-2099-406b-b843-5301d4811baf')
def test_create_object_with_x_object_meta(self):
# create object with object_meta
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata)
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
object_name)
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
self.assertEqual(data, body)
@test.idempotent_id('e4183917-33db-4153-85cc-4dacbb938865')
def test_create_object_with_x_object_metakey(self):
# create object with the blank value of metadata
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata = {'X-Object-Meta-test-meta': ''}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata)
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
object_name)
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], '')
self.assertEqual(data, body)
@test.idempotent_id('ce798afc-b278-45de-a5ce-2ea124b98b99')
def test_create_object_with_x_remove_object_meta(self):
# create object with x_remove_object_meta
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=metadata_add)
metadata_remove = {'X-Remove-Object-Meta-test-meta': 'Meta'}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata_remove)
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
object_name)
self.assertNotIn('x-object-meta-test-meta', resp)
self.assertEqual(data, body)
@test.idempotent_id('ad21e342-7916-4f9e-ab62-a1f885f2aaf9')
def test_create_object_with_x_remove_object_metakey(self):
# create object with the blank value of remove metadata
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=metadata_add)
metadata_remove = {'X-Remove-Object-Meta-test-meta': ''}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data,
metadata=metadata_remove)
self.assertHeaders(resp, 'Object', 'PUT')
resp, body = self.object_client.get_object(self.container_name,
object_name)
self.assertNotIn('x-object-meta-test-meta', resp)
self.assertEqual(data, body)
@test.idempotent_id('17738d45-03bd-4d45-9e0b-7b2f58f98687')
def test_delete_object(self):
# create object
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
# delete object
resp, _ = self.object_client.delete_object(self.container_name,
object_name)
self.assertHeaders(resp, 'Object', 'DELETE')
@test.attr(type='smoke')
@test.idempotent_id('7a94c25d-66e6-434c-9c38-97d4e2c29945')
def test_update_object_metadata(self):
# update object metadata
object_name, data = self._create_object()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
resp, _ = self.object_client.update_object_metadata(
self.container_name,
object_name,
metadata,
metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
@test.idempotent_id('48650ed0-c189-4e1e-ad6b-1d4770c6e134')
def test_update_object_metadata_with_remove_metadata(self):
# update object metadata with remove metadata
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=create_metadata)
update_metadata = {'X-Remove-Object-Meta-test-meta1': 'Meta1'}
resp, _ = self.object_client.update_object_metadata(
self.container_name,
object_name,
update_metadata,
metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertNotIn('x-object-meta-test-meta1', resp)
@test.idempotent_id('f726174b-2ded-4708-bff7-729d12ce1f84')
def test_update_object_metadata_with_create_and_remove_metadata(self):
# creation and deletion of metadata with one request
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=create_metadata)
update_metadata = {'X-Object-Meta-test-meta2': 'Meta2',
'X-Remove-Object-Meta-test-meta1': 'Meta1'}
resp, _ = self.object_client.update_object_metadata(
self.container_name,
object_name,
update_metadata,
metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertNotIn('x-object-meta-test-meta1', resp)
self.assertIn('x-object-meta-test-meta2', resp)
self.assertEqual(resp['x-object-meta-test-meta2'], 'Meta2')
@test.idempotent_id('08854588-6449-4bb7-8cca-f2e1040f5e6f')
def test_update_object_metadata_with_x_object_manifest(self):
# update object metadata with x_object_manifest
# uploading segments
object_name, data_segments = self._upload_segments()
# creating a manifest file
data_empty = ''
self.object_client.create_object(self.container_name,
object_name,
data_empty,
metadata=None)
object_prefix = '%s/%s' % (self.container_name, object_name)
update_metadata = {'X-Object-Manifest': object_prefix}
resp, _ = self.object_client.update_object_metadata(
self.container_name,
object_name,
update_metadata,
metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertIn('x-object-manifest', resp)
self.assertNotEqual(len(resp['x-object-manifest']), 0)
@test.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e')
def test_update_object_metadata_with_x_object_metakey(self):
# update object metadata with a blenk value of metadata
object_name, data = self._create_object()
update_metadata = {'X-Object-Meta-test-meta': ''}
resp, _ = self.object_client.update_object_metadata(
self.container_name,
object_name,
update_metadata,
metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], '')
@test.idempotent_id('9a88dca4-b684-425b-806f-306cd0e57e42')
def test_update_object_metadata_with_x_remove_object_metakey(self):
# update object metadata with a blank value of remove metadata
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
create_metadata = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=create_metadata)
update_metadata = {'X-Remove-Object-Meta-test-meta': ''}
resp, _ = self.object_client.update_object_metadata(
self.container_name,
object_name,
update_metadata,
metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertNotIn('x-object-meta-test-meta', resp)
@test.attr(type='smoke')
@test.idempotent_id('9a447cf6-de06-48de-8226-a8c6ed31caf2')
def test_list_object_metadata(self):
# get object metadata
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=metadata)
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
@test.idempotent_id('170fb90e-f5c3-4b1f-ae1b-a18810821172')
def test_list_no_object_metadata(self):
# get empty list of object metadata
object_name, data = self._create_object()
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertNotIn('x-object-meta-', str(resp))
@test.idempotent_id('23a3674c-d6de-46c3-86af-ff92bfc8a3da')
def test_list_object_metadata_with_x_object_manifest(self):
# get object metadata with x_object_manifest
# uploading segments
object_name, data_segments = self._upload_segments()
# creating a manifest file
object_prefix = '%s/%s' % (self.container_name, object_name)
metadata = {'X-Object-Manifest': object_prefix}
data_empty = ''
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
data_empty,
metadata=metadata)
resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
# Check only the existence of common headers with custom matcher
self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
'Object', 'HEAD'))
self.assertIn('x-object-manifest', resp)
# Etag value of a large object is enclosed in double-quotations.
# This is a special case, therefore the formats of response headers
# are checked without a custom matcher.
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
self.assertTrue(resp['etag'].strip('\"').isalnum())
self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
self.assertNotEqual(len(resp['content-type']), 0)
self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
resp['x-trans-id']))
self.assertNotEqual(len(resp['date']), 0)
self.assertEqual(resp['accept-ranges'], 'bytes')
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
@test.attr(type='smoke')
@test.idempotent_id('02610ba7-86b7-4272-9ed8-aa8d417cb3cd')
def test_get_object(self):
# retrieve object's data (in response body)
# create object
object_name, data = self._create_object()
# get object
resp, body = self.object_client.get_object(self.container_name,
object_name)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('005f9bf6-e06d-41ec-968e-96c78e0b1d82')
def test_get_object_with_metadata(self):
# get object with metadata
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=metadata)
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=None)
self.assertHeaders(resp, 'Object', 'GET')
self.assertIn('x-object-meta-test-meta', resp)
self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
self.assertEqual(body, data)
@test.idempotent_id('05a1890e-7db9-4a6c-90a8-ce998a2bddfa')
def test_get_object_with_range(self):
# get object with range
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string(100)
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=None)
rand_num = random.randint(3, len(data) - 1)
metadata = {'Range': 'bytes=%s-%s' % (rand_num - 3, rand_num - 1)}
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=metadata)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data[rand_num - 3: rand_num])
@test.idempotent_id('11b4515b-7ba7-4ca8-8838-357ded86fc10')
def test_get_object_with_x_object_manifest(self):
# get object with x_object_manifest
# uploading segments
object_name, data_segments = self._upload_segments()
# creating a manifest file
object_prefix = '%s/%s' % (self.container_name, object_name)
metadata = {'X-Object-Manifest': object_prefix}
data_empty = ''
resp, body = self.object_client.create_object(
self.container_name,
object_name,
data_empty,
metadata=metadata)
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=None)
# Check only the existence of common headers with custom matcher
self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
'Object', 'GET'))
self.assertIn('x-object-manifest', resp)
# Etag value of a large object is enclosed in double-quotations.
# This is a special case, therefore the formats of response headers
# are checked without a custom matcher.
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
self.assertTrue(resp['etag'].strip('\"').isalnum())
self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
self.assertNotEqual(len(resp['content-type']), 0)
self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
resp['x-trans-id']))
self.assertNotEqual(len(resp['date']), 0)
self.assertEqual(resp['accept-ranges'], 'bytes')
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
self.assertEqual(''.join(data_segments), body)
@test.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc')
def test_get_object_with_if_match(self):
# get object with if_match
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string(10)
create_md5 = hashlib.md5(data).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=create_metadata)
list_metadata = {'If-Match': create_md5}
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=list_metadata)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('be133639-e5d2-4313-9b1f-2d59fc054a16')
def test_get_object_with_if_modified_since(self):
# get object with if_modified_since
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string()
time_now = time.time()
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=None)
http_date = time.ctime(time_now - 86400)
list_metadata = {'If-Modified-Since': http_date}
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=list_metadata)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('641500d5-1612-4042-a04d-01fc4528bc30')
def test_get_object_with_if_none_match(self):
# get object with if_none_match
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.arbitrary_string(10)
create_md5 = hashlib.md5(data).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
object_name,
data,
metadata=create_metadata)
list_data = data_utils.arbitrary_string(15)
list_md5 = hashlib.md5(list_data).hexdigest()
list_metadata = {'If-None-Match': list_md5}
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=list_metadata)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('0aa1201c-10aa-467a-bee7-63cbdd463152')
def test_get_object_with_if_unmodified_since(self):
# get object with if_unmodified_since
object_name, data = self._create_object()
time_now = time.time()
http_date = time.ctime(time_now + 86400)
list_metadata = {'If-Unmodified-Since': http_date}
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=list_metadata)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('94587078-475f-48f9-a40f-389c246e31cd')
def test_get_object_with_x_newest(self):
# get object with x_newest
object_name, data = self._create_object()
list_metadata = {'X-Newest': 'true'}
resp, body = self.object_client.get_object(
self.container_name,
object_name,
metadata=list_metadata)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('1a9ab572-1b66-4981-8c21-416e2a5e6011')
def test_copy_object_in_same_container(self):
# create source object
src_object_name = data_utils.rand_name(name='SrcObject')
src_data = data_utils.arbitrary_string(size=len(src_object_name) * 2,
base_text=src_object_name)
resp, _ = self.object_client.create_object(self.container_name,
src_object_name,
src_data)
# create destination object
dst_object_name = data_utils.rand_name(name='DstObject')
dst_data = data_utils.arbitrary_string(size=len(dst_object_name) * 3,
base_text=dst_object_name)
resp, _ = self.object_client.create_object(self.container_name,
dst_object_name,
dst_data)
# copy source object to destination
resp, _ = self.object_client.copy_object_in_same_container(
self.container_name, src_object_name, dst_object_name)
self.assertHeaders(resp, 'Object', 'PUT')
# check data
resp, body = self.object_client.get_object(self.container_name,
dst_object_name)
self.assertEqual(body, src_data)
@test.idempotent_id('2248abba-415d-410b-9c30-22dff9cd6e67')
def test_copy_object_to_itself(self):
# change the content type of an existing object
# create object
object_name, data = self._create_object()
# get the old content type
resp_tmp, _ = self.object_client.list_object_metadata(
self.container_name, object_name)
# change the content type of the object
metadata = {'content-type': 'text/plain; charset=UTF-8'}
self.assertNotEqual(resp_tmp['content-type'], metadata['content-type'])
resp, _ = self.object_client.copy_object_in_same_container(
self.container_name, object_name, object_name, metadata)
self.assertHeaders(resp, 'Object', 'PUT')
# check the content type
resp, _ = self.object_client.list_object_metadata(self.container_name,
object_name)
self.assertEqual(resp['content-type'], metadata['content-type'])
@test.idempotent_id('06f90388-2d0e-40aa-934c-e9a8833e958a')
def test_copy_object_2d_way(self):
# create source object
src_object_name = data_utils.rand_name(name='SrcObject')
src_data = data_utils.arbitrary_string(size=len(src_object_name) * 2,
base_text=src_object_name)
resp, _ = self.object_client.create_object(self.container_name,
src_object_name, src_data)
# create destination object
dst_object_name = data_utils.rand_name(name='DstObject')
dst_data = data_utils.arbitrary_string(size=len(dst_object_name) * 3,
base_text=dst_object_name)
resp, _ = self.object_client.create_object(self.container_name,
dst_object_name, dst_data)
# copy source object to destination
resp, _ = self.object_client.copy_object_2d_way(self.container_name,
src_object_name,
dst_object_name)
self.assertHeaders(resp, 'Object', 'COPY')
self.assertEqual(
resp['x-copied-from'],
self.container_name + "/" + src_object_name)
# check data
self._check_copied_obj(dst_object_name, src_data)
@test.idempotent_id('aa467252-44f3-472a-b5ae-5b57c3c9c147')
def test_copy_object_across_containers(self):
# create a container to use as a source container
src_container_name = data_utils.rand_name(name='TestSourceContainer')
self.container_client.create_container(src_container_name)
self.containers.append(src_container_name)
# create a container to use as a destination container
dst_container_name = data_utils.rand_name(
name='TestDestinationContainer')
self.container_client.create_container(dst_container_name)
self.containers.append(dst_container_name)
# create object in source container
object_name = data_utils.rand_name(name='Object')
data = data_utils.arbitrary_string(size=len(object_name) * 2,
base_text=object_name)
resp, _ = self.object_client.create_object(src_container_name,
object_name, data)
# set object metadata
meta_key = data_utils.rand_name(name='test')
meta_value = data_utils.rand_name(name='MetaValue')
orig_metadata = {meta_key: meta_value}
resp, _ = self.object_client.update_object_metadata(src_container_name,
object_name,
orig_metadata)
self.assertHeaders(resp, 'Object', 'POST')
# copy object from source container to destination container
resp, _ = self.object_client.copy_object_across_containers(
src_container_name, object_name, dst_container_name,
object_name)
self.assertHeaders(resp, 'Object', 'PUT')
# check if object is present in destination container
resp, body = self.object_client.get_object(dst_container_name,
object_name)
self.assertEqual(body, data)
actual_meta_key = 'x-object-meta-' + meta_key
self.assertIn(actual_meta_key, resp)
self.assertEqual(resp[actual_meta_key], meta_value)
@test.idempotent_id('5a9e2cc6-85b6-46fc-916d-0cbb7a88e5fd')
def test_copy_object_with_x_fresh_metadata(self):
# create source object
metadata = {'x-object-meta-src': 'src_value'}
src_object_name, data = self._create_object(metadata)
# copy source object with x_fresh_metadata header
metadata = {'X-Fresh-Metadata': 'true'}
dst_object_name, resp = self._copy_object_2d(src_object_name,
metadata)
self.assertHeaders(resp, 'Object', 'COPY')
self.assertNotIn('x-object-meta-src', resp)
self.assertEqual(resp['x-copied-from'],
self.container_name + "/" + src_object_name)
# check that destination object does NOT have any object-meta
self._check_copied_obj(dst_object_name, data, not_in_meta=["src"])
@test.idempotent_id('a28a8b99-e701-4d7e-9d84-3b66f121460b')
def test_copy_object_with_x_object_metakey(self):
# create source object
metadata = {'x-object-meta-src': 'src_value'}
src_obj_name, data = self._create_object(metadata)
# copy source object to destination with x-object-meta-key
metadata = {'x-object-meta-test': ''}
dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
self.assertHeaders(resp, 'Object', 'COPY')
expected = {'x-object-meta-test': '',
'x-object-meta-src': 'src_value',
'x-copied-from': self.container_name + "/" + src_obj_name}
for key, value in six.iteritems(expected):
self.assertIn(key, resp)
self.assertEqual(value, resp[key])
# check destination object
self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
@test.idempotent_id('edabedca-24c3-4322-9b70-d6d9f942a074')
def test_copy_object_with_x_object_meta(self):
# create source object
metadata = {'x-object-meta-src': 'src_value'}
src_obj_name, data = self._create_object(metadata)
# copy source object to destination with object metadata
metadata = {'x-object-meta-test': 'value'}
dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
self.assertHeaders(resp, 'Object', 'COPY')
expected = {'x-object-meta-test': 'value',
'x-object-meta-src': 'src_value',
'x-copied-from': self.container_name + "/" + src_obj_name}
for key, value in six.iteritems(expected):
self.assertIn(key, resp)
self.assertEqual(value, resp[key])
# check destination object
self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
@test.idempotent_id('e3e6a64a-9f50-4955-b987-6ce6767c97fb')
def test_object_upload_in_segments(self):
# create object
object_name = data_utils.rand_name(name='LObject')
data = data_utils.arbitrary_string()
segments = 10
data_segments = [data + str(i) for i in six.moves.xrange(segments)]
# uploading segments
for i in six.moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
# creating a manifest file
metadata = {'X-Object-Manifest': '%s/%s/'
% (self.container_name, object_name)}
resp, _ = self.object_client.create_object(self.container_name,
object_name, data='')
self.assertHeaders(resp, 'Object', 'PUT')
resp, _ = self.object_client.update_object_metadata(
self.container_name, object_name, metadata, metadata_prefix='')
self.assertHeaders(resp, 'Object', 'POST')
resp, _ = self.object_client.list_object_metadata(
self.container_name, object_name)
# Etag value of a large object is enclosed in double-quotations.
# After etag quotes are checked they are removed and the response is
# checked if all common headers are present and well formatted
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
resp['etag'] = resp['etag'].strip('"')
self.assertHeaders(resp, 'Object', 'HEAD')
self.assertIn('x-object-manifest', resp)
self.assertEqual(resp['x-object-manifest'],
'%s/%s/' % (self.container_name, object_name))
# downloading the object
resp, body = self.object_client.get_object(
self.container_name, object_name)
self.assertEqual(''.join(data_segments), body)
@test.idempotent_id('50d01f12-526f-4360-9ac2-75dd508d7b68')
def test_get_object_if_different(self):
# http://en.wikipedia.org/wiki/HTTP_ETag
# Make a conditional request for an object using the If-None-Match
# header, it should get downloaded only if the local file is different,
# otherwise the response code should be 304 Not Modified
object_name, data = self._create_object()
# local copy is identical, no download
md5 = hashlib.md5(data).hexdigest()
headers = {'If-None-Match': md5}
url = "%s/%s" % (self.container_name, object_name)
resp, _ = self.object_client.get(url, headers=headers)
self.assertEqual(resp['status'], '304')
# When the file is not downloaded from Swift server, response does
# not contain 'X-Timestamp' header. This is the special case, therefore
# the existence of response headers is checked without custom matcher.
self.assertIn('content-type', resp)
self.assertIn('x-trans-id', resp)
self.assertIn('date', resp)
self.assertIn('accept-ranges', resp)
# Check only the format of common headers with custom matcher
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
# local copy is different, download
local_data = "something different"
md5 = hashlib.md5(local_data).hexdigest()
headers = {'If-None-Match': md5}
resp, body = self.object_client.get(url, headers=headers)
self.assertHeaders(resp, 'Object', 'GET')
class PublicObjectTest(base.BaseObjectTest):
credentials = [['operator', CONF.object_storage.operator_role],
['operator_alt', CONF.object_storage.operator_role]]
@classmethod
def setup_credentials(cls):
super(PublicObjectTest, cls).setup_credentials()
cls.os = cls.os_roles_operator
cls.os_alt = cls.os_roles_operator_alt
@classmethod
def setup_clients(cls):
super(PublicObjectTest, cls).setup_clients()
cls.identity_client_alt = cls.os_alt.identity_client
def setUp(self):
super(PublicObjectTest, self).setUp()
self.container_name = data_utils.rand_name(name='TestContainer')
self.container_client.create_container(self.container_name)
def tearDown(self):
self.delete_containers([self.container_name])
super(PublicObjectTest, self).tearDown()
@test.idempotent_id('07c9cf95-c0d4-4b49-b9c8-0ef2c9b27193')
def test_access_public_container_object_without_using_creds(self):
# make container public-readable and access an object in it object
# anonymously, without using credentials
# update container metadata to make it publicly readable
cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers, metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
data = data_utils.arbitrary_string(size=len(object_name),
base_text=object_name)
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
self.assertHeaders(resp, 'Object', 'PUT')
# list container metadata
resp_meta, _ = self.container_client.list_container_metadata(
self.container_name)
self.assertHeaders(resp_meta, 'Container', 'HEAD')
self.assertIn('x-container-read', resp_meta)
self.assertEqual(resp_meta['x-container-read'], '.r:*,.rlistings')
# trying to get object with empty headers as it is public readable
self.object_client.auth_provider.set_alt_auth_data(
request_part='headers',
auth_data=None
)
resp, body = self.object_client.get_object(
self.container_name, object_name)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
@test.idempotent_id('54e2a2fe-42dc-491b-8270-8e4217dd4cdc')
def test_access_public_object_with_another_user_creds(self):
# make container public-readable and access an object in it using
# another user's credentials
cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
data = data_utils.arbitrary_string(size=len(object_name) * 1,
base_text=object_name)
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
self.assertHeaders(resp, 'Object', 'PUT')
# list container metadata
resp, _ = self.container_client.list_container_metadata(
self.container_name)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertIn('x-container-read', resp)
self.assertEqual(resp['x-container-read'], '.r:*,.rlistings')
# get auth token of alternative user
alt_auth_data = self.identity_client_alt.auth_provider.auth_data
self.object_client.auth_provider.set_alt_auth_data(
request_part='headers',
auth_data=alt_auth_data
)
# access object using alternate user creds
resp, body = self.object_client.get_object(
self.container_name, object_name)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)