Implement etcd API for ResourceClass

Porposed change of this commit is:

1.Add etcd db model and implements etcd API for
  ResourceClass.
2.Add 'uuid' field into ResourceClass.

Part of blueprint expose-host-capabilities

Change-Id: I9e5678e8742fd4c6a26b9ced6d6eccd6b7976363
This commit is contained in:
Wenzhi Yu 2017-02-16 13:18:48 +00:00
parent 3a84375531
commit cf1ad08b0f
11 changed files with 364 additions and 56 deletions

View File

@ -366,34 +366,34 @@ def get_resource_class(context, resource_ident):
"""Return a resource class. """Return a resource class.
:param context: The security context :param context: The security context
:param resource_ident: The id or name of a resource class. :param resource_ident: The uuid or name of a resource class.
:returns: A resource class. :returns: A resource class.
""" """
return _get_dbdriver_instance().get_resource_class( return _get_dbdriver_instance().get_resource_class(
context, resource_ident) context, resource_ident)
def destroy_resource_class(context, resource_id): def destroy_resource_class(context, resource_uuid):
"""Destroy a resource class and all associated interfaces. """Destroy a resource class and all associated interfaces.
:param context: Request context :param context: Request context
:param resource_id: The id of a resource class. :param resource_uuid: The uuid of a resource class.
""" """
return _get_dbdriver_instance().destroy_resource_class( return _get_dbdriver_instance().destroy_resource_class(
context, resource_id) context, resource_uuid)
def update_resource_class(context, resource_id, values): def update_resource_class(context, resource_uuid, values):
"""Update properties of a resource class. """Update properties of a resource class.
:context: Request context :context: Request context
:param resource_id: The id of a resource class. :param resource_uuid: The uuid of a resource class.
:values: The properties to be updated :values: The properties to be updated
:returns: A resource class. :returns: A resource class.
:raises: ResourceClassNotFound :raises: ResourceClassNotFound
""" """
return _get_dbdriver_instance().update_resource_class( return _get_dbdriver_instance().update_resource_class(
context, resource_id, values) context, resource_uuid, values)
def list_inventories(context, filters=None, limit=None, marker=None, def list_inventories(context, filters=None, limit=None, marker=None,

View File

@ -76,6 +76,8 @@ def translate_etcd_result(etcd_result, model_type):
ret = models.ZunService(data) ret = models.ZunService(data)
elif model_type == 'image': elif model_type == 'image':
ret = models.Image(data) ret = models.Image(data)
elif model_type == 'resource_class':
ret = models.ResourceClass(data)
else: else:
raise exception.InvalidParameterValue( raise exception.InvalidParameterValue(
_('The model_type value: %s is invalid.'), model_type) _('The model_type value: %s is invalid.'), model_type)
@ -436,3 +438,100 @@ class EtcdAPI(object):
if len(images) == 0: if len(images) == 0:
return None return None
return images[0] return images[0]
def list_resource_classes(self, context, filters=None, limit=None,
marker=None, sort_key=None, sort_dir=None):
try:
res = getattr(self.client.read('/resource_classes'),
'children', None)
except etcd.EtcdKeyNotFound:
return []
except Exception as e:
LOG.error(
_LE('Error occurred while reading from etcd server: %s'),
six.text_type(e))
raise
resource_classes = []
for r in res:
if r.value is not None:
resource_classes.append(
translate_etcd_result(r, 'resource_class'))
if filters:
resource_classes = self._filter_resources(
resource_classes, filters)
return self._process_list_result(
resource_classes, limit=limit, sort_key=sort_key)
@lockutils.synchronized('etcd_resource_class')
def create_resource_class(self, context, values):
resource_class = models.ResourceClass(values)
resource_class.save()
return resource_class
def get_resource_class(self, context, ident):
if uuidutils.is_uuid_like(ident):
return self._get_resource_class_by_uuid(context, ident)
else:
return self._get_resource_class_by_name(context, ident)
def _get_resource_class_by_uuid(self, context, uuid):
try:
resource_class = None
res = self.client.read('/resource_classes/' + uuid)
resource_class = translate_etcd_result(res, 'resource_class')
except etcd.EtcdKeyNotFound:
raise exception.ResourceClassNotFound(resource_class=uuid)
except Exception as e:
LOG.error(
_LE('Error occurred while retriving resource class: %s'),
six.text_type(e))
raise
return resource_class
def _get_resource_class_by_name(self, context, name):
try:
rcs = self.list_resource_classes(
context, filters={'name': name})
except etcd.EtcdKeyNotFound:
raise exception.ResourceClassNotFound(resource_class=name)
except Exception as e:
LOG.error(
_LE('Error occurred while retriving resource class: %s'),
six.text_type(e))
raise
if len(rcs) > 1:
raise exception.Conflict('Multiple resource classes exist with '
'same name. Please use uuid instead.')
elif len(rcs) == 0:
raise exception.ResourceClassNotFound(resource_class=name)
return rcs[0]
@lockutils.synchronized('etcd_resource_class')
def destroy_resource_class(self, context, uuid):
resource_class = self._get_resource_class_by_uuid(context, uuid)
self.client.delete('/resource_classes/' + resource_class.uuid)
@lockutils.synchronized('etcd_resource_class')
def update_resource_class(self, context, uuid, values):
if 'uuid' in values:
msg = _("Cannot override UUID for an existing resource class.")
raise exception.InvalidParameterValue(err=msg)
try:
target = self.client.read('/resource_classes/' + uuid)
target_value = json.loads(target.value)
target_value.update(values)
target.value = json.dumps(target_value)
self.client.update(target)
except etcd.EtcdKeyNotFound:
raise exception.ResourceClassNotFound(resource_class=uuid)
except Exception as e:
LOG.error(
_LE('Error occurred while updating resource class: %s'),
six.text_type(e))
raise
return translate_etcd_result(target, 'resource_class')

View File

@ -154,3 +154,26 @@ class Image(Base):
@classmethod @classmethod
def fields(cls): def fields(cls):
return cls._fields return cls._fields
class ResourceClass(Base):
"""Represents a resource class."""
_path = '/resource_classes'
_fields = objects.ResourceClass.fields.keys()
def __init__(self, resource_class_data):
self.path = ResourceClass.path()
for f in ResourceClass.fields():
setattr(self, f, None)
self.id = 1
self.update(resource_class_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields

View File

@ -0,0 +1,36 @@
# 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.
"""add uuid_to_resource_class
Revision ID: 8192905fd835
Revises: e4d145e195f4
Create Date: 2017-02-24 07:00:22.344162
"""
# revision identifiers, used by Alembic.
revision = '8192905fd835'
down_revision = 'e4d145e195f4'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('resource_class',
sa.Column('uuid', sa.String(length=36), nullable=False))
op.create_unique_constraint('uniq_resource_class0uuid',
'resource_class', ['uuid'])
op.drop_index('uniq_container0name', table_name='resource_class')

View File

@ -472,23 +472,23 @@ class Connection(object):
resource.save() resource.save()
except db_exc.DBDuplicateEntry: except db_exc.DBDuplicateEntry:
raise exception.ResourceClassAlreadyExists( raise exception.ResourceClassAlreadyExists(
field='name', value=values['name']) field='uuid', value=values['uuid'])
return resource return resource
def get_resource_class(self, context, resource_ident): def get_resource_class(self, context, resource_ident):
if strutils.is_int_like(resource_ident): if uuidutils.is_uuid_like(resource_ident):
return self._get_resource_class_by_id(context, resource_ident) return self._get_resource_class_by_uuid(context, resource_ident)
else: else:
return self._get_resource_class_by_name(context, resource_ident) return self._get_resource_class_by_name(context, resource_ident)
def _get_resource_class_by_id(self, context, resource_id): def _get_resource_class_by_uuid(self, context, resource_uuid):
query = model_query(models.ResourceClass) query = model_query(models.ResourceClass)
query = query.filter_by(id=resource_id) query = query.filter_by(uuid=resource_uuid)
try: try:
return query.one() return query.one()
except NoResultFound: except NoResultFound:
raise exception.ResourceClassNotFound( raise exception.ResourceClassNotFound(
resource_class=resource_id) resource_class=resource_uuid)
def _get_resource_class_by_name(self, context, resource_name): def _get_resource_class_by_name(self, context, resource_name):
query = model_query(models.ResourceClass) query = model_query(models.ResourceClass)

View File

@ -194,10 +194,11 @@ class ResourceClass(Base):
__tablename__ = 'resource_class' __tablename__ = 'resource_class'
__table_args__ = ( __table_args__ = (
schema.UniqueConstraint('name', name='uniq_resource_class0name'), schema.UniqueConstraint('uuid', name='uniq_resource_class0uuid'),
table_args() table_args()
) )
id = Column(Integer, primary_key=True, nullable=False) id = Column(Integer, primary_key=True, nullable=False)
uuid = Column(String(36), nullable=False)
name = Column(String(255), nullable=False) name = Column(String(255), nullable=False)

View File

@ -20,10 +20,12 @@ from zun.objects import fields as z_fields
@base.ZunObjectRegistry.register @base.ZunObjectRegistry.register
class ResourceClass(base.ZunPersistentObject, base.ZunObject): class ResourceClass(base.ZunPersistentObject, base.ZunObject):
# Version 1.0: Initial version # Version 1.0: Initial version
VERSION = '1.0' # Version 1.1: Add uuid field
VERSION = '1.1'
fields = { fields = {
'id': fields.IntegerField(read_only=True), 'id': fields.IntegerField(read_only=True),
'uuid': fields.UUIDField(nullable=False),
'name': z_fields.ResourceClassField(nullable=False), 'name': z_fields.ResourceClassField(nullable=False),
} }
@ -43,14 +45,14 @@ class ResourceClass(base.ZunPersistentObject, base.ZunObject):
for obj in db_objects] for obj in db_objects]
@base.remotable_classmethod @base.remotable_classmethod
def get_by_id(cls, context, rc_id): def get_by_uuid(cls, context, uuid):
"""Find a resource class based on id. """Find a resource class based on uuid.
:param rc_id: the id of a resource class. :param uuid: the uuid of a resource class.
:param context: Security context :param context: Security context
:returns: a :class:`ResourceClass` object. :returns: a :class:`ResourceClass` object.
""" """
db_resource = dbapi.get_resource_class(context, rc_id) db_resource = dbapi.get_resource_class(context, uuid)
resource = ResourceClass._from_db_object(cls(context), db_resource) resource = ResourceClass._from_db_object(cls(context), db_resource)
return resource return resource
@ -112,7 +114,7 @@ class ResourceClass(base.ZunPersistentObject, base.ZunObject):
A context should be set when instantiating the A context should be set when instantiating the
object, e.g.: ResourceClass(context) object, e.g.: ResourceClass(context)
""" """
dbapi.destroy_resource_class(context, self.id) dbapi.destroy_resource_class(context, self.uuid)
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @base.remotable
@ -130,7 +132,7 @@ class ResourceClass(base.ZunPersistentObject, base.ZunObject):
object, e.g.: ResourceClass(context) object, e.g.: ResourceClass(context)
""" """
updates = self.obj_get_changes() updates = self.obj_get_changes()
dbapi.update_resource_class(context, self.id, updates) dbapi.update_resource_class(context, self.uuid, updates)
self.obj_reset_changes() self.obj_reset_changes()
@ -150,7 +152,7 @@ class ResourceClass(base.ZunPersistentObject, base.ZunObject):
A context should be set when instantiating the A context should be set when instantiating the
object, e.g.: ResourceClass(context) object, e.g.: ResourceClass(context)
""" """
current = self.__class__.get_by_id(self._context, rc_id=self.id) current = self.__class__.get_by_uuid(self._context, self.uuid)
for field in self.fields: for field in self.fields:
if self.obj_attr_is_set(field) and \ if self.obj_attr_is_set(field) and \
getattr(self, field) != getattr(current, field): getattr(self, field) != getattr(current, field):

View File

@ -11,8 +11,13 @@
# under the License. # under the License.
"""Tests for manipulating resource classes via the DB API""" """Tests for manipulating resource classes via the DB API"""
import json
import mock
import etcd
from etcd import Client as etcd_client
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import uuidutils
import six import six
from zun.common import exception from zun.common import exception
@ -20,6 +25,8 @@ import zun.conf
from zun.db import api as dbapi from zun.db import api as dbapi
from zun.tests.unit.db import base from zun.tests.unit.db import base
from zun.tests.unit.db import utils from zun.tests.unit.db import utils
from zun.tests.unit.db.utils import FakeEtcdMultipleResult
from zun.tests.unit.db.utils import FakeEtcdResult
CONF = zun.conf.CONF CONF = zun.conf.CONF
@ -35,16 +42,16 @@ class DbResourceClassTestCase(base.DbTestCase):
def test_create_resource_class_already_exists(self): def test_create_resource_class_already_exists(self):
utils.create_test_resource_class( utils.create_test_resource_class(
context=self.context, name='123') context=self.context, uuid='123')
with self.assertRaisesRegexp(exception.ResourceClassAlreadyExists, with self.assertRaisesRegexp(exception.ResourceClassAlreadyExists,
'A resource class with name 123.*'): 'A resource class with uuid 123.*'):
utils.create_test_resource_class( utils.create_test_resource_class(
context=self.context, name='123') context=self.context, uuid='123')
def test_get_resource_class_by_id(self): def test_get_resource_class_by_uuid(self):
resource = utils.create_test_resource_class(context=self.context) resource = utils.create_test_resource_class(context=self.context)
res = dbapi.get_resource_class(self.context, resource.id) res = dbapi.get_resource_class(self.context, resource.uuid)
self.assertEqual(resource.id, res.id) self.assertEqual(resource.uuid, res.uuid)
self.assertEqual(resource.name, res.name) self.assertEqual(resource.name, res.name)
def test_get_resource_class_by_name(self): def test_get_resource_class_by_name(self):
@ -54,17 +61,16 @@ class DbResourceClassTestCase(base.DbTestCase):
self.assertEqual(resource.name, res.name) self.assertEqual(resource.name, res.name)
def test_get_resource_class_that_does_not_exist(self): def test_get_resource_class_that_does_not_exist(self):
bad_id = 1111111
self.assertRaises(exception.ResourceClassNotFound, self.assertRaises(exception.ResourceClassNotFound,
dbapi.get_resource_class, dbapi.get_resource_class,
self.context, self.context, uuidutils.generate_uuid())
bad_id)
def test_list_resource_classes(self): def test_list_resource_classes(self):
names = [] names = []
for i in range(1, 6): for i in range(1, 6):
resource = utils.create_test_resource_class( resource = utils.create_test_resource_class(
context=self.context, context=self.context,
uuid=uuidutils.generate_uuid(),
name='class'+str(i)) name='class'+str(i))
names.append(six.text_type(resource['name'])) names.append(six.text_type(resource['name']))
res = dbapi.list_resource_classes(self.context) res = dbapi.list_resource_classes(self.context)
@ -76,6 +82,7 @@ class DbResourceClassTestCase(base.DbTestCase):
for i in range(5): for i in range(5):
resource = utils.create_test_resource_class( resource = utils.create_test_resource_class(
context=self.context, context=self.context,
uuid=uuidutils.generate_uuid(),
name='class'+str(i)) name='class'+str(i))
names.append(six.text_type(resource.name)) names.append(six.text_type(resource.name))
res = dbapi.list_resource_classes(self.context, sort_key='name') res = dbapi.list_resource_classes(self.context, sort_key='name')
@ -116,3 +123,151 @@ class DbResourceClassTestCase(base.DbTestCase):
self.assertRaises(exception.ResourceClassNotFound, self.assertRaises(exception.ResourceClassNotFound,
dbapi.update_resource_class, self.context, dbapi.update_resource_class, self.context,
bad_id, {'name': new_name}) bad_id, {'name': new_name})
class EtcdDbResourceClassTestCase(base.DbTestCase):
def setUp(self):
cfg.CONF.set_override('db_type', 'etcd')
super(EtcdDbResourceClassTestCase, self).setUp()
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_create_resource_class(self, mock_write, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
utils.create_test_resource_class(context=self.context)
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_create_resource_class_already_exists(self, mock_write,
mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
utils.create_test_resource_class(context=self.context, name='123')
mock_read.side_effect = lambda *args: None
self.assertRaises(exception.ResourceExists,
utils.create_test_resource_class,
context=self.context, name='123')
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_get_resource_class_by_uuid(self, mock_write, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
resource_class = utils.create_test_resource_class(
context=self.context)
mock_read.side_effect = lambda *args: FakeEtcdResult(
resource_class.as_dict())
res = dbapi.get_resource_class(self.context, resource_class.uuid)
self.assertEqual(resource_class.uuid, res.uuid)
self.assertEqual(resource_class.name, res.name)
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_get_resource_class_by_name(self, mock_write, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
rcs = utils.create_test_resource_class(context=self.context)
mock_read.side_effect = lambda *args: FakeEtcdMultipleResult(
[rcs.as_dict()])
res = dbapi.get_resource_class(self.context, rcs.name)
self.assertEqual(rcs.uuid, res.uuid)
@mock.patch.object(etcd_client, 'read')
def test_get_resource_class_that_does_not_exist(self, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
self.assertRaises(exception.ResourceClassNotFound,
dbapi.get_resource_class,
self.context, 'fake-ident')
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_list_resource_classes(self, mock_write, mock_read):
names = []
resource_classes = []
mock_read.side_effect = etcd.EtcdKeyNotFound
for i in range(1, 6):
res_class = utils.create_test_resource_class(
context=self.context, name='class'+str(i))
resource_classes.append(res_class.as_dict())
names.append(six.text_type(res_class['name']))
mock_read.side_effect = lambda *args: FakeEtcdMultipleResult(
resource_classes)
res = dbapi.list_resource_classes(self.context)
res_names = [r.name for r in res]
self.assertEqual(sorted(names), sorted(res_names))
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_list_resource_classes_sorted(self, mock_write, mock_read):
names = []
resource_classes = []
mock_read.side_effect = etcd.EtcdKeyNotFound
for i in range(1, 6):
res_class = utils.create_test_resource_class(
context=self.context, name='class'+str(i))
resource_classes.append(res_class.as_dict())
names.append(six.text_type(res_class['name']))
mock_read.side_effect = lambda *args: FakeEtcdMultipleResult(
resource_classes)
res = dbapi.list_resource_classes(self.context, sort_key='name')
res_names = [r.name for r in res]
self.assertEqual(sorted(names), res_names)
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
@mock.patch.object(etcd_client, 'delete')
def test_destroy_resource_class(self, mock_delete,
mock_write, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
resource_class = utils.create_test_resource_class(
context=self.context)
mock_read.side_effect = lambda *args: FakeEtcdResult(
resource_class.as_dict())
dbapi.destroy_resource_class(self.context, resource_class.uuid)
mock_delete.assert_called_once_with(
'/resource_classes/%s' % resource_class.uuid)
@mock.patch.object(etcd_client, 'read')
def test_destroy_resource_class_that_does_not_exist(self, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
self.assertRaises(exception.ResourceClassNotFound,
dbapi.destroy_resource_class,
self.context,
'ca3e2a25-2901-438d-8157-de7ffd68d535')
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
@mock.patch.object(etcd_client, 'update')
def test_update_resource_class(self, mock_update,
mock_write, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
resource_class = utils.create_test_resource_class(
context=self.context)
old_name = resource_class.name
new_name = 'new-name'
self.assertNotEqual(old_name, new_name)
mock_read.side_effect = lambda *args: FakeEtcdResult(
resource_class.as_dict())
dbapi.update_resource_class(
self.context, resource_class.uuid, {'name': new_name})
self.assertEqual(new_name, json.loads(
mock_update.call_args_list[0][0][0].value)['name'])
@mock.patch.object(etcd_client, 'read')
def test_update_resource_class_not_found(self, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
new_name = 'new-name'
self.assertRaises(exception.ResourceClassNotFound,
dbapi.update_resource_class,
self.context,
'ca3e2a25-2901-438d-8157-de7ffd68d535',
{'name': new_name})
@mock.patch.object(etcd_client, 'read')
@mock.patch.object(etcd_client, 'write')
def test_update_resource_class_uuid(self, mock_write, mock_read):
mock_read.side_effect = etcd.EtcdKeyNotFound
resource_class = utils.create_test_resource_class(
context=self.context)
self.assertRaises(exception.InvalidParameterValue,
dbapi.update_resource_class,
self.context, resource_class.uuid,
{'uuid': ''})

View File

@ -172,6 +172,7 @@ def create_test_resource_provider(**kw):
def get_test_resource_class(**kw): def get_test_resource_class(**kw):
return { return {
'id': kw.get('id', 42), 'id': kw.get('id', 42),
'uuid': kw.get('uuid', '1136bf0e-66db-409d-aa4d-3af94eed8bcc'),
'name': kw.get('name', 'VCPU'), 'name': kw.get('name', 'VCPU'),
'created_at': kw.get('created_at'), 'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'), 'updated_at': kw.get('updated_at'),

View File

@ -359,7 +359,7 @@ object_data = {
'MyObj': '1.0-34c4b1aadefd177b13f9a2f894cc23cd', 'MyObj': '1.0-34c4b1aadefd177b13f9a2f894cc23cd',
'NUMANode': '1.0-cba878b70b2f8b52f1e031b41ac13b4e', 'NUMANode': '1.0-cba878b70b2f8b52f1e031b41ac13b4e',
'NUMATopology': '1.0-b54086eda7e4b2e6145ecb6ee2c925ab', 'NUMATopology': '1.0-b54086eda7e4b2e6145ecb6ee2c925ab',
'ResourceClass': '1.0-2c41abea55d0f7cb47a97bdb345b37fd', 'ResourceClass': '1.1-d661c7675b3cd5b8c3618b68ba64324e',
'ResourceProvider': '1.0-92b427359d5a4cf9ec6c72cbe630ee24', 'ResourceProvider': '1.0-92b427359d5a4cf9ec6c72cbe630ee24',
'ZunService': '1.0-2a19ab9987a746621b2ada02d8aadf22', 'ZunService': '1.0-2a19ab9987a746621b2ada02d8aadf22',
} }

View File

@ -25,16 +25,6 @@ class TestResourceClassObject(base.DbTestCase):
super(TestResourceClassObject, self).setUp() super(TestResourceClassObject, self).setUp()
self.fake_resource = utils.get_test_resource_class() self.fake_resource = utils.get_test_resource_class()
def test_get_by_id(self):
rc_id = self.fake_resource['id']
with mock.patch.object(self.dbapi, 'get_resource_class',
autospec=True) as mock_get_resource_class:
mock_get_resource_class.return_value = self.fake_resource
resource = objects.ResourceClass.get_by_id(self.context, rc_id)
mock_get_resource_class.assert_called_once_with(
self.context, rc_id)
self.assertEqual(self.context, resource._context)
def test_get_by_name(self): def test_get_by_name(self):
name = self.fake_resource['name'] name = self.fake_resource['name']
with mock.patch.object(self.dbapi, 'get_resource_class', with mock.patch.object(self.dbapi, 'get_resource_class',
@ -67,51 +57,52 @@ class TestResourceClassObject(base.DbTestCase):
self.assertEqual(self.context, resource._context) self.assertEqual(self.context, resource._context)
def test_destroy(self): def test_destroy(self):
rc_id = self.fake_resource['id'] rc_uuid = self.fake_resource['uuid']
with mock.patch.object(self.dbapi, 'get_resource_class', with mock.patch.object(self.dbapi, 'get_resource_class',
autospec=True) as mock_get_resource_class: autospec=True) as mock_get_resource_class:
mock_get_resource_class.return_value = self.fake_resource mock_get_resource_class.return_value = self.fake_resource
with mock.patch.object(self.dbapi, 'destroy_resource_class', with mock.patch.object(self.dbapi, 'destroy_resource_class',
autospec=True) as mock_destroy: autospec=True) as mock_destroy:
resource = objects.ResourceClass.get_by_id( resource = objects.ResourceClass.get_by_uuid(
self.context, rc_id) self.context, rc_uuid)
resource.destroy() resource.destroy()
mock_get_resource_class.assert_called_once_with( mock_get_resource_class.assert_called_once_with(
self.context, rc_id) self.context, rc_uuid)
mock_destroy.assert_called_once_with(None, rc_id) mock_destroy.assert_called_once_with(None, rc_uuid)
self.assertEqual(self.context, resource._context) self.assertEqual(self.context, resource._context)
def test_save(self): def test_save(self):
rc_id = self.fake_resource['id'] rc_uuid = self.fake_resource['uuid']
with mock.patch.object(self.dbapi, 'get_resource_class', with mock.patch.object(self.dbapi, 'get_resource_class',
autospec=True) as mock_get_resource_class: autospec=True) as mock_get_resource_class:
mock_get_resource_class.return_value = self.fake_resource mock_get_resource_class.return_value = self.fake_resource
with mock.patch.object(self.dbapi, 'update_resource_class', with mock.patch.object(self.dbapi, 'update_resource_class',
autospec=True) as mock_update: autospec=True) as mock_update:
resource = objects.ResourceClass.get_by_id( resource = objects.ResourceClass.get_by_uuid(
self.context, rc_id) self.context, rc_uuid)
resource.name = 'MEMORY_MB' resource.name = 'MEMORY_MB'
resource.save() resource.save()
mock_get_resource_class.assert_called_once_with( mock_get_resource_class.assert_called_once_with(
self.context, rc_id) self.context, rc_uuid)
mock_update.assert_called_once_with( mock_update.assert_called_once_with(
None, rc_id, None, rc_uuid,
{'name': 'MEMORY_MB'}) {'name': 'MEMORY_MB'})
self.assertEqual(self.context, resource._context) self.assertEqual(self.context, resource._context)
def test_refresh(self): def test_refresh(self):
rc_id = self.fake_resource['id'] rc_uuid = self.fake_resource['uuid']
name = self.fake_resource['name'] name = self.fake_resource['name']
new_name = 'MEMORY_MB' new_name = 'MEMORY_MB'
returns = [dict(self.fake_resource, name=name), returns = [dict(self.fake_resource, name=name),
dict(self.fake_resource, name=new_name)] dict(self.fake_resource, name=new_name)]
expected = [mock.call(self.context, rc_id), expected = [mock.call(self.context, rc_uuid),
mock.call(self.context, rc_id)] mock.call(self.context, rc_uuid)]
with mock.patch.object(self.dbapi, 'get_resource_class', with mock.patch.object(self.dbapi, 'get_resource_class',
side_effect=returns, side_effect=returns,
autospec=True) as mock_get_resource_class: autospec=True) as mock_get_resource_class:
resource = objects.ResourceClass.get_by_id(self.context, rc_id) resource = objects.ResourceClass.get_by_uuid(
self.context, rc_uuid)
self.assertEqual(name, resource.name) self.assertEqual(name, resource.name)
resource.refresh() resource.refresh()
self.assertEqual(new_name, resource.name) self.assertEqual(new_name, resource.name)