Merge "Fixes test_device_tagging IndexError"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 0a061b8..c2ea628 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -64,7 +64,7 @@
# openstackdocstheme options
repository_name = 'openstack/tempest'
bug_project = 'tempest'
-bug_tag = ''
+bug_tag = 'doc'
# Must set this variable to include year, month, day, hours, and minutes.
html_last_updated_fmt = '%Y-%m-%d %H:%M'
diff --git a/releasenotes/notes/add-show-encryption-specs-item-api-to-v2-encryption-types-client-290b421cd4bc0c0e.yaml b/releasenotes/notes/add-show-encryption-specs-item-api-to-v2-encryption-types-client-290b421cd4bc0c0e.yaml
new file mode 100644
index 0000000..9e13afc
--- /dev/null
+++ b/releasenotes/notes/add-show-encryption-specs-item-api-to-v2-encryption-types-client-290b421cd4bc0c0e.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add show encryption specs item API to v2 encryption_types_client library.
+ This feature enables the possibility to show specific encryption specs for
+ a volume type.
diff --git a/releasenotes/notes/add-show-quota-details-api-to-network-quotas-client-3fffd302cc5d335f.yaml b/releasenotes/notes/add-show-quota-details-api-to-network-quotas-client-3fffd302cc5d335f.yaml
new file mode 100644
index 0000000..406e282
--- /dev/null
+++ b/releasenotes/notes/add-show-quota-details-api-to-network-quotas-client-3fffd302cc5d335f.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ Add extension API show quota details to network quotas_client library.
+ This feature enables the possibility to show a quota set for a specified
+ project that includes the quota’s used, limit and reserved counts for per
+ resource
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 404fd94..b23c59f 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -17,12 +17,12 @@
from tempest.lib import decorators
-class HypervisorAdminTestJSON(base.BaseV2ComputeAdminTest):
+class HypervisorAdminTestBase(base.BaseV2ComputeAdminTest):
"""Tests Hypervisors API that require admin privileges"""
@classmethod
def setup_clients(cls):
- super(HypervisorAdminTestJSON, cls).setup_clients()
+ super(HypervisorAdminTestBase, cls).setup_clients()
cls.client = cls.os_admin.hypervisor_client
def _list_hypervisors(self):
@@ -30,6 +30,10 @@
hypers = self.client.list_hypervisors()['hypervisors']
return hypers
+
+class HypervisorAdminTestJSON(HypervisorAdminTestBase):
+ """Tests Hypervisors API that require admin privileges"""
+
@decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
def test_get_hypervisor_list(self):
# List of hypervisor and available hypervisors hostname
@@ -53,17 +57,6 @@
self.assertEqual(details['hypervisor_hostname'],
hypers[0]['hypervisor_hostname'])
- @decorators.idempotent_id('e81bba3f-6215-4e39-a286-d52d2f906862')
- def test_get_hypervisor_show_servers(self):
- # Show instances about the specific hypervisors
- hypers = self._list_hypervisors()
- self.assertNotEmpty(hypers, "No hypervisors found.")
-
- hostname = hypers[0]['hypervisor_hostname']
- hypervisors = (self.client.list_servers_on_hypervisor(hostname)
- ['hypervisors'])
- self.assertNotEmpty(hypervisors)
-
@decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
def test_get_hypervisor_stats(self):
# Verify the stats of the all hypervisor
@@ -110,6 +103,21 @@
has_valid_uptime,
"None of the hypervisors had a valid uptime: %s" % hypers)
+
+class HypervisorAdminUnderV252Test(HypervisorAdminTestBase):
+ max_microversion = '2.52'
+
+ @decorators.idempotent_id('e81bba3f-6215-4e39-a286-d52d2f906862')
+ def test_get_hypervisor_show_servers(self):
+ # Show instances about the specific hypervisors
+ hypers = self._list_hypervisors()
+ self.assertNotEmpty(hypers, "No hypervisors found.")
+
+ hostname = hypers[0]['hypervisor_hostname']
+ hypervisors = (self.client.list_servers_on_hypervisor(hostname)
+ ['hypervisors'])
+ self.assertNotEmpty(hypervisors)
+
@decorators.idempotent_id('d7e1805b-3b14-4a3b-b6fd-50ec6d9f361f')
def test_search_hypervisor(self):
hypers = self._list_hypervisors()
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 431e823..0056376 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -19,12 +19,12 @@
from tempest.lib import exceptions as lib_exc
-class HypervisorAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+class HypervisorAdminNegativeTestBase(base.BaseV2ComputeAdminTest):
"""Tests Hypervisors API that require admin privileges"""
@classmethod
def setup_clients(cls):
- super(HypervisorAdminNegativeTestJSON, cls).setup_clients()
+ super(HypervisorAdminNegativeTestBase, cls).setup_clients()
cls.client = cls.os_admin.hypervisor_client
cls.non_adm_client = cls.hypervisor_client
@@ -33,6 +33,10 @@
hypers = self.client.list_hypervisors()['hypervisors']
return hypers
+
+class HypervisorAdminNegativeTestJSON(HypervisorAdminNegativeTestBase):
+ """Tests Hypervisors API that require admin privileges"""
+
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c136086a-0f67-4b2b-bc61-8482bd68989f')
def test_show_nonexistent_hypervisor(self):
@@ -55,27 +59,6 @@
hypers[0]['id'])
@decorators.attr(type=['negative'])
- @decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
- def test_show_servers_with_non_admin_user(self):
- hypers = self._list_hypervisors()
- self.assertNotEmpty(hypers)
-
- self.assertRaises(
- lib_exc.Forbidden,
- self.non_adm_client.list_servers_on_hypervisor,
- hypers[0]['id'])
-
- @decorators.attr(type=['negative'])
- @decorators.idempotent_id('02463d69-0ace-4d33-a4a8-93d7883a2bba')
- def test_show_servers_with_nonexistent_hypervisor(self):
- nonexistent_hypervisor_id = data_utils.rand_uuid()
-
- self.assertRaises(
- lib_exc.NotFound,
- self.client.list_servers_on_hypervisor,
- nonexistent_hypervisor_id)
-
- @decorators.attr(type=['negative'])
@decorators.idempotent_id('e2b061bb-13f9-40d8-9d6e-d5bf17595849')
def test_get_hypervisor_stats_with_non_admin_user(self):
self.assertRaises(
@@ -119,13 +102,30 @@
lib_exc.Forbidden,
self.non_adm_client.list_hypervisors, detail=True)
+
+class HypervisorAdminNegativeUnderV252Test(HypervisorAdminNegativeTestBase):
+ max_microversion = '2.52'
+
@decorators.attr(type=['negative'])
- @decorators.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa')
- def test_search_nonexistent_hypervisor(self):
+ @decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
+ def test_show_servers_with_non_admin_user(self):
+ hypers = self._list_hypervisors()
+ self.assertNotEmpty(hypers)
+
+ self.assertRaises(
+ lib_exc.Forbidden,
+ self.non_adm_client.list_servers_on_hypervisor,
+ hypers[0]['id'])
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('02463d69-0ace-4d33-a4a8-93d7883a2bba')
+ def test_show_servers_with_nonexistent_hypervisor(self):
+ nonexistent_hypervisor_id = data_utils.rand_uuid()
+
self.assertRaises(
lib_exc.NotFound,
- self.client.search_hypervisor,
- 'nonexistent_hypervisor_name')
+ self.client.list_servers_on_hypervisor,
+ nonexistent_hypervisor_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
@@ -137,3 +137,11 @@
lib_exc.Forbidden,
self.non_adm_client.search_hypervisor,
hypers[0]['hypervisor_hostname'])
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa')
+ def test_search_nonexistent_hypervisor(self):
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.client.search_hypervisor,
+ 'nonexistent_hypervisor_name')
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index c9ee671..2904976 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -167,6 +167,18 @@
server = self.client.show_server(server['id'])['server']
self.assertEqual('2001:2001::3', server['accessIPv6'])
+ @decorators.related_bug('1730756')
+ @decorators.idempotent_id('defbaca5-d611-49f5-ae21-56ee25d2db49')
+ def test_create_server_specify_multibyte_character_name(self):
+ # prefix character is:
+ # http://unicode.org/cldr/utility/character.jsp?a=20A1
+
+ # We use a string with 3 byte utf-8 character due to nova
+ # will return 400(Bad Request) if we attempt to send a name which has
+ # 4 byte utf-8 character.
+ utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
+ self.create_test_server(name=utf8_name, wait_until='ACTIVE')
+
class ServerShowV247Test(base.BaseV2ComputeTest):
min_microversion = '2.47'
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 57a28bf..b1e4a58 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.network import base
from tempest.common import identity
from tempest.common import utils
@@ -89,3 +91,15 @@
def test_quotas(self):
new_quotas = {'network': 0, 'port': 0}
self._check_quotas(new_quotas)
+
+ @testtools.skipUnless(utils.is_extension_enabled(
+ 'quota_details', 'network'), 'Quota details extension not enabled.')
+ @decorators.idempotent_id('7b05ec5f-bf44-43cb-b28f-ddd72a824288')
+ def test_show_quota_details(self):
+ # Show quota details for an existing project
+ quota_details = self.admin_quotas_client.show_quota_details(
+ self.admin_quotas_client.tenant_id)['quota']
+ expected_keys = ['used', 'limit', 'reserved']
+ for resource_type in quota_details:
+ for key in expected_keys:
+ self.assertIn(key, quota_details[resource_type])
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index af1024c..1077524 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -161,6 +161,12 @@
'The fetched encryption_type %s is different '
'from the updated encryption_type' % key)
+ # Get encryption specs item
+ key = 'cipher'
+ item = self.admin_encryption_types_client.show_encryption_specs_item(
+ encrypt_type_id, key)
+ self.assertEqual(update_kwargs[key], item[key])
+
# Delete encryption type
self.admin_encryption_types_client.delete_encryption_type(
encrypt_type_id)
diff --git a/tempest/lib/services/network/quotas_client.py b/tempest/lib/services/network/quotas_client.py
index f23af88..e9666de 100644
--- a/tempest/lib/services/network/quotas_client.py
+++ b/tempest/lib/services/network/quotas_client.py
@@ -46,3 +46,8 @@
"""List default quotas for a project."""
uri = '/quotas/%s/default' % tenant_id
return self.show_resource(uri)
+
+ def show_quota_details(self, tenant_id):
+ """Show quota details for a project."""
+ uri = '/quotas/%s/details.json' % tenant_id
+ return self.show_resource(uri)
diff --git a/tempest/lib/services/volume/v2/encryption_types_client.py b/tempest/lib/services/volume/v2/encryption_types_client.py
index 20f3356..b99d1fe 100644
--- a/tempest/lib/services/volume/v2/encryption_types_client.py
+++ b/tempest/lib/services/volume/v2/encryption_types_client.py
@@ -47,6 +47,14 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+ def show_encryption_specs_item(self, volume_type_id, key):
+ """Get the encryption specs item for the specified volume type."""
+ url = "/types/%s/encryption/%s" % (volume_type_id, key)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def create_encryption_type(self, volume_type_id, **kwargs):
"""Create encryption type.
diff --git a/tempest/lib/services/volume/v3/group_types_client.py b/tempest/lib/services/volume/v3/group_types_client.py
index 1b47201..ecbcba1 100644
--- a/tempest/lib/services/volume/v3/group_types_client.py
+++ b/tempest/lib/services/volume/v3/group_types_client.py
@@ -94,7 +94,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://developer.openstack.org/api-ref/block-storage/v3/#create-group-specs-for-a-group-type
+ https://developer.openstack.org/api-ref/block-storage/v3/#create-or-update-group-specs-for-a-group-type
"""
url = "group_types/%s/group_specs" % group_type_id
post_body = json.dumps({'group_specs': group_specs})
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 06b4b59..06aa531 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1174,7 +1174,7 @@
LOG.debug("Creating an encryption type for volume type: %s", type_id)
client.create_encryption_type(
type_id, provider=provider, key_size=key_size, cipher=cipher,
- control_location=control_location)['encryption']
+ control_location=control_location)
def create_encrypted_volume(self, encryption_provider, volume_type,
key_size=256, cipher='aes-xts-plain64',
diff --git a/tempest/tests/lib/services/network/test_quotas_client.py b/tempest/tests/lib/services/network/test_quotas_client.py
index 5a09911..aa6c1a1 100644
--- a/tempest/tests/lib/services/network/test_quotas_client.py
+++ b/tempest/tests/lib/services/network/test_quotas_client.py
@@ -54,6 +54,46 @@
FAKE_QUOTA_TENANT_ID = "bab7d5c60cd041a0a36f7c4b6e1dd978"
+ FAKE_QUOTA_DETAILS = {
+ "quota": {
+ "rbac_policy": {
+ "used": 4,
+ "limit": 10,
+ "reserved": 0
+ },
+ "subnetpool": {
+ "used": 2,
+ "limit": -1,
+ "reserved": 0
+ },
+ "security_group_rule": {
+ "used": 10,
+ "limit": 100,
+ "reserved": 1
+ },
+ "security_group": {
+ "used": 3,
+ "limit": 10,
+ "reserved": 0
+ },
+ "subnet": {
+ "used": 3,
+ "limit": 100,
+ "reserved": 0
+ },
+ "port": {
+ "used": 21,
+ "limit": 500,
+ "reserved": 3
+ },
+ "network": {
+ "used": 9,
+ "limit": 100,
+ "reserved": 2
+ }
+ }
+ }
+
def setUp(self):
super(TestQuotasClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -95,6 +135,15 @@
200,
tenant_id=self.FAKE_QUOTA_TENANT_ID)
+ def _test_show_quota_details(self, bytes_body=False):
+ self.check_service_client_function(
+ self.quotas_client.show_quota_details,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_QUOTA_DETAILS,
+ bytes_body,
+ 200,
+ tenant_id=self.FAKE_QUOTA_TENANT_ID)
+
def test_reset_quotas(self):
self.check_service_client_function(
self.quotas_client.reset_quotas,
@@ -126,3 +175,9 @@
def test_update_quotas_with_bytes_body(self):
self._test_update_quotas(bytes_body=True)
+
+ def test_show_quota_details_with_str_body(self):
+ self._test_show_quota_details()
+
+ def test_show_quota_details_with_bytes_body(self):
+ self._test_show_quota_details(bytes_body=True)
diff --git a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
index d029091..8de9fb4 100644
--- a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
+++ b/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py
@@ -43,6 +43,10 @@
}
}
+ FAKE_ENCRYPTION_SPECS_ITEM = {
+ "cipher": "aes-xts-plain64"
+ }
+
def setUp(self):
super(TestEncryptionTypesClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -65,6 +69,13 @@
self.FAKE_INFO_ENCRYPTION_TYPE,
bytes_body, volume_type_id="cbc36478b0bd8e67e89")
+ def _test_show_encryption_specs_item(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_encryption_specs_item,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ENCRYPTION_SPECS_ITEM,
+ bytes_body, volume_type_id="cbc36478b0bd8e67e89", key="cipher")
+
def test_create_encryption_type_with_str_body(self):
self._test_create_encryption()
@@ -77,6 +88,12 @@
def test_show_encryption_type_with_bytes_body(self):
self._test_show_encryption_type(bytes_body=True)
+ def test_show_encryption_specs_item_with_str_body(self):
+ self._test_show_encryption_specs_item()
+
+ def test_show_encryption_specs_item_with_bytes_body(self):
+ self._test_show_encryption_specs_item(bytes_body=True)
+
def test_delete_encryption_type(self):
self.check_service_client_function(
self.client.delete_encryption_type,