From 2adeed60e5a38d3828e3d6d4b1b5b542b30891a1 Mon Sep 17 00:00:00 2001 From: Peter Hamilton Date: Wed, 1 Feb 2017 12:23:45 -0500 Subject: [PATCH] Add a QuotaClient and quota API tests This change adds a QuotaClient for testing the Barbican quota API. It adds a quota test suite and integrates the QuotaClient with the plugin testing infrastructure. Change-Id: I3249fb879f519da63129e0ec5117377a21094974 Depends-On: I813648476a3a7b0b0e416a524d4629dffe36c92e Implements: bp tempest-plugin --- barbican_tempest_plugin/plugin.py | 1 + .../services/key_manager/json/__init__.py | 3 + .../services/key_manager/json/quota_client.py | 63 +++++++++++++++ barbican_tempest_plugin/tests/api/base.py | 22 +++++- .../tests/api/test_quotas.py | 79 +++++++++++++++++++ 5 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 barbican_tempest_plugin/services/key_manager/json/quota_client.py create mode 100644 barbican_tempest_plugin/tests/api/test_quotas.py diff --git a/barbican_tempest_plugin/plugin.py b/barbican_tempest_plugin/plugin.py index a0f4ca4..2c13b24 100644 --- a/barbican_tempest_plugin/plugin.py +++ b/barbican_tempest_plugin/plugin.py @@ -45,6 +45,7 @@ class BarbicanTempestPlugin(plugins.TempestPlugin): 'ConsumerClient', 'ContainerClient', 'OrderClient', + 'QuotaClient', 'SecretClient', 'SecretMetadataClient' ], diff --git a/barbican_tempest_plugin/services/key_manager/json/__init__.py b/barbican_tempest_plugin/services/key_manager/json/__init__.py index b3ee41e..7bce46a 100644 --- a/barbican_tempest_plugin/services/key_manager/json/__init__.py +++ b/barbican_tempest_plugin/services/key_manager/json/__init__.py @@ -18,6 +18,8 @@ from barbican_tempest_plugin.services.key_manager.json.container_client \ import ContainerClient from barbican_tempest_plugin.services.key_manager.json.order_client \ import OrderClient +from barbican_tempest_plugin.services.key_manager.json.quota_client \ + import QuotaClient from barbican_tempest_plugin.services.key_manager.json.secret_client \ import SecretClient from barbican_tempest_plugin.services.key_manager.json.secret_metadata_client \ @@ -27,6 +29,7 @@ __all__ = [ 'ConsumerClient', 'ContainerClient', 'OrderClient', + 'QuotaClient', 'SecretClient', 'SecretMetadataClient' ] diff --git a/barbican_tempest_plugin/services/key_manager/json/quota_client.py b/barbican_tempest_plugin/services/key_manager/json/quota_client.py new file mode 100644 index 0000000..2f90546 --- /dev/null +++ b/barbican_tempest_plugin/services/key_manager/json/quota_client.py @@ -0,0 +1,63 @@ +# Copyright (c) 2017 Johns Hopkins University Applied Physics Laboratory +# +# 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 json + +from six.moves.urllib import parse as urllib + +from tempest import config +from tempest.lib.common import rest_client + +CONF = config.CONF + + +class QuotaClient(rest_client.RestClient): + + def list_quotas(self, **kwargs): + uri = "v1/project-quotas" + if kwargs: + uri += "?%s" % urllib.urlencode(kwargs) + + response, body = self.get(uri) + self.expected_success(200, response.status) + return json.loads(body) + + def get_default_project_quota(self): + uri = "v1/quotas" + + response, body = self.get(uri) + self.expected_success(200, response.status) + return json.loads(body) + + def get_project_quota(self, project_id): + uri = "v1/project-quotas/%s" % project_id + + response, body = self.get(uri) + self.expected_success(200, response.status) + return json.loads(body) + + def create_project_quota(self, project_id, **kwargs): + uri = "v1/project-quotas/%s" % project_id + + response, body = self.put(uri, json.dumps(kwargs)) + self.expected_success(204, response.status) + return + + def delete_project_quota(self, project_id): + uri = "v1/project-quotas/%s" % project_id + + response, _ = self.delete(uri) + self.expected_success(204, response.status) + return diff --git a/barbican_tempest_plugin/tests/api/base.py b/barbican_tempest_plugin/tests/api/base.py index abf1e830..7256a10 100644 --- a/barbican_tempest_plugin/tests/api/base.py +++ b/barbican_tempest_plugin/tests/api/base.py @@ -23,7 +23,7 @@ from barbican_tempest_plugin import clients CONF = config.CONF # NOTE(dane-fichter): We need to track resource types for cleanup. -RESOURCE_TYPES = ['container', 'order', 'secret'] +RESOURCE_TYPES = ['container', 'order', 'quota', 'secret'] def _get_uuid(href): @@ -45,6 +45,9 @@ def creates(resource): secret_ref = order_metadata.get('secret_ref') if secret_ref: cls.created_objects['secret'].add(_get_uuid(secret_ref)) + uuid = _get_uuid(resp['order_ref']) + if resource == 'quota': + uuid = _get_uuid(args[0]) if resource == 'secret': uuid = _get_uuid(resp['secret_ref']) cls.created_objects[resource].add(uuid) @@ -57,7 +60,7 @@ class BaseKeyManagerTest(test.BaseTestCase): """Base class for all api tests.""" # Why do I have to be an admin to create secrets? No idea... - credentials = ('admin', ) + credentials = ('admin', ['service_admin', 'key-manager:service-admin']) client_manager = clients.Clients created_objects = {} @@ -77,6 +80,9 @@ class BaseKeyManagerTest(test.BaseTestCase): service='key-manager' ) + os = getattr(cls, 'os_roles_%s' % cls.credentials[1][0]) + cls.quota_client = os.secret_v1.QuotaClient(service='key-manager') + @classmethod def resource_setup(cls): super(BaseKeyManagerTest, cls).resource_setup() @@ -90,6 +96,8 @@ class BaseKeyManagerTest(test.BaseTestCase): cls.delete_container(container_uuid) for order_uuid in list(cls.created_objects['order']): cls.delete_order(order_uuid) + for project_quota_uuid in list(cls.created_objects['quota']): + cls.delete_project_quota(project_quota_uuid) for secret_uuid in list(cls.created_objects['secret']): cls.delete_secret(secret_uuid) finally: @@ -119,6 +127,16 @@ class BaseKeyManagerTest(test.BaseTestCase): cls.created_objects['order'].remove(uuid) return cls.order_client.delete_order(uuid) + @classmethod + @creates('quota') + def create_project_quota(cls, project_id, **kwargs): + return cls.quota_client.create_project_quota(project_id, **kwargs) + + @classmethod + def delete_project_quota(cls, project_id): + cls.created_objects['quota'].remove(project_id) + return cls.quota_client.delete_project_quota(project_id) + @classmethod @creates('secret') def create_secret(cls, **kwargs): diff --git a/barbican_tempest_plugin/tests/api/test_quotas.py b/barbican_tempest_plugin/tests/api/test_quotas.py new file mode 100644 index 0000000..882fbb1 --- /dev/null +++ b/barbican_tempest_plugin/tests/api/test_quotas.py @@ -0,0 +1,79 @@ +# Copyright (c) 2016 Johns Hopkins University Applied Physics Laboratory +# +# 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 barbican_tempest_plugin.tests.api import base + +from tempest import config + +CONF = config.CONF + + +class QuotasTest(base.BaseKeyManagerTest): + """Quotas API tests.""" + + def test_create_get_delete_quota(self): + # Verify the default quota settings + body = self.quota_client.get_default_project_quota() + quotas = body.get('quotas') + self.assertEqual(-1, quotas.get('secrets')) + self.assertEqual(-1, quotas.get('cas')) + self.assertEqual(-1, quotas.get('orders')) + self.assertEqual(-1, quotas.get('containers')) + self.assertEqual(-1, quotas.get('consumers')) + + # Confirm that there are no quotas + body = self.quota_client.list_quotas() + self.assertEqual(0, body.get('total'), body) + self.assertEqual(0, len(body.get('project_quotas')), body) + + # Create a quota set for the test project + self.create_project_quota( + self.quota_client.tenant_id, + project_quotas={ + 'secrets': 30, + 'orders': 10, + 'containers': 20 + } + ) + + # Verify that the quotas can be found via generic listing. + body = self.quota_client.list_quotas() + self.assertEqual(1, body.get('total'), body) + self.assertEqual(1, len(body.get('project_quotas')), body) + project_quotas = body.get('project_quotas')[0] + self.assertEqual( + self.quota_client.tenant_id, + project_quotas.get('project_id'), + body + ) + project_quotas = project_quotas.get('project_quotas') + self.assertEqual(30, project_quotas.get('secrets'), body) + self.assertEqual(10, project_quotas.get('orders'), body) + self.assertEqual(20, project_quotas.get('containers'), body) + + # Verify that the quotas can be found via specific listing. + body = self.quota_client.get_project_quota( + self.quota_client.tenant_id + ) + project_quotas = body.get('project_quotas') + self.assertEqual(30, project_quotas.get('secrets'), body) + self.assertEqual(10, project_quotas.get('orders'), body) + self.assertEqual(20, project_quotas.get('containers'), body) + + # Delete the project quota and confirm that it got deleted + self.delete_project_quota(self.quota_client.tenant_id) + + body = self.quota_client.list_quotas() + self.assertEqual(0, body.get('total'), body) + self.assertEqual(0, len(body.get('project_quotas')), body)