Move files out of the namespace package

Move the public API out of oslo.middleware to oslo_middleware. Retain
the ability to import from the old namespace package for backwards
compatibility for this release cycle.

bp/drop-namespace-packages

Change-Id: If88c65c82b64f096a02f7ec62e019aea4de2f9d3
This commit is contained in:
Doug Hellmann 2015-01-06 12:04:31 -05:00
parent 860cdee514
commit 8e06ca5bd0
25 changed files with 678 additions and 265 deletions

View File

@ -2,5 +2,5 @@
API
=====
.. automodule:: oslo.middleware
.. automodule:: oslo_middleware
:members:

View File

@ -10,14 +10,19 @@
# License for the specific language governing permissions and limitations
# under the License.
__all__ = ['CatchErrors',
'CorrelationId',
'Debug',
'RequestId',
'RequestBodySizeLimiter']
import warnings
from oslo.middleware.catch_errors import CatchErrors
from oslo.middleware.correlation_id import CorrelationId
from oslo.middleware.debug import Debug
from oslo.middleware.request_id import RequestId
from oslo.middleware.sizelimit import RequestBodySizeLimiter
from oslo_middleware import *
def deprecated():
new_name = __name__.replace('.', '_')
warnings.warn(
('The oslo namespace package is deprecated. Please use %s instead.' %
new_name),
DeprecationWarning,
stacklevel=3,
)
deprecated()

View File

@ -1,6 +1,3 @@
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# 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
@ -13,44 +10,4 @@
# License for the specific language governing permissions and limitations
# under the License.
"""Base class(es) for WSGI Middleware."""
import webob.dec
class Middleware(object):
"""Base WSGI middleware wrapper.
These classes require an application to be initialized that will be called
next. By default the middleware will simply call its wrapped app, or you
can override __call__ to customize its behavior.
"""
@classmethod
def factory(cls, global_conf, **local_conf):
"""Factory method for paste.deploy."""
return cls
def __init__(self, application):
self.application = application
def process_request(self, req):
"""Called on each request.
If this returns None, the next application down the stack will be
executed. If it returns a response then that response will be returned
and execution will stop here.
"""
return None
def process_response(self, response):
"""Do whatever you'd like to the response."""
return response
@webob.dec.wsgify
def __call__(self, req):
response = self.process_request(req)
if response:
return response
response = req.get_response(self.application)
return self.process_response(response)
from oslo_middleware.base import * # noqa

View File

@ -1,6 +1,3 @@
# Copyright (c) 2013 NEC Corporation
# All Rights Reserved.
#
# 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
@ -13,31 +10,4 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
import webob.dec
import webob.exc
from oslo.middleware import base
from oslo.middleware.i18n import _LE
LOG = logging.getLogger(__name__)
class CatchErrors(base.Middleware):
"""Middleware that provides high-level error handling.
It catches all exceptions from subsequent applications in WSGI pipeline
to hide internal errors from API response.
"""
@webob.dec.wsgify
def __call__(self, req):
try:
response = req.get_response(self.application)
except Exception:
LOG.exception(_LE('An error occurred during '
'processing the request: %s'))
response = webob.exc.HTTPInternalServerError()
return response
from oslo_middleware.catch_errors import * # noqa

View File

@ -1,6 +1,3 @@
# Copyright (c) 2013 Rackspace Hosting
# All Rights Reserved.
#
# 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
@ -13,15 +10,4 @@
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from oslo.middleware import base
class CorrelationId(base.Middleware):
"Middleware that attaches a correlation id to WSGI request"
def process_request(self, req):
correlation_id = (req.headers.get("X_CORRELATION_ID") or
str(uuid.uuid4()))
req.headers['X_CORRELATION_ID'] = correlation_id
from oslo_middleware.correlation_id import * # noqa

View File

