diff options
author | Sergey Skripnick <sskripnick@mirantis.com> | 2013-07-04 10:43:33 +0300 |
---|---|---|
committer | Sergey Skripnick <sskripnick@mirantis.com> | 2013-07-29 15:12:34 +0300 |
commit | 19dfee6febc666e398909a38482b20b5672d8b9c (patch) | |
tree | 8922aec038c086b44cbc3a38f63a3023e1b806bf /tests | |
parent | d65f843829356f5ed8d8b7bb6fe92f225c30b1e6 (diff) | |
download | oslo-19dfee6febc666e398909a38482b20b5672d8b9c.tar.gz oslo-19dfee6febc666e398909a38482b20b5672d8b9c.tar.xz oslo-19dfee6febc666e398909a38482b20b5672d8b9c.zip |
Import common quota code from nova and cinder
Quota code was imported and merged from nova and cinder projects.
blueprint common-quota
Change-Id: Idc9a85fddd1665ae010bcc4740963e14d81310c3
Diffstat (limited to 'tests')
-rw-r--r-- | tests/unit/test_quota.py | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/tests/unit/test_quota.py b/tests/unit/test_quota.py new file mode 100644 index 0000000..6c9747d --- /dev/null +++ b/tests/unit/test_quota.py @@ -0,0 +1,418 @@ +# +# 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 datetime +import mock +from openstack.common import quota +from oslo.config import cfg +from tests import utils + +CONF = cfg.CONF + + +class FakeContext(object): + project_id = 'p1' + user_id = 'u1' + quota_class = 'QuotaClass_' + + def elevated(self): + return self + + +class DbQuotaDriverTestCase(utils.BaseTestCase): + + def setUp(self): + self.sample_resources = {'r1': quota.BaseResource('r1'), + 'r2': quota.BaseResource('r2')} + + dbapi = mock.Mock() + dbapi.quota_usage_get_all_by_project_and_user = mock.Mock( + return_value={'project_id': 'p1', 'user_id': 'u1', + 'r1': {'reserved': 1, 'in_use': 2}, + 'r2': {'reserved': 2, 'in_use': 3}}) + dbapi.quota_get_all_by_project_and_user = mock.Mock( + return_value={'project_id': 'p1', 'user_id': 'u1', + 'r1': 5, 'r2': 6}) + dbapi.quota_get = mock.Mock(return_value='quota_get') + dbapi.quota_reserve = mock.Mock(return_value='quota_reserve') + dbapi.quota_class_get = mock.Mock(return_value='quota_class_get') + dbapi.quota_class_reserve = mock.Mock( + return_value='quota_class_reserve') + dbapi.quota_class_get_default = mock.Mock( + return_value={'r1': 1, 'r2': 2}) + dbapi.quota_class_get_all_by_name = mock.Mock(return_value={'r1': 9}) + dbapi.quota_get_all_by_project = mock.Mock( + return_value=dict([('r%d' % i, i) for i in range(3)])) + dbapi.quota_get_all = mock.Mock( + return_value=[{'resource': 'r1', 'hard_limit': 3}, + {'resource': 'r2', 'hard_limit': 4}]) + dbapi.quota_usage_get_all_by_project = mock.Mock( + return_value=dict([('r%d' % i, {'in_use': i, 'reserved': i + 1}) + for i in range(3)])) + self.driver = quota.DbQuotaDriver(dbapi) + self.ctxt = FakeContext() + return super(DbQuotaDriverTestCase, self).setUp() + + def test_get_by_project(self): + args = ['p1', 'resource'] + self.assertEqual('quota_get', + self.driver.get_by_project(self.ctxt, *args)) + self.driver.db.quota_get.assert_called_once_with(self.ctxt, *args) + + def test_get_by_project_and_user(self): + args = ['p1', 'u1', 'resource'] + self.assertEqual('quota_get', + self.driver.get_by_project_and_user(self.ctxt, *args)) + self.driver.db.quota_get.assert_called_once_with(self.ctxt, *args) + + def test_get_by_class(self): + args = ['class', 'resource'] + self.assertEqual('quota_class_get', + self.driver.get_by_class(self.ctxt, *args)) + self.driver.db.quota_class_get.assert_called_once_with(self.ctxt, + *args) + + def test_get_defaults(self): + defaults = self.driver.get_defaults(self.ctxt, self.sample_resources) + self.assertEqual(defaults, {'r1': 1, 'r2': 2}) + self.sample_resources.pop('r1') + defaults = self.driver.get_defaults(self.ctxt, self.sample_resources) + self.assertEqual(defaults, {'r2': 2}) + + def test_get_class_quotas(self): + quotas = self.driver.get_class_quotas(self.ctxt, + self.sample_resources, + 'ClassName') + self.assertEqual(quotas, {'r1': 9, 'r2': 2}) + + def test_get_user_quotas(self): + actual = self.driver.get_user_quotas( + self.ctxt, self.sample_resources.copy(), 'p1', 'u1') + expected = {'r1': {'in_use': 2, 'limit': 5, 'reserved': 1}, + 'r2': {'in_use': 3, 'limit': 6, 'reserved': 2}} + self.assertEqual(actual, expected) + + def test_get_settable_quotas(self): + actual = self.driver.get_settable_quotas(self.ctxt, + self.sample_resources, 'p1') + expected = {'r1': {'maximum': -1, 'minimum': 3}, + 'r2': {'maximum': -1, 'minimum': 5}} + self.assertEqual(actual, expected) + + def test_get_settable_quotas_with_user_id(self): + actual = self.driver.get_settable_quotas( + self.ctxt, self.sample_resources, 'p1', user_id='u1') + expected = {'r1': {'maximum': 3, 'minimum': 3}, + 'r2': {'maximum': 4, 'minimum': 5}} + self.assertEqual(actual, expected) + + def test_get_project_quotas(self): + self.ctxt.quota_class = 'ClassName' + expected = {'r1': {'limit': 1, 'in_use': 1, 'reserved': 2}, + 'r2': {'limit': 2, 'in_use': 2, 'reserved': 3}} + quotas = self.driver.get_project_quotas(self.ctxt, + self.sample_resources, 'p1') + self.assertEqual(quotas, expected) + + def test_get_project_quotas_project_id_differs(self): + self.ctxt.project_id = 'p2' + expected = {'r1': {'limit': 1, 'in_use': 1, 'reserved': 2}, + 'r2': {'limit': 2, 'in_use': 2, 'reserved': 3}} + quotas = self.driver.get_project_quotas(self.ctxt, + self.sample_resources, 'p1') + self.assertEqual(quotas, expected) + + def test_get_project_quotas_omit_default_quota_class(self): + self.sample_resources['r3'] = quota.BaseResource('r3') + quotas = self.driver.get_project_quotas( + self.ctxt, self.sample_resources, 'p1', defaults=False) + expected = {'r1': {'limit': 1, 'in_use': 1, 'reserved': 2}, + 'r2': {'limit': 2, 'in_use': 2, 'reserved': 3}} + self.assertEqual(quotas, expected) + + def test_limit_check_invalid_quota_value(self): + self.assertRaises(quota.InvalidQuotaValue, + self.driver.limit_check, self.ctxt, [], {'r1': -1}) + + def test_limit_check_quota_resource_unknown(self): + self.assertRaises(quota.QuotaResourceUnknown, + self.driver.limit_check, + self.ctxt, + {'r1': quota.ReservableResource('r1', 'r1')}, + {'r1': 42}) + + def test_limit_check_over_quota(self): + self.assertRaises(quota.OverQuota, + self.driver.limit_check, + self.ctxt, + {'r1': quota.BaseResource('r1')}, + {'r1': 2}) + + def test_limit_check(self): + self.assertIsNone(self.driver.limit_check( + self.ctxt, {'r1': quota.BaseResource('r1')}, {'r1': 1})) + + def test_quota_reserve(self): + now = datetime.datetime.utcnow() + + class FakeTimeutils(object): + @staticmethod + def utcnow(): + return now + + self.stubs.Set(quota, "timeutils", FakeTimeutils) + + expected = [self.ctxt, self.sample_resources, {}, {}, {}, None, + CONF.until_refresh, CONF.max_age] + + # expire as None + self.assertEqual('quota_reserve', self.driver.reserve( + self.ctxt, self.sample_resources, {}, None, 'p1')) + expected[5] = now + datetime.timedelta( + seconds=CONF.reservation_expire) + self.driver.db.quota_reserve.assert_called_once_with(*expected, + project_id='p1', + user_id='u1') + self.driver.db.reset_mock() + # expire as seconds + self.assertEqual('quota_reserve', self.driver.reserve( + self.ctxt, self.sample_resources, {}, 42, 'p1')) + expected[5] = now + datetime.timedelta(seconds=42) + self.driver.db.quota_reserve.assert_called_once_with(*expected, + project_id='p1', + user_id='u1') + self.driver.db.reset_mock() + # expire as absolute + expected[5] = now + datetime.timedelta(hours=1) + self.assertEqual('quota_reserve', self.driver.reserve( + self.ctxt, self.sample_resources, {}, + now + datetime.timedelta(hours=1), 'p1')) + self.driver.db.quota_reserve.assert_called_once_with(*expected, + project_id='p1', + user_id='u1') + self.driver.db.reset_mock() + # InvalidReservationExpiration + self.assertRaises(quota.InvalidReservationExpiration, + self.driver.reserve, self.ctxt, + self.sample_resources, {}, (), 'p1') + self.driver.db.reset_mock() + # project_id is None + self.assertEqual('quota_reserve', self.driver.reserve( + self.ctxt, self.sample_resources, {}, + now + datetime.timedelta(hours=1))) + self.driver.db.quota_reserve.assert_called_once_with(*expected, + project_id='p1', + user_id='u1') + + def test_commit(self): + self.assertIsNone(self.driver.commit(self.ctxt, 'reservations', + project_id='p1')) + self.driver.db.reservation_commit.assert_called_once_with( + self.ctxt, 'reservations', project_id='p1', user_id='u1') + + def test_commit_project_id_none(self): + self.assertIsNone(self.driver.commit(self.ctxt, 'reservations')) + self.driver.db.reservation_commit.assert_called_once_with( + self.ctxt, 'reservations', project_id='p1', user_id='u1') + + def test_rollback(self): + self.assertIsNone(self.driver.rollback(self.ctxt, 'reservations', + project_id='p1')) + self.driver.db.reservation_rollback.assert_called_once_with( + self.ctxt, 'reservations', project_id='p1', user_id='u1') + + def test_rollback_project_id_none(self): + self.assertIsNone(self.driver.rollback(self.ctxt, 'reservations')) + self.driver.db.reservation_rollback.assert_called_once_with( + self.ctxt, 'reservations', project_id='p1', user_id='u1') + + def test_usage_reset(self): + resource = self.sample_resources['r1'] + self.assertIsNone(self.driver.usage_reset(self.ctxt, [resource])) + self.driver.db.quota_usage_update.assert_called_once_with( + self.ctxt, 'p1', 'u1', resource, in_use=-1) + + def test_usage_reset_quota_usage_not_found(self): + resource = self.sample_resources['r1'] + self.driver.db.quota_usage_update = mock.Mock( + side_effect=quota.QuotaUsageNotFound) + self.assertIsNone(self.driver.usage_reset(self.ctxt, [resource])) + self.driver.db.quota_usage_update.assert_called_once_with( + self.ctxt, 'p1', 'u1', resource, in_use=-1) + + def test_destroy_all_by_project_and_user(self): + self.assertIsNone(self.driver.destroy_all_by_project_and_user( + self.ctxt, 'p1', 'u1')) + method = self.driver.db.quota_destroy_all_by_project_and_user + method.assert_called_once_with(self.ctxt, 'p1', 'u1') + + def test_destroy_all_by_project(self): + self.assertIsNone(self.driver.destroy_all_by_project(self.ctxt, 'p1')) + self.driver.db.quota_destroy_all_by_project.assert_called_once_with( + self.ctxt, 'p1') + + def test_expire(self): + self.assertIsNone(self.driver.expire(self.ctxt)) + self.driver.db.reservation_expire.assert_called_once_with(self.ctxt) + + +class BaseResourceTestCase(utils.BaseTestCase): + + def setUp(self): + self.ctxt = FakeContext() + self.dbapi = mock.Mock() + self.dbapi.quota_get = mock.Mock(return_value='quota_get') + self.dbapi.quota_class_get = mock.Mock( + return_value='quota_class_get') + self.dbapi.quota_class_get_default = mock.Mock( + return_value={'r1': 1}) + self.driver = quota.DbQuotaDriver(self.dbapi) + super(BaseResourceTestCase, self).setUp() + + def test_quota(self): + resource = quota.BaseResource('r1') + self.assertEqual('quota_get', resource.quota(self.driver, self.ctxt)) + + def test_quota_no_project_id(self): + self.ctxt.project_id = None + resource = quota.BaseResource('r1') + self.assertEqual('quota_class_get', + resource.quota(self.driver, self.ctxt)) + + def test_quota_project_quota_not_found(self): + self.dbapi.quota_get = mock.Mock( + side_effect=quota.ProjectQuotaNotFound()) + resource = quota.BaseResource('r1') + self.assertEqual('quota_class_get', + resource.quota(self.driver, self.ctxt)) + + def test_quota_quota_class_not_found(self): + self.dbapi.quota_get = mock.Mock( + side_effect=quota.ProjectQuotaNotFound(project_id='p1')) + self.dbapi.quota_class_get = mock.Mock( + side_effect=quota.QuotaClassNotFound(class_name='ClassName')) + resource = quota.BaseResource('r1') + self.assertEqual(1, resource.quota(self.driver, self.ctxt)) + + +class CountableResourceTestCase(utils.BaseTestCase): + + def test_init(self): + resource = quota.CountableResource('r1', 42) + self.assertEqual('r1', resource.name) + self.assertEqual(42, resource.count) + + +class QuotaEngineTestCase(utils.BaseTestCase): + + def setUp(self): + self.ctxt = FakeContext() + self.dbapi = mock.Mock() + self.quota_driver = mock.Mock() + self.engine = quota.QuotaEngine(self.dbapi, self.quota_driver) + self.r1 = quota.BaseResource('r1') + self.r2 = quota.BaseResource('r2') + self.engine.register_resources([self.r1, self.r2]) + super(QuotaEngineTestCase, self).setUp() + + def assertProxyMethod(self, method, *args, **kwargs): + if 'retval' in kwargs: + retval = kwargs.pop('retval') + else: + retval = method + setattr(self.quota_driver, method, mock.Mock(return_value=method)) + actual = getattr(self.engine, method)(self.ctxt, *args, **kwargs) + getattr(self.quota_driver, method).assert_called_once_with(self.ctxt, + *args, + **kwargs) + self.assertEqual(actual, retval) + + def assertMethod(self, method, args, kwargs, called_args, + called_kwargs, retval): + setattr(self.quota_driver, method, mock.Mock(return_value=method)) + actual = getattr(self.engine, method)(self.ctxt, *args, **kwargs) + getattr(self.quota_driver, method).assert_called_once_with( + self.ctxt, *called_args, **called_kwargs) + self.assertEqual(actual, retval) + + def test_proxy_methods(self): + self.assertProxyMethod('get_by_project', 'p1', 'resname') + self.assertProxyMethod('get_by_project_and_user', 'p1', 'u1', 'res') + self.assertProxyMethod('get_by_class', 'quota_class', 'resname') + self.assertProxyMethod('get_default', 'resource') + self.assertProxyMethod('expire', retval=None) + self.assertProxyMethod('usage_reset', 'resources', retval=None) + self.assertProxyMethod('destroy_all_by_project', 'p1', retval=None) + self.assertProxyMethod('destroy_all_by_project_and_user', 'p1', + 'u1', retval=None) + self.assertProxyMethod('commit', 'reservations', project_id='p1', + user_id='u1', retval=None) + self.assertProxyMethod('rollback', 'reservations', project_id='p1', + user_id=None, retval=None) + + self.assertMethod('get_settable_quotas', ['p1'], {'user_id': 'u1'}, + [self.engine.resources, 'p1'], {'user_id': 'u1'}, + 'get_settable_quotas') + self.assertMethod('get_defaults', [], {}, + [self.engine.resources], {}, 'get_defaults') + self.assertMethod('get_project_quotas', ['p1', 'quotaclass'], + {'defaults': 'defaults', 'usages': 'usages'}, + [self.engine.resources, 'p1'], + {'quota_class': 'quotaclass', 'defaults': 'defaults', + 'usages': 'usages', 'remains': False}, + 'get_project_quotas') + self.assertMethod('reserve', [], + {'expire': 'expire', 'project_id': 'p1', + 'user_id': 'u1', 'deltas': 'd1'}, + [self.engine.resources, {'deltas': 'd1'}], + {'expire': 'expire', + 'project_id': 'p1', 'user_id': 'u1'}, 'reserve') + self.assertMethod('get_class_quotas', + ['quota_class'], {'defaults': 'defaults'}, + [self.engine.resources, 'quota_class'], + {'defaults': 'defaults'}, 'get_class_quotas') + self.assertMethod('get_user_quotas', ['project_id', 'user_id'], + {'quota_class': 'qc', 'defaults': 'de', + 'usages': 'us'}, + [self.engine.resources, 'project_id', 'user_id'], + {'quota_class': 'qc', 'defaults': 'de', + 'usages': 'us'}, + 'get_user_quotas') + self.assertMethod('limit_check', + [], {'project_id': 'p1', 'user_id': 'u1', + 'val1': 'val1'}, + [self.engine.resources, {'val1': 'val1'}], + {'project_id': 'p1', 'user_id': 'u1'}, 'limit_check') + + def test_resource_names(self): + self.assertEqual(['r1', 'r2'], self.engine.resource_names) + + def test_contains(self): + self.assertTrue(self.r1.name in self.engine) + self.assertTrue(self.r2.name in self.engine) + self.assertFalse('r3' in self.engine) + + def test_count(self): + count = mock.Mock(return_value=42) + r = quota.CountableResource('r1', count) + self.engine.register_resource(r) + actual = self.engine.count(self.ctxt, 'r1') + self.assertEqual(42, actual) + count.assert_called_once_with(self.ctxt) + self.assertRaises(quota.QuotaResourceUnknown, + self.engine.count, self.ctxt, 'r2') + + def test_init(self): + engine = quota.QuotaEngine(self.dbapi) + self.assertIsInstance(engine._driver, quota.DbQuotaDriver) |