Add test cases for volume quota class

Now tempest has provided tests for tenant's quota in volume, but
lacks tests for volume quota class. This patch adds this support.

Including:

[1] Add volume v2 quota class client as library
[2] Add release note
[3] Add test cases: show & update volume 'default' quota class
[4] Add unit tests for volume v2 quota class client
[5] Fix for test_volume_quotas.py

Change-Id: I30bac79b986e6e90d43dcc6f9d247e74a314bf3c
This commit is contained in:
jeremy.zhang 2017-04-13 12:59:49 +08:00
parent 0d93900ba6
commit 644b01dafe
8 changed files with 231 additions and 1 deletions

View File

@ -0,0 +1,8 @@
---
features:
- |
Define v2 quota_classes_client for the volume service as library
interfaces, allowing other projects to use this module as stable libraries
without maintenance changes.
* quota_classes_client(v2)

View File

@ -0,0 +1,89 @@
# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
# 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.
from oslo_log import log as logging
from testtools import matchers
from tempest.api.volume import base
from tempest.common import tempest_fixtures as fixtures
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
LOG = logging.getLogger(__name__)
QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups',
'backup_gigabytes', 'per_volume_gigabytes']
class VolumeQuotaClassesTest(base.BaseVolumeAdminTest):
def setUp(self):
# Note(jeremy.zhang): All test cases in this class need to externally
# lock on doing anything with default quota values.
self.useFixture(fixtures.LockFixture('volume_quotas'))
super(VolumeQuotaClassesTest, self).setUp()
def _restore_default_quotas(self, original_defaults):
LOG.debug("Restoring volume quota class defaults")
self.admin_quota_classes_client.update_quota_class_set(
'default', **original_defaults)
@decorators.idempotent_id('abb9198e-67d0-4b09-859f-4f4a1418f176')
def test_show_default_quota(self):
default_quotas = self.admin_quota_classes_client.show_quota_class_set(
'default')['quota_class_set']
self.assertIn('id', default_quotas)
self.assertEqual('default', default_quotas.pop('id'))
for key in QUOTA_KEYS:
self.assertIn(key, default_quotas)
@decorators.idempotent_id('a7644c63-2669-467a-b00e-452dd5c5397b')
def test_update_default_quota(self):
LOG.debug("Get the current default quota class values")
body = self.admin_quota_classes_client.show_quota_class_set(
'default')['quota_class_set']
body.pop('id')
# Restore the defaults when the test is done
self.addCleanup(self._restore_default_quotas, body.copy())
# Increment some of the values for updating the default quota class.
# For safety, only items with value >= 0 will be updated, and items
# with value < 0 (-1 means unlimited) will be ignored.
for quota, default in body.items():
if default >= 0:
body[quota] = default + 1
LOG.debug("Update limits for the default quota class set")
update_body = self.admin_quota_classes_client.update_quota_class_set(
'default', **body)['quota_class_set']
self.assertThat(update_body.items(),
matchers.ContainsAll(body.items()))
# Verify current project's default quotas
default_quotas = self.admin_quotas_client.show_default_quota_set(
self.os_adm.credentials.tenant_id)['quota_set']
self.assertThat(default_quotas.items(),
matchers.ContainsAll(body.items()))
# Verify a new project's default quotas
project_name = data_utils.rand_name('quota_class_tenant')
description = data_utils.rand_name('desc_')
project_id = self.identity_utils.create_project(
name=project_name, description=description)['id']
self.addCleanup(self.identity_utils.delete_project, project_id)
default_quotas = self.admin_quotas_client.show_default_quota_set(
project_id)['quota_set']
self.assertThat(default_quotas.items(),
matchers.ContainsAll(body.items()))

View File

@ -13,6 +13,7 @@
# under the License.
from tempest.api.volume import base
from tempest.common import tempest_fixtures as fixtures
from tempest.common import waiters
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@ -26,6 +27,11 @@ class BaseVolumeQuotasAdminTestJSON(base.BaseVolumeAdminTest):
credentials = ['primary', 'alt', 'admin']
def setUp(self):
# NOTE(jeremy.zhang): Avoid conflicts with volume quota class tests.
self.useFixture(fixtures.LockFixture('volume_quotas'))
super(BaseVolumeQuotasAdminTestJSON, self).setUp()
@classmethod
def setup_credentials(cls):
super(BaseVolumeQuotasAdminTestJSON, cls).setup_credentials()

View File