@ -1,6 +1,3 @@
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# 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
@ -13,48 +10,4 @@
# License for the specific language governing permissions and limitations
# under the License.
"""Debug middleware"""
from __future__ import print_function
import sys
import six
import webob.dec
from oslo.middleware import base
class Debug(base.Middleware):
"""Helper class that returns debug information.
Can be inserted into any WSGI application chain to get information about
the request and response.
"""
@webob.dec.wsgify
def __call__(self, req):
print(("*" * 40) + " REQUEST ENVIRON")
for key, value in req.environ.items():
print(key, "=", value)
print()
resp = req.get_response(self.application)
print(("*" * 40) + " RESPONSE HEADERS")
for (key, value) in six.iteritems(resp.headers):
print(key, "=", value)
print()
resp.app_iter = self.print_generator(resp.app_iter)
return resp
@staticmethod
def print_generator(app_iter):
"""Prints the contents of a wrapper string iterator when iterated."""
print(("*" * 40) + " BODY")
for part in app_iter:
sys.stdout.write(part)
sys.stdout.flush()
yield part
print()
from oslo_middleware.debug import * # noqa

View File

@ -1,6 +1,3 @@
# Copyright (c) 2013 NEC Corporation
# All Rights Reserved.
#
# 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
@ -13,28 +10,4 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_context import context
import webob.dec
from oslo.middleware import base
ENV_REQUEST_ID = 'openstack.request_id'
HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id'
class RequestId(base.Middleware):
"""Middleware that ensures request ID.
It ensures to assign request ID for each API request and set it to
request environment. The request ID is also added to API response.
"""
@webob.dec.wsgify
def __call__(self, req):
req_id = context.generate_request_id()
req.environ[ENV_REQUEST_ID] = req_id
response = req.get_response(self.application)
if HTTP_RESP_HEADER_REQUEST_ID not in response.headers:
response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, req_id)
return response
from oslo_middleware.request_id import * # noqa

View File

@ -1,5 +1,3 @@
# Copyright (c) 2012 Red Hat, Inc.
#
# 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
@ -12,84 +10,4 @@
# License for the specific language governing permissions and limitations
# under the License.
"""
Request Body limiting middleware.
"""
from oslo.config import cfg
from oslo.config import cfgfilter
import webob.dec
import webob.exc
from oslo.middleware import base
from oslo.middleware.i18n import _
_oldopts = [cfg.DeprecatedOpt('osapi_max_request_body_size',
group='DEFAULT'),
cfg.DeprecatedOpt('max_request_body_size',
group='DEFAULT')]
_opts = [
# default request size is 112k
cfg.IntOpt('max_request_body_size',
default=114688,
help='The maximum body size for each '
' request, in bytes.',
deprecated_opts=_oldopts)
]
CONF = cfgfilter.ConfigFilter(cfg.CONF)
CONF.register_opts(_opts, group='oslo_middleware')
class LimitingReader(object):
"""Reader to limit the size of an incoming request."""
def __init__(self, data, limit):
"""Initiates LimitingReader object.
:param data: Underlying data object
:param limit: maximum number of bytes the reader should allow
"""
self.data = data
self.limit = limit
self.bytes_read = 0
def __iter__(self):
for chunk in self.data:
self.bytes_read += len(chunk)
if self.bytes_read > self.limit:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
else:
yield chunk
def read(self, i=None):
# NOTE(jamielennox): We can't simply provide the default to the read()
# call as the expected default differs between mod_wsgi and eventlet
if i is None:
result = self.data.read()
else:
result = self.data.read(i)
self.bytes_read += len(result)
if self.bytes_read > self.limit:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
return result
class RequestBodySizeLimiter(base.Middleware):
"""Limit the size of incoming requests."""
@webob.dec.wsgify
def __call__(self, req):
max_size = CONF.oslo_middleware.max_request_body_size
if (req.content_length is not None and
req.content_length > max_size):
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
if req.content_length is None and req.is_body_readable:
limiter = LimitingReader(req.body_file, max_size)
req.body_file = limiter
return self.application
from oslo_middleware.sizelimit import * # noqa

