diff --git a/nova/api/openstack/compute/routes.py b/nova/api/openstack/compute/routes.py index d21e6314849e..6570bd80fc2f 100644 --- a/nova/api/openstack/compute/routes.py +++ b/nova/api/openstack/compute/routes.py @@ -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. diff --git a/nova/tests/unit/api/openstack/compute/microversions.py b/nova/tests/unit/api/openstack/compute/microversions.py index 89f720d97ffb..862be55d0d83 100644 --- a/nova/tests/unit/api/openstack/compute/microversions.py +++ b/nova/tests/unit/api/openstack/compute/microversions.py @@ -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'] + }), +) diff --git a/nova/tests/unit/api/openstack/compute/test_microversions.py b/nova/tests/unit/api/openstack/compute/test_microversions.py index 7405252e5efd..104c5eb4e299 100644 --- a/nova/tests/unit/api/openstack/compute/test_microversions.py +++ b/nova/tests/unit/api/openstack/compute/test_microversions.py @@ -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) diff --git a/nova/tests/unit/api/openstack/fakes.py b/nova/tests/unit/api/openstack/fakes.py index 74c3f26955d1..8167b34e2a32 100644 --- a/nova/tests/unit/api/openstack/fakes.py +++ b/nova/tests/unit/api/openstack/fakes.py @@ -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) diff --git a/setup.cfg b/setup.cfg index 73768fa9d191..b02cec4f3766 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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