summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLakshmi N Sampath <lakshmi.sampath@hp.com>2014-09-09 14:51:14 -0700
committerStuart McLaren <stuart.mclaren@hp.com>2014-09-12 09:12:49 +0000
commit97b1506bdbccea9fbfcac731cf8b7e0cadebcbab (patch)
tree55347541817b05a37a7435f03c1ccc90be56fb76
parentfde99a0a4df04609d7bb3a59bddc6cfe3508e71a (diff)
downloadpython-glanceclient-97b1506bdbccea9fbfcac731cf8b7e0cadebcbab.tar.gz
Fix v2 requests to non-bleeding edge servers
In the case where v2 requests are sent to a server which is not running head of tree which includes the v2 metadef code some 404 cases need to be handled to enable standard requests to complete. This patch aslo improves fetching schemas -- they are now only fetched as needed. Change-Id: I8c871f11b909337bd7df19b77e606772dbc634b2 Closes-bug: #1367326
-rw-r--r--glanceclient/common/utils.py18
-rw-r--r--glanceclient/v2/client.py48
-rw-r--r--glanceclient/v2/image_members.py14
-rw-r--r--glanceclient/v2/image_tags.py14
-rw-r--r--glanceclient/v2/images.py10
-rw-r--r--glanceclient/v2/metadefs.py39
-rw-r--r--tests/utils.py11
-rw-r--r--tests/v2/test_client.py13
-rw-r--r--tests/v2/test_images.py94
-rw-r--r--tests/v2/test_members.py29
-rw-r--r--tests/v2/test_metadefs_namespaces.py399
-rw-r--r--tests/v2/test_metadefs_objects.py285
-rw-r--r--tests/v2/test_metadefs_properties.py240
-rw-r--r--tests/v2/test_metadefs_resource_types.py112
-rw-r--r--tests/v2/test_tags.py21
15 files changed, 727 insertions, 620 deletions
diff --git a/glanceclient/common/utils.py b/glanceclient/common/utils.py
index 9071065..d1a634e 100644
--- a/glanceclient/common/utils.py
+++ b/glanceclient/common/utils.py
@@ -21,6 +21,7 @@ import json
import os
import re
import sys
+import threading
import uuid
import six
@@ -36,6 +37,8 @@ from glanceclient import exc
from glanceclient.openstack.common import importutils
from glanceclient.openstack.common import strutils
+_memoized_property_lock = threading.Lock()
+
# Decorator for cli-args
def arg(*args, **kwargs):
@@ -367,3 +370,18 @@ def integrity_iter(iter, checksum):
raise IOError(errno.EPIPE,
'Corrupt image download. Checksum was %s expected %s' %
(md5sum, checksum))
+
+
+def memoized_property(fn):
+ attr_name = '_lazy_once_' + fn.__name__
+
+ @property
+ def _memoized_property(self):
+ if hasattr(self, attr_name):
+ return getattr(self, attr_name)
+ else:
+ with _memoized_property_lock:
+ if not hasattr(self, attr_name):
+ setattr(self, attr_name, fn(self))
+ return getattr(self, attr_name)
+ return _memoized_property
diff --git a/glanceclient/v2/client.py b/glanceclient/v2/client.py
index ed80388..4aa2e83 100644
--- a/glanceclient/v2/client.py
+++ b/glanceclient/v2/client.py
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import warlock
from glanceclient.common import http
from glanceclient.common import utils
@@ -38,50 +37,21 @@ class Client(object):
self.http_client = http.HTTPClient(utils.strip_version(endpoint),
*args, **kwargs)
self.schemas = schemas.Controller(self.http_client)
- image_model = self._get_image_model()
- self.images = images.Controller(self.http_client,
- image_model)
- self.image_tags = image_tags.Controller(self.http_client, image_model)
+
+ self.images = images.Controller(self.http_client, self.schemas)
+ self.image_tags = image_tags.Controller(self.http_client,
+ self.schemas)
self.image_members = image_members.Controller(self.http_client,
- self._get_member_model())
+ self.schemas)
- resource_type_model = self._get_metadefs_resource_type_model()
self.metadefs_resource_type = (
- metadefs.ResourceTypeController(self.http_client,
- resource_type_model))
+ metadefs.ResourceTypeController(self.http_client, self.schemas))
- property_model = self._get_metadefs_property_model()
self.metadefs_property = (
- metadefs.PropertyController(self.http_client, property_model))
+ metadefs.PropertyController(self.http_client, self.schemas))
- object_model = self._get_metadefs_object_model()
self.metadefs_object = (
- metadefs.ObjectController(self.http_client, object_model))
+ metadefs.ObjectController(self.http_client, self.schemas))
- namespace_model = self._get_metadefs_namespace_model()
self.metadefs_namespace = (
- metadefs.NamespaceController(self.http_client, namespace_model))
-
- def _get_image_model(self):
- schema = self.schemas.get('image')
- return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
-
- def _get_member_model(self):
- schema = self.schemas.get('member')
- return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
-
- def _get_metadefs_namespace_model(self):
- schema = self.schemas.get('metadefs/namespace')
- return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
-
- def _get_metadefs_resource_type_model(self):
- schema = self.schemas.get('metadefs/resource_type')
- return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
-
- def _get_metadefs_property_model(self):
- schema = self.schemas.get('metadefs/property')
- return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
-
- def _get_metadefs_object_model(self):
- schema = self.schemas.get('metadefs/object')
- return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
+ metadefs.NamespaceController(self.http_client, self.schemas))
diff --git a/glanceclient/v2/image_members.py b/glanceclient/v2/image_members.py
index dcf4ac2..cb6a829 100644
--- a/glanceclient/v2/image_members.py
+++ b/glanceclient/v2/image_members.py
@@ -13,11 +13,21 @@
# License for the specific language governing permissions and limitations
# under the License.
+import warlock
+
+from glanceclient.common import utils
+from glanceclient.v2 import schemas
+
class Controller(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('member')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def list(self, image_id):
url = '/v2/images/%s/members' % image_id
diff --git a/glanceclient/v2/image_tags.py b/glanceclient/v2/image_tags.py
index 5c03648..0f2f1bb 100644
--- a/glanceclient/v2/image_tags.py
+++ b/glanceclient/v2/image_tags.py
@@ -13,11 +13,21 @@
# License for the specific language governing permissions and limitations
# under the License.
+import warlock
+
+from glanceclient.common import utils
+from glanceclient.v2 import schemas
+
class Controller(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('image')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def update(self, image_id, tag_value):
"""
diff --git a/glanceclient/v2/images.py b/glanceclient/v2/images.py
index 1144e6f..6ec9250 100644
--- a/glanceclient/v2/images.py
+++ b/glanceclient/v2/images.py
@@ -21,14 +21,20 @@ import warlock
from glanceclient.common import utils
from glanceclient import exc
from glanceclient.openstack.common import strutils
+from glanceclient.v2 import schemas
DEFAULT_PAGE_SIZE = 20
class Controller(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('image')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def list(self, **kwargs):
"""Retrieve a listing of Image objects
diff --git a/glanceclient/v2/metadefs.py b/glanceclient/v2/metadefs.py
index 0935764..3dc7efc 100644
--- a/glanceclient/v2/metadefs.py
+++ b/glanceclient/v2/metadefs.py
@@ -19,14 +19,20 @@ import warlock
from glanceclient.common import utils
from glanceclient.openstack.common import strutils
+from glanceclient.v2 import schemas
DEFAULT_PAGE_SIZE = 20
class NamespaceController(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('metadefs/namespace')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def create(self, **kwargs):
"""Create a namespace.
@@ -75,7 +81,7 @@ class NamespaceController(object):
url = '/v2/metadefs/namespaces/{0}{1}'.format(namespace, query_params)
resp, body = self.http_client.get(url)
- #NOTE(bcwaldon): remove 'self' for now until we have an elegant
+ # NOTE(bcwaldon): remove 'self' for now until we have an elegant
# way to pass it into the model constructor without conflict
body.pop('self', None)
return self.model(**body)
@@ -141,9 +147,14 @@ class NamespaceController(object):
class ResourceTypeController(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('metadefs/resource_type')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def associate(self, namespace, **kwargs):
"""Associate a resource type with a namespace."""
@@ -184,9 +195,14 @@ class ResourceTypeController(object):
class PropertyController(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('metadefs/property')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def create(self, namespace, **kwargs):
"""Create a property.
@@ -259,9 +275,14 @@ class PropertyController(object):
class ObjectController(object):
- def __init__(self, http_client, model):
+ def __init__(self, http_client, schema_client):
self.http_client = http_client
- self.model = model
+ self.schema_client = schema_client
+
+ @utils.memoized_property
+ def model(self):
+ schema = self.schema_client.get('metadefs/object')
+ return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
def create(self, namespace, **kwargs):
"""Create an object.
diff --git a/tests/utils.py b/tests/utils.py
index 0fa0e2e..8f8c255 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -18,6 +18,8 @@ import json
import six
import testtools
+from glanceclient.v2.schemas import Schema
+
class FakeAPI(object):
def __init__(self, fixtures):
@@ -60,6 +62,15 @@ class FakeAPI(object):
return self._request('HEAD', *args, **kwargs)
+class FakeSchemaAPI(FakeAPI):
+ def __init__(cls, *args):
+ super(FakeSchemaAPI, cls).__init__(*args)
+
+ def get(self, *args, **kwargs):
+ _, raw_schema = self._request('GET', *args, **kwargs)
+ return Schema(raw_schema)
+
+
class RawRequest(object):
def __init__(self, headers, body=None,
version=1.0, status=200, reason="Ok"):
diff --git a/tests/v2/test_client.py b/tests/v2/test_client.py
index 1971bf5..f775f72 100644
--- a/tests/v2/test_client.py
+++ b/tests/v2/test_client.py
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from mox3 import mox
import testtools
from glanceclient.v2 import client
@@ -23,21 +22,9 @@ class ClientTest(testtools.TestCase):
def setUp(self):
super(ClientTest, self).setUp()
- self.mock = mox.Mox()
- self.mock.StubOutWithMock(client.Client, '_get_image_model')
- self.mock.StubOutWithMock(client.Client, '_get_member_model')
- self.mock.StubOutWithMock(client.Client,
- '_get_metadefs_namespace_model')
- self.mock.StubOutWithMock(client.Client,
- '_get_metadefs_resource_type_model')
- self.mock.StubOutWithMock(client.Client,
- '_get_metadefs_property_model')
- self.mock.StubOutWithMock(client.Client,
- '_get_metadefs_object_model')
def tearDown(self):
super(ClientTest, self).tearDown()
- self.mock.UnsetStubs()
def test_endpoint(self):
gc = client.Client("http://example.com")
diff --git a/tests/v2/test_images.py b/tests/v2/test_images.py
index d231a31..8e23a21 100644
--- a/tests/v2/test_images.py
+++ b/tests/v2/test_images.py
@@ -15,10 +15,9 @@
import errno
import json
-import testtools
import six
-import warlock
+import testtools
from glanceclient import exc
from glanceclient.v2 import images
@@ -39,7 +38,31 @@ _PUBLIC_ID = '857806e7-05b6-48e0-9d40-cb0e6fb727b9'
_SHARED_ID = '331ac905-2a38-44c5-a83d-653db8f08313'
_STATUS_REJECTED_ID = 'f3ea56ff-d7e4-4451-998c-1e3d33539c8e'
-fixtures = {
+data_fixtures = {
+ '/v2/schemas/image': {
+ 'GET': (
+ {},
+ {
+ 'name': 'image',
+ 'properties': {
+ 'id': {},
+ 'name': {},
+ 'locations': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'metadata': {'type': 'object'},
+ 'url': {'type': 'string'},
+ },
+ 'required': ['url', 'metadata'],
+ },
+ },
+ },
+ 'additionalProperties': {'type': 'string'}
+ },
+ ),
+ },
'/v2/images?limit=%d' % images.DEFAULT_PAGE_SIZE: {
'GET': (
{},
@@ -325,36 +348,43 @@ fixtures = {
}
-fake_schema = {
- 'name': 'image',
- 'properties': {
- 'id': {},
- 'name': {},
- 'locations': {
- 'type': 'array',
- 'items': {
- 'type': 'object',
+schema_fixtures = {
+ 'image': {
+ 'GET': (
+ {},
+ {
+ 'name': 'image',
'properties': {
- 'metadata': {'type': 'object'},
- 'url': {'type': 'string'},
+ 'id': {},
+ 'name': {},
+ 'locations': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'metadata': {'type': 'object'},
+ 'url': {'type': 'string'},
+ },
+ 'required': ['url', 'metadata'],
+ }
+ }
},
- 'required': ['url', 'metadata'],
- },
- },
- },
- 'additionalProperties': {'type': 'string'}
+ 'additionalProperties': {'type': 'string'}
+ }
+ )
+ }
}
-FakeModel = warlock.model_factory(fake_schema)
class TestController(testtools.TestCase):
def setUp(self):
super(TestController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
- self.controller = images.Controller(self.api, FakeModel)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
+ self.controller = images.Controller(self.api, self.schema_api)
def test_list_images(self):
- #NOTE(bcwaldon): cast to list since the controller returns a generator
+ # NOTE(bcwaldon):cast to list since the controller returns a generator
images = list(self.controller.list())
self.assertEqual('3a4560a1-e585-443e-9b39-553b46ec92d1', images[0].id)
self.assertEqual('image-1', images[0].name)
@@ -362,7 +392,7 @@ class TestController(testtools.TestCase):
self.assertEqual('image-2', images[1].name)
def test_list_images_paginated(self):
- #NOTE(bcwaldon): cast to list since the controller returns a generator
+ # NOTE(bcwaldon):cast to list since the controller returns a generator
images = list(self.controller.list(page_size=1))
self.assertEqual('3a4560a1-e585-443e-9b39-553b46ec92d1', images[0].id)
self.assertEqual('image-1', images[0].name)
@@ -571,7 +601,7 @@ class TestController(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(image_id, image.id)
- #NOTE(bcwaldon): due to limitations of our fake api framework, the name
+ # NOTE(bcwaldon):due to limitations of our fake api framework, the name
# will not actually change - yet in real life it will...
self.assertEqual('image-1', image.name)
@@ -590,7 +620,7 @@ class TestController(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(image_id, image.id)
- #NOTE(bcwaldon): due to limitations of our fake api framework, the name
+ # NOTE(bcwaldon):due to limitations of our fake api framework, the name
# will not actually change - yet in real life it will...
self.assertEqual('image-1', image.name)
@@ -609,7 +639,7 @@ class TestController(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(image_id, image.id)
- #NOTE(bcwaldon): due to limitations of our fake api framework, the name
+ # NOTE(bcwaldon):due to limitations of our fake api framework, the name
# will not actually change - yet in real life it will...
self.assertEqual('image-3', image.name)
@@ -622,8 +652,8 @@ class TestController(testtools.TestCase):
expect_hdrs = {
'Content-Type': 'application/openstack-images-v2.1-json-patch',
}
- expect_body = '[{"path": "/barney", "value": "miller", ' \
- '"op": "replace"}]'
+ expect_body = ('[{"path": "/barney", "value": "miller", '
+ '"op": "replace"}]')
expect = [
('GET', '/v2/images/%s' % image_id, {}, None),
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
@@ -631,7 +661,7 @@ class TestController(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(image_id, image.id)
- #NOTE(bcwaldon): due to limitations of our fake api framework, the name
+ # NOTE(bcwaldon):due to limitations of our fake api framework, the name
# will not actually change - yet in real life it will...
self.assertEqual('image-3', image.name)
@@ -652,7 +682,7 @@ class TestController(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(image_id, image.id)
- #NOTE(bcwaldon): due to limitations of our fake api framework, the name
+ # NOTE(bcwaldon):due to limitations of our fake api framework, the name
# will not actually change - yet in real life it will...
self.assertEqual('image-3', image.name)
@@ -741,7 +771,7 @@ class TestController(testtools.TestCase):
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
new_loc = {'url': 'http://foo.com/', 'metadata': {'spam': 'ham'}}
fixture_idx = '/v2/images/%s' % (image_id)
- orig_locations = fixtures[fixture_idx]['GET'][1]['locations']
+ orig_locations = data_fixtures[fixture_idx]['GET'][1]['locations']
loc_map = dict([(l['url'], l) for l in orig_locations])
loc_map[new_loc['url']] = new_loc
mod_patch = [{'path': '/locations', 'op': 'replace',
diff --git a/tests/v2/test_members.py b/tests/v2/test_members.py
index 0b57b0c..744f3a6 100644
--- a/tests/v2/test_members.py
+++ b/tests/v2/test_members.py
@@ -15,8 +15,6 @@
import testtools
-import warlock
-
from glanceclient.v2 import image_members
from tests import utils
@@ -25,7 +23,7 @@ IMAGE = '3a4560a1-e585-443e-9b39-553b46ec92d1'
MEMBER = '11223344-5566-7788-9911-223344556677'
-fixtures = {
+data_fixtures = {
'/v2/images/{image}/members'.format(image=IMAGE): {
'GET': (
{},
@@ -58,20 +56,31 @@ fixtures = {
'status': 'accepted'
}
),
- },
+ }
}
-
-fake_schema = {'name': 'member', 'properties': {'image_id': {},
- 'member_id': {}}}
-FakeModel = warlock.model_factory(fake_schema)
+schema_fixtures = {
+ 'member': {
+ 'GET': (
+ {},
+ {
+ 'name': 'member',
+ 'properties': {
+ 'image_id': {},
+ 'member_id': {}
+ }
+ },
+ )
+ }
+}
class TestController(testtools.TestCase):
def setUp(self):
super(TestController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
- self.controller = image_members.Controller(self.api, FakeModel)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
+ self.controller = image_members.Controller(self.api, self.schema_api)
def test_list_image_members(self):
image_id = IMAGE
diff --git a/tests/v2/test_metadefs_namespaces.py b/tests/v2/test_metadefs_namespaces.py
index ebb78de..878658f 100644
--- a/tests/v2/test_metadefs_namespaces.py
+++ b/tests/v2/test_metadefs_namespaces.py
@@ -15,8 +15,6 @@
import testtools
-import warlock
-
from glanceclient.v2 import metadefs
from tests import utils
@@ -59,7 +57,7 @@ def _get_namespace_fixture(ns_name, rt_name=RESOURCE_TYPE1, **kwargs):
return ns
-fixtures = {
+data_fixtures = {
"/v2/metadefs/namespaces?limit=20": {
"GET": (
{},
@@ -271,230 +269,243 @@ fixtures = {
"updated_at": "2014-08-14T09:07:06Z",
}
),
- },
+ }
}
-fake_namespace_schema = {
- "additionalProperties": False,
- "definitions": {
- "property": {
- "additionalProperties": {
- "required": [
- "title",
- "type"
- ],
- "type": "object",
- "properties": {
- "additionalItems": {
- "type": "boolean"
+schema_fixtures = {
+ "metadefs/namespace":
+ {
+ "GET": (
+ {},
+ {
+ "additionalProperties": False,
+ "definitions": {
+ "property": {
+ "additionalProperties": {
+ "required": [
+ "title",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "additionalItems": {
+ "type": "boolean"
+ },
+ "enum": {
+ "type": "array"
+ },
+ "description": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "default": {},
+ "minLength": {
+ "$ref": "#/definitions/"
+ "positiveIntegerDefault0"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "minItems": {
+ "$ref": "#/definitions/"
+ "positiveIntegerDefault0"
+ },
+ "readonly": {
+ "type": "boolean"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "maxItems": {
+ "$ref": "#/definitions/"
+ "positiveInteger"
+ },
+ "maxLength": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "uniqueItems": {
+ "default": False,
+ "type": "boolean"
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "items": {
+ "type": "object",
+ "properties": {
+ "enum": {
+ "type": "array"
+ },
+ "type": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string",
+ "null"
+ ],
+ "type": "string"
+ }
+ }
+ },
+ "type": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string",
+ "null"
+ ],
+ "type": "string"
+ }
+ }
+ },
+ "type": "object"
+ },
+ "positiveIntegerDefault0": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ {
+ "default": 0
+ }
+ ]
},
- "enum": {
+ "stringArray": {
+ "uniqueItems": True,
+ "items": {
+ "type": "string"
+ },
"type": "array"
},
+ "positiveInteger": {
+ "minimum": 0,
+ "type": "integer"
+ }
+ },
+ "required": [
+ "namespace"
+ ],
+ "name": "namespace",
+ "properties": {
"description": {
- "type": "string"
- },
- "title": {
- "type": "string"
- },
- "default": {},
- "minLength": {
- "$ref": "#/definitions/positiveIntegerDefault0"
- },
- "required": {
- "$ref": "#/definitions/stringArray"
- },
- "maximum": {
- "type": "number"
- },
- "minItems": {
- "$ref": "#/definitions/positiveIntegerDefault0"
- },
- "readonly": {
- "type": "boolean"
+ "type": "string",
+ "description": "Provides a user friendly description "
+ "of the namespace.",
+ "maxLength": 500
},
- "minimum": {
- "type": "number"
+ "updated_at": {
+ "type": "string",
+ "description": "Date and time of the last namespace "
+ "modification (READ-ONLY)",
+ "format": "date-time"
},
- "maxItems": {
- "$ref": "#/definitions/positiveInteger"
+ "visibility": {
+ "enum": [
+ "public",
+ "private"
+ ],
+ "type": "string",
+ "description": "Scope of namespace accessibility."
},
- "maxLength": {
- "$ref": "#/definitions/positiveInteger"
+ "self": {
+ "type": "string"
},
- "uniqueItems": {
- "default": False,
- "type": "boolean"
+ "objects": {
+ "items": {
+ "type": "object",
+ "properties": {
+ "properties": {
+ "$ref": "#/definitions/property"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ }
+ }
+ },
+ "type": "array"
},
- "pattern": {
+ "owner": {
"type": "string",
- "format": "regex"
+ "description": "Owner of the namespace.",
+ "maxLength": 255
},
- "items": {
- "type": "object",
- "properties": {
- "enum": {
- "type": "array"
- },
- "type": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "number",
- "object",
- "string",
- "null"
- ],
- "type": "string"
+ "resource_types": {
+ "items": {
+ "type": "object",
+ "properties": {
+ "prefix": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "metadata_type": {
+ "type": "string"
+ }
}
- }
+ },
+ "type": "array"
},
- "type": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "number",
- "object",
- "string",
- "null"
- ],
- "type": "string"
- }
- }
- },
- "type": "object"
- },
- "positiveIntegerDefault0": {
- "allOf": [
- {
- "$ref": "#/definitions/positiveInteger"
- },
- {
- "default": 0
- }
- ]
- },
- "stringArray": {
- "uniqueItems": True,
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "positiveInteger": {
- "minimum": 0,
- "type": "integer"
- }
- },
- "required": [
- "namespace"
- ],
- "name": "namespace",
- "properties": {
- "description": {
- "type": "string",
- "description": "Provides a user friendly description of the "
- "namespace.",
- "maxLength": 500
- },
- "updated_at": {
- "type": "string",
- "description": "Date and time of the last namespace modification "
- "(READ-ONLY)",
- "format": "date-time"
- },
- "visibility": {
- "enum": [
- "public",
- "private"
- ],
- "type": "string",
- "description": "Scope of namespace accessibility."
- },
- "self": {
- "type": "string"
- },
- "objects": {
- "items": {
- "type": "object",
- "properties": {
"properties": {
"$ref": "#/definitions/property"
},
- "required": {
- "$ref": "#/definitions/stringArray"
+ "display_name": {
+ "type": "string",
+ "description": "The user friendly name for the "
+ "namespace. Used by UI if available.",
+ "maxLength": 80
},
- "name": {
- "type": "string"
+ "created_at": {
+ "type": "string",
+ "description": "Date and time of namespace creation "
+ "(READ-ONLY)",
+ "format": "date-time"
},
- "description": {
- "type": "string"
- }
- }
- },
- "type": "array"
- },
- "owner": {
- "type": "string",
- "description": "Owner of the namespace.",
- "maxLength": 255
- },
- "resource_types": {
- "items": {
- "type": "object",
- "properties": {
- "prefix": {
- "type": "string"
+ "namespace": {
+ "type": "string",
+ "description": "The unique namespace text.",
+ "maxLength": 80
},
- "name": {
- "type": "string"
+ "protected": {
+ "type": "boolean",
+ "description": "If true, namespace will not be "
+ "deletable."
},
- "metadata_type": {
+ "schema": {
"type": "string"
}
}
- },
- "type": "array"
- },
- "properties": {
- "$ref": "#/definitions/property"
- },
- "display_name": {
- "type": "string",
- "description": "The user friendly name for the namespace. Used by"
- " UI if available.",
- "maxLength": 80
- },
- "created_at": {
- "type": "string",
- "description": "Date and time of namespace creation (READ-ONLY)",
- "format": "date-time"
- },
- "namespace": {
- "type": "string",
- "description": "The unique namespace text.",
- "maxLength": 80
- },
- "protected": {
- "type": "boolean",
- "description": "If true, namespace will not be deletable."
- },
- "schema": {
- "type": "string"
- }
+ }
+ ),
}
}
-FakeNamespaceModel = warlock.model_factory(fake_namespace_schema)
class TestNamespaceController(testtools.TestCase):
def setUp(self):
super(TestNamespaceController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = metadefs.NamespaceController(self.api,
- FakeNamespaceModel)
+ self.schema_api)
def test_list_namespaces(self):
namespaces = list(self.controller.list())
diff --git a/tests/v2/test_metadefs_objects.py b/tests/v2/test_metadefs_objects.py
index 7c17e1e..ca2f8c8 100644
--- a/tests/v2/test_metadefs_objects.py
+++ b/tests/v2/test_metadefs_objects.py
@@ -16,8 +16,6 @@
import six
import testtools
-import warlock
-
from glanceclient.v2 import metadefs
from tests import utils
@@ -50,8 +48,7 @@ def _get_object_fixture(ns_name, obj_name, **kwargs):
"description": "DESCRIPTION",
"maximum": 1000000,
"title": "Quota: CPU Period"
- },
- },
+ }},
"schema": "/v2/schemas/metadefs/object",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
@@ -61,7 +58,7 @@ def _get_object_fixture(ns_name, obj_name, **kwargs):
return obj
-fixtures = {
+data_fixtures = {
"/v2/metadefs/namespaces/%s/objects" % NAMESPACE1: {
"GET": (
{},
@@ -98,166 +95,174 @@ fixtures = {
}
}
-
-fake_object_schema = {
- "additionalProperties": False,
- "definitions": {
- "property": {
- "additionalProperties": {
+schema_fixtures = {
+ "metadefs/object": {
+ "GET": (
+ {},
+ {
+ "additionalProperties": False,
+ "definitions": {
+ "property": {
+ "additionalProperties": {
+ "required": [
+ "title",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "additionalItems": {
+ "type": "boolean"
+ },
+ "enum": {
+ "type": "array"
+ },
+ "description": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "default": {},
+ "minLength": {
+ "$ref": "#/definitions/positiveInteger"
+ "Default0"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "minItems": {
+ "$ref": "#/definitions/positiveInteger"
+ "Default0"
+ },
+ "readonly": {
+ "type": "boolean"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "maxItems": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "maxLength": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "uniqueItems": {
+ "default": False,
+ "type": "boolean"
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "items": {
+ "type": "object",
+ "properties": {
+ "enum": {
+ "type": "array"
+ },
+ "type": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string",
+ "null"
+ ],
+ "type": "string"
+ }
+ }
+ },
+ "type": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string",
+ "null"
+ ],
+ "type": "string"
+ }
+ }
+ },
+ "type": "object"
+ },
+ "positiveIntegerDefault0": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ {
+ "default": 0
+ }
+ ]
+ },
+ "stringArray": {
+ "uniqueItems": True,
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "positiveInteger": {
+ "minimum": 0,
+ "type": "integer"
+ }
+ },
"required": [
- "title",
- "type"
+ "name"
],
- "type": "object",
+ "name": "object",
"properties": {
- "additionalItems": {
- "type": "boolean"
- },
- "enum": {
- "type": "array"
+ "created_at": {
+ "type": "string",
+ "description": "Date and time of object creation "
+ "(READ-ONLY)",
+ "format": "date-time"
},
"description": {
"type": "string"
},
- "title": {
+ "name": {
"type": "string"
},
- "default": {},
- "minLength": {
- "$ref": "#/definitions/positiveIntegerDefault0"
+ "self": {
+ "type": "string"
},
"required": {
"$ref": "#/definitions/stringArray"
},
- "maximum": {
- "type": "number"
- },
- "minItems": {
- "$ref": "#/definitions/positiveIntegerDefault0"
+ "properties": {
+ "$ref": "#/definitions/property"
},
- "readonly": {
- "type": "boolean"
- },
- "minimum": {
- "type": "number"
- },
- "maxItems": {
- "$ref": "#/definitions/positiveInteger"
- },
- "maxLength": {
- "$ref": "#/definitions/positiveInteger"
- },
- "uniqueItems": {
- "default": False,
- "type": "boolean"
+ "schema": {
+ "type": "string"
},
- "pattern": {
+ "updated_at": {
"type": "string",
- "format": "regex"
+ "description": "Date and time of the last object "
+ "modification (READ-ONLY)",
+ "format": "date-time"
},
- "items": {
- "type": "object",
- "properties": {
- "enum": {
- "type": "array"
- },
- "type": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "number",
- "object",
- "string",
- "null"
- ],
- "type": "string"
- }
- }
- },
- "type": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "number",
- "object",
- "string",
- "null"
- ],
- "type": "string"
- }
}
- },
- "type": "object"
- },
- "positiveIntegerDefault0": {
- "allOf": [
- {
- "$ref": "#/definitions/positiveInteger"
- },
- {
- "default": 0
- }
- ]
- },
- "stringArray": {
- "uniqueItems": True,
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "positiveInteger": {
- "minimum": 0,
- "type": "integer"
- }
- },
- "required": [
- "name"
- ],
- "name": "object",
- "properties": {
- "created_at": {
- "type": "string",
- "description": "Date and time of object creation (READ-ONLY)",
- "format": "date-time"
- },
- "description": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "self": {
- "type": "string"
- },
- "required": {
- "$ref": "#/definitions/stringArray"
- },
- "properties": {
- "$ref": "#/definitions/property"
- },
- "schema": {
- "type": "string"
- },
- "updated_at": {
- "type": "string",
- "description": "Date and time of the last object modification "
- "(READ-ONLY)",
- "format": "date-time"
- },
+ }
+ )
}
}
-FakeObjectModel = warlock.model_factory(fake_object_schema)
class TestObjectController(testtools.TestCase):
def setUp(self):
super(TestObjectController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
- self.controller = metadefs.ObjectController(self.api,
- FakeObjectModel)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
+ self.controller = metadefs.ObjectController(self.api, self.schema_api)
def test_list_object(self):
objects = list(self.controller.list(NAMESPACE1))
diff --git a/tests/v2/test_metadefs_properties.py b/tests/v2/test_metadefs_properties.py
index 23cc0fb..7c50f13 100644
--- a/tests/v2/test_metadefs_properties.py
+++ b/tests/v2/test_metadefs_properties.py
@@ -15,8 +15,6 @@
import testtools
-import warlock
-
from glanceclient.v2 import metadefs
from tests import utils
@@ -25,7 +23,7 @@ PROPERTY1 = 'Property1'
PROPERTY2 = 'Property2'
PROPERTYNEW = 'PropertyNew'
-fixtures = {
+data_fixtures = {
"/v2/metadefs/namespaces/%s/properties" % NAMESPACE1: {
"GET": (
{},
@@ -108,134 +106,140 @@ fixtures = {
{},
{}
)
- },
+ }
}
-
-fake_property_schema = {
- "additionalProperties": False,
- "definitions": {
- "positiveIntegerDefault0": {
- "allOf": [
- {
- "$ref": "#/definitions/positiveInteger"
- },
- {
- "default": 0
- }
- ]
- },
- "stringArray": {
- "minItems": 1,
- "items": {
- "type": "string"
- },
- "uniqueItems": True,
- "type": "array"
- },
- "positiveInteger": {
- "minimum": 0,
- "type": "integer"
- }
- },
- "required": [
- "name",
- "title",
- "type"
- ],
- "name": "property",
- "properties": {
- "description": {
- "type": "string"
- },
- "minLength": {
- "$ref": "#/definitions/positiveIntegerDefault0"
- },
- "enum": {
- "type": "array"
- },
- "minimum": {
- "type": "number"
- },
- "maxItems": {
- "$ref": "#/definitions/positiveInteger"
- },
- "maxLength": {
- "$ref": "#/definitions/positiveInteger"
- },
- "uniqueItems": {
- "default": False,
- "type": "boolean"
- },
- "additionalItems": {
- "type": "boolean"
- },
- "name": {
- "type": "string"
- },
- "title": {
- "type": "string"
- },
- "default": {},
- "pattern": {
- "type": "string",
- "format": "regex"
- },
- "required": {
- "$ref": "#/definitions/stringArray"
- },
- "maximum": {
- "type": "number"
- },
- "minItems": {
- "$ref": "#/definitions/positiveIntegerDefault0"
- },
- "readonly": {
- "type": "boolean"
- },
- "items": {
- "type": "object",
- "properties": {
- "enum": {
- "type": "array"
+schema_fixtures = {
+ "metadefs/property": {
+ "GET": (
+ {},
+ {
+ "additionalProperties": False,
+ "definitions": {
+ "positiveIntegerDefault0": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ {
+ "default": 0
+ }
+ ]
+ },
+ "stringArray": {
+ "minItems": 1,
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": True,
+ "type": "array"
+ },
+ "positiveInteger": {
+ "minimum": 0,
+ "type": "integer"
+ }
},
- "type": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "number",
- "object",
- "string",
- "null"
- ],
- "type": "string"
+ "required": [
+ "name",
+ "title",
+ "type"
+ ],
+ "name": "property",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "minLength": {
+ "$ref": "#/definitions/positiveIntegerDefault0"
+ },
+ "enum": {
+ "type": "array"
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "maxItems": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "maxLength": {
+ "$ref": "#/definitions/positiveInteger"
+ },
+ "uniqueItems": {
+ "default": False,
+ "type": "boolean"
+ },
+ "additionalItems": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "default": {},
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "required": {
+ "$ref": "#/definitions/stringArray"
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "minItems": {
+ "$ref": "#/definitions/positiveIntegerDefault0"
+ },
+ "readonly": {
+ "type": "boolean"
+ },
+ "items": {
+ "type": "object",
+ "properties": {
+ "enum": {
+ "type": "array"
+ },
+ "type": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string",
+ "null"
+ ],
+ "type": "string"
+ }
+ }
+ },
+ "type": {
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string",
+ "null"
+ ],
+ "type": "string"
+ }
}
}
- },
- "type": {
- "enum": [
- "array",
- "boolean",
- "integer",
- "number",
- "object",
- "string",
- "null"
- ],
- "type": "string"
- }
+ )
}
}
-FakePropertyModel = warlock.model_factory(fake_property_schema)
class TestPropertyController(testtools.TestCase):
def setUp(self):
super(TestPropertyController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = metadefs.PropertyController(self.api,
- FakePropertyModel)
+ self.schema_api)
def test_list_property(self):
properties = list(self.controller.list(NAMESPACE1))
diff --git a/tests/v2/test_metadefs_resource_types.py b/tests/v2/test_metadefs_resource_types.py
index 386464d..bcb4993 100644
--- a/tests/v2/test_metadefs_resource_types.py
+++ b/tests/v2/test_metadefs_resource_types.py
@@ -15,8 +15,6 @@
import testtools
-import warlock
-
from glanceclient.v2 import metadefs
from tests import utils
@@ -28,7 +26,7 @@ RESOURCE_TYPE4 = 'ResourceType4'
RESOURCE_TYPENEW = 'ResourceTypeNew'
-fixtures = {
+data_fixtures = {
"/v2/metadefs/namespaces/%s/resource_types" % NAMESPACE1: {
"GET": (
{},
@@ -84,64 +82,76 @@ fixtures = {
]
}
)
- },
+ }
}
-
-fake_resource_type_schema = {
- "name": "resource_type",
- "properties": {
- "prefix": {
- "type": "string",
- "description": "Specifies the prefix to use for the given "
- "resource type. Any properties in the namespace "
- "should be prefixed with this prefix when being "
- "applied to the specified resource type. Must "
- "include prefix separator (e.g. a colon :).",
- "maxLength": 80
- },
- "properties_target": {
- "type": "string",
- "description": "Some resource types allow more than one "
- "key / value pair per instance. For example, "
- "Cinder allows user and image metadata on volumes. "
- "Only the image properties metadata is evaluated "
- "by Nova (scheduling or drivers). This property "
- "allows a namespace target to remove the "
- "ambiguity.",
- "maxLength": 80
- },
- "name": {
- "type": "string",
- "description": "Resource type names should be aligned with Heat "
- "resource types whenever possible: http://docs."
- "openstack.org/developer/heat/template_guide/"
- "openstack.html",
- "maxLength": 80
- },
- "created_at": {
- "type": "string",
- "description": "Date and time of resource type association"
- " (READ-ONLY)",
- "format": "date-time"
- },
- "updated_at": {
- "type": "string",
- "description": "Date and time of the last resource type "
- "association modification (READ-ONLY)",
- "format": "date-time"
- },
+schema_fixtures = {
+ "metadefs/resource_type": {
+ "GET": (
+ {},
+ {
+ "name": "resource_type",
+ "properties": {
+ "prefix": {
+ "type": "string",
+ "description": "Specifies the prefix to use for the "
+ "given resource type. Any properties "
+ "in the namespace should be prefixed "
+ "with this prefix when being applied "
+ "to the specified resource type. Must "
+ "include prefix separator (e.g. a "
+ "colon :).",
+ "maxLength": 80
+ },
+ "properties_target": {
+ "type": "string",
+ "description": "Some resource types allow more than "
+ "one key / value pair per instance. "
+ "For example, Cinder allows user and "
+ "image metadata on volumes. Only the "
+ "image properties metadata is "
+ "evaluated by Nova (scheduling or "
+ "drivers). This property allows a "
+ "namespace target to remove the "
+ "ambiguity.",
+ "maxLength": 80
+ },
+ "name": {
+ "type": "string",
+ "description": "Resource type names should be "
+ "aligned with Heat resource types "
+ "whenever possible: http://docs."
+ "openstack.org/developer/heat/"
+ "template_guide/openstack.html",
+ "maxLength": 80
+ },
+ "created_at": {
+ "type": "string",
+ "description": "Date and time of resource type "
+ "association (READ-ONLY)",
+ "format": "date-time"
+ },
+ "updated_at": {
+ "type": "string",
+ "description": "Date and time of the last resource "
+ "type association modification "
+ "(READ-ONLY)",
+ "format": "date-time"
+ },
+ }
+ }
+ )
}
}
-FakeRTModel = warlock.model_factory(fake_resource_type_schema)
class TestResoureTypeController(testtools.TestCase):
def setUp(self):
super(TestResoureTypeController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = metadefs.ResourceTypeController(self.api,
- FakeRTModel)
+ self.schema_api)
def test_list_resource_types(self):
resource_types = list(self.controller.list())
diff --git a/tests/v2/test_tags.py b/tests/v2/test_tags.py
index 83fc368..88ec2fe 100644
--- a/tests/v2/test_tags.py
+++ b/tests/v2/test_tags.py
@@ -14,7 +14,6 @@
# under the License.
import testtools
-import warlock
from glanceclient.v2 import image_tags
from tests import utils
@@ -24,7 +23,7 @@ IMAGE = '3a4560a1-e585-443e-9b39-553b46ec92d1'
TAG = 'tag01'
-fixtures = {
+data_fixtures = {
'/v2/images/{image}/tags/{tag_value}'.format(image=IMAGE, tag_value=TAG): {
'DELETE': (
{},
@@ -37,19 +36,25 @@ fixtures = {
'tag_value': TAG
}
),
- },
+ }
}
-
-fake_schema = {'name': 'image', 'properties': {'image_id': {}, 'tags': {}}}
-FakeModel = warlock.model_factory(fake_schema)
+schema_fixtures = {
+ 'tag': {
+ 'GET': (
+ {},
+ {'name': 'image', 'properties': {'image_id': {}, 'tags': {}}}
+ )
+ }
+}
class TestController(testtools.TestCase):
def setUp(self):
super(TestController, self).setUp()
- self.api = utils.FakeAPI(fixtures)
- self.controller = image_tags.Controller(self.api, FakeModel)
+ self.api = utils.FakeAPI(data_fixtures)
+ self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
+ self.controller = image_tags.Controller(self.api, self.schema_api)
def test_update_image_tag(self):
image_id = IMAGE