View File

@ -0,0 +1,23 @@
# 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.
__all__ = ['CatchErrors',
'CorrelationId',
'Debug',
'RequestId',
'RequestBodySizeLimiter']
from oslo_middleware.catch_errors import CatchErrors
from oslo_middleware.correlation_id import CorrelationId
from oslo_middleware.debug import Debug
from oslo_middleware.request_id import RequestId
from oslo_middleware.sizelimit import RequestBodySizeLimiter

56
oslo_middleware/base.py Normal file
View File

@ -0,0 +1,56 @@
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# 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.
"""Base class(es) for WSGI Middleware."""
import webob.dec
class Middleware(object):
"""Base WSGI middleware wrapper.
These classes require an application to be initialized that will be called
next. By default the middleware will simply call its wrapped app, or you
can override __call__ to customize its behavior.
"""
@classmethod
def factory(cls, global_conf, **local_conf):
"""Factory method for paste.deploy."""
return cls
def __init__(self, application):
self.application = application
def process_request(self, req):
"""Called on each request.
If this returns None, the next application down the stack will be
executed. If it returns a response then that response will be returned
and execution will stop here.
"""
return None
def process_response(self, response):
"""Do whatever you'd like to the response."""
return response
@webob.dec.wsgify
def __call__(self, req):
response = self.process_request(req)
if response:
return response
response = req.get_response(self.application)
return self.process_response(response)

View File

@ -0,0 +1,43 @@
# Copyright (c) 2013 NEC Corporation
# All Rights Reserved.
#
# 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 logging
import webob.dec
import webob.exc
from oslo_middleware import base
from oslo_middleware.i18n import _LE
LOG = logging.getLogger(__name__)
class CatchErrors(base.Middleware):
"""Middleware that provides high-level error handling.
It catches all exceptions from subsequent applications in WSGI pipeline
to hide internal errors from API response.
"""
@webob.dec.wsgify
def __call__(self, req):
try:
response = req.get_response(self.application)
except Exception:
LOG.exception(_LE('An error occurred during '
'processing the request: %s'))
response = webob.exc.HTTPInternalServerError()
return response

View File

@ -0,0 +1,27 @@
# Copyright (c) 2013 Rackspace Hosting
# All Rights Reserved.
#
# 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 uuid
from oslo_middleware import base
class CorrelationId(base.Middleware):
"Middleware that attaches a correlation id to WSGI request"
def process_request(self, req):
correlation_id = (req.headers.get("X_CORRELATION_ID") or
str(uuid.uuid4()))
req.headers['X_CORRELATION_ID'] = correlation_id

60
oslo_middleware/debug.py Normal file
View File

@ -0,0 +1,60 @@
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# 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.
"""Debug middleware"""
from __future__ import print_function
import sys
import six
import webob.dec
from oslo_middleware import base
class Debug(base.Middleware):
"""Helper class that returns debug information.
Can be inserted into any WSGI application chain to get information about
the request and response.
"""
@webob.dec.wsgify
def __call__(self, req):
print(("*" * 40) + " REQUEST ENVIRON")
for key, value in req.environ.items():
print(key, "=", value)
print()
resp = req.get_response(self.application)
print(("*" * 40) + " RESPONSE HEADERS")
for (key, value) in six.iteritems(resp.headers):
print(key, "=", value)
print()
resp.app_iter = self.print_generator(resp.app_iter)
return resp
@staticmethod
def print_generator(app_iter):
"""Prints the contents of a wrapper string iterator when iterated."""
print(("*" * 40) + " BODY")
for part in app_iter:
sys.stdout.write(part)
sys.stdout.flush()
yield part
print()

View File

