Refactor wsgi of v2 API
Original purpose of this patch is that replacing deprecated webob.Accept.best_match method to acceptable_offers to analize 'Accept' header of a HTTP request. Instead of fixing legacy wsgi code, refactor v2 wsgi code not to use legacy wsgi code because legacy wsgi code is complicated and v2 wsgi code uses legacy wsgi code very little. Original purpose mentioned above is included in the refactoring at the same time. This patch includes the followng changes related to wsgi framework too. * check of Content-Type header is also enhanced. * check of Version header for api_versions API is relaxed. Change-Id: I4ca0beda850ecd14d65d7bc1a59d465c5ecfeacb
This commit is contained in:
parent
76adf42ead
commit
00d8f69f09
@ -35,20 +35,27 @@ supported_versions_v2 = {
|
|||||||
|
|
||||||
CURRENT_VERSION = '2.0.0'
|
CURRENT_VERSION = '2.0.0'
|
||||||
|
|
||||||
supported_versions = [
|
v1_versions = [
|
||||||
|
item['version'] for item in supported_versions_v1['apiVersions']
|
||||||
|
]
|
||||||
|
|
||||||
|
v2_versions = [
|
||||||
item['version'] for item in supported_versions_v2['apiVersions']
|
item['version'] for item in supported_versions_v2['apiVersions']
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class APIVersion(object):
|
class APIVersion(object):
|
||||||
|
|
||||||
def __init__(self, version_string=None):
|
def __init__(self, version_string=None, supported_versions=None):
|
||||||
self.ver_major = 0
|
self.ver_major = 0
|
||||||
self.ver_minor = 0
|
self.ver_minor = 0
|
||||||
self.ver_patch = 0
|
self.ver_patch = 0
|
||||||
|
|
||||||
if version_string is None:
|
if version_string is None:
|
||||||
return
|
if supported_versions is None:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
raise sol_ex.APIVersionMissing()
|
||||||
|
|
||||||
version_string = self._get_version_id(version_string)
|
version_string = self._get_version_id(version_string)
|
||||||
match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)\.([1-9]\d*|0)$",
|
match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)\.([1-9]\d*|0)$",
|
||||||
@ -60,7 +67,8 @@ class APIVersion(object):
|
|||||||
else:
|
else:
|
||||||
raise sol_ex.InvalidAPIVersionString(version=version_string)
|
raise sol_ex.InvalidAPIVersionString(version=version_string)
|
||||||
|
|
||||||
if version_string not in supported_versions:
|
if (supported_versions is not None and
|
||||||
|
version_string not in supported_versions):
|
||||||
raise sol_ex.APIVersionNotSupported(version=version_string)
|
raise sol_ex.APIVersionNotSupported(version=version_string)
|
||||||
|
|
||||||
def _get_version_id(self, version_string):
|
def _get_version_id(self, version_string):
|
||||||
|
@ -18,9 +18,10 @@ import webob
|
|||||||
|
|
||||||
import oslo_i18n as i18n
|
import oslo_i18n as i18n
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
from tacker.common import exceptions as common_ex
|
from tacker.common import exceptions as common_ex
|
||||||
from tacker import wsgi
|
from tacker import context
|
||||||
|
|
||||||
from tacker.sol_refactored.api import api_version
|
from tacker.sol_refactored.api import api_version
|
||||||
from tacker.sol_refactored.common import config
|
from tacker.sol_refactored.common import config
|
||||||
@ -30,6 +31,28 @@ from tacker.sol_refactored.common import exceptions as sol_ex
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SolRequest(webob.Request):
|
||||||
|
|
||||||
|
def best_match_accept(self, content_types):
|
||||||
|
offers = self.accept.acceptable_offers(content_types)
|
||||||
|
if not offers:
|
||||||
|
raise sol_ex.NotAllowedContentType(header=self.accept.header_value)
|
||||||
|
|
||||||
|
return offers[0][0]
|
||||||
|
|
||||||
|
def best_match_language(self):
|
||||||
|
if not self.accept_language:
|
||||||
|
return None
|
||||||
|
all_languages = i18n.get_available_languages('tacker')
|
||||||
|
return self.accept_language.best_match(all_languages)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self):
|
||||||
|
if 'tacker.context' not in self.environ:
|
||||||
|
self.environ['tacker.context'] = context.get_admin_context()
|
||||||
|
return self.environ['tacker.context']
|
||||||
|
|
||||||
|
|
||||||
class SolResponse(object):
|
class SolResponse(object):
|
||||||
|
|
||||||
# SOL013 4.2.3 Response header field
|
# SOL013 4.2.3 Response header field
|
||||||
@ -47,7 +70,7 @@ class SolResponse(object):
|
|||||||
self.headers.setdefault('version', api_version.CURRENT_VERSION)
|
self.headers.setdefault('version', api_version.CURRENT_VERSION)
|
||||||
self.headers.setdefault('accept-ranges', 'none')
|
self.headers.setdefault('accept-ranges', 'none')
|
||||||
|
|
||||||
def serialize(self, request, content_type):
|
def serialize(self, content_type):
|
||||||
self.headers.setdefault('content_type', content_type)
|
self.headers.setdefault('content_type', content_type)
|
||||||
content_type = self.headers['content_type']
|
content_type = self.headers['content_type']
|
||||||
if self.body is None:
|
if self.body is None:
|
||||||
@ -57,8 +80,7 @@ class SolResponse(object):
|
|||||||
elif content_type == 'application/zip':
|
elif content_type == 'application/zip':
|
||||||
body = self.body
|
body = self.body
|
||||||
else: # 'application/json'
|
else: # 'application/json'
|
||||||
serializer = wsgi.JSONDictSerializer()
|
body = jsonutils.dump_as_bytes(self.body)
|
||||||
body = serializer.serialize(self.body)
|
|
||||||
if len(body) > config.CONF.v2_vnfm.max_content_length:
|
if len(body) > config.CONF.v2_vnfm.max_content_length:
|
||||||
raise sol_ex.ResponseTooBig(
|
raise sol_ex.ResponseTooBig(
|
||||||
size=config.CONF.v2_vnfm.max_content_length)
|
size=config.CONF.v2_vnfm.max_content_length)
|
||||||
@ -71,8 +93,7 @@ class SolResponse(object):
|
|||||||
|
|
||||||
class SolErrorResponse(SolResponse):
|
class SolErrorResponse(SolResponse):
|
||||||
|
|
||||||
def __init__(self, ex, req):
|
def __init__(self, ex, user_locale):
|
||||||
user_locale = req.best_match_language()
|
|
||||||
problem_details = {}
|
problem_details = {}
|
||||||
if isinstance(ex, sol_ex.SolException):
|
if isinstance(ex, sol_ex.SolException):
|
||||||
problem_details = ex.make_problem_details()
|
problem_details = ex.make_problem_details()
|
||||||
@ -94,28 +115,26 @@ class SolErrorResponse(SolResponse):
|
|||||||
problem_details)
|
problem_details)
|
||||||
|
|
||||||
|
|
||||||
class SolResource(wsgi.Application):
|
class SolResource(object):
|
||||||
|
|
||||||
def __init__(self, controller, policy_name=None):
|
def __init__(self, controller, policy_name=None):
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.policy_name = policy_name
|
self.policy_name = policy_name
|
||||||
self.deserializer = wsgi.RequestDeserializer()
|
|
||||||
|
|
||||||
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
@webob.dec.wsgify(RequestClass=SolRequest)
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
LOG.info("%(method)s %(url)s", {"method": request.method,
|
LOG.info("%(method)s %(url)s", {"method": request.method,
|
||||||
"url": request.url})
|
"url": request.url})
|
||||||
try:
|
try:
|
||||||
action, args, accept = self.deserializer.deserialize(request)
|
action, args, accept = self._deserialize_request(request)
|
||||||
self.check_api_version(request)
|
self._check_api_version(request, action)
|
||||||
self.check_policy(request, action)
|
self._check_policy(request, action)
|
||||||
result = self.dispatch(request, action, args)
|
result = self._dispatch(request, action, args)
|
||||||
response = result.serialize(request, accept)
|
response = result.serialize(accept)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
result = SolErrorResponse(ex, request)
|
result = SolErrorResponse(ex, request.best_match_language())
|
||||||
try:
|
try:
|
||||||
response = result.serialize(request,
|
response = result.serialize('application/problem+json')
|
||||||
'application/problem+json')
|
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception("Unknown error")
|
LOG.exception("Unknown error")
|
||||||
return webob.exc.HTTPBadRequest(explanation="Unknown error")
|
return webob.exc.HTTPBadRequest(explanation="Unknown error")
|
||||||
@ -125,33 +144,83 @@ class SolResource(wsgi.Application):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def check_api_version(self, request):
|
def _check_api_version(self, request, action):
|
||||||
# check and set api_version
|
# check and set api_version
|
||||||
ver = request.headers.get("Version")
|
ver = request.headers.get("Version")
|
||||||
if ver is None:
|
request.context.api_version = api_version.APIVersion(
|
||||||
LOG.info("Version missing")
|
ver, self.controller.supported_api_versions(action))
|
||||||
raise sol_ex.APIVersionMissing()
|
|
||||||
request.context.api_version = api_version.APIVersion(ver)
|
|
||||||
|
|
||||||
def check_policy(self, request, action):
|
def _check_policy(self, request, action):
|
||||||
if self.policy_name is None:
|
if self.policy_name is None:
|
||||||
return
|
return
|
||||||
if action == 'reject':
|
if action == 'reject':
|
||||||
return
|
return
|
||||||
request.context.can(self.policy_name.format(action))
|
request.context.can(self.policy_name.format(action))
|
||||||
|
|
||||||
def dispatch(self, request, action, action_args):
|
def _dispatch(self, request, action, action_args):
|
||||||
controller_method = getattr(self.controller, action)
|
controller_method = getattr(self.controller, action)
|
||||||
return controller_method(request=request, **action_args)
|
return controller_method(request=request, **action_args)
|
||||||
|
|
||||||
|
def _deserialize_request(self, request):
|
||||||
|
action_args = request.environ['wsgiorg.routing_args'][1].copy()
|
||||||
|
action = action_args.pop('action', None)
|
||||||
|
action_args.pop('controller', None)
|
||||||
|
|
||||||
class SolAPIRouter(wsgi.Router):
|
body = self._deserialize_body(request, action)
|
||||||
|
if body is not None:
|
||||||
|
action_args.update({'body': body})
|
||||||
|
|
||||||
|
accept = request.best_match_accept(
|
||||||
|
self.controller.allowed_accept(action))
|
||||||
|
|
||||||
|
return (action, action_args, accept)
|
||||||
|
|
||||||
|
def _deserialize_body(self, request, action):
|
||||||
|
if request.method not in ('POST', 'PATCH', 'PUT'):
|
||||||
|
return
|
||||||
|
|
||||||
|
if not request.body:
|
||||||
|
LOG.debug("Empty body provided in request")
|
||||||
|
return
|
||||||
|
|
||||||
|
content_type = request.content_type
|
||||||
|
allowed_content_types = self.controller.allowed_content_types(action)
|
||||||
|
if not content_type:
|
||||||
|
content_type = allowed_content_types[0]
|
||||||
|
elif content_type not in allowed_content_types:
|
||||||
|
raise sol_ex.NotSupportedContentType(header=content_type)
|
||||||
|
|
||||||
|
if content_type == 'application/zip':
|
||||||
|
return request.body_file
|
||||||
|
else:
|
||||||
|
# assume json format
|
||||||
|
# ex. 'application/json', 'application/mergepatch+json'
|
||||||
|
try:
|
||||||
|
return request.json
|
||||||
|
except Exception:
|
||||||
|
raise sol_ex.MalformedRequestBody()
|
||||||
|
|
||||||
|
|
||||||
|
class SolAPIRouter(object):
|
||||||
|
"""WSGI middleware that maps incoming requests to WSGI apps."""
|
||||||
|
|
||||||
controller = None
|
controller = None
|
||||||
route_list = {}
|
route_list = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def factory(cls, global_config, **local_config):
|
||||||
|
"""Return an instance of the WSGI Router class."""
|
||||||
|
return cls()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SolAPIRouter, self).__init__(routes.Mapper())
|
mapper = routes.Mapper()
|
||||||
|
self._setup_routes(mapper)
|
||||||
|
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
|
||||||
|
mapper)
|
||||||
|
|
||||||
|
@webob.dec.wsgify
|
||||||
|
def __call__(self, req):
|
||||||
|
return self._router
|
||||||
|
|
||||||
def _setup_routes(self, mapper):
|
def _setup_routes(self, mapper):
|
||||||
for path, methods in self.route_list:
|
for path, methods in self.route_list:
|
||||||
@ -173,8 +242,44 @@ class SolAPIRouter(wsgi.Router):
|
|||||||
action='reject',
|
action='reject',
|
||||||
conditions={'method': missing_methods})
|
conditions={'method': missing_methods})
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@webob.dec.wsgify(RequestClass=SolRequest)
|
||||||
|
def _dispatch(req):
|
||||||
|
"""Dispatch a Request.
|
||||||
|
|
||||||
|
Called by self._router after matching the incoming request to a route
|
||||||
|
and putting the information into req.environ. Either returns 404
|
||||||
|
or the routed WSGI app's response.
|
||||||
|
"""
|
||||||
|
match = req.environ['wsgiorg.routing_args'][1]
|
||||||
|
if not match:
|
||||||
|
language = req.best_match_language()
|
||||||
|
msg = 'The resource could not be found.'
|
||||||
|
msg = i18n.translate(msg, language)
|
||||||
|
return webob.exc.HTTPNotFound(explanation=msg)
|
||||||
|
app = match['controller']
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
class SolAPIController(object):
|
class SolAPIController(object):
|
||||||
|
|
||||||
def reject(self, request, **kwargs):
|
def reject(self, request, **kwargs):
|
||||||
raise sol_ex.MethodNotAllowed(method=request.method)
|
raise sol_ex.MethodNotAllowed(method=request.method)
|
||||||
|
|
||||||
|
def supported_api_versions(self, action):
|
||||||
|
# NOTE: support v2 API by default. if a contorller supports
|
||||||
|
# and/or v1 API, or depending on action, override this method
|
||||||
|
# in the subclass.
|
||||||
|
return api_version.v2_versions
|
||||||
|
|
||||||
|
def allowed_content_types(self, action):
|
||||||
|
# NOTE: if other than 'application/json' is expected depending
|
||||||
|
# on action, override this method in the subclass.
|
||||||
|
# NOTE: 'text/plain' is allowed for backward compatibility.
|
||||||
|
# the body is assumed as json.
|
||||||
|
return ['application/json', 'text/plain']
|
||||||
|
|
||||||
|
def allowed_accept(self, action):
|
||||||
|
# NOTE: if other than 'application/json' is expected depending
|
||||||
|
# on action, override this method in the subclass.
|
||||||
|
return ['application/json']
|
||||||
|
@ -80,6 +80,11 @@ class SolHttpError409(SolException):
|
|||||||
title = 'Conflict'
|
title = 'Conflict'
|
||||||
|
|
||||||
|
|
||||||
|
class SolHttpError415(SolException):
|
||||||
|
status = 415
|
||||||
|
title = 'Unsupported Media Type'
|
||||||
|
|
||||||
|
|
||||||
class SolHttpError422(SolException):
|
class SolHttpError422(SolException):
|
||||||
status = 422
|
status = 422
|
||||||
title = 'Unprocessable Entity'
|
title = 'Unprocessable Entity'
|
||||||
@ -328,3 +333,17 @@ class UpdateK8SResourceFailed(SolHttpError400):
|
|||||||
|
|
||||||
class NotSupportOperationType(SolHttpError404):
|
class NotSupportOperationType(SolHttpError404):
|
||||||
message = _("This operation is not currently supported.")
|
message = _("This operation is not currently supported.")
|
||||||
|
|
||||||
|
|
||||||
|
class NotAllowedContentType(SolHttpError406):
|
||||||
|
message = _("Content type '%(header)s' specified in 'Accept' header"
|
||||||
|
" is not allowed.")
|
||||||
|
|
||||||
|
|
||||||
|
class NotSupportedContentType(SolHttpError415):
|
||||||
|
message = _("Content type '%(header)s' specified in 'Content-Type' header"
|
||||||
|
" is not allowed.")
|
||||||
|
|
||||||
|
|
||||||
|
class MalformedRequestBody(SolHttpError400):
|
||||||
|
message = _("Malformed request body.")
|
||||||
|
@ -19,7 +19,7 @@ from datetime import datetime
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from tacker.sol_refactored.api.api_version import supported_versions_v2
|
from tacker.sol_refactored.api import api_version
|
||||||
from tacker.sol_refactored.api.schemas import vnflcm_v2 as schema
|
from tacker.sol_refactored.api.schemas import vnflcm_v2 as schema
|
||||||
from tacker.sol_refactored.api import validator
|
from tacker.sol_refactored.api import validator
|
||||||
from tacker.sol_refactored.api import wsgi as sol_wsgi
|
from tacker.sol_refactored.api import wsgi as sol_wsgi
|
||||||
@ -53,7 +53,7 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
|
|||||||
self._subsc_view = vnflcm_view.SubscriptionViewBuilder(self.endpoint)
|
self._subsc_view = vnflcm_view.SubscriptionViewBuilder(self.endpoint)
|
||||||
|
|
||||||
def api_versions(self, request):
|
def api_versions(self, request):
|
||||||
return sol_wsgi.SolResponse(200, supported_versions_v2)
|
return sol_wsgi.SolResponse(200, api_version.supported_versions_v2)
|
||||||
|
|
||||||
@validator.schema(schema.CreateVnfRequest_V200, '2.0.0')
|
@validator.schema(schema.CreateVnfRequest_V200, '2.0.0')
|
||||||
def create(self, request, body):
|
def create(self, request, body):
|
||||||
@ -652,3 +652,21 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
|
|||||||
lcmocc.delete(context)
|
lcmocc.delete(context)
|
||||||
|
|
||||||
return sol_wsgi.SolResponse(204, None)
|
return sol_wsgi.SolResponse(204, None)
|
||||||
|
|
||||||
|
def supported_api_versions(self, action):
|
||||||
|
if action == 'api_versions':
|
||||||
|
# support all versions and it is OK there is no Version header.
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return api_version.v2_versions
|
||||||
|
|
||||||
|
def allowed_content_types(self, action):
|
||||||
|
if action == 'update':
|
||||||
|
# Content-Type of Modify request shall be
|
||||||
|
# 'application/mergepatch+json' according to SOL spec.
|
||||||
|
# But 'application/json' and 'text/plain' is OK for backward
|
||||||
|
# compatibility.
|
||||||
|
return ['application/mergepatch+json', 'application/json',
|
||||||
|
'text/plain']
|
||||||
|
else:
|
||||||
|
return ['application/json', 'text/plain']
|
||||||
|
@ -25,3 +25,7 @@ class VnfLcmVersionsController(sol_wsgi.SolAPIController):
|
|||||||
body = {"uriPrefix": "/vnflcm",
|
body = {"uriPrefix": "/vnflcm",
|
||||||
"apiVersions": api_versions}
|
"apiVersions": api_versions}
|
||||||
return sol_wsgi.SolResponse(200, body)
|
return sol_wsgi.SolResponse(200, body)
|
||||||
|
|
||||||
|
def supported_api_versions(self, action):
|
||||||
|
# support all versions and it is OK there is no Version header.
|
||||||
|
return None
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from tacker.sol_refactored.api import api_version
|
from tacker.sol_refactored.api import api_version
|
||||||
from tacker.sol_refactored.common import exceptions as sol_ex
|
from tacker.sol_refactored.common import exceptions as sol_ex
|
||||||
from tacker.tests import base
|
from tacker.tests import base
|
||||||
@ -26,37 +24,37 @@ class TestAPIVersion(base.BaseTestCase):
|
|||||||
vers = api_version.APIVersion()
|
vers = api_version.APIVersion()
|
||||||
self.assertTrue(vers.is_null())
|
self.assertTrue(vers.is_null())
|
||||||
|
|
||||||
@mock.patch.object(api_version, 'supported_versions',
|
|
||||||
new=["3.1.4159", "2.0.0"])
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
|
supported_versions = ["3.1.4159", "2.0.0"]
|
||||||
for vers, vers_str in [("2.0.0", "2.0.0"),
|
for vers, vers_str in [("2.0.0", "2.0.0"),
|
||||||
("3.1.4159", "3.1.4159"),
|
("3.1.4159", "3.1.4159"),
|
||||||
("2.0.0-impl:foobar", "2.0.0")]:
|
("2.0.0-impl:foobar", "2.0.0")]:
|
||||||
v = api_version.APIVersion(vers)
|
v = api_version.APIVersion(vers, supported_versions)
|
||||||
self.assertEqual(str(v), vers_str)
|
self.assertEqual(str(v), vers_str)
|
||||||
|
|
||||||
def test_init_exceptions(self):
|
def test_init_exceptions(self):
|
||||||
|
supported_versions = ["2.0.0"]
|
||||||
self.assertRaises(sol_ex.InvalidAPIVersionString,
|
self.assertRaises(sol_ex.InvalidAPIVersionString,
|
||||||
api_version.APIVersion, "0.1.2")
|
api_version.APIVersion, "0.1.2", supported_versions)
|
||||||
|
|
||||||
self.assertRaises(sol_ex.APIVersionNotSupported,
|
self.assertRaises(sol_ex.APIVersionNotSupported,
|
||||||
api_version.APIVersion, "9.9.9")
|
api_version.APIVersion, "9.9.9", supported_versions)
|
||||||
|
|
||||||
@mock.patch.object(api_version, 'supported_versions',
|
|
||||||
new=["1.3.0", "1.3.1", "2.0.0"])
|
|
||||||
def test_compare(self):
|
def test_compare(self):
|
||||||
self.assertTrue(api_version.APIVersion("1.3.0") <
|
supported_versions = ["1.3.0", "1.3.1", "2.0.0"]
|
||||||
api_version.APIVersion("1.3.1"))
|
self.assertTrue(api_version.APIVersion("1.3.0", supported_versions) <
|
||||||
|
api_version.APIVersion("1.3.1", supported_versions))
|
||||||
|
|
||||||
self.assertTrue(api_version.APIVersion("2.0.0") >
|
self.assertTrue(api_version.APIVersion("2.0.0", supported_versions) >
|
||||||
api_version.APIVersion("1.3.1"))
|
api_version.APIVersion("1.3.1", supported_versions))
|
||||||
|
|
||||||
@mock.patch.object(api_version, 'supported_versions',
|
|
||||||
new=["1.3.0", "1.3.1", "2.0.0"])
|
|
||||||
def test_matches(self):
|
def test_matches(self):
|
||||||
|
supported_versions = ["1.3.0", "1.3.1", "2.0.0"]
|
||||||
vers = api_version.APIVersion("2.0.0")
|
vers = api_version.APIVersion("2.0.0")
|
||||||
self.assertTrue(vers.matches(api_version.APIVersion("1.3.0"),
|
self.assertTrue(
|
||||||
api_version.APIVersion()))
|
vers.matches(api_version.APIVersion("1.3.0", supported_versions),
|
||||||
|
api_version.APIVersion()))
|
||||||
|
|
||||||
self.assertFalse(vers.matches(api_version.APIVersion(),
|
self.assertFalse(
|
||||||
api_version.APIVersion("1.3.1")))
|
vers.matches(api_version.APIVersion(),
|
||||||
|
api_version.APIVersion("1.3.1", supported_versions)))
|
||||||
|
@ -56,25 +56,28 @@ class TestValidator(base.BaseTestCase):
|
|||||||
def _test_method(self, request, body):
|
def _test_method(self, request, body):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@mock.patch.object(api_version, 'supported_versions',
|
|
||||||
new=['2.0.0', '2.0.1', '2.0.2', '2.1.0', '2.2.0'])
|
|
||||||
def test_validator(self):
|
def test_validator(self):
|
||||||
|
supported_versions = ['2.0.0', '2.0.1', '2.0.2', '2.1.0', '2.2.0']
|
||||||
body = {"vnfdId": "vnfd_id", "ProductId": "product_id"}
|
body = {"vnfdId": "vnfd_id", "ProductId": "product_id"}
|
||||||
for ok_ver in ['2.0.0', '2.0.1', '2.0.2']:
|
for ok_ver in ['2.0.0', '2.0.1', '2.0.2']:
|
||||||
self.context.api_version = api_version.APIVersion(ok_ver)
|
self.context.api_version = api_version.APIVersion(
|
||||||
|
ok_ver, supported_versions)
|
||||||
result = self._test_method(request=self.request, body=body)
|
result = self._test_method(request=self.request, body=body)
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
for ng_ver in ['2.1.0', '2.2.0']:
|
for ng_ver in ['2.1.0', '2.2.0']:
|
||||||
self.context.api_version = api_version.APIVersion(ng_ver)
|
self.context.api_version = api_version.APIVersion(
|
||||||
|
ng_ver, supported_versions)
|
||||||
self.assertRaises(sol_ex.SolValidationError,
|
self.assertRaises(sol_ex.SolValidationError,
|
||||||
self._test_method, request=self.request, body=body)
|
self._test_method, request=self.request, body=body)
|
||||||
|
|
||||||
body = {"vnfdId": "vnfd_id", "flavourId": "flavour_id"}
|
body = {"vnfdId": "vnfd_id", "flavourId": "flavour_id"}
|
||||||
for ok_ver in ['2.1.0', '2.2.0']:
|
for ok_ver in ['2.1.0', '2.2.0']:
|
||||||
self.context.api_version = api_version.APIVersion(ok_ver)
|
self.context.api_version = api_version.APIVersion(
|
||||||
|
ok_ver, supported_versions)
|
||||||
result = self._test_method(request=self.request, body=body)
|
result = self._test_method(request=self.request, body=body)
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
for ng_ver in ['2.0.0', '2.0.1', '2.0.2']:
|
for ng_ver in ['2.0.0', '2.0.1', '2.0.2']:
|
||||||
self.context.api_version = api_version.APIVersion(ng_ver)
|
self.context.api_version = api_version.APIVersion(
|
||||||
|
ng_ver, supported_versions)
|
||||||
self.assertRaises(sol_ex.SolValidationError,
|
self.assertRaises(sol_ex.SolValidationError,
|
||||||
self._test_method, request=self.request, body=body)
|
self._test_method, request=self.request, body=body)
|
||||||
|
@ -27,7 +27,7 @@ class TestWsgi(base.TestCase):
|
|||||||
body = {"key": "value0123456789"}
|
body = {"key": "value0123456789"}
|
||||||
response = sol_wsgi.SolResponse(200, body)
|
response = sol_wsgi.SolResponse(200, body)
|
||||||
self.assertRaises(sol_ex.ResponseTooBig,
|
self.assertRaises(sol_ex.ResponseTooBig,
|
||||||
response.serialize, mock.Mock(), 'application/json')
|
response.serialize, 'application/json')
|
||||||
|
|
||||||
def test_unknown_error_response(self):
|
def test_unknown_error_response(self):
|
||||||
err_msg = "Test error"
|
err_msg = "Test error"
|
||||||
@ -41,8 +41,8 @@ class TestWsgi(base.TestCase):
|
|||||||
self.assertEqual(problem_details, response.body)
|
self.assertEqual(problem_details, response.body)
|
||||||
|
|
||||||
def test_check_api_version_no_version(self):
|
def test_check_api_version_no_version(self):
|
||||||
resource = sol_wsgi.SolResource(mock.Mock())
|
resource = sol_wsgi.SolResource(sol_wsgi.SolAPIController())
|
||||||
request = mock.Mock()
|
request = mock.Mock()
|
||||||
request.headers = {}
|
request.headers = {}
|
||||||
self.assertRaises(sol_ex.APIVersionMissing,
|
self.assertRaises(sol_ex.APIVersionMissing,
|
||||||
resource.check_api_version, request)
|
resource._check_api_version, request, 'action')
|
||||||
|
Loading…
Reference in New Issue
Block a user