Add Quota objects
Change-Id: I9f8d906a08267a50d628e060f9a05d8694c150b5 Partial-Implements: blueprint quota-support
This commit is contained in:
parent
697412bdb8
commit
cae313d166
@ -19,6 +19,8 @@ from zun.objects import image
|
|||||||
from zun.objects import numa
|
from zun.objects import numa
|
||||||
from zun.objects import pci_device
|
from zun.objects import pci_device
|
||||||
from zun.objects import pci_device_pool
|
from zun.objects import pci_device_pool
|
||||||
|
from zun.objects import quota
|
||||||
|
from zun.objects import quota_class
|
||||||
from zun.objects import resource_class
|
from zun.objects import resource_class
|
||||||
from zun.objects import resource_provider
|
from zun.objects import resource_provider
|
||||||
from zun.objects import volume_mapping
|
from zun.objects import volume_mapping
|
||||||
@ -37,6 +39,8 @@ ComputeNode = compute_node.ComputeNode
|
|||||||
Capsule = capsule.Capsule
|
Capsule = capsule.Capsule
|
||||||
PciDevice = pci_device.PciDevice
|
PciDevice = pci_device.PciDevice
|
||||||
PciDevicePool = pci_device_pool.PciDevicePool
|
PciDevicePool = pci_device_pool.PciDevicePool
|
||||||
|
Quota = quota.Quota
|
||||||
|
QuotaClass = quota_class.QuotaClass
|
||||||
ContainerPCIRequest = container_pci_requests.ContainerPCIRequest
|
ContainerPCIRequest = container_pci_requests.ContainerPCIRequest
|
||||||
ContainerPCIRequests = container_pci_requests.ContainerPCIRequests
|
ContainerPCIRequests = container_pci_requests.ContainerPCIRequests
|
||||||
ContainerAction = container_action.ContainerAction
|
ContainerAction = container_action.ContainerAction
|
||||||
@ -55,6 +59,8 @@ __all__ = (
|
|||||||
Capsule,
|
Capsule,
|
||||||
PciDevice,
|
PciDevice,
|
||||||
PciDevicePool,
|
PciDevicePool,
|
||||||
|
Quota,
|
||||||
|
QuotaClass,
|
||||||
ContainerPCIRequest,
|
ContainerPCIRequest,
|
||||||
ContainerPCIRequests,
|
ContainerPCIRequests,
|
||||||
ContainerAction,
|
ContainerAction,
|
||||||
|
112
zun/objects/quota.py
Normal file
112
zun/objects/quota.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# 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_versionedobjects import fields
|
||||||
|
|
||||||
|
from zun.db import api as dbapi
|
||||||
|
from zun.objects import base
|
||||||
|
|
||||||
|
|
||||||
|
@base.ZunObjectRegistry.register
|
||||||
|
class Quota(base.ZunPersistentObject, base.ZunObject):
|
||||||
|
# Version 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'id': fields.IntegerField(),
|
||||||
|
'project_id': fields.StringField(nullable=True),
|
||||||
|
'resource': fields.StringField(),
|
||||||
|
'hard_limit': fields.IntegerField(nullable=True)
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _from_db_object(quota, db_quota):
|
||||||
|
"""Converts a database entity to a formal object"""
|
||||||
|
for field in quota.fields:
|
||||||
|
setattr(quota, field, db_quota[field])
|
||||||
|
|
||||||
|
quota.obj_reset_changes()
|
||||||
|
return quota
|
||||||
|
|
||||||
|
@base.remotable_classmethod
|
||||||
|
def get(cls, context, project_id, resource):
|
||||||
|
"""Find a quota based on project_id and resource
|
||||||
|
|
||||||
|
:param project_id: the project id.
|
||||||
|
:param context: security context.
|
||||||
|
:param resource: the name of resource.
|
||||||
|
:returns: a :class:`Quota` object.
|
||||||
|
"""
|
||||||
|
db_quota = dbapi.quota_get(context, project_id, resource)
|
||||||
|
quota = Quota._from_db_object(cls(context), db_quota)
|
||||||
|
return quota
|
||||||
|
|
||||||
|
@base.remotable_classmethod
|
||||||
|
def get_all(cls, context, project_id):
|
||||||
|
"""Find all quotas associated with project
|
||||||
|
|
||||||
|
:param context: security context.
|
||||||
|
:param project_id: the project id.
|
||||||
|
:returns: a dict
|
||||||
|
"""
|
||||||
|
return dbapi.quota_get_all_by_project(context, project_id)
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def create(self, context):
|
||||||
|
"""Create a Quota record in the DB.
|
||||||
|
|
||||||
|
:param context: security context. NOTE: This should only be
|
||||||
|
used internally by the indirection api.
|
||||||
|
Unfortunately, RPC requires context as the first
|
||||||
|
argument, even though we don't use it.
|
||||||
|
A context should be set when instantiating the
|
||||||
|
object, e.g.: Quota(context)
|
||||||
|
"""
|
||||||
|
values = self.obj_get_changes()
|
||||||
|
project_id = values.get('project_id')
|
||||||
|
resource = values.get('resource')
|
||||||
|
limit = values.get('hard_limit')
|
||||||
|
db_quota = dbapi.quota_create(context, project_id, resource, limit)
|
||||||
|
self._from_db_object(self, db_quota)
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def destroy(self, context=None):
|
||||||
|
"""Delete the Quota from the DB.
|
||||||
|
|
||||||
|
:param context: security context. NOTE: This should only be
|
||||||
|
used internally by the indirection api.
|
||||||
|
Unfortunately, RPC requires context as the first
|
||||||
|
argument, even though we don't use it.
|
||||||
|
A context should be set when instantiating the
|
||||||
|
object, e.g.: Quota(context)
|
||||||
|
"""
|
||||||
|
dbapi.quota_destroy(context, self.project_id, self.resource)
|
||||||
|
self.obj_reset_changes()
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def update(self, context=None):
|
||||||
|
"""Save updates to this Quota.
|
||||||
|
|
||||||
|
Updates will be made column by column based on the result
|
||||||
|
of self.what_changed().
|
||||||
|
|
||||||
|
:param context: security context. NOTE: This should only be
|
||||||
|
used internally by the indirection api.
|
||||||
|
Unfortunately, RPC requires context as the first
|
||||||
|
argument, even though we don't use it.
|
||||||
|
A context should be set when instantiating the
|
||||||
|
object, e.g.: Quota(context)
|
||||||
|
"""
|
||||||
|
updates = self.obj_get_changes()
|
||||||
|
dbapi.quota_update(context, self.project_id, self.resource,
|
||||||
|
updates.get('hard_limit'))
|
||||||
|
self.obj_reset_changes()
|
101
zun/objects/quota_class.py
Normal file
101
zun/objects/quota_class.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# 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_versionedobjects import fields
|
||||||
|
|
||||||
|
from zun.db import api as dbapi
|
||||||
|
from zun.objects import base
|
||||||
|
|
||||||
|
|
||||||
|
@base.ZunObjectRegistry.register
|
||||||
|
class QuotaClass(base.ZunPersistentObject, base.ZunObject):
|
||||||
|
# Version 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'id': fields.IntegerField(),
|
||||||
|
'class_name': fields.StringField(nullable=True),
|
||||||
|
'resource': fields.StringField(nullable=True),
|
||||||
|
'hard_limit': fields.IntegerField(nullable=True)
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _from_db_method(quota_class, db_quota_class):
|
||||||
|
"""Convert a database entity to a format object"""
|
||||||
|
for field in quota_class.fields:
|
||||||
|
setattr(quota_class, field, db_quota_class[field])
|
||||||
|
|
||||||
|
quota_class.obj_reset_changes()
|
||||||
|
return quota_class
|
||||||
|
|
||||||
|
@base.remotable_classmethod
|
||||||
|
def get(cls, context, class_name, resource):
|
||||||
|
"""Find a quota class based on class_name and resource name.
|
||||||
|
|
||||||
|
:param class_name: the name of class.
|
||||||
|
:param context: security context.
|
||||||
|
:param resource: the name of resource.
|
||||||
|
:returns: a :class:`QuotaClass` object.
|
||||||
|
"""
|
||||||
|
db_quota_class = dbapi.quota_class_get(context, class_name, resource)
|
||||||
|
quota_class = QuotaClass._from_db_method(cls(context), db_quota_class)
|
||||||
|
return quota_class
|
||||||
|
|
||||||
|
@base.remotable_classmethod
|
||||||
|
def get_all(cls, context, class_name=None):
|
||||||
|
"""Find quota based on class_name
|
||||||
|
|
||||||
|
:param context: security context.
|
||||||
|
:param class_name: the class name.
|
||||||
|
:return a dict
|
||||||
|
"""
|
||||||
|
if class_name is None:
|
||||||
|
res = dbapi.quota_class_get_default(context)
|
||||||
|
else:
|
||||||
|
res = dbapi.quota_class_get_all_by_name(context, class_name)
|
||||||
|
return res
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def create(self, context):
|
||||||
|
"""Create a QuotaClass record in the DB.
|
||||||
|
|
||||||
|
:param context: security context. NOTE: This should only be
|
||||||
|
used internally by the indirection api.
|
||||||
|
Unfortunately, RPC requires context as the first
|
||||||
|
argument, even though we don't use it.
|
||||||
|
A context should be set when instantiating the
|
||||||
|
object, e.g.: QuotaClass(context)
|
||||||
|
"""
|
||||||
|
values = self.obj_get_changes()
|
||||||
|
class_name = values.get('class_name')
|
||||||
|
resource = values.get('resource')
|
||||||
|
limit = values.get('hard_limit')
|
||||||
|
dbapi.quota_class_create(context, class_name, resource, limit)
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def update(self, context=None):
|
||||||
|
"""Save updates to this QuotaClass.
|
||||||
|
|
||||||
|
Updates will be made column by column based on the result
|
||||||
|
of self.what_changed().
|
||||||
|
|
||||||
|
:param context: security context. NOTE: This should only be
|
||||||
|
used internally by the indirection api.
|
||||||
|
Unfortunately, RPC requires context as the first
|
||||||
|
argument, even though we don't use it.
|
||||||
|
A context should be set when instantiating the
|
||||||
|
object, e.g.: QuotaClass(context)
|
||||||
|
"""
|
||||||
|
updates = self.obj_get_changes()
|
||||||
|
limit = updates.get('hard_limit')
|
||||||
|
dbapi.quota_class_update(context, self.class_name,
|
||||||
|
self.resource, limit)
|
@ -513,3 +513,47 @@ def create_test_quota_class(**kwargs):
|
|||||||
limit = kwargs.get('limit', 100)
|
limit = kwargs.get('limit', 100)
|
||||||
dbapi = _get_dbapi()
|
dbapi = _get_dbapi()
|
||||||
return dbapi.quota_class_create(context, class_name, resource, limit)
|
return dbapi.quota_class_create(context, class_name, resource, limit)
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_quota_value(**kwargs):
|
||||||
|
quota_values = {
|
||||||
|
'created_at': kwargs.get('created_at'),
|
||||||
|
'updated_at': kwargs.get('updated_at'),
|
||||||
|
'id': kwargs.get('id', 123),
|
||||||
|
'project_id': kwargs.get('project_id', 'fake_project_id'),
|
||||||
|
'resource': kwargs.get('resource', 'container'),
|
||||||
|
'hard_limit': kwargs.get('hard_limit', 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
return quota_values
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_quota(**kwargs):
|
||||||
|
quota_values = get_test_quota_value(**kwargs)
|
||||||
|
fake_quota = FakeObject()
|
||||||
|
for k, v in quota_values.items():
|
||||||
|
setattr(fake_quota, k, v)
|
||||||
|
|
||||||
|
return fake_quota
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_quota_class_value(**kwargs):
|
||||||
|
quota_values = {
|
||||||
|
'created_at': kwargs.get('created_at'),
|
||||||
|
'updated_at': kwargs.get('updated_at'),
|
||||||
|
'id': kwargs.get('id', 123),
|
||||||
|
'class_name': kwargs.get('class_name', 'fake_class_name'),
|
||||||
|
'resource': kwargs.get('resource', 'container'),
|
||||||
|
'hard_limit': kwargs.get('hard_limit', 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
return quota_values
|
||||||
|
|
||||||
|
|
||||||
|
def get_test_quota_class(**kwargs):
|
||||||
|
quota_class_values = get_test_quota_class_value(**kwargs)
|
||||||
|
fake_quota_class = FakeObject()
|
||||||
|
for k, v in quota_class_values.items():
|
||||||
|
setattr(fake_quota_class, k, v)
|
||||||
|
|
||||||
|
return fake_quota_class
|
||||||
|
@ -358,6 +358,8 @@ object_data = {
|
|||||||
'ComputeNode': '1.11-08be22db017745f4f0bc8f873eca7db0',
|
'ComputeNode': '1.11-08be22db017745f4f0bc8f873eca7db0',
|
||||||
'PciDevicePool': '1.0-3f5ddc3ff7bfa14da7f6c7e9904cc000',
|
'PciDevicePool': '1.0-3f5ddc3ff7bfa14da7f6c7e9904cc000',
|
||||||
'PciDevicePoolList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e',
|
'PciDevicePoolList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e',
|
||||||
|
'Quota': '1.0-4daf54427ac19cb23182cad82fcde751',
|
||||||
|
'QuotaClass': '1.0-4739583a70891fbc145031228fb8001e',
|
||||||
'ContainerPCIRequest': '1.0-b060f9f9f734bedde79a71a4d3112ee0',
|
'ContainerPCIRequest': '1.0-b060f9f9f734bedde79a71a4d3112ee0',
|
||||||
'ContainerPCIRequests': '1.0-7b8f7f044661fe4e24e6949c035af2c4',
|
'ContainerPCIRequests': '1.0-7b8f7f044661fe4e24e6949c035af2c4',
|
||||||
'ContainerAction': '1.1-b0c721f9e10c6c0d1e41e512c49eb877',
|
'ContainerAction': '1.1-b0c721f9e10c6c0d1e41e512c49eb877',
|
||||||
|
96
zun/tests/unit/objects/test_quota.py
Normal file
96
zun/tests/unit/objects/test_quota.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# 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 mock
|
||||||
|
|
||||||
|
from zun import objects
|
||||||
|
from zun.tests.unit.db import base
|
||||||
|
from zun.tests.unit.db import utils
|
||||||
|
|
||||||
|
|
||||||
|
class TestQuotaObject(base.DbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestQuotaObject, self).setUp()
|
||||||
|
self.fake_quota = utils.get_test_quota()
|
||||||
|
|
||||||
|
def test_get_quota(self):
|
||||||
|
project_id = self.fake_quota['project_id']
|
||||||
|
resource = self.fake_quota['resource']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_get',
|
||||||
|
autospec=True) as mock_get:
|
||||||
|
mock_get.return_value = self.fake_quota
|
||||||
|
quota = objects.Quota.get(self.context, project_id, resource)
|
||||||
|
mock_get.assert_called_once_with(
|
||||||
|
self.context, project_id, resource)
|
||||||
|
self.assertEqual(self.context, quota._context)
|
||||||
|
|
||||||
|
def test_get_all_quotas_by_project(self):
|
||||||
|
project_id = self.fake_quota['project_id']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_get_all_by_project',
|
||||||
|
autospec=True) as mock_get_all:
|
||||||
|
mock_get_all.return_value = {
|
||||||
|
'project_id': project_id,
|
||||||
|
'resource_1': 10,
|
||||||
|
'resource_2': 20
|
||||||
|
}
|
||||||
|
quotas_dict = objects.Quota.get_all(self.context, project_id)
|
||||||
|
mock_get_all.assert_called_once_with(self.context, project_id)
|
||||||
|
self.assertEqual(project_id, quotas_dict['project_id'])
|
||||||
|
|
||||||
|
def test_create_quota(self):
|
||||||
|
project_id = self.fake_quota['project_id']
|
||||||
|
resource = self.fake_quota['resource']
|
||||||
|
hard_limit = self.fake_quota['hard_limit']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_create',
|
||||||
|
autospec=True) as mock_create:
|
||||||
|
mock_create.return_value = self.fake_quota
|
||||||
|
quota = objects.Quota(
|
||||||
|
self.context, **utils.get_test_quota_value())
|
||||||
|
quota.create(self.context)
|
||||||
|
mock_create.assert_called_once_with(
|
||||||
|
self.context, project_id, resource, hard_limit)
|
||||||
|
|
||||||
|
def test_destroy_quota(self):
|
||||||
|
project_id = self.fake_quota['project_id']
|
||||||
|
resource = self.fake_quota['resource']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_get',
|
||||||
|
autospec=True) as mock_get:
|
||||||
|
mock_get.return_value = self.fake_quota
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_destroy',
|
||||||
|
autospec=True) as mock_destroy:
|
||||||
|
quota = objects.Quota.get(self.context, project_id,
|
||||||
|
resource)
|
||||||
|
quota.destroy()
|
||||||
|
mock_destroy.assert_called_once_with(
|
||||||
|
None, project_id, resource)
|
||||||
|
self.assertEqual(self.context, quota._context)
|
||||||
|
|
||||||
|
def test_update_quota(self):
|
||||||
|
project_id = self.fake_quota['project_id']
|
||||||
|
resource = self.fake_quota['resource']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_get',
|
||||||
|
autospec=True) as mock_get:
|
||||||
|
mock_get.return_value = self.fake_quota
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_update',
|
||||||
|
autospec=True) as mock_update:
|
||||||
|
quota = objects.Quota.get(self.context, project_id,
|
||||||
|
resource)
|
||||||
|
quota.hard_limit = 100
|
||||||
|
quota.update()
|
||||||
|
|
||||||
|
mock_get.assert_called_once_with(self.context, project_id,
|
||||||
|
resource)
|
||||||
|
mock_update.assert_called_once_with(
|
||||||
|
None, project_id, resource, 100)
|
||||||
|
self.assertEqual(self.context, quota._context)
|
||||||
|
self.assertEqual(100, quota.hard_limit)
|
97
zun/tests/unit/objects/test_quota_class.py
Normal file
97
zun/tests/unit/objects/test_quota_class.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# 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 mock
|
||||||
|
|
||||||
|
from zun.db.sqlalchemy import api
|
||||||
|
from zun import objects
|
||||||
|
from zun.tests.unit.db import base
|
||||||
|
from zun.tests.unit.db import utils
|
||||||
|
|
||||||
|
|
||||||
|
class TestQuotaClassObject(base.DbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestQuotaClassObject, self).setUp()
|
||||||
|
self.fake_quota_class = utils.get_test_quota_class()
|
||||||
|
|
||||||
|
def test_get_quota_class(self):
|
||||||
|
class_name = self.fake_quota_class['class_name']
|
||||||
|
resource = self.fake_quota_class['resource']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_class_get',
|
||||||
|
autospec=True) as mock_get:
|
||||||
|
mock_get.return_value = self.fake_quota_class
|
||||||
|
quota_class = objects.QuotaClass.get(
|
||||||
|
self.context, class_name, resource)
|
||||||
|
mock_get.assert_called_once_with(
|
||||||
|
self.context, class_name, resource)
|
||||||
|
self.assertEqual(self.context, quota_class._context)
|
||||||
|
|
||||||
|
def test_get_all_with_default(self):
|
||||||
|
class_name = api._DEFAULT_QUOTA_NAME
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_class_get_default',
|
||||||
|
autospec=True) as mock_get_all:
|
||||||
|
mock_get_all.return_value = {
|
||||||
|
'class_name': class_name,
|
||||||
|
'resource_1': 10,
|
||||||
|
'resource_2': 20
|
||||||
|
}
|
||||||
|
quota_class_dict = objects.QuotaClass.get_all(self.context)
|
||||||
|
mock_get_all.assert_called_once_with(self.context)
|
||||||
|
self.assertEqual(class_name, quota_class_dict['class_name'])
|
||||||
|
|
||||||
|
def test_get_all_with_class_name(self):
|
||||||
|
class_name = self.fake_quota_class['class_name']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_class_get_all_by_name',
|
||||||
|
autospec=True) as mock_get_all:
|
||||||
|
mock_get_all.return_value = {
|
||||||
|
'class_name': class_name,
|
||||||
|
'resource_1': 10,
|
||||||
|
'resource_2': 20
|
||||||
|
}
|
||||||
|
quota_class_dict = objects.QuotaClass.get_all(
|
||||||
|
self.context, class_name)
|
||||||
|
mock_get_all.assert_called_once_with(self.context, class_name)
|
||||||
|
self.assertEqual(class_name, quota_class_dict['class_name'])
|
||||||
|
|
||||||
|
def test_create_quota_class(self):
|
||||||
|
class_name = self.fake_quota_class['class_name']
|
||||||
|
resource = self.fake_quota_class['resource']
|
||||||
|
hard_limit = self.fake_quota_class['hard_limit']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_class_create',
|
||||||
|
autospec=True) as mock_create:
|
||||||
|
mock_create.return_value = self.fake_quota_class
|
||||||
|
quota_class = objects.QuotaClass(
|
||||||
|
self.context, **utils.get_test_quota_class_value())
|
||||||
|
quota_class.create(self.context)
|
||||||
|
mock_create.assert_called_once_with(
|
||||||
|
self.context, class_name, resource, hard_limit)
|
||||||
|
|
||||||
|
def test_update_quota(self):
|
||||||
|
class_name = self.fake_quota_class['class_name']
|
||||||
|
resource = self.fake_quota_class['resource']
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_class_get',
|
||||||
|
autospec=True) as mock_get:
|
||||||
|
mock_get.return_value = self.fake_quota_class
|
||||||
|
with mock.patch.object(self.dbapi, 'quota_class_update',
|
||||||
|
autospec=True) as mock_update:
|
||||||
|
quota_class = objects.QuotaClass.get(
|
||||||
|
self.context, class_name, resource)
|
||||||
|
quota_class.hard_limit = 100
|
||||||
|
quota_class.update()
|
||||||
|
|
||||||
|
mock_get.assert_called_once_with(
|
||||||
|
self.context, class_name, resource)
|
||||||
|
mock_update.assert_called_once_with(
|
||||||
|
None, class_name, resource, 100)
|
||||||
|
self.assertEqual(self.context, quota_class._context)
|
||||||
|
self.assertEqual(100, quota_class.hard_limit)
|
Loading…
Reference in New Issue
Block a user