Merge "Refactor version negotiation middleware"
This commit is contained in:
commit
e51e7e88fc
|
@ -15,12 +15,10 @@ from senlin.api.middleware import fault
|
|||
from senlin.api.middleware import trust
|
||||
from senlin.api.middleware import version_negotiation as vn
|
||||
from senlin.api.middleware import webhook
|
||||
from senlin.api.openstack import versions
|
||||
|
||||
|
||||
def version_filter(app, conf, **local_conf):
|
||||
return vn.VersionNegotiationFilter(versions.Controller, app,
|
||||
conf, **local_conf)
|
||||
return vn.VersionNegotiationFilter(app, conf)
|
||||
|
||||
|
||||
def fault_filter(app, conf, **local_conf):
|
||||
|
|
|
@ -34,8 +34,8 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
class VersionNegotiationFilter(wsgi.Middleware):
|
||||
|
||||
def __init__(self, version_controller, app, conf, **local_conf):
|
||||
self.versions_app = version_controller(conf)
|
||||
def __init__(self, app, conf):
|
||||
self.versions_app = os_ver.Controller(conf)
|
||||
self.version_uri_regex = re.compile(r"^v([1-9]\d*)\.?([1-9]\d*|0)?$")
|
||||
self.conf = conf
|
||||
super(VersionNegotiationFilter, self).__init__(app)
|
||||
|
@ -55,7 +55,7 @@ class VersionNegotiationFilter(wsgi.Middleware):
|
|||
return self.versions_app
|
||||
|
||||
# Check if there is a requested (micro-)version for API
|
||||
self.check_version_request(req)
|
||||
self._check_version_request(req)
|
||||
match = self._match_version_string(req.path_info_peek(), req)
|
||||
if match:
|
||||
major = req.environ['api.major']
|
||||
|
@ -120,7 +120,7 @@ class VersionNegotiationFilter(wsgi.Middleware):
|
|||
|
||||
return match is not None
|
||||
|
||||
def check_version_request(self, req):
|
||||
def _check_version_request(self, req):
|
||||
"""Set API version request based on the request header."""
|
||||
api_version = microversion_parse.get_version(req.headers,
|
||||
service_type='clustering')
|
||||
|
|
|
@ -19,7 +19,6 @@ from senlin.api.middleware import fault
|
|||
from senlin.api.middleware import trust
|
||||
from senlin.api.middleware import version_negotiation as vn
|
||||
from senlin.api.middleware import webhook
|
||||
from senlin.api.openstack import versions
|
||||
from senlin.tests.unit.common import base
|
||||
|
||||
|
||||
|
@ -40,9 +39,7 @@ class MiddlewareFilterTest(base.SenlinTestCase):
|
|||
actual = mw.version_filter(self.app, self.conf, **self.local_conf)
|
||||
|
||||
self.assertEqual(exp, actual)
|
||||
mock_vnf.assert_called_once_with(versions.Controller,
|
||||
self.app, self.conf,
|
||||
**self.local_conf)
|
||||
mock_vnf.assert_called_once_with(self.app, self.conf)
|
||||
|
||||
@mock.patch.object(fault, 'FaultWrapper')
|
||||
def test_faultwrap_filter(self, mock_fw):
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import six
|
||||
import webob
|
||||
|
||||
|
@ -21,170 +22,154 @@ from senlin.common import exception
|
|||
from senlin.tests.unit.common import base
|
||||
|
||||
|
||||
class VersionController(object):
|
||||
pass
|
||||
@mock.patch("senlin.api.openstack.versions.Controller")
|
||||
class VersionNegotiationTest(base.SenlinTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(VersionNegotiationTest, self).setUp()
|
||||
|
||||
class VersionNegotiationMiddlewareTest(base.SenlinTestCase):
|
||||
def _version_controller_factory(self, conf):
|
||||
return VersionController()
|
||||
|
||||
def test_match_version_string(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_match_version_string(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({})
|
||||
major = 1
|
||||
minor = 0
|
||||
|
||||
match = version_negotiation._match_version_string(
|
||||
'v{0}.{1}'.format(major, minor), request)
|
||||
match = vnf._match_version_string('v{0}.{1}'.format(major, minor),
|
||||
request)
|
||||
self.assertTrue(match)
|
||||
self.assertEqual(major, request.environ['api.major'])
|
||||
self.assertEqual(minor, request.environ['api.minor'])
|
||||
|
||||
def test_not_match_version_string(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_not_match_version_string(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({})
|
||||
|
||||
match = version_negotiation._match_version_string("invalid", request)
|
||||
match = vnf._match_version_string("invalid", request)
|
||||
self.assertFalse(match)
|
||||
|
||||
def test_return_version_controller_when_request_path_is_version(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_request_path_is_version(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({'PATH_INFO': 'versions'})
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsInstance(response, VersionController)
|
||||
self.assertIs(mock_vc.return_value, response)
|
||||
|
||||
def test_return_version_controller_when_request_path_is_empty(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_request_path_is_empty(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({'PATH_INFO': '/'})
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsInstance(response, VersionController)
|
||||
self.assertIs(mock_vc.return_value, response)
|
||||
|
||||
def test_request_path_contains_valid_version(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_request_path_contains_valid_version(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
major = 1
|
||||
minor = 0
|
||||
request = webob.Request({'PATH_INFO':
|
||||
'v{0}.{1}/resource'.format(major, minor)})
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsNone(response)
|
||||
self.assertEqual(major, request.environ['api.major'])
|
||||
self.assertEqual(minor, request.environ['api.minor'])
|
||||
|
||||
def test_removes_version_from_request_path(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_removes_version_from_request_path(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
expected_path = 'resource'
|
||||
request = webob.Request({'PATH_INFO': 'v1.0/%s' % expected_path})
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsNone(response)
|
||||
self.assertEqual(expected_path, request.path_info_peek())
|
||||
|
||||
def test_request_path_contains_unknown_version(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_request_path_contains_unknown_version(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({'PATH_INFO': 'v2.0/resource'})
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsInstance(response, VersionController)
|
||||
self.assertIs(mock_vc.return_value, response)
|
||||
|
||||
def test_accept_header_contains_valid_version(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_accept_header_contains_valid_version(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
major = 1
|
||||
minor = 0
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers['Accept'] = 'application/vnd.openstack.clustering-v1.0'
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsNone(response)
|
||||
self.assertEqual(major, request.environ['api.major'])
|
||||
self.assertEqual(minor, request.environ['api.minor'])
|
||||
|
||||
def test_accept_header_contains_unknown_version(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_accept_header_contains_unknown_version(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers['Accept'] = 'application/vnd.openstack.clustering-v2.0'
|
||||
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
|
||||
self.assertIsInstance(response, VersionController)
|
||||
self.assertIs(mock_vc.return_value, response)
|
||||
|
||||
request.headers['Accept'] = 'application/vnd.openstack.clustering-vab'
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
self.assertIsNone(response)
|
||||
|
||||
def test_no_URI_version_accept_header_contains_invalid_MIME_type(self):
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
def test_no_URI_version_accept_with_invalid_MIME_type(self, mock_vc):
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers['Accept'] = 'application/invalidMIMEType'
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
self.assertIsInstance(response, webob.exc.HTTPNotFound)
|
||||
|
||||
request.headers['Accept'] = ''
|
||||
response = version_negotiation.process_request(request)
|
||||
response = vnf.process_request(request)
|
||||
self.assertIsInstance(response, webob.exc.HTTPNotFound)
|
||||
|
||||
def test_check_version_request(self):
|
||||
def test__check_version_request(self, mock_vc):
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers[wsgi.API_VERSION_KEY] = 'clustering 1.0,compute 2.0'
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
|
||||
version_negotiation.check_version_request(request)
|
||||
vnf._check_version_request(request)
|
||||
self.assertIsNotNone(request.version_request)
|
||||
expected = vr.APIVersionRequest('1.0')
|
||||
self.assertEqual(expected, request.version_request)
|
||||
|
||||
def test_check_version_request_default(self):
|
||||
def test__check_version_request_default(self, mock_vc):
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers[wsgi.API_VERSION_KEY] = 'compute 2.0'
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
|
||||
version_negotiation.check_version_request(request)
|
||||
vnf._check_version_request(request)
|
||||
self.assertIsNotNone(request.version_request)
|
||||
expected = vr.APIVersionRequest(wsgi.DEFAULT_API_VERSION)
|
||||
self.assertEqual(expected, request.version_request)
|
||||
|
||||
def test_check_version_request_invalid_format(self):
|
||||
def test__check_version_request_invalid_format(self, mock_vc):
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers[wsgi.API_VERSION_KEY] = 'clustering 2.03'
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
|
||||
ex = self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
version_negotiation.check_version_request,
|
||||
vnf._check_version_request,
|
||||
request)
|
||||
self.assertEqual("API Version String (2.03) is of invalid format. It "
|
||||
"must be of format 'major.minor'.",
|
||||
six.text_type(ex))
|
||||
|
||||
def test_check_version_request_invalid_version(self):
|
||||
def test__check_version_request_invalid_version(self, mock_vc):
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers[wsgi.API_VERSION_KEY] = 'clustering 2.3'
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
|
||||
ex = self.assertRaises(exception.InvalidGlobalAPIVersion,
|
||||
version_negotiation.check_version_request,
|
||||
vnf._check_version_request,
|
||||
request)
|
||||
expected = ("Version 2.3 is not supported by the API. Minimum is "
|
||||
"%(min_ver)s and maximum is %(max_ver)s." %
|
||||
|
@ -192,13 +177,12 @@ class VersionNegotiationMiddlewareTest(base.SenlinTestCase):
|
|||
'max_ver': str(os_ver.max_api_version())})
|
||||
self.assertEqual(expected, six.text_type(ex))
|
||||
|
||||
def test_check_version_request_latest(self):
|
||||
def test__check_version_request_latest(self, mock_vc):
|
||||
request = webob.Request({'PATH_INFO': 'resource'})
|
||||
request.headers[wsgi.API_VERSION_KEY] = 'clustering Latest'
|
||||
version_negotiation = vn.VersionNegotiationFilter(
|
||||
self._version_controller_factory, None, None)
|
||||
vnf = vn.VersionNegotiationFilter(None, None)
|
||||
|
||||
version_negotiation.check_version_request(request)
|
||||
vnf._check_version_request(request)
|
||||
self.assertIsNotNone(request.version_request)
|
||||
expected = os_ver.max_api_version()
|
||||
self.assertEqual(expected, request.version_request)
|
||||
|
|
Loading…
Reference in New Issue