Support custom properties in schemas for v2 API
* Add glance schema API (glance.schema:API) * Disallow custom properties that conflict with base properties * Implements bp api-v2-schemas Change-Id: Ibfa617cb5edf16627627debc30149669213d4b2d
This commit is contained in:
parent
7553b4fcb6
commit
eee5fecdf6
1
etc/schema-access.json
Normal file
1
etc/schema-access.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
14
etc/schema-image.json
Normal file
14
etc/schema-image.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The type code for the image"
|
||||||
|
"required": true,
|
||||||
|
"enum": ["kernel", "ramdisk", "filesystem", "iso9660", "disk"]
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The format code for the image"
|
||||||
|
"required": true,
|
||||||
|
"enum": ["raw", "vhd", "vmdk", "vdi", "qcow2", "qed"]
|
||||||
|
},
|
||||||
|
}
|
@ -19,7 +19,6 @@ import jsonschema
|
|||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
from glance.api.v2 import base
|
from glance.api.v2 import base
|
||||||
from glance.api.v2 import schemas
|
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
import glance.registry.db.api
|
import glance.registry.db.api
|
||||||
@ -77,12 +76,13 @@ class Controller(base.Controller):
|
|||||||
|
|
||||||
|
|
||||||
class RequestDeserializer(wsgi.JSONRequestDeserializer):
|
class RequestDeserializer(wsgi.JSONRequestDeserializer):
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, schema_api):
|
||||||
super(RequestDeserializer, self).__init__()
|
super(RequestDeserializer, self).__init__()
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
self.schema_api = schema_api
|
||||||
|
|
||||||
def _validate(self, request, obj):
|
def _validate(self, request, obj):
|
||||||
schema = schemas.SchemasController(self.conf).access(request)
|
schema = self.schema_api.get_schema('access')
|
||||||
jsonschema.validate(obj, schema)
|
jsonschema.validate(obj, schema)
|
||||||
|
|
||||||
def create(self, request):
|
def create(self, request):
|
||||||
@ -140,9 +140,9 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
|
|||||||
response.status_int = 204
|
response.status_int = 204
|
||||||
|
|
||||||
|
|
||||||
def create_resource(conf):
|
def create_resource(conf, schema_api):
|
||||||
"""Image access resource factory method"""
|
"""Image access resource factory method"""
|
||||||
deserializer = RequestDeserializer(conf)
|
deserializer = RequestDeserializer(conf, schema_api)
|
||||||
serializer = ResponseSerializer()
|
serializer = ResponseSerializer()
|
||||||
controller = Controller(conf)
|
controller = Controller(conf)
|
||||||
return wsgi.Resource(controller, deserializer, serializer)
|
return wsgi.Resource(controller, deserializer, serializer)
|
||||||
|
@ -66,12 +66,13 @@ class ImagesController(base.Controller):
|
|||||||
|
|
||||||
|
|
||||||
class RequestDeserializer(wsgi.JSONRequestDeserializer):
|
class RequestDeserializer(wsgi.JSONRequestDeserializer):
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, schema_api):
|
||||||
super(RequestDeserializer, self).__init__()
|
super(RequestDeserializer, self).__init__()
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
self.schema_api = schema_api
|
||||||
|
|
||||||
def _validate(self, request, obj):
|
def _validate(self, request, obj):
|
||||||
schema = schemas.SchemasController(self.conf).image(request)
|
schema = self.schema_api.get_schema('image')
|
||||||
jsonschema.validate(obj, schema)
|
jsonschema.validate(obj, schema)
|
||||||
|
|
||||||
def create(self, request):
|
def create(self, request):
|
||||||
@ -131,9 +132,9 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
|
|||||||
response.status_int = 204
|
response.status_int = 204
|
||||||
|
|
||||||
|
|
||||||
def create_resource(conf):
|
def create_resource(conf, schema_api):
|
||||||
"""Images resource factory method"""
|
"""Images resource factory method"""
|
||||||
deserializer = RequestDeserializer(conf)
|
deserializer = RequestDeserializer(conf, schema_api)
|
||||||
serializer = ResponseSerializer()
|
serializer = ResponseSerializer()
|
||||||
controller = ImagesController(conf)
|
controller = ImagesController(conf)
|
||||||
return wsgi.Resource(controller, deserializer, serializer)
|
return wsgi.Resource(controller, deserializer, serializer)
|
||||||
|
@ -26,6 +26,7 @@ from glance.api.v2 import images
|
|||||||
from glance.api.v2 import root
|
from glance.api.v2 import root
|
||||||
from glance.api.v2 import schemas
|
from glance.api.v2 import schemas
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
|
import glance.schema
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -38,10 +39,12 @@ class API(wsgi.Router):
|
|||||||
self.conf = conf
|
self.conf = conf
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
|
|
||||||
|
schema_api = glance.schema.API()
|
||||||
|
|
||||||
root_resource = root.create_resource(conf)
|
root_resource = root.create_resource(conf)
|
||||||
mapper.connect('/', controller=root_resource, action='index')
|
mapper.connect('/', controller=root_resource, action='index')
|
||||||
|
|
||||||
schemas_resource = schemas.create_resource(conf)
|
schemas_resource = schemas.create_resource(conf, schema_api)
|
||||||
mapper.connect('/schemas',
|
mapper.connect('/schemas',
|
||||||
controller=schemas_resource,
|
controller=schemas_resource,
|
||||||
action='index',
|
action='index',
|
||||||
@ -55,7 +58,7 @@ class API(wsgi.Router):
|
|||||||
action='access',
|
action='access',
|
||||||
conditions={'method': ['GET']})
|
conditions={'method': ['GET']})
|
||||||
|
|
||||||
images_resource = images.create_resource(conf)
|
images_resource = images.create_resource(conf, schema_api)
|
||||||
mapper.connect('/images',
|
mapper.connect('/images',
|
||||||
controller=images_resource,
|
controller=images_resource,
|
||||||
action='index',
|
action='index',
|
||||||
@ -101,7 +104,7 @@ class API(wsgi.Router):
|
|||||||
action='delete',
|
action='delete',
|
||||||
conditions={'method': ['DELETE']})
|
conditions={'method': ['DELETE']})
|
||||||
|
|
||||||
image_access_resource = image_access.create_resource(conf)
|
image_access_resource = image_access.create_resource(conf, schema_api)
|
||||||
mapper.connect('/images/{image_id}/access',
|
mapper.connect('/images/{image_id}/access',
|
||||||
controller=image_access_resource,
|
controller=image_access_resource,
|
||||||
action='index',
|
action='index',
|
||||||
|
@ -15,45 +15,14 @@
|
|||||||
|
|
||||||
import glance.api.v2.base
|
import glance.api.v2.base
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
|
import glance.schema
|
||||||
|
|
||||||
|
|
||||||
#NOTE(bcwaldon): this is temporary until we generate them on the fly
|
class Controller(glance.api.v2.base.Controller):
|
||||||
IMAGE_SCHEMA = {
|
def __init__(self, conf, schema_api):
|
||||||
"name": "image",
|
super(Controller, self).__init__(conf)
|
||||||
"properties": {
|
self.schema_api = schema_api
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "An identifier for the image",
|
|
||||||
"required": False,
|
|
||||||
"maxLength": 36,
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Descriptive name for the image",
|
|
||||||
"required": True,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ACCESS_SCHEMA = {
|
|
||||||
'name': 'access',
|
|
||||||
'properties': {
|
|
||||||
"tenant_id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The tenant identifier",
|
|
||||||
"required": True,
|
|
||||||
},
|
|
||||||
"can_share": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Ability of tenant to share with others",
|
|
||||||
"required": True,
|
|
||||||
"default": False,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class SchemasController(glance.api.v2.base.Controller):
|
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
links = [
|
links = [
|
||||||
{'rel': 'image', 'href': '/v2/schemas/image'},
|
{'rel': 'image', 'href': '/v2/schemas/image'},
|
||||||
@ -62,12 +31,12 @@ class SchemasController(glance.api.v2.base.Controller):
|
|||||||
return {'links': links}
|
return {'links': links}
|
||||||
|
|
||||||
def image(self, req):
|
def image(self, req):
|
||||||
return IMAGE_SCHEMA
|
return self.schema_api.get_schema('image')
|
||||||
|
|
||||||
def access(self, req):
|
def access(self, req):
|
||||||
return ACCESS_SCHEMA
|
return self.schema_api.get_schema('access')
|
||||||
|
|
||||||
|
|
||||||
def create_resource(conf):
|
def create_resource(conf, schema_api):
|
||||||
controller = SchemasController(conf)
|
controller = Controller(conf, schema_api)
|
||||||
return wsgi.Resource(controller)
|
return wsgi.Resource(controller)
|
||||||
|
@ -236,3 +236,7 @@ class RegionAmbiguity(GlanceException):
|
|||||||
|
|
||||||
class WorkerCreationFailure(GlanceException):
|
class WorkerCreationFailure(GlanceException):
|
||||||
message = _("Server worker creation failed: %(reason)s.")
|
message = _("Server worker creation failed: %(reason)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class SchemaLoadError(GlanceException):
|
||||||
|
message = _("Unable to load schema: %(reason)s")
|
||||||
|
80
glance/schema.py
Normal file
80
glance/schema.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 copy
|
||||||
|
|
||||||
|
from glance.common import exception
|
||||||
|
|
||||||
|
|
||||||
|
_BASE_SCHEMA_PROPERTIES = {
|
||||||
|
'image': {
|
||||||
|
'id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'An identifier for the image',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 36,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
'maxLength': 255,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'access': {
|
||||||
|
'tenant_id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'The tenant identifier',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
'can_share': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'description': 'Ability of tenant to share with others',
|
||||||
|
'required': True,
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class API(object):
|
||||||
|
def __init__(self, base_properties=_BASE_SCHEMA_PROPERTIES):
|
||||||
|
self.base_properties = base_properties
|
||||||
|
self.schema_properties = copy.deepcopy(self.base_properties)
|
||||||
|
|
||||||
|
def get_schema(self, name):
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'properties': self.schema_properties[name],
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_custom_schema_properties(self, schema_name, custom_properties):
|
||||||
|
"""Update the custom properties of a schema with those provided."""
|
||||||
|
schema_properties = copy.deepcopy(self.base_properties[schema_name])
|
||||||
|
|
||||||
|
# Ensure custom props aren't attempting to override base props
|
||||||
|
base_keys = set(schema_properties.keys())
|
||||||
|
custom_keys = set(custom_properties.keys())
|
||||||
|
intersecting_keys = base_keys.intersection(custom_keys)
|
||||||
|
conflicting_keys = [k for k in intersecting_keys
|
||||||
|
if schema_properties[k] != custom_properties[k]]
|
||||||
|
if len(conflicting_keys) > 0:
|
||||||
|
props = ', '.join(conflicting_keys)
|
||||||
|
reason = _("custom properties (%(props)s) conflict "
|
||||||
|
"with base properties")
|
||||||
|
raise exception.SchemaLoadError(reason=reason % {'props': props})
|
||||||
|
|
||||||
|
schema_properties.update(copy.deepcopy(custom_properties))
|
||||||
|
self.schema_properties[schema_name] = schema_properties
|
35
glance/tests/functional/test_schema.py
Normal file
35
glance/tests/functional/test_schema.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 unittest
|
||||||
|
|
||||||
|
import glance.schema
|
||||||
|
|
||||||
|
|
||||||
|
class TestSchemaAPI(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_load_image_schema(self):
|
||||||
|
schema_api = glance.schema.API()
|
||||||
|
output = schema_api.get_schema('image')
|
||||||
|
self.assertEqual('image', output['name'])
|
||||||
|
expected_keys = ['id', 'name']
|
||||||
|
self.assertEqual(expected_keys, output['properties'].keys())
|
||||||
|
|
||||||
|
def test_load_access_schema(self):
|
||||||
|
schema_api = glance.schema.API()
|
||||||
|
output = schema_api.get_schema('access')
|
||||||
|
self.assertEqual('access', output['name'])
|
||||||
|
expected_keys = ['tenant_id', 'can_share']
|
||||||
|
self.assertEqual(expected_keys, output['properties'].keys())
|
162
glance/tests/unit/test_schema.py
Normal file
162
glance/tests/unit/test_schema.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 unittest
|
||||||
|
|
||||||
|
from glance.common import exception
|
||||||
|
import glance.schema
|
||||||
|
|
||||||
|
|
||||||
|
FAKE_BASE_PROPERTIES = {
|
||||||
|
'fake1': {
|
||||||
|
'id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'An identifier for the image',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 36,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestSchemaAPI(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.schema_api = glance.schema.API(FAKE_BASE_PROPERTIES)
|
||||||
|
|
||||||
|
def test_get_schema(self):
|
||||||
|
output = self.schema_api.get_schema('fake1')
|
||||||
|
expected = {
|
||||||
|
'name': 'fake1',
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'An identifier for the image',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 36,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_get_schema_after_load(self):
|
||||||
|
extra_props = {
|
||||||
|
'prop1': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Just some property',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 128,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.schema_api.set_custom_schema_properties('fake1', extra_props)
|
||||||
|
output = self.schema_api.get_schema('fake1')
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'name': 'fake1',
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'An identifier for the image',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 36,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
'prop1': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Just some property',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 128,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_get_schema_load_conflict(self):
|
||||||
|
extra_props = {
|
||||||
|
'name': {
|
||||||
|
'type': 'int',
|
||||||
|
'description': 'Descriptive integer for the image',
|
||||||
|
'required': False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertRaises(exception.SchemaLoadError,
|
||||||
|
self.schema_api.set_custom_schema_properties,
|
||||||
|
'fake1',
|
||||||
|
extra_props)
|
||||||
|
|
||||||
|
# Schema should not have changed due to the conflict
|
||||||
|
output = self.schema_api.get_schema('fake1')
|
||||||
|
expected = {
|
||||||
|
'name': 'fake1',
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'An identifier for the image',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 36,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_get_schema_load_conflict_base_property(self):
|
||||||
|
extra_props = {
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Schema update should not raise an exception, but it should also
|
||||||
|
# remain unchanged
|
||||||
|
self.schema_api.set_custom_schema_properties('fake1', extra_props)
|
||||||
|
output = self.schema_api.get_schema('fake1')
|
||||||
|
expected = {
|
||||||
|
'name': 'fake1',
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'An identifier for the image',
|
||||||
|
'required': False,
|
||||||
|
'maxLength': 36,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Descriptive name for the image',
|
||||||
|
'required': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(output, expected)
|
@ -21,6 +21,7 @@ import webob
|
|||||||
from glance.api.v2 import image_access
|
from glance.api.v2 import image_access
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
|
import glance.schema
|
||||||
import glance.tests.unit.utils as test_utils
|
import glance.tests.unit.utils as test_utils
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +109,8 @@ class TestImageAccessController(unittest.TestCase):
|
|||||||
|
|
||||||
class TestImageAccessDeserializer(unittest.TestCase):
|
class TestImageAccessDeserializer(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.deserializer = image_access.RequestDeserializer({})
|
schema_api = glance.schema.API()
|
||||||
|
self.deserializer = image_access.RequestDeserializer({}, schema_api)
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
fixture = {
|
fixture = {
|
||||||
|
@ -93,7 +93,9 @@ class TestImagesController(unittest.TestCase):
|
|||||||
|
|
||||||
class TestImagesDeserializer(unittest.TestCase):
|
class TestImagesDeserializer(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.deserializer = glance.api.v2.images.RequestDeserializer({})
|
schema_api = glance.schema.API()
|
||||||
|
self.deserializer = glance.api.v2.images.RequestDeserializer(
|
||||||
|
{}, schema_api)
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
request = test_utils.FakeRequest()
|
request = test_utils.FakeRequest()
|
||||||
|
@ -15,15 +15,17 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import glance.api.v2.schemas
|
from glance.api.v2 import schemas
|
||||||
import glance.tests.unit.utils as test_utils
|
import glance.tests.unit.utils as test_utils
|
||||||
|
import glance.schema
|
||||||
|
|
||||||
|
|
||||||
class TestSchemasController(unittest.TestCase):
|
class TestSchemasController(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestSchemasController, self).setUp()
|
super(TestSchemasController, self).setUp()
|
||||||
self.controller = glance.api.v2.schemas.SchemasController({})
|
self.schema_api = glance.schema.API()
|
||||||
|
self.controller = schemas.Controller({}, self.schema_api)
|
||||||
|
|
||||||
def test_index(self):
|
def test_index(self):
|
||||||
req = test_utils.FakeRequest()
|
req = test_utils.FakeRequest()
|
||||||
@ -37,9 +39,9 @@ class TestSchemasController(unittest.TestCase):
|
|||||||
def test_image(self):
|
def test_image(self):
|
||||||
req = test_utils.FakeRequest()
|
req = test_utils.FakeRequest()
|
||||||
output = self.controller.image(req)
|
output = self.controller.image(req)
|
||||||
self.assertEqual(glance.api.v2.schemas.IMAGE_SCHEMA, output)
|
self.assertEqual(self.schema_api.get_schema('image'), output)
|
||||||
|
|
||||||
def test_access(self):
|
def test_access(self):
|
||||||
req = test_utils.FakeRequest()
|
req = test_utils.FakeRequest()
|
||||||
output = self.controller.access(req)
|
output = self.controller.access(req)
|
||||||
self.assertEqual(glance.api.v2.schemas.ACCESS_SCHEMA, output)
|
self.assertEqual(self.schema_api.get_schema('access'), output)
|
||||||
|
Loading…
Reference in New Issue
Block a user