Using plain routes for the microversions test

Few microversions unittest still depend on the stevedore to load few
fake controller. This patch uses the plain routes to instead of stevedore.

For the unittest can injects routes which are used for test, the `custom_routes`
parameter is added to the APIRouterV21.

Partial-implement-blueprint api-no-more-extensions-pike

Change-Id: I1a7c653ab21be41b1a41f748a35ec9a57dd8b15d
This commit is contained in:
He Jie Xu 2017-07-19 15:02:29 +08:00
parent c11e9c4848
commit d8928e4a7c
5 changed files with 97 additions and 121 deletions

View File

@ -877,11 +877,18 @@ class APIRouterV21(nova.api.openstack.APIRouterV21):
and method. The URL mapping based on the plain list `ROUTE_LIST` is built
at here. The stevedore based API loading will be replaced by this.
"""
def __init__(self):
def __init__(self, custom_routes=None):
""":param custom_routes: the additional routes can be added by this
parameter. This parameter is used to test on some fake routes
primarily.
"""
self._loaded_extension_info = extension_info.LoadedExtensionInfo()
super(APIRouterV21, self).__init__()
for path, methods in ROUTE_LIST:
if custom_routes is None:
custom_routes = tuple()
for path, methods in ROUTE_LIST + custom_routes:
# NOTE(alex_xu): The variable 'methods' is a dict in normal, since
# the dict includes all the methods supported in the path. But
# if the variable 'method' is a string, it means a redirection.

View File

@ -13,16 +13,15 @@
# under the License.
"""Microversions Test Extension"""
import functools
import webob
from nova.api.openstack import extensions
from nova.api.openstack.compute import routes
from nova.api.openstack import wsgi
from nova.api import validation
from nova.tests.unit.api.openstack.compute import dummy_schema
ALIAS = 'test-microversions'
class MicroversionsController(wsgi.Controller):
@ -124,32 +123,51 @@ class MicroversionsExtendsController3(wsgi.Controller):
resp_obj.obj['extend_ctrlr3'] = 'val_3'
class Microversions(extensions.V21APIExtensionBase):
"""Basic Microversions Extension."""
mv_controller = functools.partial(routes._create_controller,
MicroversionsController, [], [])
name = "Microversions"
alias = ALIAS
version = 1
def get_resources(self):
res1 = extensions.ResourceExtension('microversions',
MicroversionsController())
res2 = extensions.ResourceExtension('microversions2',
MicroversionsController2())
res3 = extensions.ResourceExtension('microversions3',
MicroversionsController3(),
member_actions={"action": "POST"})
res4 = extensions.ResourceExtension('microversions4',
MicroversionsController4())
res5 = extensions.ResourceExtension(
'microversions5', MicroversionsExtendsBaseController())
return [res1, res2, res3, res4, res5]
mv2_controller = functools.partial(routes._create_controller,
MicroversionsController2, [], [])
def get_controller_extensions(self):
extension1 = extensions.ControllerExtension(
self, 'microversions5', MicroversionsExtendsController1())
extension2 = extensions.ControllerExtension(
self, 'microversions5', MicroversionsExtendsController2())
extension3 = extensions.ControllerExtension(
self, 'microversions5', MicroversionsExtendsController3())
return [extension1, extension2, extension3]
mv3_controller = functools.partial(routes._create_controller,
MicroversionsController3, [], [])
mv4_controller = functools.partial(routes._create_controller,
MicroversionsController4, [], [])
mv5_controller = functools.partial(routes._create_controller,
MicroversionsExtendsBaseController,
[
MicroversionsExtendsController1,
MicroversionsExtendsController2,
MicroversionsExtendsController3
], [])
ROUTES = (
('/microversions', {
'GET': [mv_controller, 'index']
}),
('/microversions2', {
'GET': [mv2_controller, 'index']
}),
('/microversions3', {
'POST': [mv3_controller, 'create']
}),
('/microversions3/{id}', {
'PUT': [mv3_controller, 'update']
}),
('/microversions3/{id}/action', {
'POST': [mv3_controller, 'action']
}),
('/microversions4', {
'POST': [mv4_controller, 'create']
}),
('/microversions5/{id}', {
'GET': [mv5_controller, 'show']
}),
)

View File

@ -17,6 +17,7 @@ from oslo_serialization import jsonutils
from nova.api.openstack import api_version_request as api_version
from nova import test
from nova.tests.unit.api.openstack.compute import microversions
from nova.tests.unit.api.openstack import fakes
@ -24,6 +25,10 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
header_name = 'X-OpenStack-Nova-API-Version'
def setUp(self):
super(LegacyMicroversionsTest, self).setUp()
self.app = fakes.wsgi_app_v21(custom_routes=microversions.ROUTES)
def _test_microversions(self, app, req, ret_code, ret_header=None):
req.environ['CONTENT_TYPE'] = "application/json"
@ -43,22 +48,16 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
headers = {self.header_name: 'compute %s' % req_header}
return headers
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_no_header(self, mock_namespace):
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions')
res = req.get_response(app)
def test_microversions_no_header(self):
req = fakes.HTTPRequest.blank('/v2/fake/microversions', method='GET')
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('val', resp_json['param'])
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_return_header(self, mock_namespace):
app = fakes.wsgi_app_v21()
def test_microversions_return_header(self):
req = fakes.HTTPRequest.blank('/v2/fake/microversions')
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('val', resp_json['param'])
@ -69,16 +68,13 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertIn(self.header_name, res.headers.getall('Vary'))
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_return_header_non_default(self, mock_namespace,
mock_maxver):
def test_microversions_return_header_non_default(self,
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("2.3")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions')
req.headers = self._make_header('2.3')
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('val2', resp_json['param'])
@ -89,16 +85,12 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertIn(self.header_name, res.headers.getall('Vary'))
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_return_header_fault(self, mock_namespace,
mock_maxver):
def test_microversions_return_header_fault(self, mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.0")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions')
req.headers = self._make_header('3.0')
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(400, res.status_int)
if 'nova' in self.header_name.lower():
self.assertEqual("3.0", res.headers[self.header_name])
@ -107,16 +99,13 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertIn(self.header_name, res.headers.getall('Vary'))
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def _check_microversion_response(self, url, req_version, resp_param,
mock_namespace, mock_maxver):
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest('2.3')
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank(url)
req.headers = self._make_header(req_version)
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual(resp_param, resp_json['param'])
@ -134,52 +123,39 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
'2.3', 'controller2_val1')
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions2_later_version(self, mock_namespace, mock_maxver):
def test_microversions2_later_version(self, mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.1")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions2')
req.headers = self._make_header('3.0')
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(202, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('controller2_val2', resp_json['param'])
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions2_version_too_high(self, mock_namespace,
mock_maxver):
def test_microversions2_version_too_high(self, mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.5")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions2')
req.headers = {self.header_name: '3.2'}
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(404, res.status_int)
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions2_version_too_low(self, mock_namespace):
app = fakes.wsgi_app_v21()
def test_microversions2_version_too_low(self):
req = fakes.HTTPRequest.blank('/v2/fake/microversions2')
req.headers = {self.header_name: '2.1'}
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(404, res.status_int)
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_global_version_too_high(self, mock_namespace,
def test_microversions_global_version_too_high(self,
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.5")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions2')
req.headers = self._make_header('3.7')
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(406, res.status_int)
res_json = jsonutils.loads(res.body)
self.assertEqual("Version 3.7 is not supported by the API. "
@ -187,19 +163,16 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
res_json['computeFault']['message'])
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_schema(self, mock_namespace, mock_maxver):
def test_microversions_schema(self, mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.3")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions3')
req.method = 'POST'
req.headers = self._make_header('2.2')
req.environ['CONTENT_TYPE'] = "application/json"
req.body = jsonutils.dump_as_bytes({'dummy': {'val': 'foo'}})
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('create_val1', resp_json['param'])
@ -210,39 +183,33 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertIn(self.header_name, res.headers.getall('Vary'))
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_schema_fail(self, mock_namespace, mock_maxver):
def test_microversions_schema_fail(self, mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.3")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions3')
req.method = 'POST'
req.headers = {self.header_name: '2.2'}
req.environ['CONTENT_TYPE'] = "application/json"
req.body = jsonutils.dump_as_bytes({'dummy': {'invalid_param': 'foo'}})
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(400, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertTrue(resp_json['badRequest']['message'].startswith(
"Invalid input for field/attribute dummy."))
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_schema_out_of_version_check(self, mock_namespace,
def test_microversions_schema_out_of_version_check(self,
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.3")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions3/1')
req.method = 'PUT'
req.headers = self._make_header('2.2')
req.body = jsonutils.dump_as_bytes({'dummy': {'inv_val': 'foo'}})
req.environ['CONTENT_TYPE'] = "application/json"
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('update_val1', resp_json['param'])
@ -252,20 +219,17 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertEqual("compute 2.2", res.headers[self.header_name])
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_microversions_schema_second_version(self, mock_namespace,
mock_maxver):
def test_microversions_schema_second_version(self,
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("3.3")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions3/1')
req.headers = self._make_header('2.10')
req.environ['CONTENT_TYPE'] = "application/json"
req.method = 'PUT'
req.body = jsonutils.dump_as_bytes({'dummy': {'val2': 'foo'}})
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual('update_val1', resp_json['param'])
@ -275,20 +239,16 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertEqual("compute 2.10", res.headers[self.header_name])
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def _test_microversions_inner_function(self, version, expected_resp,
mock_namespace,
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("2.2")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions4')
req.headers = self._make_header(version)
req.environ['CONTENT_TYPE'] = "application/json"
req.method = 'POST'
req.body = b''
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
resp_json = jsonutils.loads(res.body)
self.assertEqual(expected_resp, resp_json['param'])
@ -303,15 +263,12 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self._test_microversions_inner_function('2.1', 'controller4_val1')
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def test_with_extends_decorator(self, mock_namespace, mock_maxver):
def test_with_extends_decorator(self, mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest('2.4')
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions5/item')
req.headers = {'X-OpenStack-Nova-API-Version': '2.4'}
res = req.get_response(app)
res = req.get_response(self.app)
self.assertEqual(200, res.status_int)
expected_res = {
@ -326,21 +283,17 @@ class LegacyMicroversionsTest(test.NoDBTestCase):
self.assertEqual(3, len(resp_json))
@mock.patch("nova.api.openstack.api_version_request.max_api_version")
@mock.patch("nova.api.openstack.APIRouterV21.api_extension_namespace",
return_value='nova.api.v21.test_extensions')
def _test_microversions_actions(self, ret_code, ret_header, req_header,
mock_namespace,
mock_maxver):
mock_maxver.return_value = api_version.APIVersionRequest("2.3")
app = fakes.wsgi_app_v21()
req = fakes.HTTPRequest.blank('/v2/fake/microversions3/1/action')
if req_header:
req.headers = self._make_header(req_header)
req.method = 'POST'
req.body = jsonutils.dump_as_bytes({'foo': None})
res = self._test_microversions(app, req, ret_code,
res = self._test_microversions(self.app, req, ret_code,
ret_header=ret_header)
if ret_code == 202:
resp_json = jsonutils.loads(res.body)

View File

@ -63,9 +63,10 @@ def fake_wsgi(self, req):
return self.application
def wsgi_app_v21(fake_auth_context=None, v2_compatible=False):
def wsgi_app_v21(fake_auth_context=None, v2_compatible=False,
custom_routes=None):
inner_app_v21 = compute.APIRouterV21()
inner_app_v21 = compute.APIRouterV21(custom_routes=custom_routes)
if v2_compatible:
inner_app_v21 = openstack_api.LegacyV2CompatibleWrapper(inner_app_v21)

View File

@ -73,9 +73,6 @@ wsgi_scripts =
nova-api-wsgi = nova.api.openstack.compute.wsgi:init_application
nova-metadata-wsgi = nova.api.metadata.wsgi:init_application
nova.api.v21.test_extensions =
microversions = nova.tests.unit.api.openstack.compute.microversions:Microversions
nova.ipv6_backend =
rfc2462 = nova.ipv6.rfc2462
account_identifier = nova.ipv6.account_identifier