Move unit tests to standard directory

This patch moves the glanceclient unit tests to the standard directory
(xxxclient/tests/unit) in preparation for adding functional gate tests
'check-glanceclient-dsvm-functional' in the same vein as existing client
tests for other projects, eg:

* check-novaclient-dsvm-functional
* check-keystoneclient-dsvm-functional
* check-neutronclient-dsvm-functional

Change-Id: I29d4b9e3a428c851575ee9afde40d6df583456c4
This commit is contained in:
Stuart McLaren
2015-04-17 14:02:33 +00:00
parent 825c4a5df2
commit f2a8a520e7
33 changed files with 16 additions and 16 deletions
File diff suppressed because it is too large Load Diff
+120
View File
@@ -0,0 +1,120 @@
# Copyright 2013 OpenStack Foundation
# 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 testtools
from glanceclient.tests import utils
from glanceclient.v2 import image_members
IMAGE = '3a4560a1-e585-443e-9b39-553b46ec92d1'
MEMBER = '11223344-5566-7788-9911-223344556677'
data_fixtures = {
'/v2/images/{image}/members'.format(image=IMAGE): {
'GET': (
{},
{'members': [
{
'image_id': IMAGE,
'member_id': MEMBER,
},
]},
),
'POST': (
{},
{
'image_id': IMAGE,
'member_id': MEMBER,
'status': 'pending'
}
)
},
'/v2/images/{image}/members/{mem}'.format(image=IMAGE, mem=MEMBER): {
'DELETE': (
{},
None,
),
'PUT': (
{},
{
'image_id': IMAGE,
'member_id': MEMBER,
'status': 'accepted'
}
),
}
}
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(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
#NOTE(iccha): cast to list since the controller returns a generator
image_members = list(self.controller.list(image_id))
self.assertEqual(IMAGE, image_members[0].image_id)
self.assertEqual(MEMBER, image_members[0].member_id)
def test_delete_image_member(self):
image_id = IMAGE
member_id = MEMBER
self.controller.delete(image_id, member_id)
expect = [
('DELETE',
'/v2/images/{image}/members/{mem}'.format(image=IMAGE,
mem=MEMBER),
{},
None)]
self.assertEqual(expect, self.api.calls)
def test_update_image_members(self):
image_id = IMAGE
member_id = MEMBER
status = 'accepted'
image_member = self.controller.update(image_id, member_id, status)
self.assertEqual(IMAGE, image_member.image_id)
self.assertEqual(MEMBER, image_member.member_id)
self.assertEqual(status, image_member.status)
def test_create_image_members(self):
image_id = IMAGE
member_id = MEMBER
status = 'pending'
image_member = self.controller.create(image_id, member_id)
self.assertEqual(IMAGE, image_member.image_id)
self.assertEqual(MEMBER, image_member.member_id)
self.assertEqual(status, image_member.status)
@@ -0,0 +1,674 @@
# Copyright 2012 OpenStack Foundation.
# 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 testtools
from glanceclient.tests import utils
from glanceclient.v2 import metadefs
NAMESPACE1 = 'Namespace1'
NAMESPACE2 = 'Namespace2'
NAMESPACE3 = 'Namespace3'
NAMESPACE4 = 'Namespace4'
NAMESPACE5 = 'Namespace5'
NAMESPACE6 = 'Namespace6'
NAMESPACE7 = 'Namespace7'
NAMESPACE8 = 'Namespace8'
NAMESPACENEW = 'NamespaceNew'
RESOURCE_TYPE1 = 'ResourceType1'
RESOURCE_TYPE2 = 'ResourceType2'
OBJECT1 = 'Object1'
PROPERTY1 = 'Property1'
PROPERTY2 = 'Property2'
def _get_namespace_fixture(ns_name, rt_name=RESOURCE_TYPE1, **kwargs):
ns = {
"display_name": "Flavor Quota",
"description": "DESCRIPTION1",
"self": "/v2/metadefs/namespaces/%s" % ns_name,
"namespace": ns_name,
"visibility": "public",
"protected": True,
"owner": "admin",
"resource_types": [
{
"name": rt_name
}
],
"schema": "/v2/schemas/metadefs/namespace",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
ns.update(kwargs)
return ns
data_fixtures = {
"/v2/metadefs/namespaces?limit=20": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=20",
"namespaces": [
_get_namespace_fixture(NAMESPACE1),
_get_namespace_fixture(NAMESPACE2),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=1": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=1",
"namespaces": [
_get_namespace_fixture(NAMESPACE7),
],
"schema": "/v2/schemas/metadefs/namespaces",
"next": "/v2/metadefs/namespaces?marker=%s&limit=1"
% NAMESPACE7,
}
)
},
"/v2/metadefs/namespaces?limit=1&marker=%s" % NAMESPACE7: {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=2",
"namespaces": [
_get_namespace_fixture(NAMESPACE8),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=2&marker=%s" % NAMESPACE6: {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=2",
"namespaces": [
_get_namespace_fixture(NAMESPACE7),
_get_namespace_fixture(NAMESPACE8),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&sort_dir=asc": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=1",
"namespaces": [
_get_namespace_fixture(NAMESPACE1),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&sort_key=created_at": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=1",
"namespaces": [
_get_namespace_fixture(NAMESPACE1),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&resource_types=%s" % RESOURCE_TYPE1: {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=20",
"namespaces": [
_get_namespace_fixture(NAMESPACE3),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&resource_types="
"%s%%2C%s" % (RESOURCE_TYPE1, RESOURCE_TYPE2): {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=20",
"namespaces": [
_get_namespace_fixture(NAMESPACE4),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces?limit=20&visibility=private": {
"GET": (
{},
{
"first": "/v2/metadefs/namespaces?limit=20",
"namespaces": [
_get_namespace_fixture(NAMESPACE5),
],
"schema": "/v2/schemas/metadefs/namespaces"
}
)
},
"/v2/metadefs/namespaces": {
"POST": (
{},
{
"display_name": "Flavor Quota",
"description": "DESCRIPTION1",
"self": "/v2/metadefs/namespaces/%s" % 'NamespaceNew',
"namespace": 'NamespaceNew',
"visibility": "public",
"protected": True,
"owner": "admin",
"schema": "/v2/schemas/metadefs/namespace",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
)
},
"/v2/metadefs/namespaces/%s" % NAMESPACE1: {
"GET": (
{},
{
"display_name": "Flavor Quota",
"description": "DESCRIPTION1",
"objects": [
{
"description": "DESCRIPTION2",
"name": "OBJECT1",
"self": "/v2/metadefs/namespaces/%s/objects/" %
OBJECT1,
"required": [],
"properties": {
PROPERTY1: {
"type": "integer",
"description": "DESCRIPTION3",
"title": "Quota: CPU Shares"
},
PROPERTY2: {
"minimum": 1000,
"type": "integer",
"description": "DESCRIPTION4",
"maximum": 1000000,
"title": "Quota: CPU Period"
},
},
"schema": "/v2/schemas/metadefs/object"
}
],
"self": "/v2/metadefs/namespaces/%s" % NAMESPACE1,
"namespace": NAMESPACE1,
"visibility": "public",
"protected": True,
"owner": "admin",
"resource_types": [
{
"name": RESOURCE_TYPE1
}
],
"schema": "/v2/schemas/metadefs/namespace",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
),
"PUT": (
{},
{
"display_name": "Flavor Quota",
"description": "DESCRIPTION1",
"objects": [
{
"description": "DESCRIPTION2",
"name": "OBJECT1",
"self": "/v2/metadefs/namespaces/%s/objects/" %
OBJECT1,
"required": [],
"properties": {
PROPERTY1: {
"type": "integer",
"description": "DESCRIPTION3",
"title": "Quota: CPU Shares"
},
PROPERTY2: {
"minimum": 1000,
"type": "integer",
"description": "DESCRIPTION4",
"maximum": 1000000,
"title": "Quota: CPU Period"
},
},
"schema": "/v2/schemas/metadefs/object"
}
],
"self": "/v2/metadefs/namespaces/%s" % NAMESPACENEW,
"namespace": NAMESPACENEW,
"visibility": "public",
"protected": True,
"owner": "admin",
"resource_types": [
{
"name": RESOURCE_TYPE1
}
],
"schema": "/v2/schemas/metadefs/namespace",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
),
"DELETE": (
{},
{}
)
},
"/v2/metadefs/namespaces/%s?resource_type=%s" % (NAMESPACE6,
RESOURCE_TYPE1):
{
"GET": (
{},
{
"display_name": "Flavor Quota",
"description": "DESCRIPTION1",
"objects": [],
"self": "/v2/metadefs/namespaces/%s" % NAMESPACE1,
"namespace": NAMESPACE6,
"visibility": "public",
"protected": True,
"owner": "admin",
"resource_types": [
{
"name": RESOURCE_TYPE1
}
],
"schema": "/v2/schemas/metadefs/namespace",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
),
},
}
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
}
]
},
"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"
},
"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"
},
"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"
}
}
}
),
}
}
class TestNamespaceController(testtools.TestCase):
def setUp(self):
super(TestNamespaceController, self).setUp()
self.api = utils.FakeAPI(data_fixtures)
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = metadefs.NamespaceController(self.api,
self.schema_api)
def test_list_namespaces(self):
namespaces = list(self.controller.list())
self.assertEqual(2, len(namespaces))
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE2, namespaces[1]['namespace'])
def test_list_namespaces_paginate(self):
namespaces = list(self.controller.list(page_size=1))
self.assertEqual(2, len(namespaces))
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
def test_list_with_limit_greater_than_page_size(self):
namespaces = list(self.controller.list(page_size=1, limit=2))
self.assertEqual(2, len(namespaces))
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
def test_list_with_marker(self):
namespaces = list(self.controller.list(marker=NAMESPACE6, page_size=2))
self.assertEqual(2, len(namespaces))
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
def test_list_with_sort_dir(self):
namespaces = list(self.controller.list(sort_dir='asc', limit=1))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
def test_list_with_sort_dir_invalid(self):
# NOTE(TravT): The clients work by returning an iterator.
# Invoking the iterator is what actually executes the logic.
ns_iterator = self.controller.list(sort_dir='foo')
self.assertRaises(ValueError, next, ns_iterator)
def test_list_with_sort_key(self):
namespaces = list(self.controller.list(sort_key='created_at', limit=1))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
def test_list_with_sort_key_invalid(self):
# NOTE(TravT): The clients work by returning an iterator.
# Invoking the iterator is what actually executes the logic.
ns_iterator = self.controller.list(sort_key='foo')
self.assertRaises(ValueError, next, ns_iterator)
def test_list_namespaces_with_one_resource_type_filter(self):
namespaces = list(self.controller.list(
filters={
'resource_types': [RESOURCE_TYPE1]
}
))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE3, namespaces[0]['namespace'])
def test_list_namespaces_with_multiple_resource_types_filter(self):
namespaces = list(self.controller.list(
filters={
'resource_types': [RESOURCE_TYPE1, RESOURCE_TYPE2]
}
))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE4, namespaces[0]['namespace'])
def test_list_namespaces_with_visibility_filter(self):
namespaces = list(self.controller.list(
filters={
'visibility': 'private'
}
))
self.assertEqual(1, len(namespaces))
self.assertEqual(NAMESPACE5, namespaces[0]['namespace'])
def test_get_namespace(self):
namespace = self.controller.get(NAMESPACE1)
self.assertEqual(NAMESPACE1, namespace.namespace)
self.assertTrue(namespace.protected)
def test_get_namespace_with_resource_type(self):
namespace = self.controller.get(NAMESPACE6,
resource_type=RESOURCE_TYPE1)
self.assertEqual(NAMESPACE6, namespace.namespace)
self.assertTrue(namespace.protected)
def test_create_namespace(self):
properties = {
'namespace': NAMESPACENEW
}
namespace = self.controller.create(**properties)
self.assertEqual(NAMESPACENEW, namespace.namespace)
self.assertTrue(namespace.protected)
def test_create_namespace_invalid_data(self):
properties = {}
self.assertRaises(TypeError, self.controller.create, **properties)
def test_create_namespace_invalid_property(self):
properties = {'namespace': 'NewNamespace', 'protected': '123'}
self.assertRaises(TypeError, self.controller.create, **properties)
def test_update_namespace(self):
properties = {'display_name': 'My Updated Name'}
namespace = self.controller.update(NAMESPACE1, **properties)
self.assertEqual(NAMESPACE1, namespace.namespace)
def test_update_namespace_invalid_property(self):
properties = {'protected': '123'}
self.assertRaises(TypeError, self.controller.update, NAMESPACE1,
**properties)
def test_delete_namespace(self):
self.controller.delete(NAMESPACE1)
expect = [
('DELETE',
'/v2/metadefs/namespaces/%s' % NAMESPACE1,
{},
None)]
self.assertEqual(expect, self.api.calls)
@@ -0,0 +1,323 @@
# Copyright 2012 OpenStack Foundation.
# 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 six
import testtools
from glanceclient.tests import utils
from glanceclient.v2 import metadefs
NAMESPACE1 = 'Namespace1'
OBJECT1 = 'Object1'
OBJECT2 = 'Object2'
OBJECTNEW = 'ObjectNew'
PROPERTY1 = 'Property1'
PROPERTY2 = 'Property2'
PROPERTY3 = 'Property3'
PROPERTY4 = 'Property4'
def _get_object_fixture(ns_name, obj_name, **kwargs):
obj = {
"description": "DESCRIPTION",
"name": obj_name,
"self": "/v2/metadefs/namespaces/%s/objects/%s" %
(ns_name, obj_name),
"required": [],
"properties": {
PROPERTY1: {
"type": "integer",
"description": "DESCRIPTION",
"title": "Quota: CPU Shares"
},
PROPERTY2: {
"minimum": 1000,
"type": "integer",
"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",
}
obj.update(kwargs)
return obj
data_fixtures = {
"/v2/metadefs/namespaces/%s/objects" % NAMESPACE1: {
"GET": (
{},
{
"objects": [
_get_object_fixture(NAMESPACE1, OBJECT1),
_get_object_fixture(NAMESPACE1, OBJECT2)
],
"schema": "v2/schemas/metadefs/objects"
}
),
"POST": (
{},
_get_object_fixture(NAMESPACE1, OBJECTNEW)
),
"DELETE": (
{},
{}
)
},
"/v2/metadefs/namespaces/%s/objects/%s" % (NAMESPACE1, OBJECT1): {
"GET": (
{},
_get_object_fixture(NAMESPACE1, OBJECT1)
),
"PUT": (
{},
_get_object_fixture(NAMESPACE1, OBJECT1)
),
"DELETE": (
{},
{}
)
}
}
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": [
"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"
},
}
}
)
}
}
class TestObjectController(testtools.TestCase):
def setUp(self):
super(TestObjectController, self).setUp()
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))
actual = [obj.name for obj in objects]
self.assertEqual([OBJECT1, OBJECT2], actual)
def test_get_object(self):
obj = self.controller.get(NAMESPACE1, OBJECT1)
self.assertEqual(OBJECT1, obj.name)
self.assertEqual(sorted([PROPERTY1, PROPERTY2]),
sorted(list(six.iterkeys(obj.properties))))
def test_create_object(self):
properties = {
'name': OBJECTNEW,
'description': 'DESCRIPTION'
}
obj = self.controller.create(NAMESPACE1, **properties)
self.assertEqual(OBJECTNEW, obj.name)
def test_create_object_invalid_property(self):
properties = {
'namespace': NAMESPACE1
}
self.assertRaises(TypeError, self.controller.create, **properties)
def test_update_object(self):
properties = {
'description': 'UPDATED_DESCRIPTION'
}
obj = self.controller.update(NAMESPACE1, OBJECT1, **properties)
self.assertEqual(OBJECT1, obj.name)
def test_update_object_invalid_property(self):
properties = {
'required': 'INVALID'
}
self.assertRaises(TypeError, self.controller.update, NAMESPACE1,
OBJECT1, **properties)
def test_delete_object(self):
self.controller.delete(NAMESPACE1, OBJECT1)
expect = [
('DELETE',
'/v2/metadefs/namespaces/%s/objects/%s' % (NAMESPACE1, OBJECT1),
{},
None)]
self.assertEqual(expect, self.api.calls)
def test_delete_all_objects(self):
self.controller.delete_all(NAMESPACE1)
expect = [
('DELETE',
'/v2/metadefs/namespaces/%s/objects' % NAMESPACE1,
{},
None)]
self.assertEqual(expect, self.api.calls)
@@ -0,0 +1,300 @@
# Copyright 2012 OpenStack Foundation.
# 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 testtools
from glanceclient.tests import utils
from glanceclient.v2 import metadefs
NAMESPACE1 = 'Namespace1'
PROPERTY1 = 'Property1'
PROPERTY2 = 'Property2'
PROPERTYNEW = 'PropertyNew'
data_fixtures = {
"/v2/metadefs/namespaces/%s/properties" % NAMESPACE1: {
"GET": (
{},
{
"properties": {
PROPERTY1: {
"default": "1",
"type": "integer",
"description": "Number of cores.",
"title": "cores"
},
PROPERTY2: {
"items": {
"enum": [
"Intel",
"AMD"
],
"type": "string"
},
"type": "array",
"description": "Specifies the CPU manufacturer.",
"title": "Vendor"
},
}
}
),
"POST": (
{},
{
"items": {
"enum": [
"Intel",
"AMD"
],
"type": "string"
},
"type": "array",
"description": "UPDATED_DESCRIPTION",
"title": "Vendor",
"name": PROPERTYNEW
}
),
"DELETE": (
{},
{}
)
},
"/v2/metadefs/namespaces/%s/properties/%s" % (NAMESPACE1, PROPERTY1): {
"GET": (
{},
{
"items": {
"enum": [
"Intel",
"AMD"
],
"type": "string"
},
"type": "array",
"description": "Specifies the CPU manufacturer.",
"title": "Vendor"
}
),
"PUT": (
{},
{
"items": {
"enum": [
"Intel",
"AMD"
],
"type": "string"
},
"type": "array",
"description": "UPDATED_DESCRIPTION",
"title": "Vendor"
}
),
"DELETE": (
{},
{}
)
}
}
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(data_fixtures)
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = metadefs.PropertyController(self.api,
self.schema_api)
def test_list_property(self):
properties = list(self.controller.list(NAMESPACE1))
actual = [prop.name for prop in properties]
self.assertEqual(sorted([PROPERTY1, PROPERTY2]), sorted(actual))
def test_get_property(self):
prop = self.controller.get(NAMESPACE1, PROPERTY1)
self.assertEqual(PROPERTY1, prop.name)
def test_create_property(self):
properties = {
'name': PROPERTYNEW,
'title': 'TITLE',
'type': 'string'
}
obj = self.controller.create(NAMESPACE1, **properties)
self.assertEqual(PROPERTYNEW, obj.name)
def test_create_property_invalid_property(self):
properties = {
'namespace': NAMESPACE1
}
self.assertRaises(TypeError, self.controller.create, **properties)
def test_update_property(self):
properties = {
'description': 'UPDATED_DESCRIPTION'
}
prop = self.controller.update(NAMESPACE1, PROPERTY1, **properties)
self.assertEqual(PROPERTY1, prop.name)
def test_update_property_invalid_property(self):
properties = {
'type': 'INVALID'
}
self.assertRaises(TypeError, self.controller.update, NAMESPACE1,
PROPERTY1, **properties)
def test_delete_property(self):
self.controller.delete(NAMESPACE1, PROPERTY1)
expect = [
('DELETE',
'/v2/metadefs/namespaces/%s/properties/%s' % (NAMESPACE1,
PROPERTY1),
{},
None)]
self.assertEqual(expect, self.api.calls)
def test_delete_all_properties(self):
self.controller.delete_all(NAMESPACE1)
expect = [
('DELETE',
'/v2/metadefs/namespaces/%s/properties' % NAMESPACE1,
{},
None)]
self.assertEqual(expect, self.api.calls)
@@ -0,0 +1,186 @@
# Copyright 2012 OpenStack Foundation.
# 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 testtools
from glanceclient.tests import utils
from glanceclient.v2 import metadefs
NAMESPACE1 = 'Namespace1'
RESOURCE_TYPE1 = 'ResourceType1'
RESOURCE_TYPE2 = 'ResourceType2'
RESOURCE_TYPE3 = 'ResourceType3'
RESOURCE_TYPE4 = 'ResourceType4'
RESOURCE_TYPENEW = 'ResourceTypeNew'
data_fixtures = {
"/v2/metadefs/namespaces/%s/resource_types" % NAMESPACE1: {
"GET": (
{},
{
"resource_type_associations": [
{
"name": RESOURCE_TYPE3,
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
},
{
"name": RESOURCE_TYPE4,
"prefix": "PREFIX:",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
]
}
),
"POST": (
{},
{
"name": RESOURCE_TYPENEW,
"prefix": "PREFIX:",
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
),
},
"/v2/metadefs/namespaces/%s/resource_types/%s" % (NAMESPACE1,
RESOURCE_TYPE1):
{
"DELETE": (
{},
{}
),
},
"/v2/metadefs/resource_types": {
"GET": (
{},
{
"resource_types": [
{
"name": RESOURCE_TYPE1,
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
},
{
"name": RESOURCE_TYPE2,
"created_at": "2014-08-14T09:07:06Z",
"updated_at": "2014-08-14T09:07:06Z",
}
]
}
)
}
}
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(data_fixtures)
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = metadefs.ResourceTypeController(self.api,
self.schema_api)
def test_list_resource_types(self):
resource_types = list(self.controller.list())
names = [rt.name for rt in resource_types]
self.assertEqual([RESOURCE_TYPE1, RESOURCE_TYPE2], names)
def test_get_resource_types(self):
resource_types = list(self.controller.get(NAMESPACE1))
names = [rt.name for rt in resource_types]
self.assertEqual([RESOURCE_TYPE3, RESOURCE_TYPE4], names)
def test_associate_resource_types(self):
resource_types = self.controller.associate(NAMESPACE1,
name=RESOURCE_TYPENEW)
self.assertEqual(RESOURCE_TYPENEW, resource_types['name'])
def test_associate_resource_types_invalid_property(self):
longer = '1234' * 50
properties = {'name': RESOURCE_TYPENEW, 'prefix': longer}
self.assertRaises(TypeError, self.controller.associate, NAMESPACE1,
**properties)
def test_deassociate_resource_types(self):
self.controller.deassociate(NAMESPACE1, RESOURCE_TYPE1)
expect = [
('DELETE',
'/v2/metadefs/namespaces/%s/resource_types/%s' % (NAMESPACE1,
RESOURCE_TYPE1),
{},
None)]
self.assertEqual(expect, self.api.calls)
+231
View File
@@ -0,0 +1,231 @@
# Copyright 2012 OpenStack Foundation
# 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.
from jsonpatch import JsonPatch
import testtools
import warlock
from glanceclient.tests import utils
from glanceclient.v2 import schemas
fixtures = {
'/v2/schemas': {
'GET': (
{},
{
'image': '/v2/schemas/image',
'access': '/v2/schemas/image/access',
},
),
},
'/v2/schemas/image': {
'GET': (
{},
{
'name': 'image',
'properties': {
'name': {'type': 'string',
'description': 'Name of image'},
'tags': {'type': 'array'}
},
},
),
},
}
_SCHEMA = schemas.Schema({
'name': 'image',
'properties': {
'name': {'type': 'string'},
'color': {'type': 'string'},
'shape': {'type': 'string', 'is_base': False},
'tags': {'type': 'array'}
},
})
def compare_json_patches(a, b):
"""Return 0 if a and b describe the same JSON patch."""
return JsonPatch.from_string(a) == JsonPatch.from_string(b)
class TestSchemaProperty(testtools.TestCase):
def test_property_minimum(self):
prop = schemas.SchemaProperty('size')
self.assertEqual('size', prop.name)
def test_property_description(self):
prop = schemas.SchemaProperty('size', description='some quantity')
self.assertEqual('size', prop.name)
self.assertEqual('some quantity', prop.description)
def test_property_is_base(self):
prop1 = schemas.SchemaProperty('name')
prop2 = schemas.SchemaProperty('foo', is_base=False)
prop3 = schemas.SchemaProperty('foo', is_base=True)
self.assertTrue(prop1.is_base)
self.assertFalse(prop2.is_base)
self.assertTrue(prop3.is_base)
class TestSchema(testtools.TestCase):
def test_schema_minimum(self):
raw_schema = {'name': 'Country', 'properties': {}}
schema = schemas.Schema(raw_schema)
self.assertEqual('Country', schema.name)
self.assertEqual([], schema.properties)
def test_schema_with_property(self):
raw_schema = {'name': 'Country', 'properties': {'size': {}}}
schema = schemas.Schema(raw_schema)
self.assertEqual('Country', schema.name)
self.assertEqual(['size'], [p.name for p in schema.properties])
def test_raw(self):
raw_schema = {'name': 'Country', 'properties': {}}
schema = schemas.Schema(raw_schema)
self.assertEqual(raw_schema, schema.raw())
def test_property_is_base(self):
raw_schema = {'name': 'Country',
'properties': {
'size': {},
'population': {'is_base': False}}}
schema = schemas.Schema(raw_schema)
self.assertTrue(schema.is_base_property('size'))
self.assertFalse(schema.is_base_property('population'))
self.assertFalse(schema.is_base_property('foo'))
class TestController(testtools.TestCase):
def setUp(self):
super(TestController, self).setUp()
self.api = utils.FakeAPI(fixtures)
self.controller = schemas.Controller(self.api)
def test_get_schema(self):
schema = self.controller.get('image')
self.assertEqual('image', schema.name)
self.assertEqual(['name', 'tags'],
[p.name for p in schema.properties])
class TestSchemaBasedModel(testtools.TestCase):
def setUp(self):
super(TestSchemaBasedModel, self).setUp()
self.model = warlock.model_factory(_SCHEMA.raw(),
schemas.SchemaBasedModel)
def test_patch_should_replace_missing_core_properties(self):
obj = {
'name': 'fred'
}
original = self.model(obj)
original['color'] = 'red'
patch = original.patch
expected = '[{"path": "/color", "value": "red", "op": "replace"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_add_extra_properties(self):
obj = {
'name': 'fred',
}
original = self.model(obj)
original['weight'] = '10'
patch = original.patch
expected = '[{"path": "/weight", "value": "10", "op": "add"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_replace_extra_properties(self):
obj = {
'name': 'fred',
'weight': '10'
}
original = self.model(obj)
original['weight'] = '22'
patch = original.patch
expected = '[{"path": "/weight", "value": "22", "op": "replace"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_remove_extra_properties(self):
obj = {
'name': 'fred',
'weight': '10'
}
original = self.model(obj)
del original['weight']
patch = original.patch
expected = '[{"path": "/weight", "op": "remove"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_remove_core_properties(self):
obj = {
'name': 'fred',
'color': 'red'
}
original = self.model(obj)
del original['color']
patch = original.patch
expected = '[{"path": "/color", "op": "remove"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_add_missing_custom_properties(self):
obj = {
'name': 'fred'
}
original = self.model(obj)
original['shape'] = 'circle'
patch = original.patch
expected = '[{"path": "/shape", "value": "circle", "op": "add"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_replace_custom_properties(self):
obj = {
'name': 'fred',
'shape': 'circle'
}
original = self.model(obj)
original['shape'] = 'square'
patch = original.patch
expected = '[{"path": "/shape", "value": "square", "op": "replace"}]'
self.assertTrue(compare_json_patches(patch, expected))
def test_patch_should_replace_tags(self):
obj = {'name': 'fred', }
original = self.model(obj)
original['tags'] = ['tag1', 'tag2']
patch = original.patch
expected = '[{"path": "/tags", "value": ["tag1", "tag2"], ' \
'"op": "replace"}]'
self.assertTrue(compare_json_patches(patch, expected))
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
# Copyright 2013 OpenStack Foundation
# 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 testtools
from glanceclient.tests import utils
from glanceclient.v2 import image_tags
IMAGE = '3a4560a1-e585-443e-9b39-553b46ec92d1'
TAG = 'tag01'
data_fixtures = {
'/v2/images/{image}/tags/{tag_value}'.format(image=IMAGE, tag_value=TAG): {
'DELETE': (
{},
None,
),
'PUT': (
{},
{
'image_id': IMAGE,
'tag_value': TAG
}
),
}
}
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(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
tag_value = TAG
self.controller.update(image_id, tag_value)
expect = [
('PUT',
'/v2/images/{image}/tags/{tag_value}'.format(image=IMAGE,
tag_value=TAG),
{},
None)]
self.assertEqual(expect, self.api.calls)
def test_delete_image_tag(self):
image_id = IMAGE
tag_value = TAG
self.controller.delete(image_id, tag_value)
expect = [
('DELETE',
'/v2/images/{image}/tags/{tag_value}'.format(image=IMAGE,
tag_value=TAG),
{},
None)]
self.assertEqual(expect, self.api.calls)
+285
View File
@@ -0,0 +1,285 @@
# Copyright 2013 OpenStack Foundation.
# Copyright 2013 IBM Corp.
# 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 testtools
from glanceclient.tests import utils
from glanceclient.v2 import tasks
_OWNED_TASK_ID = 'a4963502-acc7-42ba-ad60-5aa0962b7faf'
_OWNER_ID = '6bd473f0-79ae-40ad-a927-e07ec37b642f'
_FAKE_OWNER_ID = '63e7f218-29de-4477-abdc-8db7c9533188'
fixtures = {
'/v2/tasks?limit=%d' % tasks.DEFAULT_PAGE_SIZE: {
'GET': (
{},
{'tasks': [
{
'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
'type': 'import',
'status': 'pending',
},
{
'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
'type': 'import',
'status': 'processing',
},
]},
),
},
'/v2/tasks?limit=1': {
'GET': (
{},
{
'tasks': [
{
'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
'type': 'import',
'status': 'pending',
},
],
'next': ('/v2/tasks?limit=1&'
'marker=3a4560a1-e585-443e-9b39-553b46ec92d1'),
},
),
},
('/v2/tasks?limit=1&marker=3a4560a1-e585-443e-9b39-553b46ec92d1'): {
'GET': (
{},
{'tasks': [
{
'id': '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810',
'type': 'import',
'status': 'pending',
},
]},
),
},
'/v2/tasks/3a4560a1-e585-443e-9b39-553b46ec92d1': {
'GET': (
{},
{
'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
'type': 'import',
'status': 'pending',
},
),
'PATCH': (
{},
'',
),
},
'/v2/tasks/e7e59ff6-fa2e-4075-87d3-1a1398a07dc3': {
'GET': (
{},
{
'id': 'e7e59ff6-fa2e-4075-87d3-1a1398a07dc3',
'type': 'import',
'status': 'pending',
},
),
'PATCH': (
{},
'',
),
},
'/v2/tasks': {
'POST': (
{},
{
'id': '3a4560a1-e585-443e-9b39-553b46ec92d1',
'type': 'import',
'status': 'pending',
'input': '{"import_from": "file:///", '
'"import_from_format": "qcow2"}'
},
),
},
'/v2/tasks?limit=%d&owner=%s' % (tasks.DEFAULT_PAGE_SIZE, _OWNER_ID): {
'GET': (
{},
{'tasks': [
{
'id': _OWNED_TASK_ID,
},
]},
),
},
'/v2/tasks?limit=%d&status=processing' % (tasks.DEFAULT_PAGE_SIZE): {
'GET': (
{},
{'tasks': [
{
'id': _OWNED_TASK_ID,
},
]},
),
},
'/v2/tasks?limit=%d&type=import' % (tasks.DEFAULT_PAGE_SIZE): {
'GET': (
{},
{'tasks': [
{
'id': _OWNED_TASK_ID,
},
]},
),
},
'/v2/tasks?limit=%d&type=fake' % (tasks.DEFAULT_PAGE_SIZE): {
'GET': (
{},
{'tasks': [
]},
),
},
'/v2/tasks?limit=%d&status=fake' % (tasks.DEFAULT_PAGE_SIZE): {
'GET': (
{},
{'tasks': [
]},
),
},
'/v2/tasks?limit=%d&type=import' % (tasks.DEFAULT_PAGE_SIZE): {
'GET': (
{},
{'tasks': [
{
'id': _OWNED_TASK_ID,
},
]},
),
},
'/v2/tasks?limit=%d&owner=%s' % (tasks.DEFAULT_PAGE_SIZE, _FAKE_OWNER_ID):
{
'GET': ({},
{'tasks': []},
),
}
}
schema_fixtures = {
'task': {
'GET': (
{},
{
'name': 'task',
'properties': {
'id': {},
'type': {},
'status': {},
'input': {},
'result': {},
'message': {},
},
'additionalProperties': False,
}
)
}
}
class TestController(testtools.TestCase):
def setUp(self):
super(TestController, self).setUp()
self.api = utils.FakeAPI(fixtures)
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
self.controller = tasks.Controller(self.api, self.schema_api)
def test_list_tasks(self):
#NOTE(flwang): cast to list since the controller returns a generator
tasks = list(self.controller.list())
self.assertEqual(tasks[0].id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
self.assertEqual(tasks[0].type, 'import')
self.assertEqual(tasks[0].status, 'pending')
self.assertEqual(tasks[1].id, '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810')
self.assertEqual(tasks[1].type, 'import')
self.assertEqual(tasks[1].status, 'processing')
def test_list_tasks_paginated(self):
#NOTE(flwang): cast to list since the controller returns a generator
tasks = list(self.controller.list(page_size=1))
self.assertEqual(tasks[0].id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
self.assertEqual(tasks[0].type, 'import')
self.assertEqual(tasks[1].id, '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810')
self.assertEqual(tasks[1].type, 'import')
def test_list_tasks_with_status(self):
filters = {'filters': {'status': 'processing'}}
tasks = list(self.controller.list(**filters))
self.assertEqual(tasks[0].id, _OWNED_TASK_ID)
def test_list_tasks_with_wrong_status(self):
filters = {'filters': {'status': 'fake'}}
tasks = list(self.controller.list(**filters))
self.assertEqual(len(tasks), 0)
def test_list_tasks_with_type(self):
filters = {'filters': {'type': 'import'}}
tasks = list(self.controller.list(**filters))
self.assertEqual(tasks[0].id, _OWNED_TASK_ID)
def test_list_tasks_with_wrong_type(self):
filters = {'filters': {'type': 'fake'}}
tasks = list(self.controller.list(**filters))
self.assertEqual(len(tasks), 0)
def test_list_tasks_for_owner(self):
filters = {'filters': {'owner': _OWNER_ID}}
tasks = list(self.controller.list(**filters))
self.assertEqual(tasks[0].id, _OWNED_TASK_ID)
def test_list_tasks_for_fake_owner(self):
filters = {'filters': {'owner': _FAKE_OWNER_ID}}
tasks = list(self.controller.list(**filters))
self.assertEqual(tasks, [])
def test_list_tasks_filters_encoding(self):
filters = {"owner": u"ni\xf1o"}
try:
list(self.controller.list(filters=filters))
except KeyError:
# NOTE(flaper87): It raises KeyError because there's
# no fixture supporting this query:
# /v2/tasks?owner=ni%C3%B1o&limit=20
# We just want to make sure filters are correctly encoded.
pass
self.assertEqual(b"ni\xc3\xb1o", filters["owner"])
def test_get_task(self):
task = self.controller.get('3a4560a1-e585-443e-9b39-553b46ec92d1')
self.assertEqual(task.id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
self.assertEqual(task.type, 'import')
def test_create_task(self):
properties = {
'type': 'import',
'input': {'import_from_format': 'ovf', 'import_from':
'swift://cloud.foo/myaccount/mycontainer/path'},
}
task = self.controller.create(**properties)
self.assertEqual(task.id, '3a4560a1-e585-443e-9b39-553b46ec92d1')
self.assertEqual(task.type, 'import')
def test_create_task_invalid_property(self):
properties = {
'type': 'import',
'bad_prop': 'value',
}
self.assertRaises(TypeError, self.controller.create, **properties)