Add a discoverable_apis option for swift
This commit adds a new list option for the object-storage-feature-enabled
config group, discoverable_apis, which lists out which Swift discoverable
optional apis are expected to be enabled on the swift server. It also
converts the pre-existing single boolean options for these types of
features to use the new list option. This option is used in the same
manner as the extensions list options for the other services. However,
since swift doesn't have the same concept of extensions as some of the
other OpenStack projects optional discoverable apis (which are often
but not always tied with middleware) were used instead. If an optional
api being enabled isn't discoverable from an external api call then
that should have a separate config option in the
object-storage-feature-enabled config group.
Partially implements bp config-cleanup
Change-Id: I846860804050ec44491ce05d6b72e1cc639609b1
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index f306d8e..2173eb6 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -548,21 +548,10 @@
# Options defined in tempest.config
#
-# Set to True if the Container Quota middleware is enabled
-# (boolean value)
-#container_quotas=true
-
-# Set to True if the Account Quota middleware is enabled
-# (boolean value)
-#accounts_quotas=true
-
-# Set to True if the Crossdomain middleware is enabled
-# (boolean value)
-#crossdomain=true
-
-# Set to True if the TempURL middleware is enabled (boolean
-# value)
-#tempurl=true
+# A list of the enabled optional discoverable apis. A single
+# entry, all, indicates that all of these features are
+# expected to be enabled (list value)
+#discoverable_apis=all
[orchestration]
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index ac1c7d1..6312f69 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -14,21 +14,17 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.object_storage import base
from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
class AccountQuotasTest(base.BaseObjectTest):
- accounts_quotas_available = \
- CONF.object_storage_feature_enabled.accounts_quotas
@classmethod
def setUpClass(cls):
@@ -99,9 +95,8 @@
cls.data.teardown_all()
super(AccountQuotasTest, cls).tearDownClass()
- @testtools.skipIf(not accounts_quotas_available,
- "Account Quotas middleware not available")
- @attr(type="smoke")
+ @test.attr(type="smoke")
+ @test.requires_ext(extension='account_quotas', service='object')
def test_upload_valid_object(self):
object_name = data_utils.rand_name(name="TestObject")
data = data_utils.arbitrary_string()
@@ -111,9 +106,8 @@
self.assertEqual(resp["status"], "201")
self.assertHeaders(resp, 'Object', 'PUT')
- @testtools.skipIf(not accounts_quotas_available,
- "Account Quotas middleware not available")
- @attr(type=["negative", "smoke"])
+ @test.attr(type=["negative", "smoke"])
+ @test.requires_ext(extension='account_quotas', service='object')
def test_upload_large_object(self):
object_name = data_utils.rand_name(name="TestObject")
data = data_utils.arbitrary_string(30)
@@ -121,9 +115,8 @@
self.object_client.create_object,
self.container_name, object_name, data)
- @testtools.skipIf(not accounts_quotas_available,
- "Account Quotas middleware not available")
- @attr(type=["smoke"])
+ @test.attr(type=["smoke"])
+ @test.requires_ext(extension='account_quotas', service='object')
def test_admin_modify_quota(self):
"""Test that the ResellerAdmin is able to modify and remove the quota
on a user's account.
@@ -146,9 +139,8 @@
self.assertEqual(resp["status"], "204")
self.assertHeaders(resp, 'Account', 'POST')
- @testtools.skipIf(not accounts_quotas_available,
- "Account Quotas middleware not available")
- @attr(type=["negative", "smoke"])
+ @test.attr(type=["negative", "smoke"])
+ @test.requires_ext(extension='account_quotas', service='object')
def test_user_modify_quota(self):
"""Test that a user is not able to modify or remove a quota on
its account.
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 513d24a..103ee89 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -15,25 +15,19 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
CONF = config.CONF
QUOTA_BYTES = 10
QUOTA_COUNT = 3
-SKIP_MSG = "Container quotas middleware not available."
class ContainerQuotasTest(base.BaseObjectTest):
"""Attemps to test the perfect behavior of quotas in a container."""
- container_quotas_available = \
- CONF.object_storage_feature_enabled.container_quotas
def setUp(self):
"""Creates and sets a container with quotas.
@@ -58,8 +52,8 @@
self.delete_containers([self.container_name])
super(ContainerQuotasTest, self).tearDown()
- @testtools.skipIf(not container_quotas_available, SKIP_MSG)
- @attr(type="smoke")
+ @test.requires_ext(extension='container_quotas', service='object')
+ @test.attr(type="smoke")
def test_upload_valid_object(self):
"""Attempts to uploads an object smaller than the bytes quota."""
object_name = data_utils.rand_name(name="TestObject")
@@ -69,14 +63,14 @@
resp, _ = self.object_client.create_object(
self.container_name, object_name, data)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'PUT')
nafter = self._get_bytes_used()
self.assertEqual(nbefore + len(data), nafter)
- @testtools.skipIf(not container_quotas_available, SKIP_MSG)
- @attr(type="smoke")
+ @test.requires_ext(extension='container_quotas', service='object')
+ @test.attr(type="smoke")
def test_upload_large_object(self):
"""Attempts to upload an object lagger than the bytes quota."""
object_name = data_utils.rand_name(name="TestObject")
@@ -91,8 +85,8 @@
nafter = self._get_bytes_used()
self.assertEqual(nbefore, nafter)
- @testtools.skipIf(not container_quotas_available, SKIP_MSG)
- @attr(type="smoke")
+ @test.requires_ext(extension='container_quotas', service='object')
+ @test.attr(type="smoke")
def test_upload_too_many_objects(self):
"""Attempts to upload many objects that exceeds the count limit."""
for _ in range(QUOTA_COUNT):
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index 41430c8..debd432 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -19,27 +19,14 @@
from tempest.api.object_storage import base
from tempest import clients
from tempest.common import custom_matchers
-from tempest import config
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
-
-CONF = config.CONF
+from tempest import test
class CrossdomainTest(base.BaseObjectTest):
- crossdomain_available = \
- CONF.object_storage_feature_enabled.crossdomain
@classmethod
def setUpClass(cls):
super(CrossdomainTest, cls).setUpClass()
-
- # skip this test if CORS isn't enabled in the conf file.
- if not cls.crossdomain_available:
- skip_msg = ("%s skipped as Crossdomain middleware not available"
- % cls.__name__)
- raise cls.skipException(skip_msg)
-
# creates a test user. The test user will set its base_url to the Swift
# endpoint and test the healthcheck feature.
cls.data.setup_test_user()
@@ -75,12 +62,13 @@
super(CrossdomainTest, self).tearDown()
- @attr('gate')
+ @test.attr('gate')
+ @test.requires_ext(extension='crossdomain', service='object')
def test_get_crossdomain_policy(self):
resp, body = self.os_test_user.account_client.get("crossdomain.xml",
{})
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertTrue(body.startswith(self.xml_start) and
body.endswith(self.xml_end))
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index d0e5353..d1b3674 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -24,27 +24,16 @@
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
CONF = config.CONF
class ObjectTempUrlTest(base.BaseObjectTest):
- tempurl_available = \
- CONF.object_storage_feature_enabled.tempurl
-
@classmethod
def setUpClass(cls):
super(ObjectTempUrlTest, cls).setUpClass()
-
- # skip this test if TempUrl isn't enabled in the conf file.
- if not cls.tempurl_available:
- skip_msg = ("%s skipped as TempUrl middleware not available"
- % cls.__name__)
- raise cls.skipException(skip_msg)
-
# create a container
cls.container_name = data_utils.rand_name(name='TestContainer')
cls.container_client.create_container(cls.container_name)
@@ -108,7 +97,8 @@
return url
- @attr(type='gate')
+ @test.attr(type='gate')
+ @test.requires_ext(extension='tempurl', service='object')
def test_get_object_using_temp_url(self):
expires = self._get_expiry_date()
@@ -119,16 +109,17 @@
# trying to get object using temp url within expiry time
resp, body = self.object_client.get(url)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, self.content)
# Testing a HEAD on this Temp URL
resp, body = self.object_client.head(url)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
- @attr(type='gate')
+ @test.attr(type='gate')
+ @test.requires_ext(extension='tempurl', service='object')
def test_get_object_using_temp_url_key_2(self):
key2 = 'Meta2-'
metadata = {'Temp-URL-Key-2': key2}
@@ -149,10 +140,11 @@
self.object_name, "GET",
expires, key2)
resp, body = self.object_client.get(url)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertEqual(body, self.content)
- @attr(type='gate')
+ @test.attr(type='gate')
+ @test.requires_ext(extension='tempurl', service='object')
def test_put_object_using_temp_url(self):
new_data = data_utils.arbitrary_string(
size=len(self.object_name),
@@ -165,12 +157,12 @@
# trying to put random data in the object using temp url
resp, body = self.object_client.put(url, new_data, None)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'PUT')
# Testing a HEAD on this Temp URL
resp, body = self.object_client.head(url)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
# Validate that the content of the object has been modified
@@ -181,7 +173,8 @@
_, body = self.object_client.get(url)
self.assertEqual(body, new_data)
- @attr(type='gate')
+ @test.attr(type='gate')
+ @test.requires_ext(extension='tempurl', service='object')
def test_head_object_using_temp_url(self):
expires = self._get_expiry_date()
@@ -192,10 +185,11 @@
# Testing a HEAD on this Temp URL
resp, body = self.object_client.head(url)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
- @attr(type=['gate', 'negative'])
+ @test.attr(type=['gate', 'negative'])
+ @test.requires_ext(extension='tempurl', service='object')
def test_get_object_after_expiration_time(self):
expires = self._get_expiry_date(1)
diff --git a/tempest/config.py b/tempest/config.py
index d42edc9..6f6da50 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -415,19 +415,11 @@
title='Enabled object-storage features')
ObjectStoreFeaturesGroup = [
- cfg.BoolOpt('container_quotas',
- default=True,
- help="Set to True if the Container Quota middleware "
- "is enabled"),
- cfg.BoolOpt('accounts_quotas',
- default=True,
- help="Set to True if the Account Quota middleware is enabled"),
- cfg.BoolOpt('crossdomain',
- default=True,
- help="Set to True if the Crossdomain middleware is enabled"),
- cfg.BoolOpt('tempurl',
- default=True,
- help="Set to True if the TempURL middleware is enabled"),
+ cfg.ListOpt('discoverable_apis',
+ default=['all'],
+ help="A list of the enabled optional discoverable apis. "
+ "A single entry, all, indicates that all of these "
+ "features are expected to be enabled"),
]
diff --git a/tempest/test.py b/tempest/test.py
index 342846f..d57ed83 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -163,6 +163,7 @@
'compute_v3': configs.compute_feature_enabled.api_v3_extensions,
'volume': configs.volume_feature_enabled.api_extensions,
'network': configs.network_feature_enabled.api_extensions,
+ 'object': configs.object_storage_feature_enabled.discoverable_apis,
}
if config_dict[service][0] == 'all':
return True