Merge "Add Functional Tests for Quota Enforcement"

This commit is contained in:
Jenkins 2015-09-02 23:59:34 +00:00 committed by Gerrit Code Review
commit 71f892335a
12 changed files with 282 additions and 21 deletions

View File

@ -142,7 +142,7 @@ class ContainerConsumersController(controllers.ACLMixin):
except exception.NotFound:
controllers.containers.container_not_found()
self.quota_enforcer.enforce(external_project_id)
self.quota_enforcer.enforce(project)
new_consumer = models.ContainerConsumerMetadatum(self.container_id,
project.id,

View File

@ -181,7 +181,7 @@ class ContainersController(controllers.ACLMixin):
if ctxt: # in authenticated pipleline case, always use auth token user
data['creator_id'] = ctxt.user
self.quota_enforcer.enforce(external_project_id)
self.quota_enforcer.enforce(project)
LOG.debug('Start on_post...%s', data)

View File

@ -216,7 +216,7 @@ class OrdersController(controllers.ACLMixin):
external_project_id,
container_ref, pecan.request)
self.quota_enforcer.enforce(external_project_id)
self.quota_enforcer.enforce(project)
new_order = models.Order()
new_order.meta = body.get('meta')

View File

@ -311,7 +311,7 @@ class SecretsController(controllers.ACLMixin):
data = api.load_body(pecan.request, validator=self.validator)
project = res.get_or_create_project(external_project_id)
self.quota_enforcer.enforce(external_project_id)
self.quota_enforcer.enforce(project)
transport_key_needed = data.get('transport_key_needed',
'false').lower() == 'true'

View File

@ -200,14 +200,14 @@ class QuotaEnforcer(object):
self.resource_type = resource_type
self.resource_repo = resource_repo
def enforce(self, external_project_id):
def enforce(self, project):
"""Enforce the quota limit for the resource
:param external_project_id: ID of project requesting to create
:param project: the project object corresponding to the sender
:raises QuotaReached: exception raised if quota forbids request
:return: None
"""
quotas = self.quota_driver.get_effective_quotas(external_project_id)
quotas = self.quota_driver.get_effective_quotas(project.external_id)
quota = quotas[self.resource_type]
reached = False
@ -217,12 +217,12 @@ class QuotaEnforcer(object):
elif self.quota_driver.is_disabled_value(quota):
reached = True
else:
count = self.resource_repo.get_count(external_project_id)
count = self.resource_repo.get_count(project.id)
if count >= quota:
reached = True
if reached:
raise exception.QuotaReached(
external_project_id=external_project_id,
external_project_id=project.external_id,
resource_type=self.resource_type,
quota=quota)

View File

@ -778,6 +778,12 @@ class WhenCreatingConsumersUsingConsumersResource(FunctionalTest):
self.project_repo.get.return_value = self.project
self.setup_project_repository_mock(self.project_repo)
# Set up mocked quota enforcer
self.quota_patch = mock.patch(
'barbican.common.quota.QuotaEnforcer.enforce', return_value=None)
self.quota_patch.start()
self.addCleanup(self.quota_patch.stop)
# Set up mocked container
self.container = create_container(
id_ref='id1',

View File

@ -203,7 +203,7 @@ class DummyRepoForTestingQuotaEnforcement(object):
def __init__(self, get_count_return_value):
self.get_count_return_value = get_count_return_value
def get_count(self, external_project_id):
def get_count(self, internal_project_id):
return self.get_count_return_value
@ -219,7 +219,7 @@ class WhenTestingQuotaEnforcingFunctions(utils.BaseTestCase):
def test_should_pass_default_unlimited(self):
test_repo = DummyRepoForTestingQuotaEnforcement(0)
quota_enforcer = quota.QuotaEnforcer('secrets', test_repo)
quota_enforcer.enforce(self.project.external_id)
quota_enforcer.enforce(self.project)
def test_should_raise_disabled_value(self):
test_repo = DummyRepoForTestingQuotaEnforcement(0)
@ -232,7 +232,7 @@ class WhenTestingQuotaEnforcingFunctions(utils.BaseTestCase):
exception = self.assertRaises(
excep.QuotaReached,
quota_enforcer.enforce,
self.project.external_id
self.project
)
self.assertIn('Quota reached for project', exception.message)
self.assertIn('my_keystone_id', exception.message)
@ -247,7 +247,7 @@ class WhenTestingQuotaEnforcingFunctions(utils.BaseTestCase):
'transport_keys': 5}
self.quota_driver.set_project_quotas(self.project.external_id,
five_project_quotas)
quota_enforcer.enforce(self.project.external_id)
quota_enforcer.enforce(self.project)
def test_should_raise_equal_limit(self):
test_repo = DummyRepoForTestingQuotaEnforcement(5)
@ -260,7 +260,7 @@ class WhenTestingQuotaEnforcingFunctions(utils.BaseTestCase):
exception = self.assertRaises(
excep.QuotaReached,
quota_enforcer.enforce,
self.project.external_id
self.project
)
self.assertIn('Quota reached for project', exception.message)
self.assertIn('my_keystone_id', exception.message)
@ -278,7 +278,7 @@ class WhenTestingQuotaEnforcingFunctions(utils.BaseTestCase):
exception = self.assertRaises(
excep.QuotaReached,
quota_enforcer.enforce,
self.project.external_id
self.project
)
self.assertIn('Quota reached for project', exception.message)
self.assertIn('my_keystone_id', exception.message)

