Merge "Adds API version discovery support for V3"
This commit is contained in:
commit
88fb94f5fa
@ -10,6 +10,17 @@
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"updated": "2011-01-21T11:33:21Z"
|
||||
},
|
||||
{
|
||||
"id": "v3.0",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v3/",
|
||||
"rel": "self"
|
||||
}
|
||||
],
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,7 @@
|
||||
<version status="CURRENT" updated="2011-01-21T11:33:21Z" id="v2.0">
|
||||
<atom:link href="http://openstack.example.com/v2/" rel="self"/>
|
||||
</version>
|
||||
</versions>
|
||||
<version status="EXPERIMENTAL" updated="2013-07-23T11:33:21Z" id="v3.0">
|
||||
<atom:link href="http://openstack.example.com/v3/" rel="self"/>
|
||||
</version>
|
||||
</versions>
|
||||
|
57
nova/api/openstack/compute/plugins/v3/versions.py
Normal file
57
nova/api/openstack/compute/plugins/v3/versions.py
Normal file
@ -0,0 +1,57 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# 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.
|
||||
|
||||
from nova.api.openstack.compute import versions
|
||||
from nova.api.openstack.compute.views import versions as views_versions
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
|
||||
|
||||
ALIAS = "versions"
|
||||
|
||||
|
||||
class VersionsController(object):
|
||||
@extensions.expected_errors(())
|
||||
@wsgi.serializers(xml=versions.VersionTemplate,
|
||||
atom=versions.VersionAtomSerializer)
|
||||
def show(self, req):
|
||||
builder = views_versions.get_view_builder(req)
|
||||
return builder.build_version(versions.VERSIONS['v3.0'])
|
||||
|
||||
|
||||
class Versions(extensions.V3APIExtensionBase):
|
||||
"""API Version information."""
|
||||
|
||||
name = "Versions"
|
||||
alias = ALIAS
|
||||
namespace = "http://docs.openstack.org/compute/core/versions/v3"
|
||||
version = 1
|
||||
|
||||
def get_resources(self):
|
||||
resources = [
|
||||
extensions.ResourceExtension(ALIAS, VersionsController(),
|
||||
custom_routes_fn=self.version_map)]
|
||||
return resources
|
||||
|
||||
def get_controller_extensions(self):
|
||||
return []
|
||||
|
||||
def version_map(self, mapper, wsgi_resource):
|
||||
mapper.connect("versions", "/",
|
||||
controller=wsgi_resource,
|
||||
action='show', conditions={"method": ['GET']})
|
||||
mapper.redirect("", "/")
|
@ -16,6 +16,7 @@
|
||||
# under the License.
|
||||
|
||||
from lxml import etree
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.api.openstack.compute.views import versions as views_versions
|
||||
from nova.api.openstack import wsgi
|
||||
@ -23,6 +24,9 @@ from nova.api.openstack import xmlutil
|
||||
from nova.openstack.common import timeutils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('enabled', 'nova.api.openstack', group='osapi_v3')
|
||||
|
||||
LINKS = {
|
||||
'v2.0': {
|
||||
'pdf': 'http://docs.openstack.org/'
|
||||
@ -30,6 +34,12 @@ LINKS = {
|
||||
'wadl': 'http://docs.openstack.org/'
|
||||
'api/openstack-compute/2/wadl/os-compute-2.wadl'
|
||||
},
|
||||
'v3.0': {
|
||||
'pdf': 'http://docs.openstack.org/'
|
||||
'api/openstack-compute/3/os-compute-devguide-3.pdf',
|
||||
'wadl': 'http://docs.openstack.org/'
|
||||
'api/openstack-compute/3/wadl/os-compute-3.wadl'
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +70,33 @@ VERSIONS = {
|
||||
"type": "application/vnd.openstack.compute+json;version=2",
|
||||
}
|
||||
],
|
||||
},
|
||||
"v3.0": {
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": LINKS['v3.0']['pdf'],
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": LINKS['v3.0']['wadl'],
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json;version=3",
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,6 +242,8 @@ class VersionAtomSerializer(AtomSerializer):
|
||||
class Versions(wsgi.Resource):
|
||||
def __init__(self):
|
||||
super(Versions, self).__init__(None)
|
||||
if not CONF.osapi_v3.enabled:
|
||||
del VERSIONS["v3.0"]
|
||||
|
||||
@wsgi.serializers(xml=VersionsTemplate,
|
||||
atom=VersionsAtomSerializer)
|
||||
|
@ -44,7 +44,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": self.generate_href(req.path),
|
||||
"href": self.generate_href(version['id'], req.path),
|
||||
},
|
||||
],
|
||||
"media-types": version['media-types'],
|
||||
@ -75,7 +75,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
def _build_links(self, version_data):
|
||||
"""Generate a container of links that refer to the provided version."""
|
||||
href = self.generate_href()
|
||||
href = self.generate_href(version_data['id'])
|
||||
|
||||
links = [
|
||||
{
|
||||
@ -86,10 +86,14 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
return links
|
||||
|
||||
def generate_href(self, path=None):
|
||||
def generate_href(self, version, path=None):
|
||||
"""Create an url that refers to a specific version_number."""
|
||||
prefix = self._update_compute_link_prefix(self.base_url)
|
||||
version_number = 'v2'
|
||||
if version.find('v3.') == 0:
|
||||
version_number = 'v3'
|
||||
else:
|
||||
version_number = 'v2'
|
||||
|
||||
if path:
|
||||
path = path.strip('/')
|
||||
return os.path.join(prefix, version_number, path)
|
||||
|
246
nova/tests/api/openstack/compute/plugins/v3/test_versions.py
Normal file
246
nova/tests/api/openstack/compute/plugins/v3/test_versions.py
Normal file
@ -0,0 +1,246 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 IBM Corp.
|
||||
# Copyright 2010-2011 OpenStack Foundation
|
||||
#
|
||||
# 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 feedparser
|
||||
from lxml import etree
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import xmlutil
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import common
|
||||
from nova.tests.api.openstack import fakes
|
||||
|
||||
|
||||
NS = {
|
||||
'atom': 'http://www.w3.org/2005/Atom',
|
||||
'ns': 'http://docs.openstack.org/common/api/v1.0'
|
||||
}
|
||||
|
||||
|
||||
EXP_LINKS = {
|
||||
'v3.0': {
|
||||
'pdf': 'http://docs.openstack.org/'
|
||||
'api/openstack-compute/3/os-compute-devguide-3.pdf',
|
||||
'wadl': 'http://docs.openstack.org/'
|
||||
'api/openstack-compute/3/wadl/os-compute-3.wadl'
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
EXP_VERSIONS = {
|
||||
"v3.0": {
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": EXP_LINKS['v3.0']['pdf'],
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": EXP_LINKS['v3.0']['wadl'],
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json;version=3",
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class VersionsTest(test.TestCase):
|
||||
|
||||
def test_get_version_list_302(self):
|
||||
req = webob.Request.blank('/v3')
|
||||
req.accept = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app_v3())
|
||||
self.assertEqual(res.status_int, 302)
|
||||
redirect_req = webob.Request.blank('/v3/')
|
||||
self.assertEqual(res.location, redirect_req.url)
|
||||
|
||||
def test_get_version_3_detail(self):
|
||||
req = webob.Request.blank('/v3/')
|
||||
req.accept = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app_v3())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
version = jsonutils.loads(res.body)
|
||||
expected = {
|
||||
"version": {
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v3/",
|
||||
},
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v3/",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": EXP_LINKS['v3.0']['pdf'],
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": EXP_LINKS['v3.0']['wadl'],
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/"
|
||||
"vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/"
|
||||
"vnd.openstack.compute+json;version=3",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
self.assertEqual(expected, version)
|
||||
|
||||
def test_get_version_3_detail_content_type(self):
|
||||
req = webob.Request.blank('/')
|
||||
req.accept = "application/json;version=3"
|
||||
res = req.get_response(fakes.wsgi_app_v3())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
version = jsonutils.loads(res.body)
|
||||
expected = {
|
||||
"version": {
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v3/",
|
||||
},
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v3/",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": EXP_LINKS['v3.0']['pdf'],
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": EXP_LINKS['v3.0']['wadl'],
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/"
|
||||
"vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/"
|
||||
"vnd.openstack.compute+json;version=3",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
self.assertEqual(expected, version)
|
||||
|
||||
def test_get_version_3_detail_xml(self):
|
||||
req = webob.Request.blank('/v3/')
|
||||
req.accept = "application/xml"
|
||||
res = req.get_response(fakes.wsgi_app_v3())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/xml")
|
||||
|
||||
version = etree.XML(res.body)
|
||||
xmlutil.validate_schema(version, 'version')
|
||||
|
||||
expected = EXP_VERSIONS['v3.0']
|
||||
self.assertTrue(version.xpath('/ns:version', namespaces=NS))
|
||||
media_types = version.xpath('ns:media-types/ns:media-type',
|
||||
namespaces=NS)
|
||||
self.assertTrue(common.compare_media_types(media_types,
|
||||
expected['media-types']))
|
||||
for key in ['id', 'status', 'updated']:
|
||||
self.assertEqual(version.get(key), expected[key])
|
||||
links = version.xpath('atom:link', namespaces=NS)
|
||||
self.assertTrue(common.compare_links(links,
|
||||
[{'rel': 'self', 'href': 'http://localhost/v3/'}]
|
||||
+ expected['links']))
|
||||
|
||||
def test_get_version_3_detail_atom(self):
|
||||
req = webob.Request.blank('/v3/')
|
||||
req.accept = "application/atom+xml"
|
||||
res = req.get_response(fakes.wsgi_app_v3())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual("application/atom+xml", res.content_type)
|
||||
|
||||
xmlutil.validate_schema(etree.XML(res.body), 'atom')
|
||||
|
||||
f = feedparser.parse(res.body)
|
||||
self.assertEqual(f.feed.title, 'About This Version')
|
||||
self.assertEqual(f.feed.updated, '2013-07-23T11:33:21Z')
|
||||
self.assertEqual(f.feed.id, 'http://localhost/v3/')
|
||||
self.assertEqual(f.feed.author, 'Rackspace')
|
||||
self.assertEqual(f.feed.author_detail.href,
|
||||
'http://www.rackspace.com/')
|
||||
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v3/')
|
||||
self.assertEqual(f.feed.links[0]['rel'], 'self')
|
||||
|
||||
self.assertEqual(len(f.entries), 1)
|
||||
entry = f.entries[0]
|
||||
self.assertEqual(entry.id, 'http://localhost/v3/')
|
||||
self.assertEqual(entry.title, 'Version v3.0')
|
||||
self.assertEqual(entry.updated, '2013-07-23T11:33:21Z')
|
||||
self.assertEqual(len(entry.content), 1)
|
||||
self.assertEqual(entry.content[0].value,
|
||||
'Version v3.0 EXPERIMENTAL (2013-07-23T11:33:21Z)')
|
||||
self.assertEqual(len(entry.links), 3)
|
||||
self.assertEqual(entry.links[0]['href'], 'http://localhost/v3/')
|
||||
self.assertEqual(entry.links[0]['rel'], 'self')
|
||||
self.assertEqual(entry.links[1], {
|
||||
'href': EXP_LINKS['v3.0']['pdf'],
|
||||
'type': 'application/pdf',
|
||||
'rel': 'describedby'})
|
||||
self.assertEqual(entry.links[2], {
|
||||
'href': EXP_LINKS['v3.0']['wadl'],
|
||||
'type': 'application/vnd.sun.wadl+xml',
|
||||
'rel': 'describedby'})
|
@ -75,6 +75,21 @@ EXP_VERSIONS = {
|
||||
},
|
||||
],
|
||||
},
|
||||
"v3.0": {
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json;version=3",
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -98,6 +113,16 @@ class VersionsTest(test.TestCase):
|
||||
"href": "http://localhost/v2/",
|
||||
}],
|
||||
},
|
||||
{
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v3/",
|
||||
}],
|
||||
},
|
||||
]
|
||||
self.assertEqual(versions, expected)
|
||||
|
||||
@ -232,9 +257,9 @@ class VersionsTest(test.TestCase):
|
||||
|
||||
self.assertTrue(root.xpath('/ns:versions', namespaces=NS))
|
||||
versions = root.xpath('ns:version', namespaces=NS)
|
||||
self.assertEqual(len(versions), 1)
|
||||
self.assertEqual(len(versions), 2)
|
||||
|
||||
for i, v in enumerate(['v2.0']):
|
||||
for i, v in enumerate(['v2.0', 'v3.0']):
|
||||
version = versions[i]
|
||||
expected = EXP_VERSIONS[v]
|
||||
for key in ['id', 'status', 'updated']:
|
||||
@ -291,7 +316,7 @@ class VersionsTest(test.TestCase):
|
||||
|
||||
f = feedparser.parse(res.body)
|
||||
self.assertEqual(f.feed.title, 'Available API Versions')
|
||||
self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z')
|
||||
self.assertEqual(f.feed.updated, '2013-07-23T11:33:21Z')
|
||||
self.assertEqual(f.feed.id, 'http://localhost/')
|
||||
self.assertEqual(f.feed.author, 'Rackspace')
|
||||
self.assertEqual(f.feed.author_detail.href,
|
||||
@ -299,7 +324,7 @@ class VersionsTest(test.TestCase):
|
||||
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/')
|
||||
self.assertEqual(f.feed.links[0]['rel'], 'self')
|
||||
|
||||
self.assertEqual(len(f.entries), 1)
|
||||
self.assertEqual(len(f.entries), 2)
|
||||
entry = f.entries[0]
|
||||
self.assertEqual(entry.id, 'http://localhost/v2/')
|
||||
self.assertEqual(entry.title, 'Version v2.0')
|
||||
@ -311,6 +336,17 @@ class VersionsTest(test.TestCase):
|
||||
self.assertEqual(entry.links[0]['href'], 'http://localhost/v2/')
|
||||
self.assertEqual(entry.links[0]['rel'], 'self')
|
||||
|
||||
entry = f.entries[1]
|
||||
self.assertEqual(entry.id, 'http://localhost/v3/')
|
||||
self.assertEqual(entry.title, 'Version v3.0')
|
||||
self.assertEqual(entry.updated, '2013-07-23T11:33:21Z')
|
||||
self.assertEqual(len(entry.content), 1)
|
||||
self.assertEqual(entry.content[0].value,
|
||||
'Version v3.0 EXPERIMENTAL (2013-07-23T11:33:21Z)')
|
||||
self.assertEqual(len(entry.links), 1)
|
||||
self.assertEqual(entry.links[0]['href'], 'http://localhost/v3/')
|
||||
self.assertEqual(entry.links[0]['rel'], 'self')
|
||||
|
||||
def test_multi_choice_image(self):
|
||||
req = webob.Request.blank('/images/1')
|
||||
req.accept = "application/json"
|
||||
@ -320,6 +356,28 @@ class VersionsTest(test.TestCase):
|
||||
|
||||
expected = {
|
||||
"choices": [
|
||||
{
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost/v3/images/1",
|
||||
"rel": "self",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type":
|
||||
"application/vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type":
|
||||
"application/vnd.openstack.compute+json;version=3",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "v2.0",
|
||||
"status": "CURRENT",
|
||||
@ -357,9 +415,9 @@ class VersionsTest(test.TestCase):
|
||||
root = etree.XML(res.body)
|
||||
self.assertTrue(root.xpath('/ns:choices', namespaces=NS))
|
||||
versions = root.xpath('ns:version', namespaces=NS)
|
||||
self.assertEqual(len(versions), 1)
|
||||
self.assertEqual(len(versions), 2)
|
||||
|
||||
version = versions[0]
|
||||
version = versions[1]
|
||||
self.assertEqual(version.get('id'), 'v2.0')
|
||||
self.assertEqual(version.get('status'), 'CURRENT')
|
||||
media_types = version.xpath('ns:media-types/ns:media-type',
|
||||
@ -373,6 +431,20 @@ class VersionsTest(test.TestCase):
|
||||
self.assertTrue(common.compare_links(links,
|
||||
[{'rel': 'self', 'href': 'http://localhost/v2/images/1'}]))
|
||||
|
||||
version = versions[0]
|
||||
self.assertEqual(version.get('id'), 'v3.0')
|
||||
self.assertEqual(version.get('status'), 'EXPERIMENTAL')
|
||||
media_types = version.xpath('ns:media-types/ns:media-type',
|
||||
namespaces=NS)
|
||||
self.assertTrue(common.
|
||||
compare_media_types(media_types,
|
||||
EXP_VERSIONS['v3.0']['media-types']
|
||||
))
|
||||
|
||||
links = version.xpath('atom:link', namespaces=NS)
|
||||
self.assertTrue(common.compare_links(links,
|
||||
[{'rel': 'self', 'href': 'http://localhost/v3/images/1'}]))
|
||||
|
||||
def test_multi_choice_server_atom(self):
|
||||
"""
|
||||
Make sure multi choice responses do not have content-type
|
||||
@ -394,6 +466,28 @@ class VersionsTest(test.TestCase):
|
||||
|
||||
expected = {
|
||||
"choices": [
|
||||
{
|
||||
"id": "v3.0",
|
||||
"status": "EXPERIMENTAL",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost/v3/servers/" + uuid,
|
||||
"rel": "self",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type":
|
||||
"application/vnd.openstack.compute+xml;version=3",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type":
|
||||
"application/vnd.openstack.compute+json;version=3",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "v2.0",
|
||||
"status": "CURRENT",
|
||||
@ -461,7 +555,27 @@ class VersionsViewBuilderTests(test.TestCase):
|
||||
expected = "http://example.org/app/v2/"
|
||||
|
||||
builder = views.versions.ViewBuilder(base_url)
|
||||
actual = builder.generate_href()
|
||||
actual = builder.generate_href('v2')
|
||||
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_generate_href_v3(self):
|
||||
base_url = "http://example.org/app/"
|
||||
|
||||
expected = "http://example.org/app/v3/"
|
||||
|
||||
builder = views.versions.ViewBuilder(base_url)
|
||||
actual = builder.generate_href('v3.0')
|
||||
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_generate_href_unknown(self):
|
||||
base_url = "http://example.org/app/"
|
||||
|
||||
expected = "http://example.org/app/v2/"
|
||||
|
||||
builder = views.versions.ViewBuilder(base_url)
|
||||
actual = builder.generate_href('foo')
|
||||
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
|
@ -4,12 +4,23 @@
|
||||
"id": "v2.0",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2/",
|
||||
"href": "http://openstack.example.com/v2/",
|
||||
"rel": "self"
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"updated": "2011-01-21T11:33:21Z"
|
||||
},
|
||||
{
|
||||
"id": "v3.0",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v3/",
|
||||
"rel": "self"
|
||||
}
|
||||
],
|
||||
"status": "EXPERIMENTAL",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -3,4 +3,7 @@
|
||||
<version status="CURRENT" updated="2011-01-21T11:33:21Z" id="v2.0">
|
||||
<atom:link href="http://openstack.example.com/v2/" rel="self"/>
|
||||
</version>
|
||||
<version status="EXPERIMENTAL" updated="2013-07-23T11:33:21Z" id="v3.0">
|
||||
<atom:link href="http://openstack.example.com/v3/" rel="self"/>
|
||||
</version>
|
||||
</versions>
|
||||
|
@ -106,6 +106,7 @@ nova.api.v3.extensions =
|
||||
services = nova.api.openstack.compute.plugins.v3.services:Services
|
||||
simple_tenant_usage = nova.api.openstack.compute.plugins.v3.simple_tenant_usage:SimpleTenantUsage
|
||||
used_limits = nova.api.openstack.compute.plugins.v3.used_limits:UsedLimits
|
||||
versions = nova.api.openstack.compute.plugins.v3.versions:Versions
|
||||
|
||||
nova.api.v3.extensions.server.create =
|
||||
availability_zone = nova.api.openstack.compute.plugins.v3.availability_zone:AvailabilityZone
|
||||
|
Loading…
x
Reference in New Issue
Block a user