Merge "Fix v2 requests to non-bleeding edge servers"

This commit is contained in:
Jenkins
2014-09-13 07:36:36 +00:00
committed by Gerrit Code Review
15 changed files with 746 additions and 639 deletions

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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):
"""

View File

@@ -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

View File

@@ -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.

View File

@@ -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"):

View File

@@ -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")

View File

@@ -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',

View File

@@ -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

View File

@@ -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"
},
"enum": {
"positiveIntegerDefault0": {
"allOf": [
{
"$ref": "#/definitions/positiveInteger"
},
{
"default": 0
}
]
},
"stringArray": {
"uniqueItems": True,
"items": {
"type": "string"
},
"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"
"positiveInteger": {
"minimum": 0,
"type": "integer"
}
}
},
"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",
"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"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
}
},
"type": "array"
},
"owner": {
"type": "string",
"description": "Owner of the namespace.",
"maxLength": 255
},
"resource_types": {
"items": {
"type": "object",
"properties": {
"prefix": {
"type": "string"
},
"name": {
"type": "string"
},
"metadata_type": {
"type": "string"
}
}
},
"type": "array"
},
"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": {
"namespace": {
"type": "string",
"description": "The unique namespace text.",
"maxLength": 80
},
"protected": {
"type": "boolean",
"description": "If true, namespace will not be "
"deletable."
},
"schema": {
"type": "string"
}
}
},
"type": "array"
},
"owner": {
"type": "string",
"description": "Owner of the namespace.",
"maxLength": 255
},
"resource_types": {
"items": {
"type": "object",
"properties": {
"prefix": {
"type": "string"
},
"name": {
"type": "string"
},
"metadata_type": {
"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())

View File

@@ -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": {
"required": [
"title",
"type"
],
"type": "object",
"properties": {
"additionalItems": {
"type": "boolean"
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"
},
"enum": {
"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"
},
"title": {
"name": {
"type": "string"
},
"default": {},
"minLength": {
"$ref": "#/definitions/positiveIntegerDefault0"
"self": {
"type": "string"
},
"required": {
"$ref": "#/definitions/stringArray"
},
"maximum": {
"type": "number"
"properties": {
"$ref": "#/definitions/property"
},
"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"
],
"schema": {
"type": "string"
}
},
"updated_at": {
"type": "string",
"description": "Date and time of the last object "
"modification (READ-ONLY)",
"format": "date-time"
},
}
},
"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))

View File

@@ -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"
},
"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)
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"
}
},
"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"
}
}
}
)
}
}
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))

View File

@@ -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"
},
}
}
FakeRTModel = warlock.model_factory(fake_resource_type_schema)
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"
},
}
}
)
}
}
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())

View File

@@ -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