@ -20,7 +20,7 @@ __all__ = [
import copy
from oslo.middleware import sizelimit
from oslo_middleware import sizelimit
def list_opts():
@ -42,4 +42,4 @@ def list_opts():
:returns: a list of (group_name, opts) tuples
"""
return [('oslo_middleware', copy.deepcopy(sizelimit._opts))]
return [('oslo_middleware', copy.deepcopy(sizelimit._opts))]

View File

@ -0,0 +1,40 @@
# Copyright (c) 2013 NEC Corporation
# All Rights Reserved.
#
# 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_context import context
import webob.dec
from oslo_middleware import base
ENV_REQUEST_ID = 'openstack.request_id'
HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id'
class RequestId(base.Middleware):
"""Middleware that ensures request ID.
It ensures to assign request ID for each API request and set it to
request environment. The request ID is also added to API response.
"""
@webob.dec.wsgify
def __call__(self, req):
req_id = context.generate_request_id()
req.environ[ENV_REQUEST_ID] = req_id
response = req.get_response(self.application)
if HTTP_RESP_HEADER_REQUEST_ID not in response.headers:
response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, req_id)
return response

View File

@ -0,0 +1,95 @@
# Copyright (c) 2012 Red Hat, Inc.
#
# 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.
"""
Request Body limiting middleware.
"""
from oslo.config import cfg
from oslo.config import cfgfilter
import webob.dec
import webob.exc
from oslo_middleware import base
from oslo_middleware.i18n import _
_oldopts = [cfg.DeprecatedOpt('osapi_max_request_body_size',
group='DEFAULT'),
cfg.DeprecatedOpt('max_request_body_size',
group='DEFAULT')]
_opts = [
# default request size is 112k
cfg.IntOpt('max_request_body_size',
default=114688,
help='The maximum body size for each '
' request, in bytes.',
deprecated_opts=_oldopts)
]
CONF = cfgfilter.ConfigFilter(cfg.CONF)
CONF.register_opts(_opts, group='oslo_middleware')
class LimitingReader(object):
"""Reader to limit the size of an incoming request."""
def __init__(self, data, limit):
"""Initiates LimitingReader object.
:param data: Underlying data object
:param limit: maximum number of bytes the reader should allow
"""
self.data = data
self.limit = limit
self.bytes_read = 0
def __iter__(self):
for chunk in self.data:
self.bytes_read += len(chunk)
if self.bytes_read > self.limit:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
else:
yield chunk
def read(self, i=None):
# NOTE(jamielennox): We can't simply provide the default to the read()
# call as the expected default differs between mod_wsgi and eventlet
if i is None:
result = self.data.read()
else:
result = self.data.read(i)
self.bytes_read += len(result)
if self.bytes_read > self.limit:
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
return result
class RequestBodySizeLimiter(base.Middleware):
"""Limit the size of incoming requests."""
@webob.dec.wsgify
def __call__(self, req):
max_size = CONF.oslo_middleware.max_request_body_size
if (req.content_length is not None and
req.content_length > max_size):
msg = _("Request is too large.")
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg)
if req.content_length is None and req.is_body_readable:
limiter = LimitingReader(req.body_file, max_size)
req.body_file = limiter
return self.application

View File

View File

@ -0,0 +1,47 @@
# Copyright (c) 2013 NEC Corporation
# All Rights Reserved.
#
# 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 mock
from oslotest import base as test_base
import webob.dec
import webob.exc
from oslo_middleware import catch_errors
class CatchErrorsTest(test_base.BaseTestCase):
def _test_has_request_id(self, application, expected_code=None):
app = catch_errors.CatchErrors(application)
req = webob.Request.blank('/test')
res = req.get_response(app)
self.assertEqual(expected_code, res.status_int)
def test_success_response(self):
@webob.dec.wsgify
def application(req):
return 'Hello, World!!!'
self._test_has_request_id(application, webob.exc.HTTPOk.code)
def test_internal_server_error(self):
@webob.dec.wsgify
def application(req):
raise Exception()
with mock.patch.object(catch_errors.LOG, 'exception') as log_exc:
self._test_has_request_id(application,
webob.exc.HTTPInternalServerError.code)
self.assertEqual(1, log_exc.call_count)

View File

@ -0,0 +1,53 @@
# Copyright (c) 2013 Rackspace Hosting
# All Rights Reserved.
#
# 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 uuid
import mock
from oslotest import base as test_base
from oslotest import moxstubout
from oslo_middleware import correlation_id
class CorrelationIdTest(test_base.BaseTestCase):
def setUp(self):
super(CorrelationIdTest, self).setUp()
self.stubs = self.useFixture(moxstubout.MoxStubout()).stubs
def test_process_request(self):
app = mock.Mock()
req = mock.Mock()
req.headers = {}
mock_uuid4 = mock.Mock()
mock_uuid4.return_value = "fake_uuid"
self.stubs.Set(uuid, 'uuid4', mock_uuid4)
middleware = correlation_id.CorrelationId(app)
middleware(req)
self.assertEqual(req.headers.get("X_CORRELATION_ID"), "fake_uuid")
def test_process_request_should_not_regenerate_correlation_id(self):
app = mock.Mock()
req = mock.Mock()
req.headers = {"X_CORRELATION_ID": "correlation_id"}
middleware = correlation_id.CorrelationId(app)
middleware(req)
self.assertEqual(req.headers.get("X_CORRELATION_ID"), "correlation_id")

View File

@ -0,0 +1,37 @@
# Copyright (c) 2013 NEC Corporation
# All Rights Reserved.
#
# 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 oslotest import base as test_base
from testtools import matchers
import webob
import webob.dec
from oslo_middleware import request_id
class RequestIdTest(test_base.BaseTestCase):
def test_generate_request_id(self):
@webob.dec.wsgify
def application(req):
return req.environ[request_id.ENV_REQUEST_ID]
app = request_id.RequestId(application)
req = webob.Request.blank('/test')
res = req.get_response(app)
res_req_id = res.headers.get(request_id.HTTP_RESP_HEADER_REQUEST_ID)
self.assertThat(res_req_id, matchers.StartsWith(b'req-'))
# request-id in request environ is returned as response body
self.assertEqual(res_req_id, res.body)

View File

@ -0,0 +1,108 @@
# Copyright (c) 2012 Red Hat, Inc.
#
# 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 oslotest import base as test_base
import six
import webob
from oslo.config import fixture as config
from oslo_middleware import sizelimit
class TestLimitingReader(test_base.BaseTestCase):
def test_limiting_reader(self):
BYTES = 1024
bytes_read = 0
data = six.StringIO("*" * BYTES)
for chunk in sizelimit.LimitingReader(data, BYTES):
bytes_read += len(chunk)
self.assertEqual(bytes_read, BYTES)
bytes_read = 0
data = six.StringIO("*" * BYTES)
reader = sizelimit.LimitingReader(data, BYTES)
byte = reader.read(1)
while len(byte) != 0:
bytes_read += 1
byte = reader.read(1)
self.assertEqual(bytes_read, BYTES)
def test_read_default_value(self):
BYTES = 1024
data_str = "*" * BYTES
data = six.StringIO(data_str)
reader = sizelimit.LimitingReader(data, BYTES)
res = reader.read()
self.assertEqual(data_str, res)
def test_limiting_reader_fails(self):
BYTES = 1024
def _consume_all_iter():
bytes_read = 0
data = six.StringIO("*" * BYTES)
for chunk in sizelimit.LimitingReader(data, BYTES - 1):
bytes_read += len(chunk)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
_consume_all_iter)
def _consume_all_read():
bytes_read = 0
data = six.StringIO("*" * BYTES)
reader = sizelimit.LimitingReader(data, BYTES - 1)
byte = reader.read(1)
while len(byte) != 0:
bytes_read += 1
byte = reader.read(1)
self.assertRaises(webob.exc.HTTPRequestEntityTooLarge,
_consume_all_read)
class TestRequestBodySizeLimiter(test_base.BaseTestCase):
def setUp(self):
super(TestRequestBodySizeLimiter, self).setUp()
fixture = self.useFixture(config.Config(sizelimit.CONF))
self.MAX_REQUEST_BODY_SIZE = \
fixture.conf.oslo_middleware.max_request_body_size
@webob.dec.wsgify()
def fake_app(req):
return webob.Response(req.body)
self.middleware = sizelimit.RequestBodySizeLimiter(fake_app)
self.request = webob.Request.blank('/', method='POST')
def test_content_length_acceptable(self):
self.request.headers['Content-Length'] = self.MAX_REQUEST_BODY_SIZE
self.request.body = b"0" * self.MAX_REQUEST_BODY_SIZE
response = self.request.get_response(self.middleware)
self.assertEqual(response.status_int, 200)
def test_content_length_too_large(self):
self.request.headers['Content-Length'] = self.MAX_REQUEST_BODY_SIZE + 1
self.request.body = b"0" * (self.MAX_REQUEST_BODY_SIZE + 1)
response = self.request.get_response(self.middleware)
self.assertEqual(response.status_int, 413)
def test_request_too_large_no_content_length(self):
self.request.body = b"0" * (self.MAX_REQUEST_BODY_SIZE + 1)
self.request.headers['Content-Length'] = None
response = self.request.get_response(self.middleware)
self.assertEqual(response.status_int, 413)

View File

@ -22,12 +22,13 @@ classifier =
[files]
packages =
oslo
oslo_middleware
namespace_packages =
oslo
[entry_points]
oslo.config.opts =
oslo.middleware = oslo.middleware.opts:list_opts
oslo.middleware = oslo_middleware.opts:list_opts
[build_sphinx]
source-dir = doc/source

61
tests/test_warning.py Normal file
View File

@ -0,0 +1,61 @@
# 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 imp
import os
import warnings
import mock
from oslotest import base as test_base
import six
class DeprecationWarningTest(test_base.BaseTestCase):
@mock.patch('warnings.warn')
def test_warning(self, mock_warn):
import oslo.middleware
imp.reload(oslo.middleware)
self.assertTrue(mock_warn.called)
args = mock_warn.call_args
self.assertIn('oslo_middleware', args[0][0])
self.assertIn('deprecated', args[0][0])
self.assertTrue(issubclass(args[0][1], DeprecationWarning))
def test_real_warning(self):
with warnings.catch_warnings(record=True) as warning_msgs:
warnings.resetwarnings()
warnings.simplefilter('always', DeprecationWarning)
import oslo.middleware
# Use a separate function to get the stack level correct
# so we know the message points back to this file. This
# corresponds to an import or reload, which isn't working
# inside the test under Python 3.3. That may be due to a
# difference in the import implementation not triggering
# warnings properly when the module is reloaded, or
# because the warnings module is mostly implemented in C
# and something isn't cleanly resetting the global state
# used to track whether a warning needs to be
# emitted. Whatever the cause, we definitely see the
# warnings.warn() being invoked on a reload (see the test
# above) and warnings are reported on the console when we
# run the tests. A simpler test script run outside of
# testr does correctly report the warnings.
def foo():
oslo.middleware.deprecated()
foo()
self.assertEqual(1, len(warning_msgs))
msg = warning_msgs[0]
self.assertIn('oslo_middleware', six.text_type(msg.message))
self.assertEqual('test_warning.py', os.path.basename(msg.filename))

View File

@ -1,6 +1,6 @@
[tox]
minversion = 1.6
envlist = py26,py27,py33,py34,pypy,pep8
envlist = py33,py34,py26,py27,pypy,pep8
# NOTE(dhellmann): We cannot set skipdist=True
# for oslo libraries because of the namespace package.
#skipsdist = True
@ -37,4 +37,4 @@ ignore = E123,E125,H305,H803,H904
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,__init__.py
[hacking]
import_exceptions = oslo.middleware.i18n
import_exceptions = oslo_middleware.i18n