@ -255,6 +255,8 @@ class BaseVolumeAdminTest(BaseVolumeTest):
cls.admin_backups_client = cls.os_adm.backups_v2_client
cls.admin_encryption_types_client = \
cls.os_adm.encryption_types_v2_client
cls.admin_quota_classes_client = \
cls.os_adm.volume_quota_classes_v2_client
cls.admin_quotas_client = cls.os_adm.volume_quotas_v2_client
cls.admin_volume_limits_client = cls.os_adm.volume_v2_limits_client
cls.admin_capabilities_client = \

View File

@ -274,6 +274,8 @@ class Manager(clients.ServiceClients):
self.volume_hosts_v2_client = self.volume_v2.HostsClient()
self.volume_quotas_client = self.volume_v1.QuotasClient()
self.volume_quotas_v2_client = self.volume_v2.QuotasClient()
self.volume_quota_classes_v2_client = \
self.volume_v2.QuotaClassesClient()
self.volumes_extension_client = self.volume_v1.ExtensionsClient()
self.volumes_v2_extension_client = self.volume_v2.ExtensionsClient()
self.volume_availability_zone_client = \

View File

@ -23,6 +23,8 @@ from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient
from tempest.lib.services.volume.v2.hosts_client import HostsClient
from tempest.lib.services.volume.v2.limits_client import LimitsClient
from tempest.lib.services.volume.v2.qos_client import QosSpecsClient
from tempest.lib.services.volume.v2.quota_classes_client import \
QuotaClassesClient
from tempest.lib.services.volume.v2.quotas_client import QuotasClient
from tempest.lib.services.volume.v2.scheduler_stats_client import \
SchedulerStatsClient
@ -40,4 +42,5 @@ __all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient',
'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient',
'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient',
'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient',
'SnapshotManageClient', 'VolumeManageClient', 'TransfersClient']
'SnapshotManageClient', 'VolumeManageClient', 'TransfersClient',
'QuotaClassesClient']

View File

@ -0,0 +1,49 @@
# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
# 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.
from oslo_serialization import jsonutils as json
from tempest.lib.common import rest_client
class QuotaClassesClient(rest_client.RestClient):
"""Volume quota class V2 client."""
api_version = "v2"
def show_quota_class_set(self, quota_class_id):
"""List quotas for a quota class.
TODO: Current api-site doesn't contain this API description.
LP: https://bugs.launchpad.net/nova/+bug/1602400
"""
url = 'os-quota-class-sets/%s' % quota_class_id
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def update_quota_class_set(self, quota_class_id, **kwargs):
"""Update quotas for a quota class.
TODO: Current api-site doesn't contain this API description.
LP: https://bugs.launchpad.net/nova/+bug/1602400
"""
url = 'os-quota-class-sets/%s' % quota_class_id
put_body = json.dumps({'quota_class_set': kwargs})
resp, body = self.put(url, put_body)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)

View File

@ -0,0 +1,71 @@
# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
# 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 copy
from tempest.lib.services.volume.v2 import quota_classes_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib.services import base
class TestQuotaClassesClient(base.BaseServiceTest):
FAKE_QUOTA_CLASS_SET = {
"id": "test",
"gigabytes": 2000,
"volumes": 200,
"snapshots": 50,
"backups": 20,
"backup_gigabytes": 1500,
"per_volume_gigabytes": 500,
}
def setUp(self):
super(TestQuotaClassesClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.client = quota_classes_client.QuotaClassesClient(
fake_auth, 'volume', 'regionOne')
def _test_show_quota_class_set(self, bytes_body=False):
fake_body = {'quota_class_set': self.FAKE_QUOTA_CLASS_SET}
self.check_service_client_function(
self.client.show_quota_class_set,
'tempest.lib.common.rest_client.RestClient.get',
fake_body,
bytes_body,
quota_class_id="test")
def _test_update_quota_class_set(self, bytes_body=False):
fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET)
fake_quota_class_set.pop("id")
fake_body = {'quota_class_set': fake_quota_class_set}
self.check_service_client_function(
self.client.update_quota_class_set,
'tempest.lib.common.rest_client.RestClient.put',
fake_body,
bytes_body,
quota_class_id="test")
def test_show_quota_class_set_with_str_body(self):
self._test_show_quota_class_set()
def test_show_quota_class_set_with_bytes_body(self):
self._test_show_quota_class_set(bytes_body=True)
def test_update_quota_class_set_with_str_boy(self):
self._test_update_quota_class_set()
def test_update_quota_class_set_with_bytes_body(self):
self._test_update_quota_class_set(bytes_body=True)