Increase attribute types

In order to do proper JSON rendering, ooi needs to to further refine
the Object attribute type into numbers, bools and strings. All
attributes are updated to include the type. Object attribute type is
only used now for source and targets in links. Handling of attributes
in network is simplified thanks to this change.

Change-Id: If1c0e6b1e08139b369b3c68c4a12ff7244c3445f
This commit is contained in:
Enol Fernandez 2016-11-09 22:53:33 +00:00 committed by Enol Fernández
parent 1df2897254
commit 967f1a2cab
18 changed files with 226 additions and 109 deletions

View File

@ -56,17 +56,10 @@ def process_parameters(req, scheme=None,
:param: required_attr: attributes required
"""
parameters = parse_validate_schema(req, scheme, required_attr)
try:
attributes = {}
if 'X_PROJECT_ID' in req.headers:
attributes["X_PROJECT_ID"] = req.headers["X_PROJECT_ID"]
if "attributes" in parameters:
for k, v in parameters.get("attributes", None).items():
attributes[k.strip()] = v.strip()
if not attributes:
attributes = None
except Exception:
raise exception.Invalid
attributes = {}
if 'X_PROJECT_ID' in req.headers:
attributes["X_PROJECT_ID"] = req.headers["X_PROJECT_ID"]
attributes.update(parameters.get("attributes", {}))
return attributes
@ -194,4 +187,4 @@ class Controller(base.Controller):
if action is None or action not in occi_actions:
raise exception.InvalidAction(action=action)
raise exception.NotImplemented("Network actions are not implemented")
raise exception.NotImplemented("Network actions are not implemented")

View File

@ -15,26 +15,67 @@
import abc
import collections
import copy
import numbers
import enum
import six
@enum.unique
class AttributeType(enum.Enum):
object_type = 1
list_type = 2
hash_type = 3
number_type = 1
string_type = 2
boolean_type = 3
object_type = 4
list_type = 5
hash_type = 6
def __init__(self, attr_type):
self.attr_type = attr_type
@classmethod
def check_number_type(cls, value):
if isinstance(value, bool) or not isinstance(value, numbers.Number):
raise TypeError("Expecting numeric value")
@classmethod
def check_string_type(cls, value):
if not isinstance(value, six.string_types):
raise TypeError("Expecting string type")
@classmethod
def check_boolean_type(cls, value):
if not isinstance(value, bool):
raise TypeError("Expecting boolean value")
@classmethod
def check_object_type(cls, value):
# object type can handle anything
return
@classmethod
def check_list_type(cls, value):
if not isinstance(value, list):
raise TypeError("Expecting list type")
@classmethod
def check_hash_type(cls, value):
if not isinstance(value, dict):
raise TypeError("Expecting hash type")
def check_type(self, value):
if self.attr_type == AttributeType.list_type.value:
if not isinstance(value, list):
raise TypeError("Expecting list value")
elif self.attr_type == AttributeType.hash_type.value:
if not isinstance(value, dict):
raise TypeError("Expecting hash value")
py_types_map = {
AttributeType.number_type.value: AttributeType.check_number_type,
AttributeType.boolean_type.value: AttributeType.check_boolean_type,
AttributeType.string_type.value: AttributeType.check_string_type,
AttributeType.object_type.value: AttributeType.check_object_type,
AttributeType.list_type.value: AttributeType.check_list_type,
AttributeType.hash_type.value: AttributeType.check_hash_type,
}
# do not mess with uninitialized values
if value is None:
return
py_types_map[self.attr_type](value)
@six.add_metaclass(abc.ABCMeta)
@ -42,7 +83,6 @@ class Attribute(object):
def __init__(self, name, value=None, required=False, default=None,
description=None, attr_type=None):
self._name = name
self._value = value
self.required = required
self.default = default
self.description = description
@ -52,6 +92,8 @@ class Attribute(object):
raise TypeError("Unexpected attribute type")
else:
self.attr_type = attr_type
self.attr_type.check_type(value)
self._value = value
@property
def name(self):

View File

@ -58,9 +58,11 @@ class Entity(object):
attributes = attribute.AttributeCollection({
"occi.core.id": attribute.InmutableAttribute(
"occi.core.id", description="A unique identifier"),
"occi.core.id", description="A unique identifier",
attr_type=attribute.AttributeType.string_type),
"occi.core.title": attribute.MutableAttribute(
"occi.core.title", description="The display name of the instance"),
"occi.core.title", description="The display name of the instance",
attr_type=attribute.AttributeType.string_type),
})
kind = kind.Kind(helpers.build_scheme('core'), 'entity',

View File

@ -28,11 +28,13 @@ class Link(entity.Entity):
attributes = attribute.AttributeCollection({
"occi.core.source": attribute.MutableAttribute(
"occi.core.source", required=True,
description="The Resource instance the link originates from"),
description="The Resource instance the link originates from",
attr_type=attribute.AttributeType.object_type),
"occi.core.target": attribute.MutableAttribute(
"occi.core.target", required=True,
description=("The unique identifier of an Object this Link "
"instance points to")),
"instance points to"),
attr_type=attribute.AttributeType.object_type),
})
kind = kind.Kind(helpers.build_scheme("core"), 'link', 'link',

View File

@ -34,7 +34,8 @@ class Resource(entity.Entity):
attributes = attribute.AttributeCollection({
"occi.core.summary": attribute.MutableAttribute(
"occi.core.summary", description=("A summarizing description of "
"the resource instance."))
"the resource instance."),
attr_type=attribute.AttributeType.string_type),
})
kind = kind.Kind(helpers.build_scheme('core'), 'resource',

View File

@ -35,25 +35,32 @@ class ComputeResource(resource.Resource):
attributes = attr.AttributeCollection({
"occi.compute.architecture": attr.MutableAttribute(
"occi.compute.architecture",
description="CPU architecture of the instance"),
description="CPU architecture of the instance",
attr_type=attr.AttributeType.string_type),
"occi.compute.cores": attr.MutableAttribute(
"occi.compute.cores",
description="Number of virtual cores assigned to the instance"),
description="Number of virtual cores assigned to the instance",
attr_type=attr.AttributeType.number_type),
"occi.compute.hostname": attr.MutableAttribute(
"occi.compute.hostname",
description="Fully Qualified DNS hostname for the instance"),
description="Fully Qualified DNS hostname for the instance",
attr_type=attr.AttributeType.string_type),
"occi.compute.share": attr.MutableAttribute(
"occi.compute.share",
description="Relative number of CPU shares for the instance"),
description="Relative number of CPU shares for the instance",
attr_type=attr.AttributeType.number_type),
"occi.compute.memory": attr.MutableAttribute(
"occi.compute.memory",
description="Maximum RAM in gigabytes allocated to the instance"),
description="Maximum RAM in gigabytes allocated to the instance",
attr_type=attr.AttributeType.number_type),
"occi.compute.state": attr.InmutableAttribute(
"occi.compute.state", description="Current state of the instance"),
"occi.compute.state", description="Current state of the instance",
attr_type=attr.AttributeType.string_type),
"occi.compute.state.message": attr.InmutableAttribute(
"occi.compute.state.message",
description=("Human-readable explanation of the current instance "
"state")),
"state"),
attr_type=attr.AttributeType.string_type),
})
actions = (start, stop, restart, suspend)

View File

@ -29,15 +29,19 @@ down = action.Action(helpers.build_scheme('infrastructure/network/action'),
class NetworkResource(resource.Resource):
attributes = attr.AttributeCollection({
"occi.network.vlan": attr.MutableAttribute(
"occi.network.vlan", description="802.1q VLAN identifier"),
"occi.network.vlan", description="802.1q VLAN identifier",
attr_type=attr.AttributeType.string_type),
"occi.network.label": attr.MutableAttribute(
"occi.network.label", description="Tag based VLANs"),
"occi.network.label", description="Tag based VLANs",
attr_type=attr.AttributeType.string_type),
"occi.network.state": attr.InmutableAttribute(
"occi.network.state", description="Current state of the instance"),
"occi.network.state", description="Current state of the instance",
attr_type=attr.AttributeType.string_type),
"occi.network.state.message": attr.InmutableAttribute(
"occi.network.state.message",
description=("Human-readable explanation of the current instance "
"state")),
"state"),
attr_type=attr.AttributeType.string_type),
})
actions = (up, down)
@ -90,13 +94,15 @@ ip_network = mixin.Mixin(
attributes=attr.AttributeCollection({
"occi.network.address": attr.MutableAttribute(
"occi.network.address",
description="Internet Protocol (IP) network address"),
description="Internet Protocol (IP) network address",
attr_type=attr.AttributeType.string_type),
"occi.network.gateway": attr.MutableAttribute(
"occi.network.gateway",
description="Internet Protocol (IP) network address"),
description="Internet Protocol (IP) network address",
attr_type=attr.AttributeType.string_type),
"occi.network.allocation": attr.MutableAttribute(
"occi.network.allocation",
description="Address allocation mechanism: dynamic, static",
),
attr_type=attr.AttributeType.string_type),
}),
applies=[NetworkResource.kind])

View File

@ -24,18 +24,22 @@ class NetworkInterface(link.Link):
"occi.networkinterface.interface": attr.InmutableAttribute(
"occi.networkinterface.interface",
description=("Identifier that relates the link to the link's "
"device interface.")),
"device interface."),
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.mac": attr.MutableAttribute(
"occi.networkinterface.mac",
description=("MAC address associated with the link's device "
"interface.")),
"interface."),
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.state": attr.InmutableAttribute(
"occi.networkinterface.state",
description="Current state of the instance"),
description="Current state of the instance",
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.state.message": attr.InmutableAttribute(
"occi.networkinterface.state.message",
description=("Human-readable explanation of the current instance "
"state")),
"state"),
attr_type=attr.AttributeType.string_type),
})
kind = kind.Kind(helpers.build_scheme('infrastructure'),
@ -87,13 +91,15 @@ ip_network_interface = mixin.Mixin(
attributes=attr.AttributeCollection({
"occi.networkinterface.address": attr.MutableAttribute(
"occi.networkinterface.address",
description="Internet Protocol (IP) network address of the link"),
description="Internet Protocol (IP) network address of the link",
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.gateway": attr.MutableAttribute(
"occi.networkinterface.gateway",
description="Internet Protocol (IP) network address"),
description="Internet Protocol (IP) network address",
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.allocation": attr.MutableAttribute(
"occi.networkinterface.allocation",
description="Address allocation mechanism: dynamic, static",
),
attr_type=attr.AttributeType.string_type),
}),
applies=[NetworkInterface.kind])

View File

@ -38,13 +38,16 @@ class StorageResource(resource.Resource):
attributes = attr.AttributeCollection({
"occi.storage.size": attr.MutableAttribute(
"occi.storage.size", required=True,
description="Storage size of the instance in gigabytes"),
description="Storage size of the instance in gigabytes",
attr_type=attr.AttributeType.number_type),
"occi.storage.state": attr.InmutableAttribute(
"occi.storage.state", description="Current state of the instance"),
"occi.storage.state", description="Current state of the instance",
attr_type=attr.AttributeType.string_type),
"occi.storage.state.message": attr.InmutableAttribute(
"occi.storage.state.message",
description=("Human-readable explanation of the current instance "
"state")),
"state"),
attr_type=attr.AttributeType.string_type),
})
actions = (online, offline, backup, snapshot, resize)
kind = kind.Kind(helpers.build_scheme('infrastructure'), 'storage',

View File

@ -23,18 +23,22 @@ class StorageLink(link.Link):
"occi.storagelink.deviceid": attr.MutableAttribute(
"occi.storagelink.deviceid",
description=("Device identifier as defined by the OCCI service "
"provider")),
"provider"),
attr_type=attr.AttributeType.string_type),
"occi.storagelink.mountpoint": attr.MutableAttribute(
"occi.storagelink.mountpoint",
description=("Point to where the storage is mounted "
"in the guest OS")),
"in the guest OS"),
attr_type=attr.AttributeType.string_type),
"occi.storagelink.state": attr.InmutableAttribute(
"occi.storagelink.state",
description="Current state of the instance"),
description="Current state of the instance",
attr_type=attr.AttributeType.string_type),
"occi.storagelink.state.message": attr.InmutableAttribute(
"occi.storagelink.state.message",
description=("Human-readable explanation of the current instance "
"state")),
"state"),
attr_type=attr.AttributeType.string_type),
})
kind = kind.Kind(helpers.build_scheme('infrastructure'), 'storagelink',
'storage link resource', attributes, 'storagelink/',

View File

@ -23,8 +23,9 @@ class OpenStackUserData(mixin.Mixin):
def __init__(self, user_data=None):
attrs = [
attribute.InmutableAttribute("org.openstack.compute.user_data",
user_data, required=True),
attribute.InmutableAttribute(
"org.openstack.compute.user_data", user_data, required=True,
attr_type=attribute.AttributeType.string_type),
]
attrs = attribute.AttributeCollection({a.name: a for a in attrs})
@ -46,10 +47,11 @@ class OpenStackPublicKey(mixin.Mixin):
def __init__(self, name=None, data=None):
attrs = [
attribute.InmutableAttribute(
"org.openstack.credentials.publickey.name", name),
"org.openstack.credentials.publickey.name", name,
attr_type=attribute.AttributeType.string_type),
attribute.InmutableAttribute(
"org.openstack.credentials.publickey.data", data,
required=True),
attr_type=attribute.AttributeType.string_type, required=True),
]
attrs = attribute.AttributeCollection({a.name: a for a in attrs})

View File

@ -32,14 +32,16 @@ class OSNetworkInterface(network_link.NetworkInterface):
attributes = attr.AttributeCollection({
"occi.networkinterface.address": attr.MutableAttribute(
"occi.networkinterface.address",
description="Internet Protocol (IP) network address of the link"),
description="Internet Protocol (IP) network address of the link",
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.gateway": attr.MutableAttribute(
"occi.networkinterface.gateway",
description="Internet Protocol (IP) network address"),
description="Internet Protocol (IP) network address",
attr_type=attr.AttributeType.string_type),
"occi.networkinterface.allocation": attr.MutableAttribute(
"occi.networkinterface.allocation",
description="Address allocation mechanism: dynamic, static",
),
attr_type=attr.AttributeType.string_type),
})
def __init__(self, source, target, mac, address, ip_id=None,
@ -106,17 +108,20 @@ class OSNetworkResource(network.NetworkResource):
attributes = attr.AttributeCollection({
"occi.network.address": attr.MutableAttribute(
"occi.network.address", required=True,
description="Internet Protocol (IP) network address"),
description="Internet Protocol (IP) network address",
attr_type=attr.AttributeType.string_type),
"occi.network.gateway": attr.MutableAttribute(
"occi.network.gateway",
description="Internet Protocol (IP) network address"),
description="Internet Protocol (IP) network address",
attr_type=attr.AttributeType.string_type),
"occi.network.allocation": attr.MutableAttribute(
"occi.network.allocation",
description="Address allocation mechanism: dynamic, static",
),
attr_type=attr.AttributeType.string_type),
"org.openstack.network.ip_version": attr.MutableAttribute(
"org.openstack.network.ip_version",
description="Internet Protocol (IP) version"),
description="Internet Protocol (IP) version",
attr_type=attr.AttributeType.number_type),
})
def __init__(self, title=None, summary=None,

View File

@ -34,13 +34,24 @@ class OpenStackResourceTemplate(templates.OCCIResourceTemplate):
def __init__(self, id, name, cores, memory, disk, ephemeral=0, swap=0):
attrs = [
attribute.InmutableAttribute("occi.compute.cores", cores),
attribute.InmutableAttribute("occi.compute.memory", memory),
attribute.InmutableAttribute("org.openstack.flavor.disk", disk),
attribute.InmutableAttribute("org.openstack.flavor.ephemeral",
ephemeral),
attribute.InmutableAttribute("org.openstack.flavor.swap", swap),
attribute.InmutableAttribute("org.openstack.flavor.name", name)
attribute.InmutableAttribute(
"occi.compute.cores", cores,
attr_type=attribute.AttributeType.number_type),
attribute.InmutableAttribute(
"occi.compute.memory", memory,
attr_type=attribute.AttributeType.number_type),
attribute.InmutableAttribute(
"org.openstack.flavor.disk", disk,
attr_type=attribute.AttributeType.number_type),
attribute.InmutableAttribute(
"org.openstack.flavor.ephemeral", ephemeral,
attr_type=attribute.AttributeType.number_type),
attribute.InmutableAttribute(
"org.openstack.flavor.swap", swap,
attr_type=attribute.AttributeType.number_type),
attribute.InmutableAttribute(
"org.openstack.flavor.name", name,
attr_type=attribute.AttributeType.string_type),
]
attrs = attribute.AttributeCollection({a.name: a for a in attrs})

View File

@ -15,6 +15,7 @@
import json
import uuid
import six
import webob.dec
import webob.exc
@ -39,14 +40,14 @@ subnets = [
"id": uuid.uuid4().hex,
"name": "private-subnet",
"cidr": "33.0.0.1/24",
"ip_version": "IPv4",
"ip_version": 4,
"gateway_ip": "33.0.0.1",
},
{
"id": uuid.uuid4().hex,
"name": "public-subnet",
"cidr": "44.0.0.1/24",
"ip_version": "IPv4",
"ip_version": 4,
"gateway_ip": "44.0.0.1",
},
]
@ -212,8 +213,10 @@ def create_header_occi(params, category, project=None):
att = ""
if params is not None:
for k, v in params.items():
# FIXME(enolfc): this assumes all attributes are strings
att = "%s, %s=\"%s\"" % (att, k, v)
if isinstance(v, six.string_types):
att = "%s, %s=\"%s\"" % (att, k, v)
else:
att = "%s, %s=%s" % (att, k, v)
headers["X_OCCI_Attribute"] = att
if category is not None:
cat = ""
@ -249,7 +252,7 @@ def fake_network_link_occi(os_list_net):
def fake_build_net(name, ip_version=4, address='0.0.0.11', gateway='0.0.0.1',
id=33, state='active'):
id="33", state='active'):
link = {}
link['id'] = id
link['name'] = name
@ -309,7 +312,7 @@ def build_occi_network(network):
'occi.core.id="%s"' % network_id,
'occi.core.title="%s"' % name,
'occi.network.state="%s"' % status,
'org.openstack.network.ip_version="%s"' % subnet_info["ip_version"],
'org.openstack.network.ip_version=%s' % subnet_info["ip_version"],
'occi.network.address="%s"' % subnet_info["cidr"],
'occi.network.gateway="%s"' % subnet_info["gateway_ip"],
]

View File

@ -675,7 +675,7 @@ class TestOpenStackHelper(TestBaseHelper):
req_mock.get_response.return_value = resp
m.return_value = req_mock
name = uuid.uuid4().hex
size = "10"
size = 10
ret = self.helper.volume_create(None, name, size)
self.assertEqual("FOO", ret)
m.assert_called_with(None, name, size)
@ -689,7 +689,7 @@ class TestOpenStackHelper(TestBaseHelper):
req_mock.get_response.return_value = resp
m.return_value = req_mock
name = uuid.uuid4().hex
size = "10"
size = 10
m_exc.return_value = webob.exc.HTTPInternalServerError()
self.assertRaises(webob.exc.HTTPInternalServerError,
self.helper.volume_create,
@ -1081,7 +1081,7 @@ class TestOpenStackHelperReqs(TestBaseHelper):
tenant = fakes.tenants["foo"]
req = self._build_req(tenant["id"])
name = "foo server"
size = "10"
size = 10
body = {
"volume": {

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import uuid
import mock
@ -50,6 +51,7 @@ class TestNetworkControllerNeutron(base.TestController):
@mock.patch.object(helpers_neutron.OpenStackNeutron, "get_network_details")
def test_show(self, m_network):
m_network.return_value = collections.defaultdict(lambda: "foo")
test_networks = fakes.networks[fakes.tenants["foo"]["id"]]
for net in test_networks:
ret = self.controller.show(None, net["id"])
@ -133,7 +135,7 @@ class TestNetworkControllerNeutron(base.TestController):
def test_filter_attributes(self):
parameters = {"occi.core.title": 'name',
"org.openstack.network.ip_version": '4',
"org.openstack.network.ip_version": 4,
"occi.network.address": '00001/24',
"occi.network.gateway": '00001',
}
@ -146,7 +148,6 @@ class TestNetworkControllerNeutron(base.TestController):
]
}
ret = network_api.process_parameters(req, occi_scheme)
self.assertIsNotNone(ret)
self.assertEqual(parameters, ret)
def test_filter_attributes_empty(self):
@ -159,7 +160,7 @@ class TestNetworkControllerNeutron(base.TestController):
]
}
attributes = network_api.process_parameters(req, occi_scheme)
self.assertIsNone(attributes)
self.assertEqual({}, attributes)
def test_run_action_invalid(self):
tenant = fakes.tenants["foo"]
@ -206,6 +207,7 @@ class TestNetworkControllerNova(base.TestController):
@mock.patch.object(helpers.OpenStackHelper, "get_network_details")
def test_show(self, m_network):
m_network.return_value = collections.defaultdict(lambda: "foo")
test_networks = fakes.networks[fakes.tenants["foo"]["id"]]
for net in test_networks:
ret = self.controller.show(None, net["id"])
@ -305,4 +307,4 @@ class TestNetworkControllerNova(base.TestController):
self.controller.run_action,
req,
server_uuid,
None)
None)

View File

@ -87,7 +87,7 @@ class TestStorageController(base.TestController):
tenant = fakes.tenants["foo"]
req = self._build_req(tenant["id"])
name = "foo volume"
size = "10"
size = 10
obj = {
"attributes": {
"occi.core.title": name,

View File

@ -51,9 +51,11 @@ class TestAttributes(base.TestCase):
attr = attribute.MutableAttribute("occi.foo.bar", "bar")
attr.value = "bazonk"
self.assertEqual("bazonk", attr.value)
self.assertEqual(attribute.AttributeType.object_type, attr.attr_type)
def test_inmutable(self):
attr = attribute.InmutableAttribute("occi.foo.bar", "bar")
self.assertEqual(attribute.AttributeType.object_type, attr.attr_type)
def set_val():
attr.value = "bazonk"
@ -61,32 +63,58 @@ class TestAttributes(base.TestCase):
self.assertRaises(AttributeError, set_val)
def test_attribute_type_list(self):
attr = attribute.MutableAttribute(
"occi.foo.bar", "bar", attr_type=attribute.AttributeType.list_type)
attr.value = ['2']
def set_object_val():
attr.value = "object"
def set_hash_val():
attr.value = {}
self.assertRaises(TypeError, set_object_val)
self.assertRaises(TypeError, set_hash_val)
l = attribute.AttributeType.list_type
l.check_type([1])
l.check_type(None)
self.assertRaises(TypeError, l.check_type, 1)
self.assertRaises(TypeError, l.check_type, {"a": "b"})
self.assertRaises(TypeError, l.check_type, "foo")
self.assertRaises(TypeError, l.check_type, True)
def test_attribute_type_hash(self):
attr = attribute.MutableAttribute(
"occi.foo.bar", "bar", attr_type=attribute.AttributeType.hash_type)
attr.value = {'foo': 'bar'}
h = attribute.AttributeType.hash_type
h.check_type({})
h.check_type(None)
self.assertRaises(TypeError, h.check_type, 1)
self.assertRaises(TypeError, h.check_type, [])
self.assertRaises(TypeError, h.check_type, "foo")
self.assertRaises(TypeError, h.check_type, True)
def set_object_val():
attr.value = "object"
def test_attribute_type_string(self):
s = attribute.AttributeType.string_type
s.check_type("hey")
s.check_type(None)
self.assertRaises(TypeError, s.check_type, 1)
self.assertRaises(TypeError, s.check_type, [])
self.assertRaises(TypeError, s.check_type, {})
self.assertRaises(TypeError, s.check_type, True)
def set_list_val():
attr.value = []
def test_attribute_type_number(self):
n = attribute.AttributeType.number_type
n.check_type(1.0)
n.check_type(None)
self.assertRaises(TypeError, n.check_type, [])
self.assertRaises(TypeError, n.check_type, {})
self.assertRaises(TypeError, n.check_type, "foo")
self.assertRaises(TypeError, n.check_type, True)
self.assertRaises(TypeError, set_object_val)
self.assertRaises(TypeError, set_list_val)
def test_attribute_type_bool(self):
b = attribute.AttributeType.boolean_type
b.check_type(True)
b.check_type(None)
self.assertRaises(TypeError, b.check_type, 1)
self.assertRaises(TypeError, b.check_type, [])
self.assertRaises(TypeError, b.check_type, {})
self.assertRaises(TypeError, b.check_type, "foo")
def test_attribute_type_object(self):
o = attribute.AttributeType.object_type
o.check_type(None)
o.check_type(1)
o.check_type([])
o.check_type({})
o.check_type("foo")
o.check_type(True)
class TestAttributeCollection(base.TestCase):
@ -324,7 +352,7 @@ class TestCoreOCCIResource(base.TestCase):
def test_mixins(self):
m = mixin.Mixin(None, None, None)
r = resource.Resource(None, [m], [])
r = resource.Resource(None, [m])
self.assertIsInstance(r.kind, kind.Kind)
self.assertEqual([m], r.mixins)