Add config options for enabled extensions
This commit adds a new set of config options to the feature_enabled
groups for a list of enabled extensions. These options are used to
specify whether all extensions are enabled or which subset is expected
to be enabled. This just sets up the initial framework for doing
this and converts the FlavorExtraSpecs tests to use it.
paritally implements bp config-cleanup
Change-Id: I6a5a9b16e62eb8a216334a0662c99f0dd0d16873
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 937bbd3..9357b62 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -524,6 +524,16 @@
#disk_format=raw
+[debug]
+
+#
+# Options defined in tempest.config
+#
+
+# Enable diagnostic commands (boolean value)
+#enable=true
+
+
[dashboard]
#
@@ -610,14 +620,15 @@
#operator_role=Member
-[debug]
+[network-feature-enabled]
#
# Options defined in tempest.config
#
-# Enable diagnostic commands (boolean value)
-#enable=true
+# A list of enabled extensions with a special entry all which
+# indicates every extension is enabled (list value)
+#api_extensions=all
[service_available]
@@ -671,8 +682,13 @@
# If false, skip disk config tests (boolean value)
#disk_config=true
-# If false, skip flavor extra data test (boolean value)
-#flavor_extra=true
+# A list of enabled extensions with a special entry all which
+# indicates every extension is enabled (list value)
+#api_extensions=all
+
+# A list of enabled v3 extensions with a special entry all
+# which indicates every extension is enabled (list value)
+#api_v3_extensions=all
# Does the test environment support changing the admin
# password? (boolean value)
@@ -730,4 +746,8 @@
# (boolean value)
#multi_backend=false
+# A list of enabled extensions with a special entry all which
+# indicates every extension is enabled (list value)
+#api_extensions=all
+
diff --git a/tempest/api/compute/__init__.py b/tempest/api/compute/__init__.py
index a528754..dd92ee9 100644
--- a/tempest/api/compute/__init__.py
+++ b/tempest/api/compute/__init__.py
@@ -26,7 +26,6 @@
RESIZE_AVAILABLE = CONFIG.compute_feature_enabled.resize
CHANGE_PASSWORD_AVAILABLE = CONFIG.compute_feature_enabled.change_password
DISK_CONFIG_ENABLED = CONFIG.compute_feature_enabled.disk_config
-FLAVOR_EXTRA_DATA_ENABLED = CONFIG.compute_feature_enabled.flavor_extra
MULTI_USER = True
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index c5a8772..cf72e49 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -17,12 +17,10 @@
import uuid
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
class FlavorsAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -36,7 +34,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsAdminTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -87,19 +85,19 @@
return flavor['id']
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_flavor_with_int_id(self):
flavor_id = data_utils.rand_int_id(start=1000)
new_flavor_id = self._create_flavor(flavor_id)
self.assertEqual(new_flavor_id, str(flavor_id))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_flavor_with_uuid_id(self):
flavor_id = str(uuid.uuid4())
new_flavor_id = self._create_flavor(flavor_id)
self.assertEqual(new_flavor_id, flavor_id)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_flavor_with_none_id(self):
# If nova receives a request with None as flavor_id,
# nova generates flavor_id of uuid.
@@ -107,7 +105,7 @@
new_flavor_id = self._create_flavor(flavor_id)
self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id)))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_flavor_verify_entry_in_list_details(self):
# Create a flavor and ensure it's details are listed
# This operation requires the user to have 'admin' role
@@ -132,7 +130,7 @@
flag = True
self.assertTrue(flag)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_flavor_details_for_deleted_flavor(self):
# Delete a flavor and ensure it is not listed
# Create a test flavor
@@ -166,7 +164,7 @@
flag = False
self.assertTrue(flag)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_list_flavor_without_extra_data(self):
# Create a flavor and ensure it is listed
# This operation requires the user to have 'admin' role
@@ -210,8 +208,8 @@
flag = True
self.assertTrue(flag)
- @skip_because(bug="1209101")
- @attr(type='gate')
+ @test.skip_because(bug="1209101")
+ @test.attr(type='gate')
def test_list_non_public_flavor(self):
# Create a flavor with os-flavor-access:is_public false should
# be present in list_details.
@@ -244,7 +242,7 @@
flag = True
self.assertFalse(flag)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_server_with_non_public_flavor(self):
# Create a flavor with os-flavor-access:is_public false
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -264,7 +262,7 @@
self.os.servers_client.create_server,
'test', self.image_ref, flavor['id'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_public_flavor_with_other_user(self):
# Create a Flavor with public access.
# Try to List/Get flavor with another user
@@ -288,7 +286,7 @@
flag = True
self.assertTrue(flag)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_is_public_string_variations(self):
flavor_id_not_public = data_utils.rand_int_id(start=1000)
flavor_name_not_public = data_utils.rand_name(self.flavor_name_prefix)
@@ -331,7 +329,7 @@
_test_string_variations(['t', 'true', 'yes', '1'],
flavor_name_public)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_flavor_using_string_ram(self):
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
new_flavor_id = data_utils.rand_int_id(start=1000)
@@ -349,13 +347,13 @@
self.assertEqual(flavor['ram'], int(ram))
self.assertEqual(int(flavor['id']), new_flavor_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_invalid_is_public_string(self):
self.assertRaises(exceptions.BadRequest,
self.client.list_flavors_with_detail,
{'is_public': 'invalid'})
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_flavor_as_user(self):
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
new_flavor_id = data_utils.rand_int_id(start=1000)
@@ -366,13 +364,13 @@
new_flavor_id, ephemeral=self.ephemeral,
swap=self.swap, rxtx=self.rxtx)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_flavor_as_user(self):
self.assertRaises(exceptions.Unauthorized,
self.user_client.delete_flavor,
self.flavor_ref_alt)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_flavor_using_invalid_ram(self):
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
new_flavor_id = data_utils.rand_int_id(start=1000)
@@ -382,7 +380,7 @@
flavor_name, -1, self.vcpus,
self.disk, new_flavor_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_flavor_using_invalid_vcpus(self):
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
new_flavor_id = data_utils.rand_int_id(start=1000)
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index b866db1..048312b 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -15,10 +15,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
@@ -33,7 +32,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsAccessTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -51,7 +50,7 @@
cls.vcpus = 1
cls.disk = 10
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_access_list_with_private_flavor(self):
# Test to list flavor access successfully by querying private flavor
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -70,7 +69,7 @@
self.assertEqual(str(new_flavor_id), str(first_flavor['flavor_id']))
self.assertEqual(self.adm_tenant_id, first_flavor['tenant_id'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_access_add_remove(self):
# Test to add and remove flavor access to a given tenant.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 340c1c7..976124e 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -17,11 +17,10 @@
import uuid
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -36,7 +35,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -54,7 +53,7 @@
cls.vcpus = 1
cls.disk = 10
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_access_list_with_public_flavor(self):
# Test to list flavor access with exceptions by querying public flavor
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -70,7 +69,7 @@
self.client.list_flavor_access,
new_flavor_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_add(self):
# Test to add flavor access as a user without admin privileges.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -86,7 +85,7 @@
new_flavor['id'],
self.tenant_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_remove(self):
# Test to remove flavor access as a user without admin privileges.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -106,7 +105,7 @@
new_flavor['id'],
self.tenant_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_add_flavor_access_duplicate(self):
# Create a new flavor.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -130,7 +129,7 @@
new_flavor['id'],
self.tenant_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_remove_flavor_access_not_found(self):
# Create a new flavor.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 49b0429..875f742 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -15,10 +15,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
@@ -34,7 +33,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -61,7 +60,7 @@
cls.client.wait_for_resource_deletion(cls.flavor['id'])
super(FlavorsExtraSpecsTestJSON, cls).tearDownClass()
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_set_get_update_show_unset_keys(self):
# Test to SET, GET, UPDATE, SHOW, UNSET flavor extra
# spec as a user with admin privileges.
@@ -101,7 +100,7 @@
self.client.unset_flavor_extra_spec(self.flavor['id'], "key2")
self.assertEqual(unset_resp.status, 200)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_non_admin_get_all_keys(self):
specs = {"key1": "value1", "key2": "value2"}
set_resp, set_body = self.client.set_flavor_extra_spec(
@@ -113,7 +112,7 @@
for key in specs:
self.assertEqual(body[key], specs[key])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_non_admin_get_specific_key(self):
specs = {"key1": "value1", "key2": "value2"}
resp, body = self.client.set_flavor_extra_spec(
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index d7e1f9f..fb09a63 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -16,11 +16,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -35,7 +34,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -62,7 +61,7 @@
cls.client.wait_for_resource_deletion(cls.flavor['id'])
super(FlavorsExtraSpecsNegativeTestJSON, cls).tearDownClass()
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_set_keys(self):
# Test to SET flavor extra spec as a user without admin privileges.
specs = {"key1": "value1", "key2": "value2"}
@@ -71,7 +70,7 @@
self.flavor['id'],
specs)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_update_specific_key(self):
# non admin user is not allowed to update flavor extra spec
specs = {"key1": "value1", "key2": "value2"}
@@ -86,7 +85,7 @@
'key1',
key1='value1_new')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_unset_keys(self):
specs = {"key1": "value1", "key2": "value2"}
set_resp, set_body = self.client.set_flavor_extra_spec(
@@ -97,7 +96,7 @@
self.flavor['id'],
'key1')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_unset_nonexistent_key(self):
nonexistent_key = data_utils.rand_name('flavor_key')
self.assertRaises(exceptions.NotFound,
@@ -105,14 +104,14 @@
self.flavor['id'],
nonexistent_key)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_get_nonexistent_key(self):
self.assertRaises(exceptions.NotFound,
self.flavors_client.get_flavor_extra_spec_with_key,
self.flavor['id'],
"nonexistent_key")
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_update_mismatch_key(self):
# the key will be updated should be match the key in the body
self.assertRaises(exceptions.BadRequest,
@@ -121,7 +120,7 @@
"key2",
key1="value")
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_update_more_key(self):
# there should be just one item in the request body
self.assertRaises(exceptions.BadRequest,
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
index b866db1..048312b 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -15,10 +15,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
@@ -33,7 +32,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsAccessTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -51,7 +50,7 @@
cls.vcpus = 1
cls.disk = 10
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_access_list_with_private_flavor(self):
# Test to list flavor access successfully by querying private flavor
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -70,7 +69,7 @@
self.assertEqual(str(new_flavor_id), str(first_flavor['flavor_id']))
self.assertEqual(self.adm_tenant_id, first_flavor['tenant_id'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_access_add_remove(self):
# Test to add and remove flavor access to a given tenant.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
index 340c1c7..976124e 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -17,11 +17,10 @@
import uuid
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -36,7 +35,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -54,7 +53,7 @@
cls.vcpus = 1
cls.disk = 10
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_access_list_with_public_flavor(self):
# Test to list flavor access with exceptions by querying public flavor
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -70,7 +69,7 @@
self.client.list_flavor_access,
new_flavor_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_add(self):
# Test to add flavor access as a user without admin privileges.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -86,7 +85,7 @@
new_flavor['id'],
self.tenant_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_remove(self):
# Test to remove flavor access as a user without admin privileges.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -106,7 +105,7 @@
new_flavor['id'],
self.tenant_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_add_flavor_access_duplicate(self):
# Create a new flavor.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -130,7 +129,7 @@
new_flavor['id'],
self.tenant_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_remove_flavor_access_not_found(self):
# Create a new flavor.
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
index 49b0429..875f742 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
@@ -15,10 +15,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
@@ -34,7 +33,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -61,7 +60,7 @@
cls.client.wait_for_resource_deletion(cls.flavor['id'])
super(FlavorsExtraSpecsTestJSON, cls).tearDownClass()
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_set_get_update_show_unset_keys(self):
# Test to SET, GET, UPDATE, SHOW, UNSET flavor extra
# spec as a user with admin privileges.
@@ -101,7 +100,7 @@
self.client.unset_flavor_extra_spec(self.flavor['id'], "key2")
self.assertEqual(unset_resp.status, 200)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_non_admin_get_all_keys(self):
specs = {"key1": "value1", "key2": "value2"}
set_resp, set_body = self.client.set_flavor_extra_spec(
@@ -113,7 +112,7 @@
for key in specs:
self.assertEqual(body[key], specs[key])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_flavor_non_admin_get_specific_key(self):
specs = {"key1": "value1", "key2": "value2"}
resp, body = self.client.set_flavor_extra_spec(
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
index d7e1f9f..fb09a63 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
@@ -16,11 +16,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -35,7 +34,7 @@
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
- if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ if not test.is_extension_enabled('FlavorExtraData', 'compute'):
msg = "FlavorExtraData extension not enabled."
raise cls.skipException(msg)
@@ -62,7 +61,7 @@
cls.client.wait_for_resource_deletion(cls.flavor['id'])
super(FlavorsExtraSpecsNegativeTestJSON, cls).tearDownClass()
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_set_keys(self):
# Test to SET flavor extra spec as a user without admin privileges.
specs = {"key1": "value1", "key2": "value2"}
@@ -71,7 +70,7 @@
self.flavor['id'],
specs)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_update_specific_key(self):
# non admin user is not allowed to update flavor extra spec
specs = {"key1": "value1", "key2": "value2"}
@@ -86,7 +85,7 @@
'key1',
key1='value1_new')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_non_admin_unset_keys(self):
specs = {"key1": "value1", "key2": "value2"}
set_resp, set_body = self.client.set_flavor_extra_spec(
@@ -97,7 +96,7 @@
self.flavor['id'],
'key1')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_unset_nonexistent_key(self):
nonexistent_key = data_utils.rand_name('flavor_key')
self.assertRaises(exceptions.NotFound,
@@ -105,14 +104,14 @@
self.flavor['id'],
nonexistent_key)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_get_nonexistent_key(self):
self.assertRaises(exceptions.NotFound,
self.flavors_client.get_flavor_extra_spec_with_key,
self.flavor['id'],
"nonexistent_key")
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_update_mismatch_key(self):
# the key will be updated should be match the key in the body
self.assertRaises(exceptions.BadRequest,
@@ -121,7 +120,7 @@
"key2",
key1="value")
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_flavor_update_more_key(self):
# there should be just one item in the request body
self.assertRaises(exceptions.BadRequest,
diff --git a/tempest/config.py b/tempest/config.py
index 220fd04..3d9eba9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -208,9 +208,14 @@
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
- cfg.BoolOpt('flavor_extra',
- default=True,
- help="If false, skip flavor extra data test"),
+ cfg.ListOpt('api_extensions',
+ default=['all'],
+ help='A list of enabled extensions with a special entry all '
+ 'which indicates every extension is enabled'),
+ cfg.ListOpt('api_v3_extensions',
+ default=['all'],
+ help='A list of enabled v3 extensions with a special entry all'
+ ' which indicates every extension is enabled'),
cfg.BoolOpt('change_password',
default=False,
help="Does the test environment support changing the admin "
@@ -317,6 +322,16 @@
"connectivity"),
]
+network_feature_group = cfg.OptGroup(name='network-feature-enabled',
+ title='Enabled network service features')
+
+NetworkFeaturesGroup = [
+ cfg.ListOpt('api_extensions',
+ default=['all'],
+ help='A list of enabled extensions with a special entry all '
+ 'which indicates every extension is enabled'),
+]
+
volume_group = cfg.OptGroup(name='volume',
title='Block Storage Options')
@@ -360,7 +375,11 @@
VolumeFeaturesGroup = [
cfg.BoolOpt('multi_backend',
default=False,
- help="Runs Cinder multi-backend test (requires 2 backends)")
+ help="Runs Cinder multi-backend test (requires 2 backends)"),
+ cfg.ListOpt('api_extensions',
+ default=['all'],
+ help='A list of enabled extensions with a special entry all '
+ 'which indicates every extension is enabled'),
]
@@ -659,6 +678,8 @@
register_opt_group(cfg.CONF, image_group, ImageGroup)
register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
register_opt_group(cfg.CONF, network_group, NetworkGroup)
+ register_opt_group(cfg.CONF, network_feature_group,
+ NetworkFeaturesGroup)
register_opt_group(cfg.CONF, volume_group, VolumeGroup)
register_opt_group(cfg.CONF, volume_feature_group,
VolumeFeaturesGroup)
@@ -680,6 +701,7 @@
self.images = cfg.CONF.image
self.image_feature_enabled = cfg.CONF['image-feature-enabled']
self.network = cfg.CONF.network
+ self.network_feature_enabled = cfg.CONF['network-feature-enabled']
self.volume = cfg.CONF.volume
self.volume_feature_enabled = cfg.CONF['volume-feature-enabled']
self.object_storage = cfg.CONF['object-storage']
diff --git a/tempest/test.py b/tempest/test.py
index 6ae7925..ceb2c80 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -123,6 +123,42 @@
return decorator
+def requires_ext(*args, **kwargs):
+ """A decorator to skip tests if an extension is not enabled
+
+ @param extension
+ @param service
+ """
+ def decorator(func):
+ @functools.wraps(func)
+ def wrapper(*func_args, **func_kwargs):
+ if not is_extension_enabled(kwargs['extension'],
+ kwargs['service']):
+ msg = "Skipped because %s extension: %s is not enabled" % (
+ kwargs['service'], kwargs['extension'])
+ raise testtools.TestCase.skipException(msg)
+ return func(*func_args, **func_kwargs)
+ return wrapper
+ return decorator
+
+
+def is_extension_enabled(extension_name, service):
+ """A function that will check the list of enabled extensions from config
+
+ """
+ configs = config.TempestConfig()
+ config_dict = {
+ 'compute': configs.compute_feature_enabled.api_extensions,
+ 'compute_v3': configs.compute_feature_enabled.api_v3_extensions,
+ 'volume': configs.volume_feature_enabled.api_extensions,
+ 'network': configs.network_feature_enabled.api_extensions,
+ }
+ if config_dict[service][0] == 'all':
+ return True
+ if extension_name in config_dict[service]:
+ return True
+ return False
+
# there is a mis-match between nose and testtools for older pythons.
# testtools will set skipException to be either
# unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip