Refactor modules used by senlin-api

This patch moves wsgi into api module, merge JSON serializers and
deserializers into the same module for easier maintenance.

Change-Id: I579de8701c69ef6e231762b9eb3192dc3208a9de
This commit is contained in:
tengqm 2016-01-15 09:47:48 -05:00
parent 7c58fa23e9
commit 4203e1a779
34 changed files with 403 additions and 389 deletions

View File

@ -36,10 +36,10 @@ from oslo_log import log as logging
from oslo_service import systemd
import six
from senlin.api.common import wsgi
from senlin.common import config
from senlin.common.i18n import _LI
from senlin.common import messaging
from senlin.common import wsgi
from senlin import version
_lazy.enable_lazy()

View File

@ -4,7 +4,7 @@
pipeline = request_id faultwrap ssl versionnegotiation webhook authtoken context trust apiv1app
[app:apiv1app]
paste.app_factory = senlin.common.wsgi:app_factory
paste.app_factory = senlin.api.common.wsgi:app_factory
senlin.app_factory = senlin.api.openstack.v1:API
# Middleware to set x-openstack-request-id in http response header
@ -12,26 +12,26 @@ senlin.app_factory = senlin.api.openstack.v1:API
paste.filter_factory = oslo_middleware.request_id:RequestId.factory
[filter:faultwrap]
paste.filter_factory = senlin.common.wsgi:filter_factory
paste.filter_factory = senlin.api.common.wsgi:filter_factory
senlin.filter_factory = senlin.api.openstack:faultwrap_filter
[filter:context]
paste.filter_factory = senlin.common.wsgi:filter_factory
paste.filter_factory = senlin.api.common.wsgi:filter_factory
senlin.filter_factory = senlin.api.openstack:contextmiddleware_filter
[filter:ssl]
paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory
[filter:versionnegotiation]
paste.filter_factory = senlin.common.wsgi:filter_factory
paste.filter_factory = senlin.api.common.wsgi:filter_factory
senlin.filter_factory = senlin.api.openstack:version_negotiation_filter
[filter:trust]
paste.filter_factory = senlin.common.wsgi:filter_factory
paste.filter_factory = senlin.api.common.wsgi:filter_factory
senlin.filter_factory = senlin.api.openstack:trustmiddleware_filter
[filter:webhook]
paste.filter_factory = senlin.common.wsgi:filter_factory
paste.filter_factory = senlin.api.common.wsgi:filter_factory
senlin.filter_factory = senlin.api.openstack:webhookmiddleware_filter
# Auth middleware that validates token against keystone

View File

View File

@ -0,0 +1,92 @@
# 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.
"""
Utility methods for serializing responses
"""
import datetime
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
import six
import webob
from senlin.common import exception
from senlin.common.i18n import _
LOG = logging.getLogger(__name__)
def is_json_content_type(request):
content_type = request.content_type
if not content_type or content_type.startswith('text/plain'):
content_type = 'application/json'
if (content_type in ('JSON', 'application/json') and
request.body.startswith(b'{')):
return True
return False
class JSONRequestDeserializer(object):
def has_body(self, request):
"""Returns whether a Webob.Request object will possess an entity body.
:param request: A Webob.Request object
"""
if request is None or request.content_length is None:
return False
if request.content_length > 0 and is_json_content_type(request):
return True
return False
def from_json(self, datastring):
try:
if len(datastring) > cfg.CONF.max_json_body_size:
msg = _('JSON body size (%(len)s bytes) exceeds maximum '
'allowed size (%(limit)s bytes).'
) % {'len': len(datastring),
'limit': cfg.CONF.max_json_body_size}
raise exception.RequestLimitExceeded(message=msg)
return jsonutils.loads(datastring)
except ValueError as ex:
raise webob.exc.HTTPBadRequest(six.text_type(ex))
def default(self, request):
if self.has_body(request):
return {'body': self.from_json(request.body)}
else:
return {}
class JSONResponseSerializer(object):
def to_json(self, data):
def sanitizer(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
return six.text_type(obj)
response = jsonutils.dumps(data, default=sanitizer, sort_keys=True)
LOG.debug("JSON response : %s" % response)
return response
def default(self, response, result):
response.content_type = 'application/json'
response.body = encodeutils.safe_encode(self.to_json(result))

View File

@ -1,20 +1,14 @@
# 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
#
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2013 IBM Corp.
# All Rights Reserved.
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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.
# 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.
"""
Utility methods for working with WSGI servers
@ -37,7 +31,6 @@ import functools
from oslo_config import cfg
import oslo_i18n
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import importutils
from paste import deploy
import routes
@ -46,12 +39,12 @@ import six
import webob.dec
import webob.exc
from senlin.api.common import serializers
from senlin.common import exception
from senlin.common.i18n import _
from senlin.common.i18n import _LE
from senlin.common.i18n import _LI
from senlin.common.i18n import _LW
from senlin.common import serializers
LOG = logging.getLogger(__name__)
@ -643,52 +636,6 @@ class Request(webob.Request):
return self.accept_language.best_match(all_languages)
def is_json_content_type(request):
content_type = request.content_type
if not content_type or content_type.startswith('text/plain'):
content_type = 'application/json'
if (content_type in ('JSON', 'application/json') and
request.body.startswith(b'{')):
return True
return False
class JSONRequestDeserializer(object):
def has_body(self, request):
"""Returns whether a Webob.Request object will possess an entity body.
:param request: A Webob.Request object
"""
if request is None or request.content_length is None:
return False
if request.content_length > 0 and is_json_content_type(request):
return True
return False
def from_json(self, datastring):
try:
if len(datastring) > cfg.CONF.max_json_body_size:
msg = _('JSON body size (%(len)s bytes) exceeds maximum '
'allowed size (%(limit)s bytes).'
) % {'len': len(datastring),
'limit': cfg.CONF.max_json_body_size}
raise exception.RequestLimitExceeded(message=msg)
return jsonutils.loads(datastring)
except ValueError as ex:
raise webob.exc.HTTPBadRequest(six.text_type(ex))
def default(self, request):
if self.has_body(request):
return {'body': self.from_json(request.body)}
else:
return {}
class Resource(object):
"""WSGI app that handles (de)serialization and controller dispatch.

View File

@ -14,9 +14,9 @@ from oslo_config import cfg
from oslo_middleware import request_id as oslo_request_id
from oslo_utils import encodeutils
from senlin.api.common import wsgi
from senlin.common import context
from senlin.common import exception
from senlin.common import wsgi
class ContextMiddleware(wsgi.Middleware):

View File

@ -22,9 +22,9 @@ from oslo_config import cfg
import six
import webob
from senlin.api.common import serializers
from senlin.api.common import wsgi
from senlin.common import exception
from senlin.common import serializers
from senlin.common import wsgi
class Fault(object):

View File

@ -10,9 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from senlin.api.common import wsgi
from senlin.common import context
from senlin.common import exception
from senlin.common import wsgi
from senlin.db import api as db_api
from senlin.drivers import base as driver_base

View File

@ -18,11 +18,11 @@ return
"""
import re
import webob
from oslo_log import log as logging
import webob
from senlin.common import wsgi
from senlin.api.common import wsgi
LOG = logging.getLogger(__name__)

View File

@ -14,10 +14,10 @@ from oslo_log import log as logging
import six
from six.moves.urllib import parse as urlparse
from senlin.api.common import wsgi
from senlin.common import context
from senlin.common import exception as exc
from senlin.common.i18n import _
from senlin.common import wsgi
from senlin.drivers import base as driver_base
from senlin.rpc import client as rpc

View File

@ -13,6 +13,7 @@
import routes
from senlin.api.common import wsgi
from senlin.api.openstack.v1 import actions
from senlin.api.openstack.v1 import build_info
from senlin.api.openstack.v1 import cluster_policies
@ -25,7 +26,6 @@ from senlin.api.openstack.v1 import profile_types
from senlin.api.openstack.v1 import profiles
from senlin.api.openstack.v1 import receivers
from senlin.api.openstack.v1 import webhooks
from senlin.common import wsgi
class API(wsgi.Router):

View File

@ -13,12 +13,12 @@
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common.i18n import _
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -119,8 +119,8 @@ class ActionController(object):
def create_resource(options):
'''Actions factory method.'''
"""Actions factory method."""
return wsgi.Resource(ActionController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -13,9 +13,9 @@
from oslo_config import cfg
from senlin.api.openstack.v1 import util
from senlin.common import serializers
from senlin.common import wsgi
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.rpc import client as rpc_client
@ -43,7 +43,7 @@ class BuildInfoController(object):
def create_resource(options):
'''BuildInfo factory method.'''
deserializer = wsgi.JSONRequestDeserializer()
deserializer = serializers.JSONRequestDeserializer()
serializer = serializers.JSONResponseSerializer()
return wsgi.Resource(BuildInfoController(options), deserializer,
serializer)

View File

@ -16,11 +16,11 @@ ClusterPolicies endpoint for Senlin v1 ReST API.
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -71,5 +71,5 @@ def create_resource(options):
'''ClusterPolicies resource factory method.'''
return wsgi.Resource(ClusterPolicyController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -19,13 +19,13 @@ from oslo_config import cfg
import six
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common import exception as senlin_exc
from senlin.common.i18n import _
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -366,8 +366,8 @@ class ClusterController(object):
def create_resource(options):
'''Clusters resource factory method.'''
"""Clusters resource factory method."""
return wsgi.Resource(ClusterController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -12,11 +12,11 @@
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -80,5 +80,5 @@ def create_resource(options):
'''Events factory method.'''
return wsgi.Resource(EventController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -16,12 +16,12 @@ Node endpoint for Senlin v1 ReST API.
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common.i18n import _
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -166,8 +166,8 @@ class NodeController(object):
def create_resource(options):
'''Nodes resource factory method.'''
"""Nodes resource factory method."""
return wsgi.Resource(NodeController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -16,12 +16,12 @@ Policy endpoint for Senlin v1 ReST API.
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common.i18n import _
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -121,8 +121,8 @@ class PolicyController(object):
def create_resource(options):
'''Policies resource factory method.'''
"""Policies resource factory method."""
return wsgi.Resource(PolicyController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -10,15 +10,15 @@
# License for the specific language governing permissions and limitations
# under the License.
'''
"""
Policy type endpoint for Senlin v1 ReST API.
'''
"""
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.common import serializers
from senlin.common import wsgi
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.rpc import client as rpc_client
@ -46,8 +46,8 @@ class PolicyTypeController(object):
def create_resource(options):
'''Policy type resource factory method.'''
"""Policy type resource factory method."""
return wsgi.Resource(PolicyTypeController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -10,15 +10,15 @@
# License for the specific language governing permissions and limitations
# under the License.
'''
"""
Profile type endpoint for Senlin v1 ReST API.
'''
"""
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.common import serializers
from senlin.common import wsgi
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.rpc import client as rpc_client
@ -48,8 +48,8 @@ class ProfileTypeController(object):
def create_resource(options):
'''Profile types resource factory method.'''
"""Profile types resource factory method."""
return wsgi.Resource(ProfileTypeController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -16,12 +16,12 @@ Profile endpoint for Senlin v1 ReST API.
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common.i18n import _
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -142,5 +142,5 @@ def create_resource(options):
'''Profiles resource factory method.'''
return wsgi.Resource(ProfileController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -16,12 +16,12 @@ Webhook endpoint for Senlin v1 ReST API.
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common.i18n import _
from senlin.common import serializers
from senlin.common import utils
from senlin.common import wsgi
from senlin.rpc import client as rpc_client
@ -141,5 +141,5 @@ def create_resource(options):
"""Receiver resource factory method."""
return wsgi.Resource(ReceiverController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -16,9 +16,9 @@ Webhook endpoint for Senlin v1 ReST API.
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.common import serializers
from senlin.common import wsgi
from senlin.api.common import serializers
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.rpc import client as rpc_client
@ -52,5 +52,5 @@ def create_resource(options):
"""Webhooks resource factory method."""
return wsgi.Resource(WebhookController(options),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
serializers.JSONResponseSerializer())

View File

@ -21,8 +21,8 @@ import socket
from oslo_config import cfg
from oslo_log import log as logging
from senlin.api.common import wsgi
from senlin.common.i18n import _
from senlin.common import wsgi
paste_deploy_group = cfg.OptGroup('paste_deploy')
paste_deploy_opts = [

View File

@ -1,41 +0,0 @@
# 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.
"""
Utility methods for serializing responses
"""
import datetime
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
import six
LOG = logging.getLogger(__name__)
class JSONResponseSerializer(object):
def to_json(self, data):
def sanitizer(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
return six.text_type(obj)
response = jsonutils.dumps(data, default=sanitizer, sort_keys=True)
LOG.debug("JSON response : %s" % response)
return response
def default(self, response, result):
response.content_type = 'application/json'
response.body = encodeutils.safe_encode(self.to_json(result))

View File

View File

@ -0,0 +1,202 @@
# 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 oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import timeutils as tu
import six
import webob
from senlin.api.common import serializers
from senlin.api.common import wsgi
from senlin.common import exception
from senlin.tests.unit.common import base
class JSONRequestDeserializerTest(base.SenlinTestCase):
def test_has_body_no_content_length(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('asdf')
request.headers.pop('Content-Length')
request.headers['Content-Type'] = 'application/json'
obj = serializers.JSONRequestDeserializer()
self.assertFalse(obj.has_body(request))
def test_has_body_zero_content_length(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('asdf')
request.headers['Content-Length'] = 0
request.headers['Content-Type'] = 'application/json'
obj = serializers.JSONRequestDeserializer()
self.assertFalse(obj.has_body(request))
def test_has_body_has_content_length_no_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
obj = serializers.JSONRequestDeserializer()
self.assertTrue(obj.has_body(request))
def test_has_body_has_content_length_plain_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'text/plain'
obj = serializers.JSONRequestDeserializer()
self.assertTrue(obj.has_body(request))
def test_has_body_has_content_type_malformed(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('asdf')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'application/json'
obj = serializers.JSONRequestDeserializer()
self.assertFalse(obj.has_body(request))
def test_has_body_has_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'application/json'
obj = serializers.JSONRequestDeserializer()
self.assertTrue(obj.has_body(request))
def test_has_body_has_wrong_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'application/xml'
obj = serializers.JSONRequestDeserializer()
self.assertFalse(obj.has_body(request))
def test_has_body_has_aws_content_type_only(self):
request = wsgi.Request.blank('/?ContentType=JSON')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
obj = serializers.JSONRequestDeserializer()
self.assertTrue(obj.has_body(request))
def test_has_body_content_type_with_get(self):
request = wsgi.Request.blank('/')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
obj = serializers.JSONRequestDeserializer()
self.assertTrue(obj.has_body(request))
def test_no_body_no_content_length(self):
request = wsgi.Request.blank('/')
obj = serializers.JSONRequestDeserializer()
self.assertFalse(obj.has_body(request))
def test_from_json(self):
fixture = '{"key": "value"}'
expected = {"key": "value"}
actual = serializers.JSONRequestDeserializer().from_json(fixture)
self.assertEqual(expected, actual)
def test_from_json_malformed(self):
fixture = 'kjasdklfjsklajf'
self.assertRaises(webob.exc.HTTPBadRequest,
serializers.JSONRequestDeserializer().from_json,
fixture)
def test_default_no_body(self):
request = wsgi.Request.blank('/')
actual = serializers.JSONRequestDeserializer().default(request)
expected = {}
self.assertEqual(expected, actual)
def test_default_with_body(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
actual = serializers.JSONRequestDeserializer().default(request)
expected = {"body": {"key": "value"}}
self.assertEqual(expected, actual)
def test_default_with_get_with_body(self):
request = wsgi.Request.blank('/')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
actual = serializers.JSONRequestDeserializer().default(request)
expected = {"body": {"key": "value"}}
self.assertEqual(expected, actual)
def test_default_with_get_with_body_with_aws(self):
request = wsgi.Request.blank('/?ContentType=JSON')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
actual = serializers.JSONRequestDeserializer().default(request)
expected = {"body": {"key": "value"}}
self.assertEqual(expected, actual)
def test_from_json_exceeds_max_json_mb(self):
cfg.CONF.set_override('max_json_body_size', 10, enforce_type=True)
body = jsonutils.dumps(['a'] * cfg.CONF.max_json_body_size)
self.assertTrue(len(body) > cfg.CONF.max_json_body_size)
obj = serializers.JSONRequestDeserializer()
error = self.assertRaises(exception.RequestLimitExceeded,
obj.from_json,
body)
msg = ('Request limit exceeded: JSON body size '
'(%s bytes) exceeds maximum allowed size (%s bytes).'
) % (len(body), cfg.CONF.max_json_body_size)
self.assertEqual(msg, six.text_type(error))
class JSONResponseSerializerTest(base.SenlinTestCase):
def test_to_json(self):
fixture = {"key": "value"}
expected = '{"key": "value"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_to_json_with_date_format_value(self):
test_date = tu.parse_strtime("0001-03-08T02:00:00",
'%Y-%m-%dT%H:%M:%S')
fixture = {"date": test_date}
expected = '{"date": "0001-03-08T02:00:00"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_to_json_with_more_deep_format(self):
val = complex(1, 2)
fixture = {"is_public": True, "v": val}
expected = '{"is_public": true, "v": "(1+2j)"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_default(self):
fixture = {"key": "value"}
response = webob.Response()
serializers.JSONResponseSerializer().default(response, fixture)
self.assertEqual(200, response.status_int)
content_types = filter(lambda h: h[0] == 'Content-Type',
response.headerlist)
# NOTE: filter returns a iterator in python 3.
types = [t for t in content_types]
self.assertEqual(1, len(types))
self.assertEqual('application/json', response.content_type)
self.assertEqual('{"key": "value"}',
encodeutils.safe_decode(response.body))

View File

@ -13,10 +13,10 @@
import mock
from webob import exc
from senlin.api.openstack.v1 import util
from senlin.api.common import util
from senlin.api.common import wsgi
from senlin.common import context
from senlin.common import policy
from senlin.common import wsgi
from senlin.tests.unit.common import base

View File

@ -10,19 +10,19 @@
# License for the specific language governing permissions and limitations
# under the License.
import fixtures
import json
import mock
import six
import socket
import fixtures
import mock
from oslo_config import cfg
from oslo_utils import encodeutils
import six
import stubout
import webob
from oslo_config import cfg
from oslo_utils import encodeutils
from senlin.api.common import serializers
from senlin.api.common import wsgi
from senlin.common import exception
from senlin.common import wsgi
from senlin.tests.unit.common import base
@ -166,7 +166,7 @@ class ResourceTest(base.SenlinTestCase):
request = wsgi.Request.blank('/tests/123', environ=env)
request.body = encodeutils.safe_encode('{"foo" : "value"}')
resource = wsgi.Resource(Controller(),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
None)
# The Resource does not throw webob.HTTPExceptions, since they
@ -190,7 +190,7 @@ class ResourceTest(base.SenlinTestCase):
translated_ex = webob.exc.HTTPBadRequest(message_es)
resource = wsgi.Resource(Controller(),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
None)
def fake_translate_exception(ex, locale):
@ -230,157 +230,28 @@ class ResourceExceptionHandlingTest(base.SenlinTestCase):
request = wsgi.Request.blank('/tests/123', environ=env)
request.body = encodeutils.safe_encode('{"foo": "value"}')
resource = wsgi.Resource(Controller(self.exception),
wsgi.JSONRequestDeserializer(),
serializers.JSONRequestDeserializer(),
None)
e = self.assertRaises(self.exception_catch, resource, request)
e = e.exc if hasattr(e, 'exc') else e
self.assertNotIn(six.text_type(e), self.LOG.output)
class JSONRequestDeserializerTest(base.SenlinTestCase):
def test_has_body_no_content_length(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('asdf')
request.headers.pop('Content-Length')
request.headers['Content-Type'] = 'application/json'
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_zero_content_length(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('asdf')
request.headers['Content-Length'] = 0
request.headers['Content-Type'] = 'application/json'
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_has_content_length_no_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_has_content_length_plain_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'text/plain'
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_has_content_type_malformed(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('asdf')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'application/json'
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_has_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'application/json'
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_has_wrong_content_type(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
request.headers['Content-Type'] = 'application/xml'
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_has_aws_content_type_only(self):
request = wsgi.Request.blank('/?ContentType=JSON')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
def test_has_body_content_type_with_get(self):
request = wsgi.Request.blank('/')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
self.assertIn('Content-Length', request.headers)
self.assertTrue(wsgi.JSONRequestDeserializer().has_body(request))
def test_no_body_no_content_length(self):
request = wsgi.Request.blank('/')
self.assertFalse(wsgi.JSONRequestDeserializer().has_body(request))
def test_from_json(self):
fixture = '{"key": "value"}'
expected = {"key": "value"}
actual = wsgi.JSONRequestDeserializer().from_json(fixture)
self.assertEqual(expected, actual)
def test_from_json_malformed(self):
fixture = 'kjasdklfjsklajf'
self.assertRaises(webob.exc.HTTPBadRequest,
wsgi.JSONRequestDeserializer().from_json, fixture)
def test_default_no_body(self):
request = wsgi.Request.blank('/')
actual = wsgi.JSONRequestDeserializer().default(request)
expected = {}
self.assertEqual(expected, actual)
def test_default_with_body(self):
request = wsgi.Request.blank('/')
request.method = 'POST'
request.body = encodeutils.safe_encode('{"key": "value"}')
actual = wsgi.JSONRequestDeserializer().default(request)
expected = {"body": {"key": "value"}}
self.assertEqual(expected, actual)
def test_default_with_get_with_body(self):
request = wsgi.Request.blank('/')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
actual = wsgi.JSONRequestDeserializer().default(request)
expected = {"body": {"key": "value"}}
self.assertEqual(expected, actual)
def test_default_with_get_with_body_with_aws(self):
request = wsgi.Request.blank('/?ContentType=JSON')
request.method = 'GET'
request.body = encodeutils.safe_encode('{"key": "value"}')
actual = wsgi.JSONRequestDeserializer().default(request)
expected = {"body": {"key": "value"}}
self.assertEqual(expected, actual)
def test_from_json_exceeds_max_json_mb(self):
cfg.CONF.set_override('max_json_body_size', 10, enforce_type=True)
body = json.dumps(['a'] * cfg.CONF.max_json_body_size)
self.assertTrue(len(body) > cfg.CONF.max_json_body_size)
error = self.assertRaises(exception.RequestLimitExceeded,
wsgi.JSONRequestDeserializer().from_json,
body)
msg = ('Request limit exceeded: JSON body size '
'(%s bytes) exceeds maximum allowed size (%s bytes).'
) % (len(body), cfg.CONF.max_json_body_size)
self.assertEqual(msg, six.text_type(error))
class GetSocketTestCase(base.SenlinTestCase):
def setUp(self):
super(GetSocketTestCase, self).setUp()
self.useFixture(fixtures.MonkeyPatch(
"senlin.common.wsgi.get_bind_addr",
"senlin.api.common.wsgi.get_bind_addr",
lambda x, y: ('192.168.0.13', 1234)))
addr_info_list = [(2, 1, 6, '', ('192.168.0.13', 80)),
(2, 2, 17, '', ('192.168.0.13', 80)),
(2, 3, 0, '', ('192.168.0.13', 80))]
self.useFixture(fixtures.MonkeyPatch(
"senlin.common.wsgi.socket.getaddrinfo",
"senlin.api.common.wsgi.socket.getaddrinfo",
lambda *x: addr_info_list))
self.useFixture(fixtures.MonkeyPatch(
"senlin.common.wsgi.time.time",
"senlin.api.common.wsgi.time.time",
mock.Mock(side_effect=[0, 1, 5, 10, 20, 35])))
wsgi.cfg.CONF.senlin_api.cert_file = '/etc/ssl/cert'
wsgi.cfg.CONF.senlin_api.key_file = '/etc/ssl/key'
@ -390,10 +261,10 @@ class GetSocketTestCase(base.SenlinTestCase):
def test_correct_configure_socket(self):
mock_socket = mock.Mock()
self.useFixture(fixtures.MonkeyPatch(
'senlin.common.wsgi.ssl.wrap_socket',
'senlin.api.common.wsgi.ssl.wrap_socket',
mock_socket))
self.useFixture(fixtures.MonkeyPatch(
'senlin.common.wsgi.eventlet.listen',
'senlin.api.common.wsgi.eventlet.listen',
lambda *x, **y: mock_socket))
server = wsgi.Server(name='senlin-api', conf=cfg.CONF.senlin_api)
server.default_port = 1234
@ -417,11 +288,11 @@ class GetSocketTestCase(base.SenlinTestCase):
def test_get_socket_with_bind_problems(self):
self.useFixture(fixtures.MonkeyPatch(
'senlin.common.wsgi.eventlet.listen',
'senlin.api.common.wsgi.eventlet.listen',
mock.Mock(side_effect=(
[wsgi.socket.error(socket.errno.EADDRINUSE)] * 3 + [None]))))
self.useFixture(fixtures.MonkeyPatch(
'senlin.common.wsgi.ssl.wrap_socket',
'senlin.api.common.wsgi.ssl.wrap_socket',
lambda *x, **y: None))
self.assertRaises(RuntimeError,
@ -429,10 +300,10 @@ class GetSocketTestCase(base.SenlinTestCase):
def test_get_socket_with_unexpected_socket_errno(self):
self.useFixture(fixtures.MonkeyPatch(
'senlin.common.wsgi.eventlet.listen',
'senlin.api.common.wsgi.eventlet.listen',
mock.Mock(side_effect=wsgi.socket.error(socket.errno.ENOMEM))))
self.useFixture(fixtures.MonkeyPatch(
'senlin.common.wsgi.ssl.wrap_socket',
'senlin.api.common.wsgi.ssl.wrap_socket',
lambda *x, **y: None))
self.assertRaises(wsgi.socket.error, wsgi.get_socket,
wsgi.cfg.CONF.senlin_api, 1234)

View File

@ -17,8 +17,8 @@ from oslo_log import log
from oslo_messaging._drivers import common as rpc_common
from oslo_utils import encodeutils
from senlin.api.common import wsgi
from senlin.common import consts
from senlin.common import wsgi
from senlin.tests.unit.common import utils

View File

@ -16,8 +16,8 @@ from oslo_utils import encodeutils
from six.moves import http_client
import webob
from senlin.api.common import wsgi
from senlin.api.openstack import versions
from senlin.common import wsgi
from senlin.tests.unit.common import base

View File

@ -1,57 +0,0 @@
# 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 webob
from oslo_utils import encodeutils
from oslo_utils import timeutils as tu
from senlin.common import serializers
from senlin.tests.unit.common import base
class JSONResponseSerializerTest(base.SenlinTestCase):
def test_to_json(self):
fixture = {"key": "value"}
expected = '{"key": "value"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_to_json_with_date_format_value(self):
test_date = tu.parse_strtime("0001-03-08T02:00:00",
'%Y-%m-%dT%H:%M:%S')
fixture = {"date": test_date}
expected = '{"date": "0001-03-08T02:00:00"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_to_json_with_more_deep_format(self):
val = complex(1, 2)
fixture = {"is_public": True, "v": val}
expected = '{"is_public": true, "v": "(1+2j)"}'
actual = serializers.JSONResponseSerializer().to_json(fixture)
self.assertEqual(expected, actual)
def test_default(self):
fixture = {"key": "value"}
response = webob.Response()
serializers.JSONResponseSerializer().default(response, fixture)
self.assertEqual(200, response.status_int)
content_types = filter(lambda h: h[0] == 'Content-Type',
response.headerlist)
# NOTE: filter returns a iterator in python 3.
types = [t for t in content_types]
self.assertEqual(1, len(types))
self.assertEqual('application/json', response.content_type)
self.assertEqual('{"key": "value"}',
encodeutils.safe_decode(response.body))

View File

@ -2,7 +2,7 @@
output_file = etc/senlin/senlin.conf.sample
wrap_width = 119
namespace = senlin.common.config
namespace = senlin.common.wsgi
namespace = senlin.api.common.wsgi
namespace = senlin.engine.health_manager
namespace = keystonemiddleware.auth_token
namespace = oslo.db