View File

@ -20,12 +20,14 @@ from functionaltests.api.v1.models import consumer_model
class ConsumerBehaviors(base_behaviors.BaseBehaviors):
def create_consumer(self, model, container_ref, extra_headers=None,
use_auth=True):
user_name=None, admin=None, use_auth=True):
"""Register a consumer to a container.
:param model: The metadata for the consumer
:param container_ref: Full reference to a container
:param extra_headers: Any additional headers to pass to the request
:param user_name: The user name used to create the consumer
:param admin: The user with permission to delete the consumer
:param use_auth: Boolean for whether to send authentication headers
:return: A tuple containing the response from the create
@ -35,18 +37,25 @@ class ConsumerBehaviors(base_behaviors.BaseBehaviors):
url = '{0}/consumers'.format(container_ref)
resp = self.client.post(url, request_model=model,
extra_headers=extra_headers, use_auth=use_auth)
extra_headers=extra_headers,
user_name=user_name, use_auth=use_auth)
if resp.status_code == 401 and not use_auth:
return resp, None
if resp.status_code == 200:
if admin is None:
admin = user_name
self.created_entities.append((container_ref, model, admin))
returned_data = self.get_json(resp)
consumer_data = returned_data.get('consumers')
return resp, consumer_data
def get_consumers(self, container_ref, limit=10, offset=0,
extra_headers=None, use_auth=True):
extra_headers=None,
user_name=None, use_auth=True):
"""Gets a list of consumers on a container.
:param container_ref: Full reference to a container
@ -54,6 +63,7 @@ class ConsumerBehaviors(base_behaviors.BaseBehaviors):
:param offset: represents how many records to skip before retrieving
the list
:param extra_headers: Any additional headers to pass to the request
:param user_name: The user name used to get the consumer
:param use_auth: Boolean for whether to send authentication headers
:return: The response from the get and refs to the next/previous list
@ -64,7 +74,7 @@ class ConsumerBehaviors(base_behaviors.BaseBehaviors):
params = {'limit': limit, 'offset': offset}
resp = self.client.get(url, params=params, extra_headers=extra_headers,
use_auth=use_auth)
user_name=user_name, use_auth=use_auth)
if resp.status_code == 401 and not use_auth:
return resp, None, None, None
@ -77,12 +87,13 @@ class ConsumerBehaviors(base_behaviors.BaseBehaviors):
return resp, consumers, next_ref, prev_ref
def delete_consumer(self, model, container_ref, extra_headers=None,
use_auth=True):
user_name=None, use_auth=True):
"""Deletes a consumer from a container.
:param model: The metadata for the consumer
:param container_ref: Full reference to a container
:param extra_headers: Any additional headers to pass to the request
:param user_name: The user name used to delete the consumer
:param use_auth: Boolean for whether to send authentication headers
:return: The response from the delete
@ -91,6 +102,7 @@ class ConsumerBehaviors(base_behaviors.BaseBehaviors):
resp = self.client.delete(url, request_model=model,
extra_headers=extra_headers,
user_name=user_name,
use_auth=use_auth)
if resp.status_code == 401 and not use_auth:
@ -100,3 +112,9 @@ class ConsumerBehaviors(base_behaviors.BaseBehaviors):
consumer_data = returned_data['consumers']
return resp, consumer_data
def delete_all_created_consumers(self):
"""Delete all of the consumers that we have created."""
entities = list(self.created_entities)
for (container_ref, model, admin) in entities:
self.delete_consumer(model, container_ref, user_name=admin)

View File

@ -45,6 +45,8 @@ class OrderBehaviors(base_behaviors.BaseBehaviors):
# remember this order and its admin for our housekeeping cleanup
if order_ref:
if admin is None:
admin = user_name
self.created_entities.append((order_ref, admin))
return resp, order_ref

View File

@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from testtools import testcase
from functionaltests.api import base
from functionaltests.api.v1.behaviors import quota_behaviors
from functionaltests.api.v1.models import quota_models
@ -100,6 +102,7 @@ class QuotasTestCase(base.TestCase):
self.assertEqual(404, resp.status_code)
@testcase.attr('no_parallel')
class ProjectQuotasPagingTestCase(base.PagingTestCase):
def setUp(self):

View File

@ -0,0 +1,232 @@
# Copyright (c) 2015 Cisco Systems
#
# 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 testtools import testcase
from functionaltests.api import base
from functionaltests.api.v1.behaviors import consumer_behaviors
from functionaltests.api.v1.behaviors import container_behaviors
from functionaltests.api.v1.behaviors import order_behaviors
from functionaltests.api.v1.behaviors import quota_behaviors
from functionaltests.api.v1.behaviors import secret_behaviors
from functionaltests.api.v1.models import consumer_model
from functionaltests.api.v1.models import container_models
from functionaltests.api.v1.models import order_models
from functionaltests.api.v1.models import quota_models
from functionaltests.api.v1.models import secret_models
from functionaltests.common import config
CONF = config.get_config()
admin_b = CONF.rbac_users.admin_b
service_admin = CONF.identity.service_admin
@testcase.attr('no_parallel')
class QuotaEnforcementTestCase(base.TestCase):
def setUp(self):
super(QuotaEnforcementTestCase, self).setUp()
self.quota_behaviors = quota_behaviors.QuotaBehaviors(self.client)
self.secret_behaviors = secret_behaviors.SecretBehaviors(self.client)
self.container_behaviors = container_behaviors.ContainerBehaviors(
self.client)
self.order_behaviors = order_behaviors.OrderBehaviors(self.client)
self.consumer_behaviors = consumer_behaviors.ConsumerBehaviors(
self.client)
self.secret_data = self.get_default_secret_data()
self.quota_data = self.get_default_quota_data()
self.project_id = self.quota_behaviors.get_project_id_from_name(
admin_b)
self.order_secrets = []
def tearDown(self):
self.quota_behaviors.delete_all_created_quotas()
self.consumer_behaviors.delete_all_created_consumers()
self.container_behaviors.delete_all_created_containers()
self.secret_behaviors.delete_all_created_secrets()
for secret_ref in self.order_secrets:
resp = self.secret_behaviors.delete_secret(
secret_ref, user_name=admin_b)
self.assertEqual(204, resp.status_code)
self.order_behaviors.delete_all_created_orders()
super(QuotaEnforcementTestCase, self).tearDown()
def test_secrets_unlimited(self):
self.set_quotas('secrets', -1)
self.create_secrets(count=5)
def test_secrets_disabled(self):
self.set_quotas('secrets', 0)
self.create_secrets(expected_return=403)
def test_secrets_limited_one(self):
self.set_quotas('secrets', 1)
self.create_secrets(count=1)
self.create_secrets(expected_return=403)
def test_secrets_limited_five(self):
self.set_quotas('secrets', 5)
self.create_secrets(count=5)
self.create_secrets(expected_return=403)
def test_containers_unlimited(self):
self.set_quotas('containers', -1)
self.create_containers(count=5)
def test_containers_disabled(self):
self.set_quotas('containers', 0)
self.create_containers(expected_return=403)
def test_containers_limited_one(self):
self.set_quotas('containers', 1)
self.create_containers(count=1)
self.create_containers(expected_return=403)
def test_containers_limited_five(self):
self.set_quotas('containers', 5)
self.create_containers(count=5)
self.create_containers(expected_return=403)
def test_orders_unlimited(self):
self.set_quotas('orders', -1)
self.create_orders(count=5)
def test_orders_disabled(self):
self.set_quotas('orders', 0)
self.create_orders(expected_return=403)
def test_orders_limited_one(self):
self.set_quotas('orders', 1)
self.create_orders(count=1)
self.create_orders(expected_return=403)
def test_orders_limited_five(self):
self.set_quotas('orders', 5)
self.create_orders(count=5)
self.create_orders(expected_return=403)
def test_consumers_unlimited(self):
self.set_quotas('consumers', -1)
self.create_consumers(count=5)
def test_consumers_disabled(self):
self.set_quotas('consumers', 0)
self.create_consumers(expected_return=403)
def test_consumers_limited_one(self):
self.set_quotas('consumers', 1)
self.create_consumers(count=1)
self.create_consumers(expected_return=403)
def test_consumers_limited_five(self):
self.set_quotas('consumers', 5)
self.create_consumers(count=5)
self.create_consumers(expected_return=403)
# ----------------------- Helper Functions ---------------------------
def get_default_quota_data(self):
return {"project_quotas":
{"secrets": -1,
"orders": -1,
"containers": -1,
"consumers": -1}}
def set_quotas(self, resource, quota):
"""Utility function to set resource quotas"""
self.quota_data["project_quotas"][resource] = quota
request_model = quota_models.ProjectQuotaRequestModel(
**self.quota_data)
resp = self.quota_behaviors.set_project_quotas(self.project_id,
request_model,
user_name=service_admin)
self.assertEqual(204, resp.status_code)
def get_default_secret_data(self):
return {
"name": "AES key",
"expiration": "2050-02-28T19:14:44.180394",
"algorithm": "aes",
"bit_length": 256,
"mode": "cbc",
"payload": "Z0Y2K2xMb0Yzb2hBOWFQUnB0KzZiUT09",
"payload_content_type": "application/octet-stream",
"payload_content_encoding": "base64",
}
def create_secrets(self, count=1, expected_return=201):
"""Utility function to create secrets"""
secret_ref = None
for _ in range(count):
test_model = secret_models.SecretModel(**self.secret_data)
resp, secret_ref = self.secret_behaviors.create_secret(
test_model, user_name=admin_b)
self.assertEqual(expected_return, resp.status_code)
return secret_ref
def get_container_req(self, secret_ref):
return {"name": "test_container",
"type": "generic",
"secret_refs": [{'name': 'secret1', 'secret_ref': secret_ref}]}
def create_containers(self, count=1, expected_return=201):
"""Utility function to create containers"""
container_ref = None
for _ in range(count):
secret_ref = self.create_secrets()
test_model = container_models.ContainerModel(
**self.get_container_req(secret_ref))
resp, container_ref = self.container_behaviors.create_container(
test_model, user_name=admin_b)
self.assertEqual(expected_return, resp.status_code)
return container_ref
def get_default_order_data(self):
return {'type': 'key',
"meta": {
"name": "barbican functional test order name",
"algorithm": "aes",
"bit_length": 256,
"mode": "cbc"}}
def create_orders(self, count=1, expected_return=202):
"""Utility function to create orders"""
for _ in range(count):
order_data = self.get_default_order_data()
test_model = order_models.OrderModel(**order_data)
resp, order_ref = self.order_behaviors.create_order(
test_model, user_name=admin_b)
self.assertEqual(expected_return, resp.status_code)
if resp.status_code == 202:
order_resp = self.order_behaviors.get_order(
order_ref, user_name=admin_b)
self.assertEqual(order_resp.status_code, 200)
self.order_secrets.append(order_resp.model.secret_ref)
def get_default_consumer_data(self):
return {"name": "consumer_name",
"URL": "consumer_url"}
def create_consumers(self, count=1, expected_return=200):
"""Utility function to create consumers"""
for _ in range(count):
container_ref = self.create_containers()
model = consumer_model.ConsumerModel(
**self.get_default_consumer_data())
resp, consumer_dat = self.consumer_behaviors.create_consumer(
model, container_ref, user_name=admin_b)
self.assertEqual(expected_return, resp.status_code)

View File

@ -35,7 +35,7 @@ retval=$?
testr slowest
# run the tests in parallel
SKIP=^\(\?\!\.\*ProjectQuotasPagingTestCase\)
SKIP=^\(\?\!\.\*\(ProjectQuotasPagingTestCase\|QuotaEnforcementTestCase\)\)
testr init
testr run $SKIP --parallel --subunit | subunit-trace --no-failure-debug -f
retval=$?