Added Swift tests:
* account: delete account metadata
* container: retrieve/delete container metadata
* object: retrieve/copy(2 ways) object
Syntax bug fix in container_client.py:
return resp. body => return resp, body
Fixed passing headers parameter in head method in rest_client.py:
return self.request('HEAD', url, headers)
Removed unused imports.
Change-Id: Ica67d6ecae80f851e9e05ebeb4c7d461eba143ee
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 6683b78..52ed6bc 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -172,7 +172,10 @@
return self.request('PUT', url, headers, body)
def head(self, url, headers=None):
- return self.request('HEAD', url, headers=None)
+ return self.request('HEAD', url, headers)
+
+ def copy(self, url, headers=None):
+ return self.request('COPY', url, headers)
def _log(self, req_url, body, resp, resp_body):
self.log.error('Request URL: ' + req_url)
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 2a686f6..4eaeb34 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -47,6 +47,18 @@
resp, body = self.post('', headers=headers, body=None)
return resp, body
+ def delete_account_metadata(self, metadata,
+ metadata_prefix='X-Remove-Account-Meta-'):
+ """
+ Deletes an account metadata entry.
+ """
+
+ headers = {"X-Storage-Token": self.token}
+ for item in metadata:
+ headers[metadata_prefix + item] = 'x'
+ resp, body = self.post('', headers=headers, body=None)
+ return resp, body
+
def list_account_containers(self, params=None):
"""
GET on the (base) storage URL
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index 56dffde..bb08de2 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -63,8 +63,29 @@
headers[metadata_prefix + key] = metadata[key]
resp, body = self.post(url, body=None, headers=headers)
+ return resp, body
- return resp. body
+ def delete_container_metadata(self, container_name, metadata,
+ metadata_prefix='X-Remove-Container-Meta-'):
+ """Deletes arbitrary metadata on container"""
+ url = container_name
+ headers = {}
+
+ if metadata is not None:
+ for item in metadata:
+ headers[metadata_prefix + item] = 'x'
+
+ resp, body = self.post(url, body=None, headers=headers)
+ return resp, body
+
+ def list_container_metadata(self, container_name):
+ """
+ Retrieves container metadata headers
+ """
+ url = container_name
+ headers = {"X-Storage-Token": self.token}
+ resp, body = self.head(url, headers=headers)
+ return resp, body
def list_all_container_objects(self, container, params=None):
"""
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 0fc7ad4..440d043 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -61,3 +61,41 @@
url = "%s/%s" % (str(container), str(object_name))
resp, body = self.head(url)
return resp, body
+
+ def get_object(self, container, object_name):
+ """Retrieve object's data."""
+
+ url = "{0}/{1}".format(container, object_name)
+ resp, body = self.get(url)
+ return resp, body
+
+ def copy_object(self, container, src_object_name, dest_object_name,
+ metadata=None):
+ """Copy storage object's data to the new object using PUT"""
+
+ url = "{0}/{1}".format(container, dest_object_name)
+ headers = {}
+ headers['X-Copy-From'] = "%s/%s" % (str(container),
+ str(src_object_name))
+ headers['content-length'] = '0'
+ if metadata:
+ for key in metadata:
+ headers[str(key)] = metadata[key]
+
+ resp, body = self.put(url, None, headers=headers)
+ return resp, body
+
+ def copy_object_2d_way(self, container, src_object_name, dest_object_name,
+ metadata=None):
+ """Copy storage object's data to the new object using COPY"""
+
+ url = "{0}/{1}".format(container, src_object_name)
+ headers = {}
+ headers['Destination'] = "%s/%s" % (str(container),
+ str(dest_object_name))
+ if metadata:
+ for key in metadata:
+ headers[str(key)] = metadata[key]
+
+ resp, body = self.copy(url, headers=headers)
+ return resp, body
diff --git a/tempest/tests/object_storage/test_account_services.py b/tempest/tests/object_storage/test_account_services.py
index 6d34bb8..db3aa69 100644
--- a/tempest/tests/object_storage/test_account_services.py
+++ b/tempest/tests/object_storage/test_account_services.py
@@ -15,13 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import unittest2 as unittest
-import tempest.config
-import re
-
from nose.plugins.attrib import attr
-from tempest import exceptions
-from tempest import openstack
from tempest.common.utils.data_utils import rand_name
from tempest.tests.object_storage import base
@@ -74,3 +68,15 @@
resp, metadata = self.account_client.list_account_metadata()
self.assertIn('x-account-meta-test-account-meta', resp)
self.assertEqual(resp['x-account-meta-test-account-meta'], 'Meta!')
+
+ @attr(type='smoke')
+ def test_delete_account_metadata(self):
+ """Delete metadata from account"""
+
+ metadata = ['test-account-meta']
+ resp, _ = \
+ self.account_client.delete_account_metadata(metadata=metadata)
+ self.assertEqual(resp['status'], '204')
+
+ resp, metadata = self.account_client.list_account_metadata()
+ self.assertNotIn('x-account-meta-test-account-meta', resp)
diff --git a/tempest/tests/object_storage/test_container_services.py b/tempest/tests/object_storage/test_container_services.py
index 639698b..e57256b 100644
--- a/tempest/tests/object_storage/test_container_services.py
+++ b/tempest/tests/object_storage/test_container_services.py
@@ -15,13 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import re
-import unittest2 as unittest
-import tempest.config
-
from nose.plugins.attrib import attr
-from tempest import exceptions
-from tempest import openstack
from tempest.common.utils.data_utils import rand_name, arbitrary_string
from tempest.tests.object_storage import base
@@ -108,3 +102,47 @@
object_names = [obj['name'] for obj in object_list]
self.assertIn(object_name, object_names)
+
+ @attr(type='smoke')
+ def test_container_metadata(self):
+ """Update/Retrieve/Delete Container Metadata"""
+
+ # Create a container
+ container_name = rand_name(name='TestContainer')
+ resp, _ = self.container_client.create_container(container_name)
+ self.containers.append(container_name)
+
+ # Update container metadata
+ metadata = {'name': 'Pictures',
+ 'description': 'Travel'
+ }
+ resp, _ = \
+ self.container_client.update_container_metadata(container_name,
+ metadata=metadata)
+ self.assertEqual(resp['status'], '204')
+
+ # List container metadata
+ resp, _ = self.container_client.list_container_metadata(
+ container_name)
+ self.assertEqual(resp['status'], '204')
+ self.assertIn('x-container-meta-name', resp)
+ self.assertIn('x-container-meta-description', resp)
+ self.assertEqual(resp['x-container-meta-name'], 'Pictures')
+ self.assertEqual(resp['x-container-meta-description'], 'Travel')
+
+ # Delete container metadata
+ resp, _ = \
+ self.container_client.delete_container_metadata(
+ container_name,
+ metadata=metadata.keys())
+ self.assertEqual(resp['status'], '204')
+
+ resp, _ = self.container_client.list_container_metadata(container_name)
+ self.assertEqual(resp['status'], '204')
+ self.assertNotIn('x-container-meta-name', resp)
+ self.assertNotIn('x-container-meta-description', resp)
+
+ # Delete Container
+ resp, _ = self.container_client.delete_container(container_name)
+ self.assertEqual(resp['status'], '204')
+ self.containers.remove(container_name)
diff --git a/tempest/tests/object_storage/test_object_services.py b/tempest/tests/object_storage/test_object_services.py
index ab92d26..cb72e9d 100644
--- a/tempest/tests/object_storage/test_object_services.py
+++ b/tempest/tests/object_storage/test_object_services.py
@@ -15,13 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import re
-import unittest2 as unittest
-import tempest.config
-
from nose.plugins.attrib import attr
-from tempest import exceptions
-from tempest import openstack
from tempest.common.utils.data_utils import rand_name, arbitrary_string
from tempest.tests.object_storage import base
@@ -110,3 +104,104 @@
actual_meta_key = 'x-object-meta-' + meta_key
self.assertTrue(actual_meta_key in resp)
self.assertEqual(resp[actual_meta_key], meta_value)
+
+ @attr(type='smoke')
+ def test_get_object(self):
+ """Retrieve object's data(in response body)"""
+
+ #Create Object
+ object_name = rand_name(name='TestObject')
+ data = arbitrary_string()
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, data)
+
+ resp, body = self.object_client.get_object(self.container_name,
+ object_name)
+ self.assertEqual(resp['status'], '200')
+ # Check data
+ self.assertEqual(body, data)
+
+ @attr(type='smoke')
+ def test_copy_object(self):
+ """Copy storage object"""
+
+ # Create source Object
+ src_object_name = rand_name(name='SrcObject')
+ src_data = 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 destinametion Object
+ dst_object_name = rand_name(name='DstObject')
+ dst_data = 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(self.container_name,
+ src_object_name,
+ dst_object_name)
+ self.assertEqual(resp['status'], '201')
+
+ # Check data
+ resp, body = self.object_client.get_object(self.container_name,
+ dst_object_name)
+ self.assertEqual(body, src_data)
+
+ @attr(type='smoke')
+ def test_copy_object_to_itself(self):
+ """Change the content type of an existing object"""
+
+ # Create Object
+ object_name = rand_name(name='TestObject')
+ data = arbitrary_string()
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, data)
+ # 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(self.container_name,
+ object_name,
+ object_name,
+ metadata)
+ self.assertEqual(resp['status'], '201')
+
+ # Check the content type
+ resp, _ = self.object_client.list_object_metadata(self.container_name,
+ object_name)
+ self.assertEqual(resp['content-type'], metadata['content-type'])
+
+ @attr(type='smoke')
+ def test_copy_object_2d_way(self):
+ """Copy storage object"""
+
+ # Create source Object
+ src_object_name = rand_name(name='SrcObject')
+ src_data = 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 destinametion Object
+ dst_object_name = rand_name(name='DstObject')
+ dst_data = 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.assertEqual(resp['status'], '201')
+
+ # Check data
+ resp, body = self.object_client.get_object(self.container_name,
+ dst_object_name)
+ self.assertEqual(body, src_data)